Die Inter­na­tio­na­li­sierung ist immer wieder ein großes Thema in Software-Projekten. Heutzutage wandern verstärkt Teile des Backends ins Frontend. Für moderne Single Page Appli­ca­tions (SPA) muss hier seitens der Framework-Technologie überlegt werden, wie man am Besten mit der Übersetzung bzw. dem größeren Thema der Inter­na­tio­na­li­sierung — von der die reine Übersetzung nur ein Teila­spekt ist — umgeht. Es gab hier in Vergan­genheit vielfältige Entwick­lungen, die aber oft nicht ausge­reift sind. Ich möchte versuchen einen Überblick zu geben.

Bereiche der Inter­na­tio­na­li­sierung

Mit dem Begriff der Inter­na­tio­na­li­sierung fassen wir die Übersetzung von Texten aber auch die Anpassung an andere Länder und Kulturen in einen handlichen Begriff zusammen. Übersetzung hat man in den Anfängen der Software-Entwicklung sehr trivial unter­stützt. Es wurden einfache 1:1-Mappings genutzt, die den Original-Text übersetzten. Dann wurde dieser Text im Quelltext über eine ID bzw. den meist englisch­spra­chigen Origi­naltext verwiesen. Problem hierbei ist, dass die Übersetzung nicht ganz so trivial ist. So gibt es zum Beispiel folgende „Details“, die man beachten sollte:

  • Platz­halter im Text für dynamische Werte aus der Anwendung
  • Plural-Regeln der indivi­du­ellen Regionen und Sprachen müssen berück­sichtigt werden. Es gibt Länder mit mehr als nur Singular und Plural - dort gibt es mehrere Gruppen von Formu­lie­rungen je nach der auszu­drückenden Anzahl - im arabi­schen z.B. 6 an der Zahl.
  • Gender-Unterstützung - wir wollen den Nutzer ja möglichst passend und höflich anspre­chen. Dazu gehört dann auch das Geschlecht.

Es gibt auch ein paar gute, englisch­spra­chige Slides von Google zu dem Thema.

Übersetzungs-Technologien

  • ICU: Das aktuell leistungs­stärkste Format. Hier verpackt man die Logik zur Übersetzung mit in den Überset­­zungs­­text. Dies reduziert die Menge an Doppel­de­fi­ni­tionen in der Überset­zung. Gleich­zeitig läuft ICU in Gefahr, dass die Erstellung der Übersetzung nicht so trivial ist wie bei einfachen Key-Value-Paaren. MacOS und iOS nutzen das XLIFF-Format für die Übersetzung mittels ICU. Gibt‘s zum Beispiel auch von IBM für Java-Entwickler.
Das ICU-Format nutzt speziell forma­tierte Ausdrücke innerhalb der Übersetzung für die Logik­teile.
  • Gettext: Älteres Format, welches noch oft im OpenSource-Bereich verwendet wird. Es handelt sich um eine Entwicklung der Free Software Foundation. Leider verfügt Gettext über keine Gender-Unterstützung und nur reduzierte Plural-Unterstützung (im Vergleich zu ICU nur eine Plural-Logik pro Text) lassen es aktuell als weniger sinnvoll einsetz­baren Kandi­daten erscheinen.
  • Eigene XML- bzw. Text-Dateien: Android scheint auf ein XML-basiertes triviales Key-Value-System aufzu­setzen. Von Gender-Unterstützung wird leider nichts gesagt. Plural-Unterstützung gibt es mit den sogenannten Quantity Strings. In der alten Java-Welt gibt es Property-Files - auch in einem XML-Dialekt.

Lokali­sie­rungs­daten

Es gibt hier eigentlich nur einen Spieler und zwar das sogenannte CLDR-Archiv des Unicode-Konsortiums. Die dort gesam­melten Daten werden von allen großen IT-Unternehmen wie Apple, Google, Microsoft und IBM genutzt.

Enthalten ist in diesem Repository z.B. folgendes:

  • Daten für die Forma­tierung und das Parsen von Zahlen, Währungen, Datums­werten, Zeiten und Zeitzonen.
  • Übersetzung von festste­henden Namen für Sprachen, Länder, Regionen, Währungen, Wochen­tagen, Einheiten und mehr
  • Infor­ma­tionen zur Sprache: Plural-Formen, Geschlechter, Regeln für Sortierung und Suche, Laufrichtung der Schrift, etc.
  • Lände­r­in­for­ma­tionen: Telefon­num­mern, Währungen, Kalender-Formate, Tasta­tur­lay­outs, etc.
Das Unicode Projekt beher­bergt auch das Archiv Common Locale Data Repository (CLDR).

Wie man sieht ist dies eine ganze Menge. Es macht also unbedingt Sinn diese mühevoll gesam­melten und gepflegten Daten für eigene Anwen­dungen zu nutzen.

Für das Frontend besteht durch den Übergang zu JSON als Ausgangs­format hier im Prinzip eine einfache Möglichkeit zur Nutzung dieser Daten. Leider stellt sich im Detail dann raus, dass die Daten oft ungünstig struk­tu­riert (z.B. gibt es die Namen der Jahrzehnte des indischen Kalenders auch im Deutschen Daten­be­stand) sind und es daher oft erfor­derlich erscheint die Daten für eigene Zwecke neu zusam­men­zu­stellen bzw. zu reduzieren.

Glück­li­cher­weise gibt es mittler­weile die gleichen Daten auch auf Github und in NPM. Dort aber besser struk­tu­riert. Details dazu finden sich hier im README.

Optionen im Frontend

Dieses hier ist jetzt keine Liste mit Anspruch auf Vollstän­dig­keit. Dazu ist die Frontend-Landschaft viel zu diffus. Es handelt sich vielmehr um eine Liste der funda­men­talen Techno­lo­gien. Die hier genannten Lösungen machen einen etablierten Eindruck und werden auch oft tief in Frame­works versteckt als Basis-Technologie verwendet:

Intl

Die neue Standard-API, die in modernen Browsern verbaut ist. Enthält aktuell nur Funktio­na­li­täten zur Forma­tierung von Datums­werten und Zahlen. Inter­essan­ter­weise sind nicht mal die passenden Parser an Board. Weiterhin gibt es Möglich­keiten Strings sprach­s­pe­zi­fisch zu verglei­chen. Aufgrund der großen Daten­menge ist dies aber nicht im sonst umfang­reichen Polyfill möglich (notwendig für aktuelle Versionen von Safari + alte Versionen von Internet Explorer (vor Version 11), Chrome (vor Version 24) und Firefox (vor Version 29).

Während die Browser zumindest die für den Nutzer relevante Sprache in der nativen API mitbringen sollten, kann dies für den Polyfill aufwen­diger sein. So ist zum Beispiel allein die Deutsche Übersetzung aktuell rund 75KB gross. Vieles was enthalten ist, ist für die meisten Nutzer eher wenig relevant (indische Kalender, etc.). Eine Beschränkung — zumindest für die meisten Locales — auf den Grego­ria­ni­schen Kalender wäre sicher zweck­mä­ßiger.

Für die Nutzung wird das Paket cldr-core und weitere Pakete von CLDR-JSON benötigt. Dieses Projekt hat den großen Vorteil, dass es von John Emmons — einem IBM Mitar­beiter der seit 2005 intensiv im Unicode-Umfeld tätig ist — betreut wird. Inter­essant ist, im Vergleich zur vorhe­rigen Kritik, dass diese Daten recht fein struk­tu­riert sind und so auch im Frontend-Umfeld Sinn machen würden. Es ist demnach so, dass erst durch die Verar­beitung durch die (Grunt-basierten) Build-Tools vom IntlPo­lyfill die in NPM vorhan­denen Daten zusam­men­gelegt und in der Größe unhand­licher werden. Hier wäre für zukünftige Versionen eine Verbes­serung wünschens­wert.

Globalize

jQuery-Projekt für die Globa­li­sierung (vermutlich benutzt man hier Globa­li­sierung um den Projekt­namen wieder­auf­zu­grei­fen). Unter­stützt die Forma­tierung und das Parsen von sowohl Datums als auch Zahlen­werten. Bei Währungen wird nur die Forma­tierung unter­stützt. Soweit man keinen Wert auf die Erkennung der Währung liegt kann man natürlich den Zahlen­parser auch als Währungs­parser zweck­ent­fremden. Es gibt auch eine Funktio­na­lität zur Forma­tierung von relativen Datums­in­for­ma­tionen wie z.B. „vor einem Monat“. Globalize kann als eines der Urgesteine gelten, da es schon seit rund 5 Jahren auf dem Markt ist.

Das Globalize-Projekt ist Teil der jQuery-Community.

Im Rahmen der Entwicklung von Globalize sind einige weitere Tools zum Umgang (Download + Prozes­sie­rung) mit CLDR-Daten entstanden (nachdem man von eigenen Daten gewechselt ist). Globalize liefert die CLDR-Daten nicht mit, aber kommt mit einer Armee von Abhän­gig­keiten z.B. dem CLDR-Daten-Downloader. Hier muss jeder Entwickler neben der Instal­lation des Paketes im Anschluss auch die notwen­digen CLDR-Daten via Komman­do­zeile downloaden. Man kann so natürlich gewähr­leisten dort immer den aktuellen Stand zu besitzen - soweit die Entwickler daran denken auch immer alles fleissig zu updaten.

Die Daten, die im Paket mit Globalize geladen werden, sind noch größer, als die vom Intl Polyfill. Hier ist allein die Liste der Währungen über 70KB. Diese Mengen an Daten sind im Umfeld von NodeJS vielleicht okay. Im Frontend-Umfeld ist diese Daten­menge definitiv proble­ma­tisch. Natürlich gibt es Bilder, die größer sind - der elementare Unter­schied bei JSON-Datenstrukturen ist, dass diese Daten durch den JavaScript-Parser laufen und nicht so klein (im Speicher) bleiben wie die eigentlich Dateigröße sugge­rieren würde.

FormatJS

FormatJS ist eine auf Intl aufset­zende Schicht mit zusätz­lichen Funktionen zur Forma­tierung von relativen Zeiten und ein ICU-kompatibles Message-Format. Haupt­au­genmerk liegt auf der Integration der verschie­denen Features mit Frame­works wie React, Amber und Templating-Libraries wie Handlebars oder Dust. Weiterhin kommt eine recht inter­essante Funktio­na­lität eines sogenannten Format-Caches, welches die Neuver­ar­beitung von Ausdrücken reduziert und somit für die Ausfüh­rungs­ge­schwin­digkeit zuträglich ist. FormatJS nutzt eine Weiter­ent­wicklung von Messa­ge­for­mat.js des ICU Messa­ge­formats in JavaS­cript.

Das FormatJS-Projekt wurde von Yahoo als OpenSource veröf­fent­licht.

Während Globalize für sich allein stehend, unabhängig von Intl funktio­niert, erfordert FormatJS die Existenz der API bzw. des Polyfills. FormatJS ist eine Entwicklung von Yahoo. Was im Prinzip erstmal gut klingt ist bei genauerer Betrachtung leider nicht ganz so positiv, da der Footer der Webseite sugge­riert, dass diese Library seit 2014 keine größeren Updates mehr erhalten hat.

FormatJS kommt weitest­gehend mit den Daten von Intl bzw. dem Intl Polyfill aus. Das Messa­ge­Format benötigt weiterhin eine plural­Ru­le­Function pro Sprache. Das relative Forma­tieren von Datum/Zeit benötigt eine zusätz­liche Daten­struktur vom CLDR-Bestand. Diese umfassen aber je nach Sprache nur rund 2KB. Das ist im Vergleich zu den anderen genannten Werten geradezu wenig. Die Daten liegen im Projekt intl-relativeformat offline vor (soweit dieses über das NPM-Paket instal­liert wird). Leider sind diese Pakete nur in Form von JSONP-ähnlichen Daten vorhanden, die sich automa­tisch an das globale IntlRe­la­ti­ve­Format binden. Dieses Vorgehen ist aber für moderne ES2015(ES6)-Buildprozesse eher hinder­lich, da auf diesen Wege die Daten nicht einfach integriert werden können. Die Daten sind aber eigentlich in dem CLDR-JSON-Paket auch feingra­nu­larer vorhanden. Hier wäre es sinnvoll sich eine bessere ES2015(ES6)-konforme Integration zu überlegen. Die Daten werden durch das Yahoo eigene Tool formatjs-extract-cldr-data zusam­men­ge­stellt. Evtl. kann dieses in Zukunft entspre­chend verbessert werden.

Zusam­men­fassung

Zusam­men­ge­fasst könnte man die Entscheidung zum Einsatz der Techno­logie wie folgt verein­fa­chen:

  • Übersetzung von Texten: MessageFormat/ICU
  • Datums­for­ma­tierung: natives Intl-Objekt bzw. Polyfill
  • Zahlen­for­ma­tierung: natives Intl-Objekt bzw. Polyfill
  • Forma­tierung relative Datums­werte: FormatJS oder Globalize
  • Parsen von Zahlen: Globalize oder eigene Lösung
  • Parsen von Währungen: eigene Lösung
  • Parsen von Datum/Zeit: eigene Lösung

Einfache Textüber­set­zungs­lö­sungen

Ein kleine Liste von einzelnen Libraries für die Übersetzung von Texten:

  • messa­ge­for­mat.js: ICU Messa­ge­Format für JavaS­cript - i18n Plural und Gender Varianten werden unter­stützt
  • Jed: Gleicher Autor wie Messa­ge­For­matJS - aber diesmal mit Gettext statt ICU als Basis/Inspiration
  • polyglot.js: Von Airbnb entwi­ckelte einfache Lösung (Keine Abhän­gig­keiten) zur Überset­zung. Enthält hard-coded die Pluralization-Rules für aktuell 7 Varianten (mit rund 30 Sprachen).

Spezielle Bibilio­theken

  • MomentJS: Bibiliothek zur Arbeit mit Datums­werten z.B. die einfache Berechnung sowie deren Forma­tie­rung. Die Locales werden als seperate JavaScript-Dateien via NPM/GitHub mit ausge­lie­fert. Die Daten werden scheinbar manuell von Autoren gepflegt und basieren nicht auf CLDR-Daten. (Es gab dazu mal einen Versuch - der aber nach zwei Jahren Inakti­vität wohl als gescheitert betrachtet werden muss.) Man kann aber auch via Grunt einen eigenen Build mit den benötigten Locales bauen.
  • Moment Timezones: Bibilothek zur Arbeit mit Zeitzonen.

(MVC-)Framework-Lösungen für i18n/l10n

Hier noch eine kleine Liste von Framework-spezifischen Übersetzungs- und Lokali­sie­rungs­lö­sungen:

  • ember-i18n: Einfache Überset­zungs­lösung für Ember. Nur Messages mit Plural-Regeln vom CLDR.
  • ember-intl - Inter­na­tio­na­li­sierung für Ember mittels FormatJS.
  • react-intl: Meist genutzt Lösung für React wie es scheint
  • i18n-msg: Ein Custom-Element für Polymer zur Übersetzung von Texten
  • angular-i18n: Dokumen­tation zur einbauten Lokali­sierung in Angular. Forma­tierung für Zahlen, Datum und Geldwerte. Plural­formen und Gender­formen werden unter­stützt.
  • angular-translate: AngularJS module with support of i18n and l10n including lazy loading and plura­li­za­tion.