Wo liegen die Herausforderungen?
Als Knackpunkt gibt es im wesentlichen zwei Faktoren. Zum einen solltest Du in etwa wissen wie und wo Text in Magento übersetzt wird, insofern die passende Lokalisierung geladen wurde. Der zweite Schritt ist zu verstehen, woher Übersetzungen kommen und wie diese geladen werden. Genau diese beiden Punkte untersucht der Artikel.
Wie wird übersetzt?
Grundlegend werden in Magento Strings bzw. Zeichenketten nur übersetzt, wenn diese mittels einer speziellen Helfermethode aus den vorhandenen Übersetzungen geladen werden. Im Quellcode wird diese zum Beispiel wie folgt auf angesprochen:
echo $this->__(“My Orders”);
Statt direkt Text im Template zu hinterlegen, wird dieser an die “magische” Methode __() übergeben, die durch die abstrakte Klasse Mage_Core_Helper_Abstract in jeden Helper verfügbar ist.
Wie arbeitet die magische Methode?
Die “magische” Methode ruft in der Klasse Mage_Core_Model_App die Methode getTranslator() auf und bekommt ein Objekt der Klasse Mage_Core_Model_Translate zurück. Darin wird wiederum die Methode translate($args) verwendet, um die Übersetzung vorzubereiten.
Die Übersetzung wird dann mit der Methode _getTranslatedString() (ebenfalls in Mage_Core_Model_Translate) geladen. Der Text, der an die Helfermethode __() übergeben wurde, wird dort als Index für das assoziative Array $_data genutzt das als Instanzvariable in Mage_Core_Model_Translate definiert ist. Darin sind zur Laufzeit alle relevanten Übersetzungen geladen.
Bei unserem Beispiel oben wird geprüft ob der Array-Schlüssel “My Orders” existiert. Wenn ja, wird der zugeordnete Wert zurückgegeben. Bei einer deutschen Lokalisierung wird dort “Meine Bestellungen” zurückgegeben werden. Existiert der Array-Schlüssel nicht, wird der ursprüngliche Text zurückgegeben.
Variablen im Text
Die semi-automagische Übersetzung klingt praktisch. Die Wrapper-Methode für alle ausgegebenen Strings zu verwenden ist nicht kompliziert. Früher oder später begegnest Du jedoch der Frage, wie werden Strings übersetzt, wenn sie Variablen enthalten?
Ganz einfach: Es werden Platzhalter verwendet. Die Technik ist ähnlich wie bei der PHP-Funktion sprintf(), mit der formatierte Strings ausgegeben werden. Du kannst für eine Variable, deren Wert als Zeichenkette ausgegeben werden soll, bspw. den Platzhalter %s verwenden:
$itemCount = 1;
echo $this->__(‘%s items in your cart’, $itemCount);
Übersetzt würde dieser String genau wie jeder andere auch:
“%s items in your cart’”,”%s Artikel in Deinem Warenkorb”
Der Platzhalter wird in der Übersetzung beibehalten. Die Methode __() wird beim Aufruf mit einem zusätzlichen Parameter, der Variable deren Wert in der Ausgabe gegen den Platzhalter getauscht werden sollen, angesprochen. Werden mehrere Platzhalter verwendet, werden einfach noch weitere Variablen als Parameter übergeben, jeweils mit einem Komma getrennt.
Format für Übersetzungen
Die Übersetzungen bestehen, unabhängig von der Quelle, immer aus zwei Teilen. Der erste Teil ist der zu übersetzende Text, der im Quellcode an die “magische Methode” übergeben wird. Der zweite Teil ist die Übersetzung.
Als Quelle dienen entweder CSV Dateien oder Datenbankeinträge. Letztere sind vor allen Dingen ein Ergebnis der “Inline Übersetzung” die Magento anbietet.
Lokalisierung über CSV Dateien
Der beste Weg zur Übersetzung von Magento Shops sind CSV Dateien. Diese haben den großen Vorteil, dass sie von einer hoffentlich vorhandenen Revisionskontrolle, zum Beispiel Git, berücksichtigt und erfasst werden. Werden Änderungen in Dateien gemacht, ist so nicht nur nachvollziehbar, wo im Detail Anpassungen stattgefunden haben. Fast genauso wichtig ist, dass Sie auf mehreren Systemen verfügbar sind. Sei es die lokale Entwicklungsumgebung, eine Testinstallation, ein Stagingsystem oder das Live-Deployment des Online Shops.
Der Aufbau der Dateien ist inhaltlich einfach. Um den Beispieltext “My Orders” aufzugreifen, könnte dieser mit folgender Zeile in einer der CSV-Dateien übersetzt werden:
“My Orders”,“Meine Bestellungen”
Doch das ist, wie erwähnt, nicht die einzige Möglichkeit.
Die Inline Übersetzung
Magento bietet neben den CSV-Dateien zur Lokalisierung die Möglichkeit der sogenannten Inline Übersetzung. Diese wird im Backend unter den Entwickleroptionen aktiviert:
System->Konfiguration->Inline übersetzen
Wird die Option auf “Ja” gesetzt, bietet Magento im Frontend die Möglichkeit neben dem Text auf ein Icon (ein Buch) zu klicken:
Der Dialog im Anschluss sieht wie folgt aus:
Die Benutzung sollte selbsterklärend sein. Ein Hinweis noch: Nachdem eine Übersetzung gespeichert wurde, muss die Seite neu geladen werden. Sonst greift die Übersetzung nicht. Wird sie auch dann nicht geladen, muss der Cache aktualisiert werden.
Soll auf die Übersetzungen zugegriffen werden, kann dies in der Tabelle core_translate erfolgen. Dort werden diese gespeichert, woraus sich ein entscheidender Nachteil ergibt. Die gesamte Inline Übersetzung arbeitet vollständig an der Revisionskontrolle vorbei. Außerdem ist es auch praktikabler CSV-Dateien durch externe Partner übersetzen zu lassen. Als Richtlinie würde ich empfehlen: Die Inline Übersetzung soweit es geht vermeiden.
Wo liegen die Übersetzungen konkret?
Magento kombiniert mehrere Stellen, an denen Übersetzungen definiert werden können:
1. modulspezifische Übersetzungen
2. Übersetzungen im Theme
3. Inline-Übersetzungen
Spannend ist nicht nur die Frage, welche Quellen es sind. Mindestens genauso wichtig ist es zu wissen, das Magento sie in dieser Reihenfolge lädt.
Wie oben gezeigt werden die Übersetzungen in ein assoziatives Array geladen. Der ursprüngliche Text dient als Schlüssel. Da mehrere Quellen eine Übersetzung für den gleichen Text enthalten können, werden die Array-Elemente überschrieben. Eine Regel dabei: Das zuletzt geladene Element gewinnt und überschreibt den zuvor gesetzten Wert. Das bedeutet, die modulspezifischen Übersetzungen haben die niedrigste Priorität und die Inline Übersetzung die höchste.
Der Punkt, an dem die Übersetzungen geladen werden, befindet sich in der Methode init() der Klasse Mage_Core_Model_Translate.
Modulspezifische Übersetzungen
Die modulspezifischen Übersetzungen werden in den CSV-Dateien gespeichert. Die sind unter app/locale zu finden. Dort gibt es für jedes “Locale” ein eigenes Verzeichnis. Im Standard ist dies bspw. en_US. Die Übersetzungen ins Deutsche, mit der Ausrichtung auf Deutschland, sind in de_DE gespeichert.
Dort liegen Dateien, die jeweils den Namen der zugehörigen Extension tragen. In diesen sind Strings sowie deren Übersetzungen wie das Beispiel “My Orders” hinterlegt.
Um “My Orders” im Kundenbereich zu übersetzen, muss in app/locale/de_DE die Datei Mage_Customer.csv angelegt werden. In dieser wird die Übersetzung gespeichert:
“My Orders”,”Meine Bestellungen”
Die Übersetzungen sind case-sensitiv! Es muss auf Groß-/Kleinschreibung geachtet werden. Wer sich mit den Übersetzungen aus app/locale befassen möchte, findet in der Klasse Mage_Core_Model_Translate die Methode _loadModuleTranslation(...). Dort werden die Dateien geladen.
Theme Übersetzungen
Die modulspezifischen Übersetzungen bilden die Basis für die Anpassung. Sollen jedoch vereinzelte Wörter, Sätze oder Ausdrücke abweichend übersetzt werden, wird ein anderer Weg gewählt. Es bietet sich die Datei translate.csv des Themes an. Die Anpassungen sind ohnehin meist nur für den jeweiligen Shop relevant. Das Theme wird nahezu immer individuell für den Shop erstellt oder angepasst, es spricht daher nichts gegen diesen Weg.
Es muss im Hauptverzeichnis des Themes (unter app/design…) das Verzeichnis “locale” angelegt werden. Als Unterzeichnis werden, genau wie in app/locale die Verzeichnisnamen gemäß der “Locale”-Einstellung erzeugt und die Datei translate.csv darin angelegt. Wenn das Default-Theme eingesetzt wird und eine deutsche Übersetzung angelegt oder überschrieben werden soll:
app/design/frontend/default/default/locale/de_DE/translate.csv Der Aufbau ist genau wie in den modulspezifischen Übersetzungen. Jede Zeile enthält einen ursprünglichen Text und die Übersetzung. So könntest Du nun den Text “Meine Bestellungen” bspw. in “Bestellhistorie” ändern: “My Orders”,”Bestellhistorie” Das ist noch nicht alles. Es gibt ein Feature, das nicht so bekannt ist. Die Möglichkeit spezifische Übersetzungen einzelner Module zu überschreiben. Ein Beispiel ist der String “Product Name”. Er wird in verschiedenen Extensions benutzt. Möchtest Du bspw. nur die Übersetzung für das Modul Mage_Checkout überschreiben, wird der Scope des Moduls, also der Modulname, vorangestellt und mit zwei Doppelpunkten vom String getrennt: “Mage_Checkout::Product Name”,”Name des Artikels” Von der geänderten Übersetzung sind Verwendungen in der Core-Extension Mage_Checkout betroffen. An den anderen Stellen bleibt die Übersetzung wie gehabt. Dies funktioniert auch in den Datenbank-Übersetzungen. Wer im Code Details nachvollziehen möchte, findet einen guten Einstiegspunkt in der Methode _loadThemeTranslation() der Klasse Mage_Core_Model_Translate.