Ein häufiges Thema in unseren Anwendungen ist die Internationalisierung der Oberfläche . Dabei geht es nicht ausschließlich um die Übersetzung von Labels und Texten sondern auch um das länderspezifische Anzeigen und Entgegennehmen von Zahlen und Daten. Für AngularJS bietet sich das Modul „angular-translate“ für Übersetzungen und die jQuery Bibliothek „globalize“ für das Formatieren von Eingaben an. In diesem Betrag werfen wir einen genaueren Blick auf:
angular-translate
Das Modul bietet für die Übersetzung von Texten entsprechende Filter, Direktiven und einen Service. Diese Übersetzungen basieren auf einem JSON Format welches auch verschachtelte Strukturen erlaubt (s. unten).
„angular-translate“ gliedert sich in mehrere einzelne Pakete, die je nach benötigten Funktionen installiert und verwendet werden können
- angular-translate
- Core Packet
- angular-translate-loader-static-files
- ermöglich das Laden der Übersetzung auf Basis von Dateien
- angular-translate-loader-url
- ermöglicht das Laden der Übersetzungen auf Basis einer URL
- angular-translate-loader-partial
- ermöglich das Laden von Teil-Übersetzungen
Nachdem die gewünschten Pakete installiert und die entsprechenden JavaScript Referenzen gesetzt sind besteht der zweite Schritt darin die Übersetzungen zu konfigurieren. Dies geschieht in aller Regel in der Config-Methode unserer Anwendung.
1. Abhängigkeiten definieren:
angular.module("AngularJSi18n", ['pascalprecht.translate'])
2. Config Methode erweitern (mit Zugriff auf den TranslateProvider)
.config(function ($translateProvider) {
3. Registrierung der Übersetzungen auf Basis der gewünschten Methode:
– Direkt in unserer Anwendung:
Für größere Anwendung wird man diesen Fall vermeiden
$translateProvider.translations('de', { TITLE: "i18n mit AngularJS", MENU: { HOME: 'Startseite' } });
– Über einzelne Dateien (angular-translate-loader-static-files wird benötigt):
Werden die Übersetzungen ausschließlich in der AngularJS Anwendung verwendet und wird keinerlei dynamische Erstellung benötigt.
$translateProvider.useStaticFilesLoader({ prefix: 'resources/i18n/', suffix: '.json' });
= für jede Lokalisierung (z.B. „de_DE“) wird eine entsprechende Datei im angegebenen Pfad gesucht. In unserem Beispiel für Deutsch: resources/i18n/de_DE.json
Diese Datei sollte entsprechende Werte im JSON-Format bereit halten:
{ "TITLE": "i18n mit AngularJS", „MENU“ { "HOME": "Startseite" } }
– über einen Backend-Service (angular-translate-loader-url wird benötigt)
Flexibelste Variante. Denkbar wäre hier eine Java EE Rest Schnittstelle die Java .properties Dateien in das entsprechende JSON Format umwandelt. Damit können dieselben Übersetzungen für das Backend oder weitere Anwendungen verwendet werden wie für unsere AngularJS Applikation.
$translateProvider.useUrlLoader("/webresources/i18nRestService");
= für jede Sprache wird die angegebene URL aufgerufen und um den Parameter „lang“ ergänzt. In unserem Beispiel für Deutsch: „/webresources/i18nRestService?lang=de_DE“ . Bei der Response muss sich wieder um ein JSON Format handeln.
– Partielles Laden von Übersetzungen (angular-translate-loader-partial wird benötigt)
Kann verwendet werden wenn die Datei der Übersetzungen extrem groß sind.
$translateProvider.useLoader('$translatePartialLoader', { urlTemplate: 'resources/i18n/partitial/{part}/{lang}.json' });
= wir registrieren einen Templatepfad in dem uns die beiden Variablen „lang“ für die Sprache und „part“ als Key zur Verfügung stehen. Wir können dann in einzelnen Controllern konkrete Teile der Übersetzungen Abrufen:
.controller('detail', function ($translate, $translatePartialLoader) { $translatePartialLoader.addPart('details'); $translate.refresh(); }
= wird bei eingestellter Kultur „de_DE“ folgenden Pfad abrufen:
‘resources/i18n/partitial/details/de_DE.json‘ und die Übersetzungen aktualisieren.
Welche Sprache darf es sein?
Bevor wir nun unsere Übersetzungen zum Einsatz bringen müssen wir der Anwendung noch mitteilen welche Sprache denn zu nutzen ist. Dies geschieht ebenfalls in der Config-Methode indem wir das Modul anweisen die Browsersprache zu ermitteln. Zusätzlich definieren wir eine Sprache die verwendet werden soll wenn die Browser-Sprache nicht verfügbar ist
$translateProvider.determinePreferredLanguage(); $translateProvider.fallbackLanguage('de');
Wichtig dabei ist das die Browser-Sprache inklusive Region ermittelt wird. Demzufolge wird ein auf Deutsch eingestellter Browser in aller Regel die Datei „de_DE“ suchen. Diese Unterscheidung der Regionen ist in unseren Projekten eher unüblich aus dem Grund bietet angular-translate die Möglichkeit die zur Verfügung stehenden Sprachen zu deklarieren und auch ein Mapping an zu geben:
$translateProvider.registerAvailableLanguageKeys(['de', 'en'], { 'en_*': 'en', 'de_*': 'de' });
= alle Kulturen die mit „en“ oder „de“ beginnen, also unabhängig der Region, werden auf unseren Sprachschlüssel „en“ bzw. „de“ gemappt.
Übersetzen bitte!
Die eigentliche Übersetzungen ein zu setzen ist nun der kleinste der Schritte. “angular-translate” bietet drei unterschiedliche Varianten an um Texte zu übersetzen:
per Filter (‚translate‘)
{{'TITLE' | translate}}
per Direktive (‚translate‘)
<span translate='TITLE'></span>
per Service (‚$translate‘)
$translate('TITLE').then(function (text) { vm.title = text; });
Bei der Verwendung des Services ist es wichtig zu beachten das es sich bei dem Rückgabewert des translate-Services nicht um die Übersetzung handelt sondern um ein „promise”, aus dem Grund verwendet das Beispiel die Methode “then” um die Übersetzung nach erfolgreicher Ermittlung entgegeben zu nehmen und zu verarbeiten.
Egal welche Methode zum Einsatz kommt, die Übersetzungen werden auf Basis des Keys ermittelt (im Beispiel ‚TITLE‘). Innerhalb der Übersetzungsdateien kann wie oben bereits gesehen auch mit einer Hierarchischen Struktur gearbeitet werden. Die entsprechenden Keys werden dann mit einem Punkt zusammengesetzt: „MENU.HOME“
Übersetzung mit Parametern
In den Übersetzungen lassen sich auch dynamische Werte verwenden. Diese sind mittels „{{}}“ im Nachrichtentext gekennzeichnet:
"DEMOTITLE": "Demo: {{title}}"
Bei der Verwendung kann dieser Parameter dann übergeben werden:
{{'DEMOTITLE' | translate:'{title: "i18n"}'}} <span translate='DEMOTITLE' translate-values='{title: "i18n"}'></span> $translate('DEMOTITLE', {title: "i18n"}).then(function (text) { vm.title = text; });
$translateSanitization: No sanitization strategy has been configured
Eine Warnung die bei der Verwendung von „angular-translate“ im Log des Browsers auftaucht. Diese Warnung weißt daraufhin das keinerlei Escaping der Übersetzungen stattfindet. Mit dieser Konstellation ist es von Angreifern leicht möglich schädliche Scripte aus zu führen da diese über die Übersetzungs-Dateien ungefiltert von der Anwendung ausgeführt werden.
"DEMOTITLE": "alert('Böses Script)"
Wird zu einer entsprechenden Anzeige des alerts-führen. Im Standard stehen folgende Strategien zur Verfügung:
- null : (Default)
- sanitize: bereinigt die gesamte Übersetzung von HTML/Script Tags
- escape: escaped die gesamte Übersetzung
- sanitizeParameters: bereinigt nur die Parameter von HTML/Script
- escapeParameters: escaped nur die Parameter
Verwendung (.config-Methode):
$translateProvider.useSanitizeValueStrategy('sanitize')
(‘sanitize’ wird ab Version 3.0 auch der Standardfall sein)
Mit ‘angular-translate’ ist das Internationalisieren von Anwendungen wie gerade gesehen kein Hexenwerk. Die verschiedenen Quellen die für das Laden der Übersetzungen herangezogen werden können sind flexibel Einsetzbar und sollten in jeder Projekt-Konstellation eine passende Möglichkeit bieten.
Hier gibt es das Projekt noch einmal komplett…
Den zweiten Teil dieser Reihe werden wir der Verarbeitung von lokalisierten Daten mittels ‘globalize’ widmen…
2 Kommentare. Hinterlasse eine Antwort
für jeden kultur!?
komischer kulturbegriff …
Ja stimmt. Habe jetzt “Kultur” durch “Lokalisierung” ersetzt.
Danke!