Internationalisierung (i18n) ist entscheidend für den Aufbau globaler Angular-Anwendungen. Dieser Leitfaden zeigt Ihnen, wie Sie i18next in Angular mit ordnungsgemäßer Ressourcenladung, Initialisierung und Nutzungsmustern implementieren.
i18next ist eines der beliebtesten i18n-Frameworks und bietet leistungsstarke Funktionen und Flexibilität:
Installieren Sie i18next mit npm oder yarn:
npm install i18nextDas war's! i18next ist eine eigenständige Bibliothek ohne framework-spezifische Abhängigkeiten. Sie benötigen kein angular-i18next oder einen anderen Wrapper - verwenden Sie einfach i18next direkt in Ihrer Angular-Anwendung.
Es gibt zwei Hauptansätze zum Laden von Übersetzungsressourcen in Angular mit i18next:
Die Verwendung dynamischer Importe nutzt das Code-Splitting von Webpack, um Übersetzungen nach Bedarf zu laden. Dieser Ansatz ist ideal für Anwendungen mit vielen Sprachen oder großen Übersetzungsdateien.
Vorteile:
Beispiel: Laden mit dynamischen Importen
private async loadLanguageResources(
lang: string,
): Promise<Record<string, Record<string, unknown>>> {
const languageResources: Record<string, Record<string, unknown>> = {};
for (const namespace of NAMESPACES) {
const translationModule = await this.loadJson(lang, namespace);
languageResources[namespace] = translationModule.default;
}
return languageResources;
}
private async loadJson(
language: string,
namespace: string,
): Promise<{ default: Record<string, unknown> }> {
// Webpack automatically code-splits this into separate chunks
return import(`../../i18n/${language}/${namespace}.json`);
}Dieser Ansatz importiert Übersetzungsdateien als ES-Module, sodass Webpack sie automatisch in separate Chunks aufteilen kann, die nach Bedarf geladen werden.
Das HTTP-Backend-Plugin lädt Übersetzungen über HTTP-Anfragen von einem Server oder CDN. Dies ist nützlich, wenn Sie Übersetzungen aktualisieren möchten, ohne Ihre App neu zu erstellen.
Vorteile:
Nachteile:
Beispiel: Laden mit HTTP-Backend
import HttpBackend from 'i18next-http-backend';
await init({
lng: initialLanguage,
fallbackLng: DEFAULT_LANGUAGE,
backend: {
loadPath: '/assets/i18n/{{lng}}/{{ns}}.json',
},
use: [HttpBackend],
ns: NAMESPACES,
defaultNS: DEFAULT_NAMESPACE,
});Dieser Ansatz ruft Übersetzungsdateien zur Laufzeit von einem Server ab. Beachten Sie, dass dies zusätzliche Konfigurationen für SSR erfordert.
Die korrekte Initialisierung von i18next ist entscheidend, um Laufzeitfehler zu vermeiden und sicherzustellen, dass Übersetzungen verfügbar sind, wenn Ihre App gerendert wird.
Die provideAppInitializer-Funktion von Angular (eingeführt in Angular 18) stellt sicher, dass i18next vollständig initialisiert ist, bevor die Anwendung mit dem Rendern beginnt. Die bereitgestellte Funktion wird während des App-Bootstraps ausgeführt, und die Initialisierung wird nicht abgeschlossen, bis das Promise aufgelöst ist. Dies verhindert, dass Übersetzungsschlüssel anstelle von übersetztem Text angezeigt werden.
Beispiel: App-Initializer-Konfiguration
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
provideAppInitializer(initializeI18n),
// ... more providers
],
};Warum das wichtig ist:
Die Initialisierungsfunktion kümmert sich um das Laden von Ressourcen und die Konfiguration der i18next-Einstellungen.
Beispiel: i18next-Initialisierung
public async initializeI18n(): Promise<void> {
const initialLanguage = this.getInitialLanguage();
const resources: Record<string, Record<string, Record<string, unknown>>> = {};
if (isPlatformBrowser(this.platformId)) {
// Browser: Only load the specific language needed
const languageResources = await this.loadLanguageResources(initialLanguage);
resources[initialLanguage] = languageResources;
} else {
// SSR: Load all languages for prerendering
for (const lang of SUPPORTED_LANGUAGES) {
const languageResources = await this.loadLanguageResources(lang);
resources[lang] = languageResources;
}
}
await init({
lng: initialLanguage,
fallbackLng: DEFAULT_LANGUAGE,
resources,
ns: NAMESPACES,
defaultNS: DEFAULT_NAMESPACE,
interpolation: {
escapeValue: false,
},
});
}Wichtige Punkte:
Die Angular-Übersetzungs-Pipe bietet eine saubere Möglichkeit, Übersetzungen in Vorlagen zu verwenden.
Beispiel: Übersetzungs-Pipe
import { Pipe, PipeTransform } from '@angular/core';
import { t } from 'i18next';
@Pipe({
name: 't',
standalone: true,
pure: false, // Need to update when language changes
})
export class TranslatePipe implements PipeTransform {
transform(key: string, options?: Record<string, unknown>): string {
return t(key, options);
}
}Die Pipe ist als rein: false markiert, um sicherzustellen, dass sie aktualisiert wird, wenn sich die Sprache ändert. Dies ist wichtig, da Sprachänderungen den Übersetzungsschlüssel selbst nicht modifizieren.
In Vorlagen:
<!-- With namespace -->
<p>{{ "common:welcomeMessage" | t }}</p>
<!-- With nested keys -->
<p>{{ "dashboard.title" | t }}</p>
<!-- Simple interpolation -->
<p>{{ "greeting" | t: { name: userName } }}</p>
<!-- Result: "Hello, John!" from greeting: "Hello, {{name}}!" -->
<!-- With Angular pipes -->
<p>{{ "price" | t: { amount: 29.99 | currency } }}</p>
<!-- Result: "Price: $29.99" from: "Price: {{amount}}" -->
<!-- Multiple variables -->
<p>{{ "updated" | t: { date: lastModified | date, user: currentUser } }}</p>
<!-- Result: "Updated on Jan 15, 2024 by Alice" from: "Updated on {{date}} by {{user}}." -->
Interpolation ermöglicht es dir, dynamische Werte in deine Übersetzungen einzufügen. Du kannst Variablen übergeben, Angular-Pipes zur Formatierung verwenden und mehrere Werte in einer einzigen Übersetzungszeichenfolge kombinieren.
Im Komponenten-Code:
import { Component } from '@angular/core';
import { t } from 'i18next';
@Component({
selector: 'app-dashboard',
template: `
<h1>{{ title }}</h1>
<p>{{ welcomeMsg }}</p>
`,
})
export class DashboardComponent {
title = t('dashboard.title');
welcomeMsg = t('greeting', { name: 'John' });
}Für die Verwendung in Vorlagen ist die Pipe-Syntax sauber und lesbar. Für den programmgesteuerten Zugriff rufe t() direkt auf. Dies ist nützlich, um Benachrichtigungen anzuzeigen, dynamische Titel festzulegen oder Übersetzungen in der Logik der Komponente zu behandeln.
Verwende die Punktnotation, die die Struktur deiner App widerspiegelt: 'auth:login.title' anstelle von 'loginTitle' oder rohem Text.
Teile Übersetzungen in logische Namensräume (z.B. common.json, auth.json, dashboard.json) für bessere Wartbarkeit auf.
Nutze die eingebaute Pluralisierungsunterstützung von i18next, um Singular-/Pluralformen in allen Sprachen korrekt zu behandeln.
Stelle immer sicher, dass i18next initialisiert ist, bevor du deine App renderst, indem du provideAppInitializer() verwendest, um die Initialisierung während des App-Bootstraps auszuführen.
Verwende TypeScript, um Übersetzungsschlüssel direkt aus deinen JSON-Dateien für vollständige Typensicherheit zu extrahieren. Anstatt Typdefinitionen manuell zu pflegen, nutze TypeScripts typeof und dynamische Importe, um Typen automatisch aus deinen tatsächlichen Übersetzungsdateien zu generieren.
Definiere einen Typ, der alle möglichen Schlüssel aus deinen JSON-Übersetzungsdateien mithilfe eines rekursiven NestedKeys-Hilfstypen extrahiert.
import common from './en/common.json'; // defaultNS: DEFAULT_NAMESPACE,
import auth from './en/auth.json'; // namespaces
type NestedKeys<T, Prefix extends string = ''> = T extends object
? {
[K in keyof T & (string | number)]: T[K] extends object
?
| NestedKeys<T[K], `${Prefix}${K & (string | number)}.`>
| `${Prefix}${K & (string | number)}`
: `${Prefix}${K & (string | number)}`;
}[keyof T & (string | number)]
: never;
export type TranslationKey =
| `common:${NestedKeys<typeof common>}`
| `auth:${NestedKeys<typeof auth>}`;Ändere die Transformationsmethode der Pipe, um TranslationKey anstelle von string zu akzeptieren. Dies bietet Typensicherheit in Vorlagen und stellt sicher, dass nur gültige Übersetzungsschlüssel verwendet werden können.
import { Pipe, PipeTransform } from '@angular/core';
import { t } from 'i18next';
import { TranslationKey } from '../../i18n/translation-key';
@Pipe({
name: 't',
standalone: true,
pure: false, // Need to update when language changes
})
export class TranslatePipe implements PipeTransform {
transform(key: TranslationKey, options?: Record<string, unknown>): string {
return t(key, options);
}
}
Jetzt erhältst du vollständige IntelliSense-Autovervollständigung und Kompilierfehler für ungültige Schlüssel sowohl im TypeScript-Code als auch in Vorlagen.
t('common:greeting'); // ✅ Autocomplete
t('auth:login.title'); // ✅ Valid
t('invalid.key'); // ❌ IDE shows error
{{ "common:greeting" | t }} // ✅ Valid in templates
{{ "invalid.key" | t }} // ❌ IDE shows errorVorteile von typensicheren Übersetzungsschlüsseln:
Implementiere intelligente Spracherkennung und ermögliche es Benutzern, die Sprache zur Laufzeit mit automatischem Laden von Ressourcen zu wechseln.
Bestimme die Sprache des Benutzers, die beim Start deiner App verwendet werden soll, indem du mehrere Quellen in priorisierter Reihenfolge überprüfst.
private getInitialLanguage(): string {
if (isPlatformBrowser(this.platformId)) {
// Try to get language from localStorage (user preference)
const savedLang = localStorage.getItem('language');
if (savedLang) {
return savedLang;
}
// Fall back to browser language
return navigator.language ?? DEFAULT_LANGUAGE;
}
// Default language for SSR
return DEFAULT_LANGUAGE;
}Dieser Ansatz überprüft zuerst localStorage (Benutzervoreinstellung), fällt dann auf die Sprache des Browsers (navigator.language) zurück und fällt schließlich auf die Standardsprache der App zurück.
Wechsle die Sprachen zur Laufzeit, während du Übersetzungsressourcen automatisch nach Bedarf lädst.
public async switchLanguage(
language: string
): Promise<void> {
// In browser, check if we need to load the translation first
if (isPlatformBrowser(this.platformId)) {
const i18next = await import('i18next');
// Check if any namespace is missing for this language
for (const namespace of NAMESPACES) {
const currentResources = i18next.default.getResourceBundle(lang, namespace);
if (!currentResources) {
// Translation not loaded yet, load it dynamically
const translationModule = await this.loadJson(lang, namespace);
i18next.default.addResourceBundle(
lang,
namespace,
translationModule.default
);
}
}
}
// Switch to the new language
await changeLanguage(lang);
// Save preference to localStorage
if (isPlatformBrowser(this.platformId)) {
localStorage.setItem('language', lang);
}
}Bei der Verwendung von dynamischen Importen werden Übersetzungen nach Bedarf geladen. Die Methode switchLanguage() überprüft, ob Ressourcen bereits geladen sind, indem sie getResourceBundle() verwendet. Wenn sie fehlen, importiert sie sie dynamisch und fügt sie mit addResourceBundle() hinzu. Dies verhindert redundante Netzwerkaufrufe und stellt sicher, dass alle benötigten Übersetzungen verfügbar sind.
Wichtige Implementierungsdetails:
Die manuelle Verwaltung von Übersetzungen über mehrere Sprachen hinweg ist zeitaufwendig und fehleranfällig. Hier kommt die KI-gestützte Lokalisierung ins Spiel.
l10n.dev ist ein KI-gestützter Übersetzungsdienst, der speziell für i18next JSON-Dateien entwickelt wurde:
Spare Stunden manueller Übersetzungsarbeit und vermeide gängige Fehler wie gebrochene Platzhalter oder falsche Pluralformen.
Bereit, deinen Angular i18n-Workflow zu optimieren?
Lade deine i18n-Dateien hoch und lass die KI die Übersetzung mit Kontextbewusstsein und ordnungsgemäßer Formatierung übernehmen.
Entdecke, warum KI-gestützte Übersetzung besser für i18n-Dateien ist als traditionelle Methoden.
Integriere KI-gestützte Lokalisierung direkt in deine CI/CD-Pipeline.
Bringe KI-Lokalisierung in deinen Arbeitsablauf mit unseren Erweiterungen und Plugins.
Die Implementierung von i18next in Angular mit ordnungsgemäßer Initialisierung und Ressourcenlade-Strategien sorgt für ein reibungsloses Internationalisierungserlebnis.
Kombiniert mit KI-gestützten Übersetzungsdiensten wie l10n.dev kannst du wirklich globale Anwendungen schneller und mit weniger Fehlern erstellen.
Beginne noch heute mit dem Bau mehrsprachiger Angular-Apps!