i18n für your.trash.net
Von Roman (romanf auf trash.net)
Unsere Mitglieder Self-Service (https://your.trash.net/) wurde von Anfang an auf Mehrsprachigkeit (Internationalization = i18n, weil zwischen I und N 18 Buchstaben liegen) ausgelegt. Dieser Artikel beschreibt, wie dies in PHP mit den Bordmitteln von Unix/Linux (Stichwort GNU gettext) umgesetzt wurde.
*nix Grundlagen
Der Wikipedia-Artikel beschreibt die Grundlagen ziemlich erschöpfend: https://de.wikipedia.org/wiki/GNU_gettext
Für your.trash.net haben wir folgende Verzeichnis-Struktur aufgesetzt (für bessere Lesbarkeit etwas verkürzt):
/your/ = Basis-Verzeichnis von your.trash.net /your/www = Webroot für die virtuelle Domain your.trash.net /your/locale/ = Basis-Verzeichnis für die i18n Files /your/locale/source = Ausgangsfile your.pot, sowie die Klartext-Übersetzungen (your_de.po, your_fr.po, ...) /your/locale/de/LC_MESSAGES/your.mo = Kompiliertes Sprachfile für Deutsch /your/locale/fr/LC_MESSAGES/your.mo = ...
In unserem Fall ist die Original-Sprache in den PHP-Files Englisch. Darum brauchts auch keine .../en/... Struktur.
Workflow
Immer wenn ein Text im Source-Code neu hinzugefügt oder geändert wird, müssen die folgenden Schritte ausgeführt werden:
- xgettext: Sammelt aus allen PHP-Files die in _(...) gekapselten Strings ein und speichert diese im your.pot File
- msgmerge: Führt die Strings aus 1. mit den bereits übersetzten Strings zusammen. Dies ergibt geänderte <lang>.po Files
- Die Übersetzer übersetzen/korrigieren die .po Files (z.B. mit PoEdit)
- msgfmt: Die .po Files werden zu .mo Files kompiliert
Zu beachten ist, dass beim ersten Durchgang leere .po Files erzeugt werden müssen. Das geht nicht mit dem msgmerge Befehl, sondern mit msginit.
Dieser Workflow sowie das Setup der Verzeichnisstruktur ist noch völlig unabhängig von der gewählten Programmiresprache!
Der Einfachheit halber, haben wir diese Befehle in einem kleinen Skript in /your/ zusammengefasst. Dabei werden immer die Schritte 1, 2 und 4 ausgeführt:
cd /your/www
xgettext -d your_trash_net -L PHP --from-code=UTF-8 -o ../locale/source/your_trash_net.pot $(find -name "*.php")
cd ../locale/source
msgmerge -U your_de_DE.po your.pot
msgfmt your_de_DE.po -o ../de_DE/LC_MESSAGES/your.mo
cd ../..
Da xgettext hier mit -L PHP aufgerufen wird, ist dieses Beispiel natürlich auf PHP zugeschnitten.
i18n in PHP
In PHP gibt es (was gibt es da nicht?) eine Integration der gettext Library: PHP Gettext Functions. In diesem Kapitel wird eine einfache Implementierung der Funktionalität zur Auswahl und Aktivierung von Übersetzungen gezeigt.
Es braucht 3 grobe funktionale Blöcke für die Auswahl und Aktivierung von Sprachen:
- Aktivieren einer gewählten Sprache für die gettext Library (damit die gewünschte Sprache gezogen wird)
- Auswahl der gewünschten Sprache im GUI
- Persistente Speicherung der ausgewählten Sprache
Aktivieren einer Sprache
In unserem Beispiel wird die gewählte Sprache intern mit einem 2-Buchstaben-Kürzel (en, de, fr) geführt. Für gettext brauchts die längere Form, darum der Dreh über $supported. Der Rest sollte recht selbsterklärend sein.
$supported = array("en"=>"en_US", "de"=>"de_DE", "fr"=>"fr_FR");
$domain = "your_project";
if(!setlocale(LC_MESSAGES, $supported[$lang]))
exit("error_msg");
bind_textdomain_codeset($domain, "UTF-8");
bindtextdomain($domain, "/your/locale");
textdomain($domain);
Auswahl der Sprache im GUI
Damit der Anwender die Sprache wechseln kann, sollte im GUI entsprechende Schaltflächen vorgesehen sein. Ausserdem sollte - sofern noch keine Sprache gewählt ist und auch keine aus der Persistenz (s. unten) verfügbar ist - ein sinnvoller Default gewählt werden. Hierzu kann man z.B. aus dem Browser-Request HTTP_ACCEPT_LANGUAGE auswerten.
Persistente Speicherung der Sprachwahl
Damit die vom User gewählte Sprache auch erhalten bleibt, bieten sich die üblichen Verdächtigen an: Session, Cookie, Datenbank. Für your.trahs.net ist die Wahl auf Cookie gefallen.
Die gewählte Sprache wird also in einem Cookie beim User abgelegt. Das hat den Vorteil, dass sogar vor der Authentisierung die Sprache schon korrekt gezogen wird. Nachteil ist natürlich, dass Cookie-Allergische User immer auf Englisch bleiben.