Die Internationalisierung von Webprojekten ist ein Thema, dass in der Entwicklung schon sehr früh bedacht werden sollte. Selbst wenn in einem Projekt anfangs noch keine Pläne dafür vorliegen, ist es nicht gesagt, dass dies immer so bleiben wird.
Glücklicherweise bieten PHP-Frameworks inzwischen Werkzeuge dafür an, jedoch hat sich im Verlauf der Wechsel von Major Releases einiges geändert. Informationen zur Internationalisierung und Lokalisierung sind z.T. aus den Frameworks entfallen. Wo Zend Framework 1 noch mit Zend_Locale, seinen Unterklasse und Data XML-Dateien aufwartete, hat der Nachfolger Zend Framework 2 sich ganz von dem Locale Namespace getrennt. Viele der darin enthaltenen Funktionalitäten konnten nun von der Intl PHP-Extension übernommen werden.
Die Intl PHP-Extension bietet mehrere Klassen und Funktionen an, mit der länderspezifische Formatierungen, Sortierungen und Zeitinformationen umgesetzt werden können und ist somit ein Tool, welches schon seit Langem zu jeder guten PHP Installation dazugehören sollte.
Infomationen zur Verwendung der IntlCalendar-Klasse wurden bereits hier erläutert.
Die Unterschiede der verschiedenen Länder sind jedoch so umfangreich, dass früher oder später der Entwickler einen Punkt erreicht, an dem auch die Intl Extension keine passenden Daten bietet. Oder doch?
Intl ResourceBundle
Zur Extension gehört auch die ResourceBundle-Klasse, die für sich alleine genommen, vorerst gar nichts kann. Ihre Aufgabe ist es, aus einer Ressource anhand einer Lokalisierung bzw. Erkennung die länderspezifischen Daten auszulesen und zurückzugeben. Diese Ressourcen sind jedoch nicht zwingend in einer Installation der Extension integriert und müssen zunächst einem Projekt bereitgestellt werden. Hier bietet das ICU Project freundlicherweise eine Sammlung von Ressourcen an, die von der ResourceBundle-Klasse verwendet werden kann. Darunter sind z.B. Währungen, Regionen, Sprachen, Zeitzonen und mehr zu finden. Dass der Entwickler auch auf selbst erstellte Ressourcen zurückgreifen kann, muss wohl nicht weiter erwähnt werden.
„Jetzt mal ran an den Code“
Mit den Text-Dateien als Ressourcen ist leider noch nicht viel anzufangen. Diese muss man vorher in binäre Dateien konvertieren, damit sie überhaupt von ResourceBundle gelesen werden können. Dieser Schritt wird in der Konsole mit dem Programm genrb durchgeführt, das im Paket mit anderen Programmen vom ICU-Project heruntergeladen werden kann.
Als Beispiel nehmen wir eine Ressource für die deutschsprachige Bezeichnungen von Kalendernamen:
// filename: de.txt de{ Types{ calendar{ buddhist{"Buddhistischer Kalender"} chinese{"Chinesischer Kalender"} coptic{"Koptischer Kalender"} ethiopic{"Äthiopischer Kalender"} ethiopic-amete-alem{"Äthiopischer Kalender u0022Amete Alemu0022"} gregorian{"Gregorianischer Kalender"} hebrew{"Hebräischer Kalender"} indian{"Indischer Nationalkalender"} islamic{"Islamischer Kalender"} islamic-civil{"Bürgerlicher islamischer Kalender"} japanese{"Japanischer Kalender"} persian{"Persischer Kalender"} roc{"Kalender der Republik China"} } } }
Diese wandeln wir mit genrb in eine Binärdatei für ResourceBundle um:
> genrb -d /path/to/project/resources/calendar/ de.txt
Mit der Option -d wird das Zielverzeichnis der erstellten Ressource angegeben. Das resource-Verzeichnis in unserem Projekt (/path/to/project) soll all unsere Ressourcen enthalten. Da wir normalerweise weit mehr Länder als nur Deutschland haben und jedes Land eine eigene res-Datei für die Kalendernamen bekommt, wurde das Unterverzeichnis calendar erstellt. Darunter befindet sich unsere neue Datei de.res.
Mit folgendem PHP-Script testen wir unsere neu erstellte Ressource:
Der erste Parameter im Konstruktor der ResourceBundle-Klasse stellt also den Dateinamen ohne Suffix dar und ist nicht zwingend eine Lokalisierung, wie es die Dokumentation von ResourceBundle aussagt. Der zweite Parameter enthält den Pfad zum Verzeichnis, in dem sich die Ressourcen für die Kalendernamen befinden. Die Dokumentation spricht hier von „$bundlename“.
Übrigens wird im Fehlerfall von ResourceBundle keine Exception oder ein PHP Error geworfen, sondern einfach nur NULL zurückgeliefert. Das kann in der Entwicklung einiges an Nerven kosten.
Das ResourceBundle nutzt auch das Array Access Pattern, weswegen ebenfalls folgende Schreibweise verwendet werden kann:
$calendars = $res['Types']['calendar'];
Aber: Es implementiert weder das ArrayAccess Interface noch eines der Iterator Interfaces. Lediglich das Traversable Interface wird genutzt.
Ein Feature für Symfony 2 Nutzer
Mit der Intl Component von Symfony 2 kann bei installiertem genrb eine Ressource direkt aus einer Datenstruktur erstellt werden.
In diesem Beispiel wird sowohl die Binär- als auch die Textdatei in dem in $path angegebene Verzeichnis erstellt.
// de.txt de{ Data{ "entry1", "entry2", } }
Das FlagbitCurrencyBundle für Symfony 2
Mit dem FlagbitCurrencyBundle lassen sich die Währungssymbole, -namen und Abkürzungen ausgeben. Auch hier wird im Fall einer binären Ressource die ResouceBundle-Klasse über das Framework Symfony 2 verwendet.
Die Welt ist im Wandel
In den verschiedenen Ländern kann es gelegentlich vorkommen, dass sich kulturelle oder gesetzliche Änderungen ergeben, die auch Auswirkungen auf die Internationalisierung in Webprojekten haben können. Von daher ist es gut seine Daten recht flexibel und von Frameworks/Projekten entkoppelt vorliegen zu haben und bei Bedarf aufs neue generieren zu können. Mit dem ResourceBundle der Intl Extension haben PHP-Entwickler die Möglichkeit dafür bekommen.
0 Kommentare