Zum Hauptinhalt springen

Internationalisierung (i18n)

Roestify verwendet next-intl für die Mehrsprachigkeit. Aktuell werden 4 Sprachen unterstützt.

Unterstützte Sprachen

LocaleSpracheStatus
deDeutschVollständig (Standard)
enEnglischVollständig
frFranzösischEN-Fallback (in Arbeit)
esSpanischEN-Fallback (in Arbeit)

Architektur

Config

src/i18n/config.ts       # Locale-Liste, Default-Locale
src/i18n/request.ts # Server-seitige Locale-Erkennung
messages/
├── de.json # Deutsche Übersetzungen (~2562 Keys)
├── en.json # Englische Übersetzungen
├── fr.json # Französisch (EN-Fallback)
└── es.json # Spanisch (EN-Fallback)

Locale-Routing

  • App-Seiten (Dashboard): Cookie-basiert (NEXT_LOCALE), kein URL-Prefix
  • Public Pages (Pricing, Legal): URL-Prefix (/de/pricing, /en/pricing) + hreflang-Tags

DB-Persistenz

Die Sprache wird im Profil gespeichert:

profiles.locale → "de" | "en" | "fr" | "es"

Mutation: tenant.profile.updateLocale (tRPC)

Verwendung

In Client Components

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

export function MyComponent() {
const t = useTranslations('dashboard');
return <h1>{t('title')}</h1>;
}

In Server Components

import { getTranslations } from 'next-intl/server';

export default async function Page() {
const t = await getTranslations('dashboard');
return <h1>{t('title')}</h1>;
}

Message-Struktur

Keys sind nach Sektion gruppiert:

{
"dashboard": {
"title": "Dashboard",
"greeting": "Guten {timeOfDay}, {name}"
},
"roles": {
"admin": "Admin",
"adminDescription": "Voller Zugriff auf alle Bereiche"
}
}

Listen in Messages

Für Listen wird der |-Separator verwendet:

{
"features": "Feature 1|Feature 2|Feature 3"
}
const items = t('features').split('|');

Konventionen

  • Niemals hardcoded deutsche Strings in Komponenten
  • Niemals Sternchen * in Label-Strings (Pflichtfelder werden nicht markiert)
  • Rollen-Labels: useTranslations("roles") verwenden, nicht ROLE_LABELS
  • E-Mail-Templates: Bleiben Deutsch (serverseitig, kein useTranslations)
  • Optionale Felder: "(optional)" im Label-String