You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: material/i18n/README.md
+23-23Lines changed: 23 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -163,7 +163,7 @@ Die Objekt-Variante ist nützlich, wenn die Ausgangssprache beim Build unter ein
163
163
```
164
164
165
165
Durch die Angabe von `sourceLocale` wird das InjectionToken `LOCALE_ID` beim Build automatisch auf den konfigurierten Wert gesetzt.
166
-
Auch die passende Sprachdefinition wird automatisch geladen — der manuelle Provider in der `app.config.ts` und der Import in der `main.ts` sind damit nicht mehr notwendig.
166
+
Auch die passende Sprachdefinition wird automatisch geladen – der manuelle Provider in der `app.config.ts` und der Import in der `main.ts` sind damit nicht mehr notwendig.
167
167
In dieser einfachen Form unterstützt `sourceLocale` allerdings nur ein einzelnes Locale.
168
168
Wie wir mehrere Sprachen über die `angular.json` konfigurieren und die Anwendung in verschiedenen Sprachvarianten bauen können, zeigen wir im Abschnitt [Übersetzung während des Build-Prozesses](#übersetzung-während-des-build-prozesses).
169
169
@@ -213,7 +213,7 @@ export class MyComponent {
213
213
## Internationalisierung (i18n): die Anwendung übersetzen
214
214
215
215
Im vorhergehenden Abschnitt zur Lokalisierung haben wir betrachtet, wie wir Formate für ein einzelnes Locale anpassen.
216
-
Damit sind Datumsangaben, Zahlen und Währungen bereits korrekt formatiert — aber die eigentlichen Texte der Anwendung werden noch nicht übersetzt.
216
+
Damit sind Datumsangaben, Zahlen und Währungen bereits korrekt formatiert – aber die eigentlichen Texte der Anwendung werden noch nicht übersetzt.
217
217
Buttons, Überschriften, Hinweistexte und Fehlermeldungen erscheinen weiterhin in der Ursprungssprache.
218
218
Nun geht es darum, die Anwendung mehrsprachig anzubieten.
219
219
Bei der Übersetzung von Texten hilft uns das i18n-Tooling der Angular CLI.
@@ -273,7 +273,7 @@ Beide Angaben sind optional.
273
273
<h1i18n="description">Salut!</h1>
274
274
```
275
275
276
-
Steht kein DOM-Element zur Verfügung, auf dem wir das Attribut `i18n` setzen könnten, können wir die Markierung mit einem `<ng-container>` vornehmen. Angular rendert dieses Element nicht im DOM — es erzeugt also kein zusätzliches HTML-Element, sondern dient ausschließlich als Hilfskonstrukt für die Übersetzung:
276
+
Steht kein DOM-Element zur Verfügung, auf dem wir das Attribut `i18n` setzen könnten, können wir die Markierung mit einem `<ng-container>` vornehmen. Angular rendert dieses Element nicht im DOM – es erzeugt also kein zusätzliches HTML-Element, sondern dient ausschließlich als Hilfskonstrukt für die Übersetzung:
277
277
278
278
```html
279
279
<ng-containeri18n="meaning|description">
@@ -364,7 +364,7 @@ removeBook() {
364
364
365
365
### Pluralisierung und ICU-Ausdrücke
366
366
367
-
Nicht alle Texte lassen sich 1:1 übersetzen — manchmal hängt die korrekte Formulierung von einem konkreten Wert ab.
367
+
Nicht alle Texte lassen sich 1:1 übersetzen – manchmal hängt die korrekte Formulierung von einem konkreten Wert ab.
368
368
Angular unterstützt dafür die sogenannte [ICU Message Syntax](https://unicode-org.github.io/icu/userguide/format_parse/messages) (*International Components for Unicode*).
369
369
Ein ICU-Ausdruck besteht aus einem Ausdruck (z. B. einem Signal), einem ICU-Typ und den zugehörigen Varianten, eingeschlossen in geschweifte Klammern:
370
370
@@ -390,18 +390,18 @@ Mit `plural` unterscheiden wir Textbausteine anhand eines numerischen Werts:
390
390
```
391
391
392
392
Dabei ist `count` ein Signal der Komponente.
393
-
Die geschweiften Klammern um `{{count()}}` innerhalb der `other`-Variante sind die gewohnte Interpolation von Angular — die äußeren Klammern gehören zur ICU-Syntax.
393
+
Die geschweiften Klammern um `{{count()}}` innerhalb der `other`-Variante sind die gewohnte Interpolation von Angular – die äußeren Klammern gehören zur ICU-Syntax.
394
394
395
395
Neben exakten Werten wie `=0` oder `=1` definiert die ICU-Spezifikation auch benannte Kategorien: `zero`, `one`, `two`, `few`, `many` und `other`.
396
396
Welche dieser Kategorien tatsächlich greifen, wird durch die [CLDR Plural Rules](https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html) festgelegt und hängt vom eingestellten Locale ab.
397
397
Die Bezeichnungen `few` und `many` sind dabei leicht irreführend: Sie beschreiben keine Größenordnungen, sondern sprachspezifische grammatische Kategorien.
398
398
Im Polnischen etwa gilt `few` für Zahlen mit den Endziffern 2–4 (außer 12–14), im Arabischen für 3–10.
399
-
Deutsch und Englisch verwenden lediglich `one` und `other`— die übrigen Kategorien existieren für diese Sprachen nicht.
400
-
Die Kategorie `other` ist der Fallback und muss immer angegeben werden. Nicht zutreffende Kategorien werden stillschweigend ignoriert — solange `other` vorhanden ist, kann es nicht zu einem Laufzeitfehler kommen.
399
+
Deutsch und Englisch verwenden lediglich `one` und `other`– die übrigen Kategorien existieren für diese Sprachen nicht.
400
+
Die Kategorie `other` ist der Fallback und muss immer angegeben werden. Nicht zutreffende Kategorien werden stillschweigend ignoriert – solange `other` vorhanden ist, kann es nicht zu einem Laufzeitfehler kommen.
401
401
402
402
Im Idealfall definieren wir im Quelltext alle Kategorien, die für eine der Zielsprachen relevant sein könnten.
403
403
Das Übersetzungsteam muss dann aber nur diejenigen Kategorien übersetzen, die in der jeweiligen Zielsprache auch tatsächlich greifen.
404
-
Für eine deutsche Übersetzung reicht es aus, `one` und `other` zu übersetzen —`two`, `few` und `many` werden hier nie ausgewertet.
404
+
Für eine deutsche Übersetzung reicht es aus, `one` und `other` zu übersetzen –`two`, `few` und `many` werden hier nie ausgewertet.
405
405
Für eine arabische Übersetzung hingegen sollten alle sechs Kategorien berücksichtigt werden.
406
406
Exakte Werte wie `=0` oder `=2` funktionieren unabhängig vom Locale immer und können zusätzlich zu den benannten Kategorien verwendet werden.
407
407
@@ -519,19 +519,19 @@ Wie bereits erwähnt, bietet Angular zwei Wege, um die übersetzten Texte in die
519
519
Wir beginnen mit dem ersten der beiden Ansätze: Die Anwendung wird direkt beim Build in mehreren Sprachen erzeugt.
520
520
Das Ergebnis sind mehrere gebaute Varianten der gesamten Angular-Anwendung in jeweils einer Sprache.
521
521
Da keine Übersetzungen zur Laufzeit geladen werden müssen, ist die Anwendung sofort einsatzbereit.
522
-
Ein Nachteil ist jedoch, dass die Texte nach dem Build nicht mehr angepasst werden können — sie sind fester Bestandteil des Quellcodes.
522
+
Ein Nachteil ist jedoch, dass die Texte nach dem Build nicht mehr angepasst werden können – sie sind fester Bestandteil des Quellcodes.
523
523
524
524
### Die App mit Übersetzungen bauen
525
525
526
526
Wir haben bereits alle Nachrichten markiert, extrahiert und übersetzt.
527
-
Die Datei mit den übersetzten Nachrichten liegt ebenfalls im Projekt — und nun muss die Anwendung nur noch gebaut werden.
527
+
Die Datei mit den übersetzten Nachrichten liegt ebenfalls im Projekt – und nun muss die Anwendung nur noch gebaut werden.
528
528
529
529
Der empfohlene Weg ist, dass die Anwendung für jedes Locale separat kompiliert wird.
530
530
Das Ergebnis ist eine kleine, schnelle und sofort einsatzbereite App mit einer einzigen eingebauten Sprache.
531
531
Die Startzeit wird nicht durch das dynamische Nachladen der Übersetzungen verlängert.
532
532
533
533
Zunächst konfigurieren wir das Standard-Locale in der `angular.json`.
534
-
Den Eintrag `sourceLocale` im Abschnitt `i18n` haben wir [weiter oben](#alternative-locale-über-die-build-konfiguration-setzen) bereits kennengelernt — er setzt das InjectionToken `LOCALE_ID` und lädt die passende Sprachdefinition automatisch.
534
+
Den Eintrag `sourceLocale` im Abschnitt `i18n` haben wir [weiter oben](#alternative-locale-über-die-build-konfiguration-setzen) bereits kennengelernt – er setzt das InjectionToken `LOCALE_ID` und lädt die passende Sprachdefinition automatisch.
535
535
Im BookManager verwenden wir als Ausgangssprache `en-US`:
536
536
537
537
```json
@@ -827,7 +827,7 @@ Das betrifft insbesondere die verschiedenen Abschnitte mit `localize` und die Ko
827
827
### Übersetzungen zur Laufzeit laden
828
828
829
829
Jetzt betrachten wir die zweite Variante: Statt die Übersetzungen beim Build einzubauen, laden wir sie zur Laufzeit.
830
-
Dafür müssen die Übersetzungen verfügbar sein, bevor die Anwendung startet — damit Angular die Texte beim Bootstrapping direkt austauschen kann.
830
+
Dafür müssen die Übersetzungen verfügbar sein, bevor die Anwendung startet – damit Angular die Texte beim Bootstrapping direkt austauschen kann.
831
831
Deshalb müssen wir den Code in der Datei `main.ts` unterbringen, bevor wir `bootstrapApplication()` aufrufen.
832
832
Hier legen wir uns eine neue Funktion `setupLocale()` an.
833
833
Sie soll alle Schritte erledigen, die vor dem Start der Anwendung notwendig sind:
@@ -929,12 +929,12 @@ Auf der aktuellen Grundlage können wir nun einen einfachen Sprachwechsel implem
929
929
Dafür müssen wir die gewählte Sprache persistieren und beim Start entscheiden, welche Sprachdatei geladen wird.
930
930
Je nach Architektur der Anwendung bieten sich dafür unterschiedliche Mechanismen an:
931
931
932
-
-**`localStorage`**: Die einfachste Lösung im Browser — die Sprachauswahl wird lokal gespeichert und steht beim nächsten Seitenaufruf sofort zur Verfügung. Auf dem Server (SSR) ist `localStorage` allerdings nicht verfügbar (mehr dazu später im Artikel).
932
+
-**`localStorage`**: Die einfachste Lösung im Browser – die Sprachauswahl wird lokal gespeichert und steht beim nächsten Seitenaufruf sofort zur Verfügung. Auf dem Server (SSR) ist `localStorage` allerdings nicht verfügbar (mehr dazu später im Artikel).
933
933
-**Session oder Identity-Token**: Verfügt die Anwendung über ein Session-Management oder eine Authentifizierung, kann die Sprachpräferenz im Nutzerprofil oder in der Session hinterlegt werden. Dieser Ansatz funktioniert sowohl im Browser als auch auf dem Server.
934
934
-**`Accept-Language`-Header**: Der Browser sendet bei jeder Anfrage einen Header mit den im Browser eingestellten Sprachen. Dieser kann als Fallback dienen, wenn keine explizite Auswahl vorliegt.
935
935
-**Cookies**: Cookies werden bei jedem HTTP-Request an den Server gesendet und könnten die Sprachauswahl transportieren. Allerdings bringen Cookies zahlreiche Nachteile mit sich: Sie erhöhen die Größe jedes Requests, erfordern besondere Sicherheitsmaßnahmen (z. B. `HttpOnly`, `Secure`, `SameSite`) und unterliegen strengen datenschutzrechtlichen Anforderungen. In der Regel sind die anderen genannten Ansätze vorzuziehen.
936
936
937
-
Im Folgenden verwenden wir exemplarisch `localStorage`— die einfachste Variante für eine rein clientseitige Anwendung.
937
+
Im Folgenden verwenden wir exemplarisch `localStorage`– die einfachste Variante für eine rein clientseitige Anwendung.
938
938
Dies ist keine generelle Handlungsempfehlung: Für das jeweilige Projekt können die anderen Ansätze besser geeignet sein, insbesondere wenn Server-Side Rendering zum Einsatz kommt.
939
939
940
940
Damit die Sprache in der Oberfläche umgeschaltet werden kann, erstellen wir in der `App`-Komponente eine Methode `changeLocale()`:
@@ -955,7 +955,7 @@ export class App {
955
955
956
956
> **Hinweis:** Bei Anwendungen mit Server-Side Rendering (SSR) ist zu beachten, dass `localStorage` und `location` Browser-APIs sind, die in Node.js nicht zur Verfügung stehen.
957
957
> Eine Verwendung auf dem Server würde zu einem Laufzeitfehler führen.
958
-
> Die Methode `changeLocale()` wird hier ausschließlich durch ein Click-Event ausgelöst und ist daher unkritisch — Events finden nur im Browser statt.
958
+
> Die Methode `changeLocale()` wird hier ausschließlich durch ein Click-Event ausgelöst und ist daher unkritisch – Events finden nur im Browser statt.
959
959
> Auf die Besonderheiten beim Zusammenspiel mit SSR gehen wir weiter unten noch einmal ein.
960
960
961
961
Im Template der Komponente erzeugen wir zwei Buttons, um die Methode `changeLocale()` aufzurufen.
@@ -973,7 +973,7 @@ So ist es möglich, die Sprache zwischen Deutsch und Englisch zu wechseln.
973
973
<!-- ... -->
974
974
```
975
975
976
-
Die gewählte Sprache wird nun im Browser gespeichert — jetzt müssen wir diese Entscheidung beim Start der Anwendung in der Datei `main.ts` berücksichtigen.
976
+
Die gewählte Sprache wird nun im Browser gespeichert – jetzt müssen wir diese Entscheidung beim Start der Anwendung in der Datei `main.ts` berücksichtigen.
977
977
978
978
Unsere Funktion `setupLocale()` soll dazu als Rückgabewert die gewählte Sprache liefern.
979
979
Diese Information können wir dann beim Bootstrapping verwenden, um den Provider für die `LOCALE_ID` zu setzen.
@@ -1036,12 +1036,12 @@ Wenn wir unsere Anwendung mit Server-Side Rendering betreiben (siehe unseren [On
1036
1036
### Separate Server-Bundles pro Locale
1037
1037
1038
1038
Beim Build-Zeit-Ansatz mit `localize: true` und `outputMode: "server"` erzeugt Angular pro Locale ein eigenes Server-Bundle.
1039
-
Die `AngularAppEngine` routet eingehende Anfragen anhand des URL-Pfads automatisch an das passende Bundle weiter — ein Aufruf von `/de/books` wird vom deutschen Server-Bundle bedient, `/en-US/books` vom englischen.
1039
+
Die `AngularAppEngine` routet eingehende Anfragen anhand des URL-Pfads automatisch an das passende Bundle weiter – ein Aufruf von `/de/books` wird vom deutschen Server-Bundle bedient, `/en-US/books` vom englischen.
1040
1040
1041
1041
### Automatische Sprachweiterleitung
1042
1042
1043
1043
Ruft jemand die Wurzel-URL `/` auf, wertet Angular den `Accept-Language`-Header des Browsers aus und leitet mit einem HTTP-302-Redirect an die passende Sprachvariante weiter.
1044
-
Diese Weiterleitung funktioniert nur mit `outputMode: "server"` und ist dort automatisch aktiv — eine manuelle Konfiguration im Webserver (z. B. Nginx oder Apache) ist nicht notwendig.
1044
+
Diese Weiterleitung funktioniert nur mit `outputMode: "server"` und ist dort automatisch aktiv – eine manuelle Konfiguration im Webserver (z. B. Nginx oder Apache) ist nicht notwendig.
1045
1045
Ohne SSR muss die Weiterleitung hingegen manuell im Webserver eingerichtet werden.
1046
1046
1047
1047
### Hydration mit i18n-Blöcken
@@ -1061,10 +1061,10 @@ Ohne `withI18nSupport()` werden Elemente mit i18n-Attributen bei der Hydration
1061
1061
1062
1062
Beim Laufzeit-Ansatz haben wir die Sprachauswahl exemplarisch im `localStorage` gespeichert.
1063
1063
Auf dem Server steht `localStorage` jedoch nicht zur Verfügung. Es handelt sich um eine reine Browser-API, die in Node.js nicht existiert.
1064
-
Anders als beim Build-Zeit-Ansatz existieren beim Laufzeit-Ansatz auch keine sprachspezifischen URL-Pfade wie `/de/` oder `/en/`— das Locale lässt sich also nicht aus der URL ableiten.
1064
+
Anders als beim Build-Zeit-Ansatz existieren beim Laufzeit-Ansatz auch keine sprachspezifischen URL-Pfade wie `/de/` oder `/en/`– das Locale lässt sich also nicht aus der URL ableiten.
1065
1065
1066
1066
Kommt Server-Side Rendering zum Einsatz, sollte deshalb einer der im [Abschnitt zum Sprachwechsel](#die-sprache-wechseln) genannten servertauglichen Ansätze gewählt werden, etwa Session-basierte Speicherung oder die Auswertung des `Accept-Language`-Headers.
1067
-
Eine pauschale Lösung gibt es hier nicht — die Wahl hängt davon ab, wie die Anwendung generell Daten persistiert und welche Infrastruktur zur Verfügung steht.
1067
+
Eine pauschale Lösung gibt es hier nicht – die Wahl hängt davon ab, wie die Anwendung generell Daten persistiert und welche Infrastruktur zur Verfügung steht.
1068
1068
Am unkompliziertesten ist es in der Praxis, die Sprache bereits zur Build-Zeit festzulegen und so den Build-Zeit-Ansatz mit SSR zu kombinieren.
1069
1069
1070
1070
## Deployment: Unterverzeichnisse mit `subPath` anpassen
@@ -1089,12 +1089,12 @@ In diesem Beispiel wird die deutsche Variante unter `/deutsch/` statt unter `/de
1089
1089
Bei beiden vorgestellten Ansätzen wurde eine technische Einschränkung deutlich:
1090
1090
Wir können nur jeweils eine einzelne Sprache laden.
1091
1091
Dazu können wir entweder eine speziell dafür gebaute Anwendung erzeugen, oder wir können die Sprache einmalig vor dem Start der App laden und festlegen.
1092
-
Ein Wechsel zur Laufzeit ist mit den Bordmitteln von Angular nicht möglich — zum Laden einer Sprache muss immer die App gewechselt bzw. die Seite neu geladen werden.
1092
+
Ein Wechsel zur Laufzeit ist mit den Bordmitteln von Angular nicht möglich – zum Laden einer Sprache muss immer die App gewechselt bzw. die Seite neu geladen werden.
1093
1093
Dafür haben wir den Vorteil, dass wir keine Einbußen bei der Performance in Kauf nehmen müssen.
1094
1094
Zur Laufzeit ist die Sprache immer schon festgelegt, und es müssen keine zusätzlichen Ressourcen dafür beansprucht werden.
1095
1095
1096
1096
Eine weitere Einschränkung betrifft dynamische Inhalte: Das i18n-Tooling von Angular übersetzt ausschließlich statische Texte in Templates und im TypeScript-Code.
1097
-
Inhalte, die zur Laufzeit von einer API geladen werden, können damit nicht übersetzt werden — hier muss entweder die API selbst die Texte in der richtigen Sprache liefern, oder wir müssen im Code eine eigene Logik dafür bereitstellen.
1097
+
Inhalte, die zur Laufzeit von einer API geladen werden, können damit nicht übersetzt werden – hier muss entweder die API selbst die Texte in der richtigen Sprache liefern, oder wir müssen im Code eine eigene Logik dafür bereitstellen.
1098
1098
1099
1099
Wenn du die Anwendung beim Sprachwechsel auf keinen Fall neu laden willst, kannst du die mitgelieferten Ansätze von Angular nicht verwenden.
1100
1100
Wir empfehlen dann, auf eine externe Bibliothek zurückzugreifen, z. B. [Transloco](https://github.com/jsverse/transloco) oder [ngx-translate](https://github.com/ngx-translate/core).
@@ -1104,7 +1104,7 @@ Dieser Ansatz kann niemals so performant sein wie eine Anwendung, die gezielt f
1104
1104
## Fazit
1105
1105
1106
1106
Angular liefert ein ausgereiftes Tooling für Lokalisierung und Internationalisierung mit.
1107
-
In diesem Artikel haben wir den gesamten Weg kennengelernt: von der Lokalisierung für ein einzelnes Locale über die Extraktion und Übersetzung von Texten bis hin zur mehrsprachigen Auslieferung — sowohl zur Build-Zeit als auch zur Laufzeit.
1107
+
In diesem Artikel haben wir den gesamten Weg kennengelernt: von der Lokalisierung für ein einzelnes Locale über die Extraktion und Übersetzung von Texten bis hin zur mehrsprachigen Auslieferung – sowohl zur Build-Zeit als auch zur Laufzeit.
1108
1108
Wir können jetzt eine Angular-Anwendung vollständig internationalisieren, ohne auf externe Bibliotheken angewiesen zu sein.
1109
1109
Das i18n-Tooling der Angular CLI übernimmt dabei die schwere Arbeit: Es extrahiert die Texte, erzeugt Übersetzungsdateien und baut die lokalisierten Varianten automatisch.
1110
1110
Wir wünschen viel Erfolg bei der Bereitstellung eurer Anwendung für eine internationale Zielgruppe!
0 commit comments