managarten/docs/I18N.md
Till JS 22a73943e1 chore: complete ManaCore → Mana rename (docs, go modules, plists, images)
Final cleanup of references missed in previous rename commits:

- Dockerfiles: PUBLIC_MANA_CORE_AUTH_URL → PUBLIC_MANA_AUTH_URL
- Go modules: github.com/manacore/* → github.com/mana/* (7 go.mod files)
- launchd plists: com.manacore.* → com.mana.* (14 files renamed + content)
- Image assets: *_Manacore_AI_Credits* → *_Mana_AI_Credits* (11 files)
- .env.example files: ManaCore brand strings → Mana
- .prettierignore: stale apps/manacore/* paths → apps/mana/*
- Markdown docs (CLAUDE.md, /docs/*): mana-core-auth → mana-auth, etc.

Excluded from rename: .claude/, devlog/, manascore/ (historical content),
client testimonials, blueprints, npm package refs (@mana-core/*).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:26:10 +02:00

5.4 KiB

Internationalization (i18n) im Mana Monorepo

Alle Web-Projekte im Monorepo verwenden svelte-i18n für die Internationalisierung. Diese Dokumentation beschreibt die einheitliche Implementierung.

Übersicht

Projekt Sprachen Default
maerchenzauber de, en, es, fr, it de
mana de, en, es, fr, it de
cards de, en, es, fr, it de
memoro de, en, es, fr, it de
picture de, en de
uload de, en, es, fr, it en

Projektstruktur

Jedes Web-Projekt hat die folgende i18n-Struktur:

apps/web/
└── src/
    └── lib/
        └── i18n/
            ├── index.ts          # Initialisierung & Konfiguration
            └── locales/
                ├── de.json       # Deutsche Übersetzungen
                ├── en.json       # Englische Übersetzungen
                ├── es.json       # Spanische Übersetzungen (optional)
                ├── fr.json       # Französische Übersetzungen (optional)
                └── it.json       # Italienische Übersetzungen (optional)

Implementierung

1. index.ts - Konfiguration

import { browser } from '$app/environment';
import { init, register, locale, waitLocale } from 'svelte-i18n';

// Sprachen registrieren
register('de', () => import('./locales/de.json'));
register('en', () => import('./locales/en.json'));
// ... weitere Sprachen

// Unterstützte Sprachen
export const supportedLocales = ['de', 'en', 'es', 'fr', 'it'] as const;
export type SupportedLocale = (typeof supportedLocales)[number];

const defaultLocale = 'de';

// Initiale Sprache ermitteln
function getInitialLocale(): SupportedLocale {
    if (browser) {
        // 1. localStorage prüfen
        const stored = localStorage.getItem('locale');
        if (stored && supportedLocales.includes(stored as SupportedLocale)) {
            return stored as SupportedLocale;
        }

        // 2. Browser-Sprache prüfen
        const browserLang = navigator.language.split('-')[0];
        if (supportedLocales.includes(browserLang as SupportedLocale)) {
            return browserLang as SupportedLocale;
        }
    }
    return defaultLocale;
}

// i18n initialisieren
init({
    fallbackLocale: defaultLocale,
    initialLocale: getInitialLocale()
});

// Sprache ändern und speichern
export function setLocale(newLocale: SupportedLocale) {
    locale.set(newLocale);
    if (browser) {
        localStorage.setItem('locale', newLocale);
    }
}

export { waitLocale };

2. Locale-Dateien (JSON)

Die Übersetzungen werden als flache oder verschachtelte JSON-Objekte gespeichert:

{
    "nav_login": "Anmelden",
    "nav_register": "Registrieren",
    "common": {
        "save": "Speichern",
        "cancel": "Abbrechen"
    }
}

3. Verwendung in Svelte-Komponenten

<script lang="ts">
    import { t } from 'svelte-i18n';
</script>

<!-- Einfacher Key -->
<button>{$t('nav_login')}</button>

<!-- Verschachtelter Key -->
<button>{$t('common.save')}</button>

<!-- Mit Parametern -->
<p>{$t('welcome', { values: { name: 'Max' } })}</p>

4. Language Switcher

<script lang="ts">
    import { locale } from 'svelte-i18n';
    import { setLocale, supportedLocales } from '$lib/i18n';

    const languages = [
        { code: 'de', name: 'Deutsch', flag: '🇩🇪' },
        { code: 'en', name: 'English', flag: '🇬🇧' }
    ];
</script>

{#each languages as lang}
    <button
        onclick={() => setLocale(lang.code)}
        class:active={$locale === lang.code}
    >
        {lang.flag} {lang.name}
    </button>
{/each}

Neues Projekt einrichten

  1. svelte-i18n installieren:

    pnpm add svelte-i18n
    
  2. i18n-Ordner erstellen:

    mkdir -p src/lib/i18n/locales
    
  3. index.ts kopieren von einem bestehenden Projekt und anpassen

  4. Locale-Dateien erstellen (de.json, en.json, etc.)

  5. In +layout.svelte importieren:

    <script>
        import '$lib/i18n';
    </script>
    

Neue Übersetzung hinzufügen

  1. Key in allen Locale-Dateien hinzufügen:

    // de.json
    { "new_key": "Neue Übersetzung" }
    
    // en.json
    { "new_key": "New translation" }
    
  2. In Komponente verwenden:

    {$t('new_key')}
    

Best Practices

  • Keys: Snake_case verwenden (nav_login, home_title)
  • Namespacing: Präfixe für Bereiche (auth_, nav_, home_, toast_)
  • Fallback: Immer fallbackLocale setzen
  • SSR: waitLocale() in Server-Load-Funktionen verwenden
  • Konsistenz: Gleiche Keys in allen Projekten für gemeinsame Elemente

Fehlerbehebung

Übersetzung wird nicht angezeigt

  1. Prüfen ob Key in allen Locale-Dateien existiert
  2. Prüfen ob $lib/i18n importiert wurde
  3. Browser-Cache leeren

SSR-Fehler

// In +layout.ts oder +page.ts
import { waitLocale } from '$lib/i18n';

export const load = async () => {
    await waitLocale();
    return {};
};

Sprache wechselt nicht

Prüfen ob locale.set() aufgerufen wird und localStorage Zugriff erlaubt ist.

Shared i18n Package

Für gemeinsame Übersetzungen zwischen Projekten kann das Package @mana/shared-i18n verwendet werden (wenn vorhanden).

// In index.ts
import sharedTranslations from '@mana/shared-i18n/de.json';

register('de', async () => {
    const local = await import('./locales/de.json');
    return { ...sharedTranslations, ...local.default };
});