Skip to content

Commit 8f34351

Browse files
committed
material i18n: Gedankenstriche
1 parent b67c5d4 commit 8f34351

1 file changed

Lines changed: 23 additions & 23 deletions

File tree

material/i18n/README.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ Die Objekt-Variante ist nützlich, wenn die Ausgangssprache beim Build unter ein
163163
```
164164

165165
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.
167167
In dieser einfachen Form unterstützt `sourceLocale` allerdings nur ein einzelnes Locale.
168168
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).
169169

@@ -213,7 +213,7 @@ export class MyComponent {
213213
## Internationalisierung (i18n): die Anwendung übersetzen
214214

215215
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.
217217
Buttons, Überschriften, Hinweistexte und Fehlermeldungen erscheinen weiterhin in der Ursprungssprache.
218218
Nun geht es darum, die Anwendung mehrsprachig anzubieten.
219219
Bei der Übersetzung von Texten hilft uns das i18n-Tooling der Angular CLI.
@@ -273,7 +273,7 @@ Beide Angaben sind optional.
273273
<h1 i18n="description">Salut!</h1>
274274
```
275275

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:
277277

278278
```html
279279
<ng-container i18n="meaning|description">
@@ -364,7 +364,7 @@ removeBook() {
364364

365365
### Pluralisierung und ICU-Ausdrücke
366366

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.
368368
Angular unterstützt dafür die sogenannte [ICU Message Syntax](https://unicode-org.github.io/icu/userguide/format_parse/messages) (*International Components for Unicode*).
369369
Ein ICU-Ausdruck besteht aus einem Ausdruck (z. B. einem Signal), einem ICU-Typ und den zugehörigen Varianten, eingeschlossen in geschweifte Klammern:
370370

@@ -390,18 +390,18 @@ Mit `plural` unterscheiden wir Textbausteine anhand eines numerischen Werts:
390390
```
391391

392392
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.
394394

395395
Neben exakten Werten wie `=0` oder `=1` definiert die ICU-Spezifikation auch benannte Kategorien: `zero`, `one`, `two`, `few`, `many` und `other`.
396396
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.
397397
Die Bezeichnungen `few` und `many` sind dabei leicht irreführend: Sie beschreiben keine Größenordnungen, sondern sprachspezifische grammatische Kategorien.
398398
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.
401401

402402
Im Idealfall definieren wir im Quelltext alle Kategorien, die für eine der Zielsprachen relevant sein könnten.
403403
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.
405405
Für eine arabische Übersetzung hingegen sollten alle sechs Kategorien berücksichtigt werden.
406406
Exakte Werte wie `=0` oder `=2` funktionieren unabhängig vom Locale immer und können zusätzlich zu den benannten Kategorien verwendet werden.
407407

@@ -519,19 +519,19 @@ Wie bereits erwähnt, bietet Angular zwei Wege, um die übersetzten Texte in die
519519
Wir beginnen mit dem ersten der beiden Ansätze: Die Anwendung wird direkt beim Build in mehreren Sprachen erzeugt.
520520
Das Ergebnis sind mehrere gebaute Varianten der gesamten Angular-Anwendung in jeweils einer Sprache.
521521
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.
523523

524524
### Die App mit Übersetzungen bauen
525525

526526
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.
528528

529529
Der empfohlene Weg ist, dass die Anwendung für jedes Locale separat kompiliert wird.
530530
Das Ergebnis ist eine kleine, schnelle und sofort einsatzbereite App mit einer einzigen eingebauten Sprache.
531531
Die Startzeit wird nicht durch das dynamische Nachladen der Übersetzungen verlängert.
532532

533533
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.
535535
Im BookManager verwenden wir als Ausgangssprache `en-US`:
536536

537537
```json
@@ -827,7 +827,7 @@ Das betrifft insbesondere die verschiedenen Abschnitte mit `localize` und die Ko
827827
### Übersetzungen zur Laufzeit laden
828828

829829
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.
831831
Deshalb müssen wir den Code in der Datei `main.ts` unterbringen, bevor wir `bootstrapApplication()` aufrufen.
832832
Hier legen wir uns eine neue Funktion `setupLocale()` an.
833833
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
929929
Dafür müssen wir die gewählte Sprache persistieren und beim Start entscheiden, welche Sprachdatei geladen wird.
930930
Je nach Architektur der Anwendung bieten sich dafür unterschiedliche Mechanismen an:
931931

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).
933933
- **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.
934934
- **`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.
935935
- **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.
936936

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.
938938
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.
939939

940940
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 {
955955

956956
> **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.
957957
> 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.
959959
> Auf die Besonderheiten beim Zusammenspiel mit SSR gehen wir weiter unten noch einmal ein.
960960
961961
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.
973973
<!-- ... -->
974974
```
975975

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.
977977

978978
Unsere Funktion `setupLocale()` soll dazu als Rückgabewert die gewählte Sprache liefern.
979979
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
10361036
### Separate Server-Bundles pro Locale
10371037

10381038
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.
10401040

10411041
### Automatische Sprachweiterleitung
10421042

10431043
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.
10451045
Ohne SSR muss die Weiterleitung hingegen manuell im Webserver eingerichtet werden.
10461046

10471047
### Hydration mit i18n-Blöcken
@@ -1061,10 +1061,10 @@ Ohne `withI18nSupport()` werden Elemente mit i18n-Attributen bei der Hydration
10611061

10621062
Beim Laufzeit-Ansatz haben wir die Sprachauswahl exemplarisch im `localStorage` gespeichert.
10631063
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.
10651065

10661066
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.
10681068
Am unkompliziertesten ist es in der Praxis, die Sprache bereits zur Build-Zeit festzulegen und so den Build-Zeit-Ansatz mit SSR zu kombinieren.
10691069

10701070
## Deployment: Unterverzeichnisse mit `subPath` anpassen
@@ -1089,12 +1089,12 @@ In diesem Beispiel wird die deutsche Variante unter `/deutsch/` statt unter `/de
10891089
Bei beiden vorgestellten Ansätzen wurde eine technische Einschränkung deutlich:
10901090
Wir können nur jeweils eine einzelne Sprache laden.
10911091
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.
10931093
Dafür haben wir den Vorteil, dass wir keine Einbußen bei der Performance in Kauf nehmen müssen.
10941094
Zur Laufzeit ist die Sprache immer schon festgelegt, und es müssen keine zusätzlichen Ressourcen dafür beansprucht werden.
10951095

10961096
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.
10981098

10991099
Wenn du die Anwendung beim Sprachwechsel auf keinen Fall neu laden willst, kannst du die mitgelieferten Ansätze von Angular nicht verwenden.
11001100
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
11041104
## Fazit
11051105

11061106
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.
11081108
Wir können jetzt eine Angular-Anwendung vollständig internationalisieren, ohne auf externe Bibliotheken angewiesen zu sein.
11091109
Das i18n-Tooling der Angular CLI übernimmt dabei die schwere Arbeit: Es extrahiert die Texte, erzeugt Übersetzungsdateien und baut die lokalisierten Varianten automatisch.
11101110
Wir wünschen viel Erfolg bei der Bereitstellung eurer Anwendung für eine internationale Zielgruppe!

0 commit comments

Comments
 (0)