# Internationalisierung (i18n) Dokumentation

Hördle unterstützt vollständige Mehrsprachigkeit (Internationalisierung) für Deutsch und Englisch.

## Übersicht

Die i18n-Implementierung basiert auf [next-intl](https://next-intl-docs.vercel.app/) und nutzt den Next.js App Router mit dynamischen `[locale]`-Segmenten.

## Unterstützte Sprachen

- **Englisch (en)** - Standardsprache
- **Deutsch (de)**

## URL-Struktur

Alle Routen sind lokalisiert:

- `http://localhost:3000/` → Redirect zu `/en` (Standard)
- `http://localhost:3000/de` → Deutsche Version
- `http://localhost:3000/en` → Englische Version
- `http://localhost:3000/de/admin` → Admin-Dashboard (Deutsch)
- `http://localhost:3000/de/Rock` → Rock Genre (Deutsch)
- `http://localhost:3000/de/special/Weihnachtslieder` → Special (Deutsch)

## Architektur

### Verzeichnisstruktur

```
app/
  [locale]/              # Lokalisierte Routen
    layout.tsx           # Root Layout mit i18n Provider
    page.tsx             # Homepage
    admin/
      page.tsx           # Admin Dashboard
    [genre]/
      page.tsx           # Genre-spezifische Seite
    special/
      [name]/
        page.tsx         # Special-Seite

i18n/
  request.ts             # next-intl Konfiguration

messages/
  de.json                # Deutsche Übersetzungen
  en.json                # Englische Übersetzungen

lib/
  i18n.ts                # Helper-Funktionen für lokalisierte DB-Werte
  navigation.ts          # Lokalisierte Navigation (Link, useRouter, etc.)
```

### Übersetzungsdateien

Die Übersetzungen sind in JSON-Dateien unter `messages/` organisiert:

```json
{
  "Common": {
    "loading": "Laden...",
    "error": "Ein Fehler ist aufgetreten"
  },
  "Game": {
    "play": "Abspielen",
    "pause": "Pause",
    "won": "Gewonnen!"
  },
  "Home": {
    "welcome": "Willkommen bei Hördle"
  }
}
```

### Datenbank-Schema

Die folgenden Modelle unterstützen mehrsprachige Felder:

#### Genre
- `name`: JSON `{ "de": "Rock", "en": "Rock" }`
- `subtitle`: JSON `{ "de": "Klassischer Rock", "en": "Classic Rock" }`

#### Special
- `name`: JSON `{ "de": "Weihnachtslieder", "en": "Christmas Songs" }`
- `subtitle`: JSON `{ "de": "Festliche Musik", "en": "Festive Music" }`

#### News
- `title`: JSON `{ "de": "Neues Feature", "en": "New Feature" }`
- `content`: JSON `{ "de": "Markdown Inhalt...", "en": "Markdown content..." }`

### Helper-Funktionen

#### `getLocalizedValue(value, locale, fallback?)`

Extrahiert den lokalisierten Wert aus einem JSON-Objekt:

```typescript
import { getLocalizedValue } from '@/lib/i18n';

const genreName = getLocalizedValue(genre.name, 'de'); // "Rock"
const genreNameEn = getLocalizedValue(genre.name, 'en'); // "Rock"
```

**Fallback-Verhalten:**
1. Versucht die angeforderte Locale (`de` oder `en`)
2. Fallback zu `en` falls nicht vorhanden
3. Fallback zu `de` falls nicht vorhanden
4. Fallback zum ersten verfügbaren Schlüssel
5. Fallback zum übergebenen `fallback`-Parameter

#### `createLocalizedObject(de, en?)`

Erstellt ein lokalisiertes Objekt:

```typescript
import { createLocalizedObject } from '@/lib/i18n';

const name = createLocalizedObject('Rock', 'Rock');
// { de: "Rock", en: "Rock" }
```

## Verwendung in Komponenten

### Server Components

```typescript
import { getTranslations } from 'next-intl/server';
import { getLocalizedValue } from '@/lib/i18n';

export default async function Page({ params }: { params: { locale: string } }) {
  const { locale } = await params;
  const t = await getTranslations('Home');
  
  const genreName = getLocalizedValue(genre.name, locale);
  
  return <h1>{t('welcome')}</h1>;
}
```

### Client Components

```typescript
'use client';
import { useTranslations } from 'next-intl';
import { useLocale } from 'next-intl';

export default function Game() {
  const t = useTranslations('Game');
  const locale = useLocale();
  
  return <button>{t('play')}</button>;
}
```

### Navigation

Verwende die lokalisierte Navigation aus `lib/navigation.ts`:

```typescript
import { Link } from '@/lib/navigation';

// Automatisch lokalisiert
<Link href="/admin">Admin</Link>
<Link href="/Rock">Rock</Link>
```

## Admin-Interface

Das Admin-Dashboard unterstützt mehrsprachige Eingaben:

1. **Sprach-Tabs:** Wechsle zwischen `DE` und `EN` Tabs
2. **Genre/Special/News:** Alle Felder können in beiden Sprachen bearbeitet werden
3. **Vorschau:** Sieh dir die lokalisierte Version direkt an

### Beispiel: Genre erstellen

1. Öffne `/de/admin`
2. Wähle den `DE` Tab
3. Gib Name und Subtitle ein
4. Wechsle zum `EN` Tab
5. Gib die englischen Übersetzungen ein
6. Speichere

## Migration bestehender Daten

Bestehende Daten werden automatisch migriert:

1. **Migration `20251128131405_add_i18n_columns`:** Fügt neue JSON-Spalten hinzu
2. **Migration `20251128132806_switch_to_json_columns`:** Konvertiert String-Spalten zu JSON

**Wichtig:** Alte String-Werte werden automatisch in beide Sprachen kopiert:
- `"Rock"` → `{ "de": "Rock", "en": "Rock" }`

## Proxy

Der Proxy (`proxy.ts`) leitet Anfragen automatisch um:

- `/` → `/en` (Standard)
- Ungültige Locales → 404
- Validiert Locale-Parameter

## Sprachumschalter

Die `LanguageSwitcher`-Komponente ermöglicht Nutzern, zwischen Sprachen zu wechseln:

```typescript
import LanguageSwitcher from '@/components/LanguageSwitcher';

<LanguageSwitcher />
```

Die aktuelle Route bleibt erhalten, nur die Locale ändert sich:
- `/de/admin` → `/en/admin`
- `/de/Rock` → `/en/Rock`

## API-Endpunkte

API-Routen unterstützen einen optionalen `locale`-Parameter:

```typescript
GET /api/genres?locale=de
GET /api/specials?locale=en
GET /api/news?locale=de
```

Falls kein `locale` angegeben wird, wird `en` als Standard verwendet.

## Best Practices

### 1. Immer `getLocalizedValue` verwenden

❌ **Falsch:**
```typescript
<span>{genre.name}</span> // Rendert { de: "...", en: "..." }
```

✅ **Richtig:**
```typescript
<span>{getLocalizedValue(genre.name, locale)}</span>
```

### 2. Übersetzungsschlüssel konsistent benennen

Verwende Namespaces für bessere Organisation:
- `Common.*` - Allgemeine UI-Elemente
- `Game.*` - Spiel-spezifische Texte
- `Home.*` - Homepage-Texte
- `Navigation.*` - Navigations-Elemente

### 3. Fallbacks definieren

Immer einen Fallback-Wert angeben:

```typescript
const name = getLocalizedValue(genre.name, locale, 'Unbekannt');
```

### 4. Neue Übersetzungen hinzufügen

1. Füge den Schlüssel zu `messages/de.json` hinzu
2. Füge den Schlüssel zu `messages/en.json` hinzu
3. Verwende `useTranslations('Namespace')` oder `getTranslations('Namespace')`

## Troubleshooting

### 404-Fehler auf `/de` oder `/en`

**Problem:** Route wird nicht gefunden.

**Lösung:**
1. Überprüfe, ob `proxy.ts` korrekt konfiguriert ist
2. Stelle sicher, dass `app/[locale]/layout.tsx` existiert
3. Prüfe die `i18n/request.ts` Konfiguration

### "Objects are not valid as a React child"

**Problem:** Ein JSON-Objekt wird direkt gerendert statt des lokalisierten Werts.

**Lösung:**
Verwende `getLocalizedValue()`:

```typescript
// ❌ Falsch
<span>{genre.name}</span>

// ✅ Richtig
<span>{getLocalizedValue(genre.name, locale)}</span>
```

### Übersetzungen werden nicht angezeigt

**Problem:** Texte erscheinen als Schlüssel (z.B. `"Game.play"`).

**Lösung:**
1. Überprüfe, ob der Übersetzungsschlüssel in `messages/de.json` und `messages/en.json` existiert
2. Stelle sicher, dass der Namespace korrekt ist: `useTranslations('Game')` für `Game.play`
3. Prüfe die JSON-Syntax auf Fehler

### Admin-Interface zeigt Objekte statt Text

**Problem:** In Dropdowns oder Listen werden `{ de: "...", en: "..." }` angezeigt.

**Lösung:**
Verwende `getLocalizedValue()` in allen Render-Funktionen:

```typescript
// ❌ Falsch
<option value={s.id}>{s.name}</option>

// ✅ Richtig
<option value={s.id}>{getLocalizedValue(s.name, activeTab)}</option>
```

## Erweiterung um weitere Sprachen

Um eine neue Sprache hinzuzufügen (z.B. Französisch):

1. **Übersetzungsdatei erstellen:**
   ```bash
   cp messages/de.json messages/fr.json
   ```

2. **Übersetzungen hinzufügen:**
   Bearbeite `messages/fr.json` mit französischen Übersetzungen

3. **Locale zur Konfiguration hinzufügen:**
   - `i18n/request.ts`: `const locales = ['en', 'de', 'fr'];`
   - `proxy.ts`: `locales: ['en', 'de', 'fr']`
   - `lib/navigation.ts`: `export const locales = ['de', 'en', 'fr'] as const;`

4. **Layout aktualisieren:**
   ```typescript
   // app/[locale]/layout.tsx
   if (!['en', 'de', 'fr'].includes(locale)) {
     notFound();
   }
   ```

5. **LanguageSwitcher erweitern:**
   Füge einen Button für `fr` hinzu

6. **Datenbank-Migration:**
   Bestehende Daten behalten ihre Struktur, neue Einträge können optional `fr` enthalten

## Weitere Ressourcen

- [next-intl Dokumentation](https://next-intl-docs.vercel.app/)
- [Next.js App Router i18n](https://nextjs.org/docs/app/building-your-application/routing/internationalization)

