Internationalisierung für Angular, Teil 1: Bordmittel

Seite 3: Dynamische Übersetzungen

Inhaltsverzeichnis

In Fällen, in denen die Übersetzung von einer dynamischen Anzahl oder dem Wert des Inhalts abhängig ist, lässt sich mit spezieller Syntax arbeiten.

Die Tabelle, die im vorherigen Abschnitt ihren Tabellenkopf erhalten hat, zeigt nun Buchungseinträge durch das JavaScript-Objekt bookings an:

bookings = [
{
from: 'Graz',
to: 'Hamburg',
passengers: 3,
children: 1,
returnFlight: 'yes',
date: new Date('2017-04-26T12:00')
},
{
from: 'Graz',
to: 'Hamburg',
passengers: 6,
children: 4,
returnFlight: 'no',
date: new Date('2017-05-27T12:00')
}
]

Jeder Eintrag enthält Informationen über die Anzahl der Passagiere und wie viele davon Kinder sind. Je nach Buchung kann es sich um eine Person oder mehrere handeln. Das gilt auch für die Kinder. Für die Anwendung benötigen ihre Anbieter folglich unterschiedliche Übersetzungen:

<table class="table table-striped">
<tbody>
<tr *ngFor="let booking of bookings">
<td>{{booking.from}}</td>
<td>{{booking.to}}</td>
<td i18n="booking.passengers">{{booking.passengers}} ↵
{booking.passengers, plural, =1 {Passenger} other ↵
{Passengers}}</td>
<td i18n="booking.children">{booking.children, plural, =0 ↵
{No children} =1 {One child} =2 {Two children} other ↵
{More than two children}}</td>
<td i18n="booking.returnFlight">{booking.returnFlight, ↵
select, yes {Yes} no {No}}</td>
<td i18n="booking.date">{{booking.date | date: 'M/d/y'}}</td>
</tr>
</tbody>
</table>

Sobald ein Tag mit i18n markiert ist, können Entwickler durch eine spezielle Syntax unterschiedliche Formen für Ein- und Mehrzahl definieren. Der erste Parameter gibt die Anzahl an. Für ihn erwartet das Programm tatsächlich eine Zahl als Wert. Der zweite gibt die gewünschte Methode plural an. Sie vergleicht den Wert des ersten Parameters aus booking.children mit den Konfigurationen des letzten Parameters und gibt die entsprechende Übersetzung zurück.

Der letzte Parameter definiert die einzelnen Stadien. Die Liste lässt sich beliebig fortsetzen (=x). Alle nicht extra definierten Werte können Entwickler mit other abfangen. So kommen nun anhand der Anzahl der Kinder unterschiedliche Übersetzungen zurück:

<td i18n>
{booking.children, plural, =0 {No children} =1 {One child} =2 ↵
{Two children} other {More than two children}}
</td>

Die Übersetzung im XML ist identisch aufgebaut:

<trans-unit id="ce78c2334a8324384adb155b4c30e65cfd6978a2" datatype="html">
<target>
{booking.children, plural, =0 {Keine Kinder} =1 {Ein Kind} =2 {Zwei ↵
Kinder} other {Mehr als zwei Kinder}}
</target>
</trans-unit>

Der zweite Ansatz dynamischer Übersetzung nutzt die Methode select. Die Syntax bleibt in dem Fall gleich, jedoch nutzt man statt einer Zahl einen String, der von booking.returnFlight kommt:

{booking.returnFlight, select, yes {Yes} no {No}}

Auf dessen Basis ist es nun möglich, eine Alternative anzubieten:

<target>{booking.returnFlight, select, yes {Ja} no {Nein}}</target>

Damit die erstellte Übersetzung den Weg in die Applikation findet, ist die Datei zu integrieren. Das Nachladen von Übersetzungen, beispielsweise über ein Backend, ist nicht möglich während die Anwendung läuft. Je nach Projektaufbau geschieht die Integration entweder mittels Just-in-time- oder Ahead-of-time-Methode.

Angular selbst wird vor der eigentlichen Ausführung immer extra kompiliert beziehungsweise für die Nutzung optimiert. Bei Just in time (JIT) passiert das im Browser. Mit dem Ahead-of-time-Ansatz (AOT) übernimmt der Build-Prozess den Vorgang, bevor die Anwendung überhaupt ausgeliefert wurde. Im Browser entfällt nun dieser Teil, wodurch die Applikation schneller läuft, die Build-Zeit sich jedoch erhöht.

Über die Angular CLI können Entwickler die erstellte Übersetzungsdatei beim Bau der Applikation mit folgendem Befehl angeben:

ng build --aot --i18n-file src/locale/messages.de.xlf --locale de ↵
--i18n-format xlf

Der direkte Weg über den Angular-Compiler ist eine weitere Option:

"./node_modules/.bin/ngc" --i18nFile=./src/locale/messages.de.xlf ↵
--locale=de --i18nFormat=xlf

Ohne die Nutzung der Angular CLI, zum Beispiel durch eine eigene Webpack-Konfiguration, kann auch die JIT-Methode eine andere Sprache zur Verfügung stellen. Um das zu bewerkstelligen, sind dem Bootstrap der Anwendung drei Provider mitzugeben. Sie werden nicht wie sonst üblich im Root-Modul, sondern als eigene Parameter der Methode bootstrapModule übergeben. Angular kann so vor dem Start die Templates übersetzen.

Der Provider TRANSLATIONS hält den Inhalt der Übersetzungsdatei als String vor. Hier lässt sich kein externer Pfad angeben. Das gezeigte Beispiel funktioniert, da Webpack durch require angewiesen ist, den angegeben Pfad durch die dahinterliegende Datei zu ersetzen:

import { LOCALE_ID, TRANSLATIONS_FORMAT, TRANSLATIONS } from ↵
'@angular/core';
const options: any = {
providers: [
{provide: TRANSLATIONS, useValue: require('./locale ↵
/messages.de.xlf')},
{provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
{provide: LOCALE_ID, useValue: 'de'}
]
};
platformBrowserDynamic().bootstrapModule(AppModule, options);