Gestern habe ich mich damit beschäftigt ein WordPress Theme zu internationalisieren, d.h. für Übersetzungen in verschiedene Sprachen vorzubereiten. Da die WordPress Dokumentation leider nicht sonderlich übersichtlich ist und es eine Weile gedauert hat, bis ich fündig geworden bin, hier eine kurze Zusammenfassung.
Als Internationalisierung (i18n) wird die Vorbereitung eines Programms o.ä. für die Übersetzung bezeichnet, d.h. es wird eine »Infrastruktur« geschaffen, so dass die eigentliche Übersetzung auch von Nicht-Programmierern übernommen werden kann. Das Übersetzen in andere Sprachen ist die Lokalisierung (l10n).
Grundlage für die Internationalisierung von WordPress (inkl. Themes und Plugins) ist das GNU-Tool Gettext, das nach folgendem Prinzip funktioniert:
-
Alle Strings, die übersetzt werden sollen, werden im Quellcode mit speziellen Funktionen ausgezeichnet
-
Dem Programm (bzw. Plugin oder Theme) wird einmalig ein Stück Code hinzugefügt, das die zur eingestellten Sprache passende Übersetzung einbindet — sofern vorhanden
-
Die markierten Strings werden mit xgettext extrahiert und in einer Template-Datei gespeichert (Endung .pot)
-
Aus diesem Template wird für jede Sprache eine Datei für die Übersetzungen abgeleitet (Endung .po)
-
Die fertigen Übersetzungsdateien werden kompiliert, d.h. maschinenlesbar gemacht (Endung .mo)
1. Vorbereitung des Codes
Die eigentliche Vorbereitung des Quelltextes wird unter Translating WordPress ganz gut beschrieben. Im Wesentlichen müssen sämtliche übersetzbaren Strings durch eine der folgenden beiden PHP-Funktionen ersetzt werden:
__($message, $domain)
Für die Zeichenkette$message
wird innerhalb von$domain
eine passende Übersetzung gesucht und zurückgegeben. Ist keine Übersetzung vorhanden, wird$message
zurückgegeben.Der Parameter
$domain
ist ebenfalls ein String und stellt einen Namensraum (Namespace) dar, der verhindert, dass identische Texte mit unterschiedlichen Übersetzungen in mehreren Kontexten Konflikte auslösen. Voraussetzung dabei ist selbstverständlich, dass die Domain einen eindeutigen Bezeichner besitzt. Bei Plugins wählt man dafür sinnvollerweise den Namen des Plugins, der für sich ja auch bereits eindeutig sein muss. Bei Themes ist die Wahl dieses Bezeichners insofern weniger kritisch, da nicht mehrere Themes gleichzeitig angewendet werden können. Der Name darf sich nur nicht mit dem eines Plugins überschneiden._e($message, $domain)
ist eine verkürzte Schreibweise fürecho __($message, $domain)
Zum Einbinden der Übersetzung ergänzt man noch folgenden Code:
- Für Themes (in functions.php):
load_theme_textdomain('your_domain');
- Für Plugins (wenn das Plugin »foobar« heißt):
$foobar_domain = 'foobar'; $foobar_is_setup = 0; function foobar_setup() { global $foobar_domain, $foobar_is_setup; if ($foobar_is_setup) { return; } load_plugin_textdomain($foobar_domain, 'wp-content/plugins/foobar'); }
2. Erstellung der Template-Datei (.pot)
Insbesondere bei diesem Punkt habe ich lange suchen müssen. In der WordPress-Dokumentation steht nur die lapidare Aussage
Generally, you can download a POT file for WordPress, so you shouldn’t have to generate your own.
Wirklich sehr hilfreich! Nach einigem googlen bin ich dann noch auf diesen Hinweis gestoßen:
Get the makepot.php script and execute it like this:
php makepot.php wp-plugin your-plugin-directory
Hier ist der xgettext-Aufruf, den dieses Script im Wesentlichen fabriziert (auszuführen im Verzeichnis des Themes):
xgettext --keyword=__ --keyword=_e --keyword=_c --keyword=__ngettext:1,2 --keyword=__ngettext_noop:1,2 *.php
Ruft man xgettext per Hand auf, muss man noch beachten, dass xgettext (aus historischen Gründen) eine Datei mit der Endung .po erstellt, die noch umbenannt werden muss!
Alle notwendigen Befehle (xgettext, msginit, msgfmt und msgmerge) installiert man übrigens unter Debian bzw. Ubuntu mit
aptitude install gettext
3. Anlegen und Einbinden einer neuen Übersetzung (.po und .mo)
Ab hier ist der Rest wieder einfach. Der Befehl
msginit -l de_DE -o de_DE.po
initialisiert eine neue .po-Datei (hier z.B. für die locale de_DE). Diese kann der Übersetzer nun mit dem Werkzeug seiner Wahl bearbeiten.
Das Kompilieren in ein maschinenlesbares Format erledigt anschließend die Zeile
msgfmt -o de_DE.mo de_DE.po
Die fertige .mo-Datei muss im Theme- bzw. Plugin-Verzeichnis abgelegt werden. Für das Plugin »foobar« muss die fertige Datei allerdings »foobar-de_DE.mo« heißen!
4. Update einer vorhandenen .po-Datei
Kommen nun (z.B. aufgrund einer neuen Version) weitere zu übersetzende Strings hinzu, muss man nicht wieder von vorne anfangen. Es genügt, die Template-Datei mit dem o.g. Aufruf von xgettext neu zu erzeugen. Anschließend werden die neuen Zeilen mit
msgmerge -U de_DE.po messages.pot
in die vorhandene .po-Datei eingefügt. Die Übersetzung und Kompilierung erfolgen dann wieder wie gehabt.
Links zum Thema
- Translating WordPress
- Internationalizing your plugin (gilt auch für Themes)
- I18n for WordPress developers
- Gettext Handbuch
Update: Im 2. Teil stelle ich eine Möglichkeit vor, die Generierung und Aktualisierung der .po- und .mo-Dateien mit make zu automatisieren.
Danke, das brauchbarste, was ich zum Thema finden konnte!
Sehr schönes Tutorial. Alles kurz und knapp auf den Punkt gebracht. Danke