Hilfe-Center

Angular i18next

Internationalisierung (i18n) ist für den Aufbau globaler Angular-Anwendungen unerlässlich. Dieser Leitfaden zeigt Ihnen, wie Sie i18next in Angular mit korrektem Laden von Ressourcen, Initialisierung und Nutzungsmustern implementieren.

Warum i18next für Angular?

i18next ist eines der beliebtesten i18n-Frameworks und bietet leistungsstarke Funktionen sowie Flexibilität:

  • Framework-agnostisch – funktioniert nahtlos mit Angular, React, Vue und anderen.
  • Leistungsstarke Interpolation, Pluralisierung und Kontextunterstützung.
  • Unterstützung für Lazy Loading und Code-Splitting.
  • TypeScript-Unterstützung mit Typsicherheit.
  • Großes Ökosystem mit Plugins und Erweiterungen.

Installation

Installieren Sie i18next mit npm oder yarn:

npm install i18next

Das war's! i18next ist eine eigenständige Bibliothek ohne frameworkspezifische Abhängigkeiten. Sie benötigen kein angular-i18next oder andere Wrapper – verwenden Sie i18next einfach direkt in Ihrer Angular-Anwendung.

Laden von Übersetzungsressourcen

Es gibt zwei Hauptansätze zum Laden von Übersetzungsressourcen in Angular mit i18next:

Dynamische Importe (Empfohlen)

Die Verwendung dynamischer Importe nutzt das Code-Splitting von Webpack, um Übersetzungen bei Bedarf zu laden. Dieser Ansatz ist ideal für Anwendungen mit vielen Sprachen oder großen Übersetzungsdateien.

Vorteile:

  • Optimierung der Bundle-Größe – laden Sie nur die benötigten Übersetzungen.
  • Bessere Performance – schnellere initiale Ladezeit.
  • Funktioniert perfekt mit SSR und Prerendering.
  • Keine zusätzlichen HTTP-Anfragen erforderlich.

Beispiel: Laden mit dynamischen Importen

private async loadLanguageResources(
  lang: string,
): Promise<Record<string, Record<string, unknown>>> {
  const languageResources: Record<string, Record<string, unknown>> = {};

  // Load all namespaces for the given language in parallel
  await Promise.all(
    NAMESPACES.map(async (namespace) => {
      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, wodurch Webpack sie automatisch in separate Chunks aufteilen kann, die bei Bedarf geladen werden.

i18next-http-backend

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:

  • Übersetzungen ohne erneute Bereitstellung aktualisieren.
  • Übersetzungen von einem externen CDN laden.
  • Nützlich für die Übersetzungsverwaltung zur Laufzeit.

Nachteile:

  • Zusätzliche HTTP-Anfragen verlangsamen die initiale Ladezeit.
  • Erfordert Netzwerkverbindung.
  • Komplexere SSR-Einrichtung.

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 eine zusätzliche Konfiguration für SSR erfordert.

Welchen Ansatz wählen?

Verwenden Sie dynamische Importe, wenn:

  • Sie eine optimale Bundle-Größe und Performance wünschen.
  • Übersetzungen Teil Ihres Build-Prozesses sind.
  • Sie Unterstützung für SSR/Prerendering benötigen.

Verwenden Sie das HTTP-Backend, wenn:

  • Sie Übersetzungen ohne erneute Bereitstellung aktualisieren müssen.
  • Übersetzungen extern verwaltet werden.
  • Sie ein CDN zum Bereitstellen von Übersetzungsdateien haben.

Korrekte i18next-Initialisierung

Die korrekte Initialisierung von i18next ist entscheidend, um Laufzeitfehler zu vermeiden und sicherzustellen, dass Übersetzungen verfügbar sind, wenn Ihre App gerendert wird.

Verwendung von provideAppInitializer

Die Funktion provideAppInitializer 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 ist erst abgeschlossen, wenn das Promise aufgelöst wurde. Dies verhindert, dass Übersetzungsschlüssel anstelle von übersetztem Text erscheinen.

Beispiel: Konfiguration des App-Initializers

export const appConfig: ApplicationConfig = {
  providers: [
    // ... other providers
    provideAppInitializer(initializeI18n),
    // ... more providers
  ],
};

Warum das wichtig ist:

  • Die Funktion läuft während des Anwendungsstarts im Injection-Kontext.
  • Verhindert Flackern oder das Anzeigen von Übersetzungsschlüsseln beim ersten Laden.
  • Stellt sicher, dass Übersetzungen von Anfang an in allen Komponenten verfügbar sind.
  • Funktioniert korrekt mit SSR, Prerendering und clientseitigem Rendering.

i18next-Initialisierungsfunktion

Die Initialisierungsfunktion übernimmt das Laden von Ressourcen und das Konfigurieren 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:

  • Laden Sie im Browser für optimale Performance nur die aktuelle Sprache.
  • Laden Sie während SSR alle Sprachen für die Unterstützung von Prerendering.
  • Verwenden Sie fallbackLng, um fehlende Übersetzungen elegant zu behandeln.
  • Konfigurieren Sie Namespaces für eine bessere Organisation.

Translation Pipe

Die Angular Translation Pipe bietet eine saubere Möglichkeit, Übersetzungen in Templates zu verwenden.

Pipe-Implementierung

Beispiel: Translation 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 pure: false markiert, um sicherzustellen, dass sie aktualisiert wird, wenn sich die Sprache ändert. Dies ist wichtig, da Sprachänderungen den Übersetzungsschlüssel selbst nicht ändern.

Verwendung der Translation Pipe

In Templates:

<!-- 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}}." -->

Die Interpolation ermöglicht es Ihnen, dynamische Werte in Ihre Übersetzungen einzufügen. Sie können Variablen übergeben, Angular-Pipes zur Formatierung verwenden und mehrere Werte in einem einzigen Übersetzungsstring 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 im Template ist die Pipe-Syntax sauber und lesbar. Für den programmgesteuerten Zugriff rufen Sie t() direkt auf. Dies ist nützlich, um Benachrichtigungen anzuzeigen, dynamische Titel zu setzen oder Übersetzungen in der Komponentenlogik zu handhaben.

Best Practices für Angular i18next

Verwenden Sie aussagekräftige Übersetzungsschlüssel

Verwenden Sie eine Punktnotation, die Ihre App-Struktur widerspiegelt: 'auth:login.title' anstelle von 'loginTitle' oder Rohtext.

Organisieren Sie mit Namespaces

Teilen Sie Übersetzungen in logische Namespaces auf (z. B. common.json, auth.json, dashboard.json) für eine bessere Wartbarkeit.

Behandeln Sie Pluralformen

Verwenden Sie die integrierte Pluralisierungsunterstützung von i18next, um Singular-/Pluralformen in allen Sprachen korrekt zu behandeln.

Warten Sie auf die Initialisierung

Stellen Sie immer sicher, dass i18next vor dem Rendern Ihrer App initialisiert wird, indem Sie provideAppInitializer() verwenden, um die Initialisierung während des App-Bootstraps auszuführen.

Typsicherheit für Übersetzungsschlüssel

Verwenden Sie TypeScript, um Übersetzungsschlüssel direkt aus Ihren JSON-Dateien für vollständige Typsicherheit zu extrahieren. Anstatt Typdefinitionen manuell zu pflegen, nutzen Sie typeof und dynamische Importe von TypeScript, um automatisch Typen aus Ihren tatsächlichen Übersetzungsdateien zu generieren.

Definieren Sie einen Typ, der alle möglichen Schlüssel aus Ihren JSON-Übersetzungsdateien mithilfe eines rekursiven NestedKeys-Hilfstyps 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>}`;

Ändern Sie die transform-Methode der Pipe, um TranslationKey anstelle von string zu akzeptieren. Dies bietet Typsicherheit in Templates 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 erhalten Sie vollständige IntelliSense-Autovervollständigung und Kompilierzeitfehler für ungültige Schlüssel sowohl im TypeScript-Code als auch in Templates.

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 error

Vorteile von typsicheren Übersetzungsschlüsseln:

  • Autovervollständigung in Ihrer IDE für alle verfügbaren Übersetzungsschlüssel über alle Namespaces hinweg.
  • Kompilierzeitfehler, wenn Sie einen nicht existierenden Schlüssel verwenden, um Tippfehler vor der Laufzeit abzufangen.
  • Refactoring-Unterstützung – benennen Sie Schlüssel sicher in Ihrer gesamten Codebasis um.
  • Kein Laufzeit-Overhead – Typen werden während der Kompilierung vollständig entfernt.
  • Automatisch aus Ihren tatsächlichen JSON-Dateien generiert – keine manuelle Typwartung erforderlich.

Spracherkennung und Sprachwechsel

Implementieren Sie eine intelligente Spracherkennung und ermöglichen Sie Benutzern den Sprachwechsel zur Laufzeit mit automatischem Laden von Ressourcen.

Bestimmen Sie die Sprache des Benutzers beim Start Ihrer App, indem Sie mehrere Quellen in der Prioritätsreihenfolge prüfen.

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 prüft zuerst localStorage (Benutzereinstellung), greift dann auf die Sprache des Browsers (navigator.language) zurück und verwendet schließlich die Standardsprache der App.

Wechseln Sie die Sprache zur Laufzeit, während Übersetzungsressourcen automatisch bei Bedarf geladen werden.

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');

    await Promise.all(
      NAMESPACES.map(async (namespace) => {
        const currentResources = i18next.default.getResourceBundle(
          lang,
          namespace,
        );
        // Check if any namespace is missing for this language
        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 dynamischer Importe werden Übersetzungen bei Bedarf geladen. Die Methode switchLanguage() prüft mit getResourceBundle(), ob Ressourcen bereits geladen sind. Falls sie fehlen, werden sie dynamisch importiert und mit addResourceBundle() hinzugefügt. Dies verhindert redundante Netzwerkanfragen und stellt sicher, dass alle benötigten Übersetzungen verfügbar sind.

Wichtige Implementierungsdetails:

  • Prüfen Sie zuerst localStorage, um die bevorzugte Sprache des Benutzers wiederherzustellen.
  • Verwenden Sie navigator.language als Fallback für die Spracheinstellung des Browsers.
  • Laden Sie fehlende Ressourcen dynamisch mit addResourceBundle().

Übersetzung mit KI automatisieren

Das manuelle Verwalten von Übersetzungen in mehreren Sprachen ist zeitaufwendig und fehleranfällig. Hier kommt KI-gestützte Lokalisierung ins Spiel.

Warum l10n.dev?

l10n.dev ist ein KI-gestützter Übersetzungsdienst, der speziell für i18next-JSON-Dateien entwickelt wurde:

  • Bewahrt die JSON-Struktur, Schlüssel und verschachtelte Objekte.
  • Behält Platzhalter wie {{name}}, {{count}} korrekt bei.
  • Generiert automatisch Pluralformen für alle Sprachen.
  • Behandelt Kontext und Interpolation intelligent.
  • Unterstützt alle i18next-Funktionen einschließlich Namespaces.

Einfacher Workflow

  1. Exportieren Sie Ihre JSON-Datei der Basissprache (z. B. en/common.json)
  2. Laden Sie sie auf l10n.dev hoch und wählen Sie Zielsprachen aus.
  3. Die KI übersetzt mit Kontextbewusstsein und korrekter Formatierung.
  4. Laden Sie die übersetzten Dateien herunter, die in Ihrer Angular-App einsatzbereit sind.

Sparen Sie Stunden manueller Übersetzungsarbeit und vermeiden Sie häufige Fehler wie defekte Platzhalter oder falsche Pluralformen.

Bereit, Ihren Angular-i18n-Workflow zu optimieren?