Von Pascal Precht Donnerstag, 06. Juni 2013

angular-translate - i18n für Angular Apps, einfach gemacht

Viele haben sie schon für sich entdeckt, für Andere ist es ein noch völlig neuer Begriff: AngularJS - Googles hauseigene JavaScript Bibliothek.

Dabei ist es gar keine Bibliothek im eigentlichen Sinne. AngularJS ist ein vollwertiges Framework, welches Entwicklern das Leben erleichtert, wenn es um Single-Page-Applications, kurz SPA's, geht.

angular

Wir bei Neoskop haben sehr früh erkannt, dass AngularJS ein sehr großes Potential birgt und haben bereits mehrere Apps auf Basis dieses Frameworks für verschiedene Plattformen (Desktop, Mobile etc.) realisiert. Darunter zum Beispiel die Stiebel Heizlast-App, welche mit Webtechnologien wie HTML5, CSS3 und JavaScript entwickelt und anschließend mit Phonegap zu einer hybriden App portiert wurde.

Parlez-vous français?

Apps in verschiedenen Sprachen? Sollte heutzutage eigentlich kein Problem mehr sein und AngularJS hat darauf natürlich auch eine Antwort: Internationalisierung und Lokalisierung in sämtlichen Filterkomponenten. Leider beschränkt sich der Support nur auf Datums-, Zahlen- und Währungsformatierungen - für die weiteren Inhalte gab es noch keine Lösung, die für unsere Projekte gepasst hätte.

Um dies zu ändern, habe ich das Internationalisierungsmodul angular-translate entwickelt, mit dem mehrsprachigen Angular Apps auch aus Content-Sicht wirklich nichts mehr im Wege steht. Rein gar nichts.

angular-translate enthält, neben einer Filterkomponent, eine Direktive auch einen injizerbaren Service, um das Internationalisieren von Inhalten zu ermöglichen. Darüber hinaus existieren Extensions, um beispielsweise Dateien, in denen Übersetzungsdaten geschrieben stehen, asynchron nachzuladen oder der App beizubringen, welche Sprache der Nutzer zur Laufzeit gewählt hat.

Installation – Es geht los!

Glücklicherweise gibt es Tools wie Yeoman, Grunt und Bower, die uns Frontend-Entwicklern das Leben erleichtern und somit die Installation von angular-translate.
Der einfachste Weg, angular-translate lokal zu installieren? Bower! Dazu einfach in ein Projektverzeichnis navigieren und den folgenden Befehl auf der Commandozeile ausführen:

$ bower install angular-translate

Selbstverständlich kann auch das GitHub Repository geklont, sämtliche Dependencies installiert und via Grunt ein Build vom Source erstellt werden:

$ git clone https://github.com/PascalPrecht/angular-translate
$ cd angular-translate
$ npm install
$ bower install
$ grunt build

Anschließend befindet sich ein frisches Modul im dist Verzeichnis. Zu guter Letzt muss dieses Modul noch in ein entsprechendes HTML-Dokument eingebunden werden.

<script src="pfad/zu/angular.js"></script>
<script src="pfad/zu/angular-translate.js"></script>

angular-translate benutzen

Wie alle Module, die nicht Teil des Kerns von Angular sind, muss man auch angular-translate per Dependency Injection als Abhängigkeit der eigenen App deklarieren.

angular.module('myApp', ['pascalprecht.translate']);

Ist das erst einmal geschehen, stehen einem sämtliche Komponenten zur Verfügung, die angular-translate mit an Bord hat. So kann beispielsweise der $translate Service oder der entsprechende translate Filter per Dependency Injection in seinen Controllern und Services verfügbar gemacht werden.

angular.module('myApp').controller('Ctrl', function ($translate) {
  // mach was mit $translate service
});

Dieser Schritt ist nicht unbedingt notwendig, da es andere Wege gibt die Komponenten von angular-translate zu nutzen.

Der App Sprachen beibringen

Jetzt, da angular-translate Teil der App ist, können die vorhanden Optionen genutzt werden, um sie zu internationalisieren.

Auch bei Neoskop gibt es Projekte, bei denen es völlig ausreicht eine App in einer Sprache auszuliefern. Hierfür gibt es in angular-translate Funktionen, die nichts weiter machen als so genannte Translation ID's als Platzhalter für die App zu registrieren.

Um der App eine Sprache beizubringen, muss sie über eine vorhandene Translation-Table in Kenntnis gesetzt werden. Hierzu liefert der nun verfügbare $translateProvider eine Methode translations(), der ein JavaScript-Hash als Translation-Table übergeben wird. Die Keys entsprechen den Translation ID's während die Values die konkreten Übersetzungen darstellen.

angular.module('myApp').config(function ($translateProvider) {

  // Translation-Table registrieren
  $translateProvider.translations({
    'HEADLINE': 'Großartig! Mehrsprachigkeit in meiner App!',
    'INFO_TEXT': 'Irgendein Infotext in der App.'
  });
});

Die App kennt nun bestimmte Übersetzungen und kann diese in der View-Schicht entsprechend auflösen. Dazu kann entweder die translate Direktive oder der translate Filter verwendet werden.

<!-- Verwendung des Filters -->
<h1>{{'HEADLINE' | translate}}</h1>

<!-- Verwendung der Direktive -->
<h1 translate="HEADLINE"></h1>

Mehr dazu gibt es im Wiki zum Nachlesen.

Mehrsprachigkeit

Um zusätzliche Sprachen in der App verfügbar zu machen, werden lediglich weitere Translation-Tables registriert. Wird mehr als eine Translation-Table registriert, müssen diese einen entsprechenden Key erhalten, damit angular-translate die jeweilige Translation-Table für eine bestimmte Sprache identifizieren kann.

Das erste Beispiel könnte also wie folgt erweitert werden:

angular.module('myApp').config(function ($translateProvider) {

  $translateProvider.translations('de_DE', {
    'HEADLINE': 'Großartig! Mehrsprachigkeit in meiner App!',
    'INFO_TEXT': 'Irgendein Infotext in der App.'
  });

  $translateProvider.translations('en_US', {
    'HEADLINE': 'Awesome! i18n in my App!',
    'INFO_TEXT': 'Some text'
  });

  // Welche Sprache soll nun benutzt werden?
  $translateProvider.preferredLanguage('de_DE');
});

Es hat sich nichts weiter geändert, als die Zuweisung einer Translation-Table zu einem bestimmten Key. Anschließend muss angular-translate mit $translateProvider.preferredLanguage() mitgeteilt werden, welche Translation-Table tatsächlich benutzt werden soll.

Es könnte beispielsweise ein Controller implementiert werden, der sich um den Wechsel der Sprache kümmert. Dazu wird die Methode uses() des $translate Services verwendet, um die Sprache zur Laufzeit zu wechseln.

Folgendes Markup beschreibt den Scope des LanguageCtrl. Dieser definiert eine Funktion change(), die einen Translation-Table Key übergeben bekommt, um so die Sprache zu wechseln.

<ul ng-controller="LanguageCtrl">
  <li><a href="#" ng-click="change('en_US')">English</a></li>
  <li><a href="#" ng-click="change('de_DE')">German</a></li>
</ul>

Der Controller-Code könnte so aussehen:

angular.module('myApp').controller('LanguageCtrl', function ($scope, $translate) {

  $scope.change = function (key) {
    $translate.uses(key);
  };

});

Hier ist ein funktionierendes Beispiel auf plnkr.co zu finden.

Was noch?

Seit Version 0.9.0 existieren für angular-translate verschiedenste Extensions, die beispielsweise das asynchrone Nachladen von Übersetzungsdaten ermöglichen oder einer Angular App beibringen, sich zu merken, welche Sprache von einem Benutzer gewählt wurde.

Eine Liste sämtlicher Extensions gibt es hier.

Ein Blick in die Glaskugel

angular-translate steht kurz vor Version 1.0.0. Geplant sind ein verbesserter Support für Pluralisierung und vielleicht sogar ein hübsches Logo, um dem Modul die nötige Identität zu verpassen. Außerdem wurde kürzlich die offizielle Dokumentation gelauncht. Dort kann man alles nachlesen und mit Live-Examples herumspielen.

Feature-Requests sind natürlich sehr willkommen! Ein Großteil von angular-translate ist durch die Ideen anderer Entwickler in der Open Source Community entstanden. Ja, eure Wünsche werden gehört und erfüllt!