Lokalisierung unter FLOW3/FLUID

Einige haben es ja bereits mitbekommen; seit einigen Tagen beschäftige ich mich mit dem FLOW3 Enterprise PHP Framework. FLOW3 ist vom TYPO3 Entwicklungs Team entwickelt worden um der neue Generation von TPYO3 aka TYPO3 „Phoenix“ (Version 5) ein neues Gerüst zu schaffen. Zwar steckt noch FLOW3 noch etwas in den Kinderschuhen, aber bisher sieht alles doch recht danach aus das es diese Bald in den Schrank packen kann. Es gibt zwar die eine oder andere Baustelle, in meinem jetzigen Blog ist dies die Lokalisierung.

Als erstes zu beachten ist das die Lokalisierung erst ab Version 1.1 verfügbar ist. Ich hatte zuerst mit dem 1.0 Release probiert, da ich dachte ich nehme lieber eine Version die nicht als „Beta“ deklariert ist, aber ohne Lokalisierung wollte ich dann auch nicht 😉

Wie funktioniert die Lokalisierung?

Standartmäßig sucht FLOW3 innerhalb der Resourcen des Packetes nach übersetzungen im Verzeichnis „Resources/Private/Translations/“. Dort sollte für jede Sprache ein Unterverzeichnis existieren. Als Beispiel: „de“ oder „en“. Innerhalb dieser Verzeichnisse legt man nun Dateien in XLIFF Format an. Man kann mehrere Dateien anlegen, um so eine Strukturierung der Übersetzungen anzulegen. Beispielsweise pro Model oder pro Controller. Da sollte man schauen wie man es bevorzugt. Standartmäßig wird die Datei „Main.xlf“ benutzt, wenn man die Entsprechende Argumente leer läßt.

Beispiel einer XLIFF Datei:

<?xml version="1.0"?>
<xliff version="1.2"
  xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file original="" source-language="en" 
    target-language="de" datatype="plaintext">
    <body>

      <trans-unit id="header">
        <source>Header</source>
        <target>Überschrift</target>
      </trans-unit>
      <trans-unit id="subheader">
        <source>Subheader</source>
        <target>Unterüberschrift</target>
      </trans-unit>
      <trans-unit id="impress">
        <source>Impress</source>
        <target>Impressum</target>
      </trans-unit>

    </body>
  </file>
</xliff>

In Zeile 4 und 5 kann man die Parameter „source-language“ und „target-language“ erkennen. Diese müssen entsprechend der gegebenheiten Angepasst werden. Bei meinem Projekt habe ich die Englische Sprache bei der Ausgabe sowie der Variablen- und Modeldeklarierung gewählt. Im Grunde ist das ja eigentlich auch egal, wobei es in der FLOW3 Umgebung einige dinge zu beachten sind, aber dies soll hier nicht Thema des Blogs werden 😉

Also zurück zum Thema; es gibt zwei Arten wie man die Übersetzung laufen lassen kann:

  • Übersetzung anhand einer ID (trans-unit id=““)
  • Übersetzung anhand eines Labels

Letzteres Bedeutet er nimmt den Text den man Als „dummy“ genommen hat, und sucht in den XLIFF Dateien in den „source“ Abschnitten nach diesem Wort und übersetzt dieses dann. Mir persönlich gefällt die erste Variante, da damit weniger Fehlerquellen vorhanden sind. Außerdem soll laut der Dokumentation der Lokalisierung die Übersetzung anhand der ID schneller funktionieren. Und gerade das Thema der Schnelligkeit will ich mit FLOW3 ausprobieren.

<f:translate id="header" />
<pre>Ausgabe: Überschrift</pre>
<f:translate id="subheader" source="Main">Subheader</f:translate>
<pre>Ausgabe: Unterüberschrift</pre>
<f:translate source="Main">Impress</f:translate>
<pre>Ausgabe: Impressum</pre>

Es wird ebenfalls empfohlen die Übersetzung der englischen Sprache zu erstellen. Zueinem wird einem dann das Log nicht vollgehauen 😉 und zum anderem kann man so auch Anpassungen bei Rechtschreibung oder Gramatik vornehmen ohne die Entsprechende „Source“ in allen Übersetzungen zu ändern.

Möglichkeit des Plurals

Ebenfalls Erwähnenswert ist die Funktion der Übersetzung nach Einzahl und Mehrzahl. Als Beispiel sei dort mal 1 Tag oder 2 Tage erwähnt. Nun könnte man natürlich hingehen und in FLUID eine Bedingung einfügen, aber wer will das schon?? 🙂

<group id="date.day" restype="x-gettext-plurals">
  <trans-unit id="date.day[0]">
    <source>{0} day</source>
    <target>{0} Tag</target>
  </trans-unit>
  <trans-unit  id="date.day[1]">
    <source>{0} days</source>
    <target>{0} Tage</target>
  </trans-unit>
</group>

Nun kann man im Fluid das ganze Wie folgt ansprechen:

<f:translate id="date.day" source="Main" arguments="{0: 4}/>
Ausgabe: 4 Tage
<f:translate id="date.day" source="Main" arguments="{0: 1}/>
Ausgabe: 1 Tag

Wir sehen nun, es gibt auch die Möglichkeit von Variablen:

<trans-unit id="some.label">
  <source>{0} times {1,number}</source>
  <target>{1,number} mal {0}</target>
</trans-unit>

Hier wird dann ebenfalls mit dem parameter „arguments“ gearbeitet:

<f:translate id="some.label" source="Main" arguments="{0: 'bla', 1: 5}/>

Nun haben wir soviele Übersetzungen angelegt und im Template ausprobiert, und einige werden sich wundern warum Sie keine Deutsche Übersetzung angezeigt bekommen. Ja, blöd das sowas auch immer erst zum (fast) Schluss kommt, aber wie heißt es so schön, erst lesen! 😉

Ich musste allerdings auch eine Weile suchen bis ich die Richtige Stelle gefunden habe wo man das aktiviert.

In der Settings.yaml (Global, Umgebung oder Packet) kann man mit den folgenden Einstellungen die default Sprache ändern:

TYPO3:
  FLOW3:
    i18n:
      defaultLocale: de

Mir war dies allerdings nicht genug! 😉 Bei meiner suche in den Classes, Models usw. bin ich auf einen Language Detector gestoßen. Nun frage ich mich natürlich, wie aktiviere ich diesen? Automatisch momentan wohl gerade nicht. Ich habe zwar im Forge davon gelesen und auch per Twitter wurde mir gesagt das es mit etwas Glück noch in die 1.1 schafft. Dank geht übrigens an dieser Stelle an Robert Lemke und Karsten Dambekalns die mir per Twitter die Richtung gewiesen haben 😉

Meine Lösung: Im Controller den Language Detector starten, erkennen lassen und ans Fluid übergeben 😉

 /**
   * @var \TYPO3\FLOW3\I18n\Locale
   */
  protected $lang;

  public function initializeView(\TYPO3\FLOW3\Mvc\View\ViewInterface $view) {
    $detector   = new \TYPO3\FLOW3\I18n\Detector();
    $this->lang = $detector->detectLocaleFromHttpHeader($_SERVER["HTTP_ACCEPT_LANGUAGE"]);
    $view->assign('langDetector', $this->lang);
  }

In diesem Beispiel sage ich dem Detector er soll anhand der HTTP Anfrage herrausfinden welche Sprache bevorzugt wird.
Durch die Verwendung der Klasse „initializeView“ hat nun jede Action im Controller diese Variable zugewiesen. Anschließend habe ich jedem TranslateViewHelper, oder auch der Translate Option vom SelectViewHelper das Argument „locale“ angehangen:

<f:translate id="header" locale="{langDetector.language}">Header</f:translate>

Wo wir nun im Controller angekommen sind, wie übersetzt man eigentlich hier? Mit dem Translator Objekt:

  /**
   * @var \TYPO3\FLOW3\I18n\Translator
   * @FLOW3\Inject
   */
  protected $translator;

  public function indexAction() {
    $header = $this->translator->translateById('header', 
      array(), NULL, $this->lang,'Main','Package');
  }

So… das war erstmal mein erster längerer Blog-Beitrag 😀 Ich hoffe er hilft den einen oder anderen bei seiner Suche weiter.
Da ich noch recht neu in der Blogger-Welt bin, nehme ich natürlich gerne Konstruktive Kritik entgegen 🙂

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.