Development

Documentation/de_DE/book/1.0/13-I18n-and-L10n

You must first sign up to be able to contribute.

Version 8 (modified by Jan.Kunzmann, 10 years ago)
--

ARBEITSENTWURF ROHÜBERSETZUNG / TRANSLATION WORKING DRAFT
Originaldokument: http://svn.symfony-project.com/doc/branches/1.1/book/13-I18n-and-L10n.txt, Version 7705 vom 2008-03-01
Übersetzungsfortschritt: 100%
Übersetzung: JK
Korrekturfortschritt: 0%

Kapitel 13 - I18n und L10n

Wenn Sie jemals eine internationalisierte Anwendung entwickelt haben, wissen Sie sicherlich, dass es zum Albtraum werden kann, mit allen Aspekten der Übersetzung, lokalen Standards und lokalisierten Inhalten umzugehen. Zum Glück automatisiert symfony alle Aspekte der Internationalisierung.

Da Internationalisierung so ein langes Wort ist, wird es in Entwicklerkreisen häufig als I18n abgekürzt (zählen Sie einfach die Buchstaben im englischen Wort "internationalization", dann kennen Sie den Grund). Lokalisierung wird als L10n abgekürzt (vom englischen "Localization"). Sie decken zwei unterschiedliche Aspekte von mehrsprachigen Webanwendungen ab.

Eine internationalisierte Anwendung enthält verschiedene Versionen des gleichen Inhalts in verschiedenen Sprachen oder Formaten. So kann z.B. eine Webmail-Anwendung den gleichen Dienst in verschiedenen Sprachen anbieten - es ändert sich jeweils nur die Benutzeroberfläche.

Eine lokalisierte Anwendung enthält unterschiedliche Informationen abhängig von dem Land, aus welchem sie aufgerufen wird. Denken Sie z.B. an den Inhalt eines Newsportals: Wenn es aus den USA aufgerufen wird, zeigt es die neuesten Schlagzeilen aus den USA an, aber wenn es aus Frankreich aufgerufen wird, zeigt es Schlagzeilen, die sich mit Frankreich beschäftigen. Also stellt eine L10n-Anwendung nicht nur übersetzten Inhalt zur Verfügung, sondern der Inhalt kann sich zwischen den lokalisierten Versionen unterscheiden.

Zusammenfassend kann man sagen, dass I18n und L10n bedeutet, dass die Anwendung auf folgende Punkte achtet:

  • Übersetzungen (Benutzeroberfläche und Inhalte)
  • Standards und Formate (Datumswerte, Währungsangaben, Nummern usw.)
  • Lokalisierte Inhalte (Verschiedene Versionen eines Objekts je nach Land)

Dieses Kapitel zeigt, wie symfony mit diesen Punkten umgeht und wie Sie damit internationalisierte und lokalisierte Anwendungen entwickeln können.

Benutzer-Culture

Alle eingebauten I18n-Features von Symfony basieren auf einem Session-Parameter, der Culture genannt wird. Die Culture ist die Kombination aus dem Land und der Sprache des Benutzers, und sie legt fest, wie Text und kulturabhängige Informationen angezeigt werden. Und da die Angabe in der Benutzersitzung serialisiert wird, bleibt sie zwischen den Seiten erhalten.

Angabe der Standard-Culture

Die Standard-Culture eines neuen Users ist default_culture. Sie können diesen Wert in der Konfigurationsdatei i18n.yml ändern, wie in Listing 13-1 gezeigt.

Listing 13-1 - Angabe der Standard-Culture, in myapp/config/i18n.yml

all:
  default_culture:     de_DE

NOTE Während der Entwicklungsphase sind Sie vielleicht überrascht, dass die Änderung der Culture in der Datei i18n.yml sich nicht auf die aktuelle Culture im Browser auswirkt. Dies liegt daran, dass Ihre Sitzung bereits eine Culture von den vorherigen Seiten hat. Wenn Sie die Anwendung mit der neuen Standard-Culture sehen wollen, müssen Sie das Domaincookie (Sitzungs-Cookie, Anm. d. Übers.) löschen oder Ihren Browser neustarten.

Sowohl die Sprache als auch das Land in der Culture mitzuführen ist deshalb notwendig, da Sie möglicherweise unterschiedliche französische Übersetzungen für Benutzer aus Frankreich, Belgien oder Kanada haben, und unterschiedlichen spanischen Inhalt für Benutzer aus Spanien und Mexiko. Die Sprache wird in zwei kleingeschriebenen Zeichen gemäß ISO 639-1 kodiert (z.B. en für Englisch). Das Land wird in zwei Großbuchstaben gemäß ISO 3166-1 angegeben (z.B. GB für Großbritanien)

Ändern der Culture für einen Benutzer

Die Benutzer-Culture kann während der Browse-Sitzung geändert werden, z.B. wenn ein Benutzer sich dazu entschließt, von der englischen auf die französische Version der Anwendung umzuschalten, oder wenn ein Benutzer sich einloggt und die Sprache in seinen gespeicherten Einstellungen verwendet werden soll. Aus diesem Grund hat die sfUser-Klasse Getter und Setter für die Benutzer-Culture. Listing 13-2 zeigt, wie diese Methoden in einer Action verwendet werden.

Listing 13-2 - Die Culture in einer Aktion setzen und ermitteln

[php]
// Culture setzen
$this->getUser()->setCulture('de_DE');

// Culture ermitteln
$culture = $this->getUser()->getCulture();
 => de_DE

SIDEBAR Culture in der URL

Wenn Sie symfonys Lokalisierungs- und Internationalisierungs-Features verwenden, neigen die Seiten dazu, verschiedene Versionen für die gleiche URL zu haben -- alles hängt von der Benutzersitzung ab. Dies verhindert, dass Sie die Seiten cachen oder von einer Suchmaschine indizieren lassen können.

Eine Lösung dafür ist, die Culture in jeder URL mit anzugeben, damit die übersetzten Seiten von außen über unterschiedliche URLs erreichbar sind. Dafür fügen Sie einfach das Token :sf_culture in jede Routingregeln in der routing.yml Ihrer Anwendung ein:

page:
  url: /:sf_culture/:page
  requirements: { sf_culture: (?:fr|en|de) }
  params: ...

article:
  url: /:sf_culture/:year/:month/:day/:slug
  requirements: { sf_culture: (?:fr|en|de) }
  params: ...

Damit Sie den Parameter sf_culture nicht in jedem Aufruf von link_to() setzen müssen, fügt symfony die User-Culture automatisch zu den Standardparametern hinzu. Dies funktioniert auch umgekehrt, denn symfony wird automatisch die User-Culture ändern, wenn der Parameter sf_culture in der URL auftaucht.

Die Culture automatisch ermitteln

In vielen Anwendungen wird die Culture automatisch beim ersten Zugriff festgelegt, basierend auf den Einstellungen im Browser. Benutzer können dort eine Liste von bevorzugten Sprachen hinterlegen, und diese Information wird bei jedem Request im HTTP-Header Accept-Language zum Server geschickt. In symfony können Sie sie durch das sfRequest-Objekt abfragen. Um z.B. in einer Action eine Liste der bevorzugten Sprachen eines Benutzers zu erhalten, schreiben Sie folgendes:

[php]
$languages = $this->getRequest()->getLanguages();

Der HTTP-Header ist eigentlich eine Zeichenkette, aber symfony liest sie automatisch ein und wandelt sie in ein Array um. Damit kann die bevorzugte Sprache des Benutzers im obigen Beispielt mit $languages[0] abgefragt werden.

Es kann sinnvoll sein, die Benutzer-Culture auf die bevorzugte Browsersprache zu setzen, entweder auf der Einstiegsseite Ihrer Anwendung oder mittels eines Filters für alle Seiten.

ACHTUNG Der HTTP-Header Accept-Language ist nicht unbedingt eine zuverlässige Quelle, da nur wenige Benutzer wissen, wie sie diese Angaben in ihrem Browser einstellen. Meistens ist dort eingestellte Sprache identisch mit der Sprache der Browseroberfläche, und diese wiederum sind nicht in allen Sprachen verfügbar. Wenn Sie also die Culture automatisch auf die bevorzugte Sprache des Browsers setzen, denken Sie daran, dem User eine Option zur Verfügung zu stellen, um eine andere Sprache zu wählen.

Standards und Formate

Tief im Inneren kümmter sich eine Webanwendung nicht um kulturelle Besonderheiten. Datenbanken beispielsweise benutzen internationale Standards, um Datumswerte, Währungsangeben usw. zu speichern. Aber sobald Daten zum Benutzer geschickt oder von ihm eingegeben werden, muss eine Konvertierung durchgeführt werden. Benutzer können mit einem Timestamp-Wert (Sekunden seit 1.1.1970, Anm. d. Übers.) relativ wenig anfangen, und sie würden es sicherlich begrüßen, Wenn Ihre Muttersprache Deutsch genannt wird anstatt German. Folglich benötigen Sie Unterstützung, um diese Konvertierung automatisch anhand der Benutzer-Culture durchzuführen.

Daten in der Benutzer-Culture ausgeben

Ist die Culture erst einmal festgelegt, geben die entsprechenden Helfer automatisch die korrekten Werte aus. So gibt z.B. der Helfer format_number() Zahlen automatisch in dem Format aus, das dem Benutzer gemäß seiner Culture vertraut ist, wie in Listing 13-3 zu sehen.

Listing 13-3 - Zahlen in der Benutzer-Culture ausgeben

[php]
<?php use_helper('Number') ?>

<?php $sf_user->setCulture('en_US') ?>
<?php echo format_number(12000.10) ?>
 => '12,000.10'

<?php $sf_user->setCulture('de_DE') ?>
<?php echo format_number(12000.10) ?>
 => '12.000,10'

Sie müssen den Helfer-Funktionen die Culture nicht jedes Mal übergeben. Sie schlagen sie automatisch im aktuellen Session-Objekt nach. Listing 13-4 zeigt Ihnen alle Helfer, die die Benutzer-Culture in ihrer Ausgabe berücksichtigen.

Listing 13-4 - Culture-abhängige Helfer

[php]
<?php use_helper('Date') ?>

<?php echo format_date(time()) ?>
 => '9/14/06'

<?php echo format_datetime(time()) ?>
 => 'September 14, 2006 6:11:07 PM CEST'

<?php use_helper('Number') ?>

<?php echo format_number(12000.10) ?>
 => '12,000.10'

<?php echo format_currency(1350, 'USD') ?>
 => '$1,350.00'

<?php use_helper('I18N') ?>

<?php echo format_country('US') ?>
 => 'United States'

<?php format_language('en') ?>
 => 'English'

<?php use_helper('Form') ?>

<?php echo input_date_tag('birth_date', mktime(0, 0, 0, 9, 14, 2006)) ?>
 => input type="text" name="birth_date" id="birth_date" value="9/14/06" size="11" />

<?php echo select_country_tag('country', 'US') ?>
 => <select name="country" id="country"><option value="AF">Afghanistan</option>
      ...
      <option value="GB">United Kingdom</option>
      <option value="US" selected="selected">United States</option>
      <option value="UM">United States Minor Outlying Islands</option>
      <option value="UY">Uruguay</option>
      ...
    </select>

Den Datums-Helfern können Sie einen weiteren Parameter übergeben, um ein bestimmtes Ausgabeformat unabhängig von der Benutzer-Culture zu erzwingen, aber Sie sollten ihn nicht verwenden, wenn Ihre Anwendung internationalisiert ist.

Daten einer lokalisierten Eingabe ermitteln

Wenn es notwendig ist, Daten in der Benutzer-Culture zu zeigen oder zu ermitteln, sollten Sie Ihre Benutzer weitmöglich dazu drängen, die Daten bereits in internationalisierter Form einzugeben. Dieser Ansatz erspart es Ihnen, herauszufinden, wie Sie die Daten aus verschiedenen Formaten und ungewisser Lokalisierung konvertieren. Wer z.B. würde einen Geldbetrag mit Kommaseparatoren in eine Eingabebox schreiben (??? Anm. d. Übers.)

Sie können das Format der Benutzereingaben einerseits beschränken, indem Sie die eigentlichen Daten verstecken (wie z.B. im select_country_tag()), oder andererseits, indem Sie die einzelnen Komponenten einer komplexen Datenstruktur in mehrere einfache Eingabefelder zerlegen.

Für Datumsangeben ist dies jedoch oft nicht möglich. Benutzer sind es gewohnt, Datumswerte in dem in ihrer Kultur üblichen Format anzugeben, und Sie müssen in der Lage sein, diese Angaben in ein internes (und internationales) Format umzuwendeln. Das ist der Punkt, an dem die sfI18N-Klasse ins Spiel kommt. Listing 13-5 zeigt, wie die Klasse benutzt wird.

Listing 13-5 - Ermitteln eines Datumswerts aus einem lokalisierten Format in einer Action

[php]
$date= $this->getRequestParameter('birth_date');
$user_culture = $this->getUser()->getCulture();

// Einen Timestamp ermitteln
$timestamp = $this->getContext()->getI18N()->getTimestampForCulture($date, $user_culture);

// Ein strukturiertes Datum ermitteln
list($d, $m, $y) = $this->getContext()->getI18N()->getDateForCulture($date, $user_culture);

Textinformationen in der Datenbank

Eine lokalisierte Anwendung zeigt unterschiedlichen Inhalt je nach der Benutzer-Culture. Ein Onlineshop beispielsweise kann weltweit Produkte zum gleichen Preis anbieten, aber mit einer angepassen Beschreibung für jedes Land. Dies bedeutet, dass die Datenbank in der Lage sein muss, verschiedene Versionen eines Datensatzes zu speichern, und dafür ist es notwendig, dass Sie Ihr Schema entsprechend gestalten und die Culture jedes Mal verwenden, wenn Sie lokalisierte Model-Objekte verändern.

Ein lokalisiertes Schema erzeugen

Jede Tabelle, die einige lokalisierte Felder enthält, sollten Sie in zwei Teile aufbrechen: eine Tabelle, die keine I18n-Spalte enthält, und eine zweite, die nur aus I18n-Spalten besteht. Beide Tabellen sind mit einer 1-zu-n-Relation verknüpft. Durch diesen Ansatz können Sie nach Bedarf neue Sprachen hinzufügen, ohne Ihr Model ändern zu müssen. Lassen Sie uns das am Beispiel einer Produkt-Tabelle genauer betrachten.

Zunächst einmal erzeugen Sie Tabellen in der Datei schema.yml, wie in Listing 13-6 gezeigt.

Listing 13-6 - Beispielschema für I18n-Daten, in config/schema.yml

my_connection:
  my_product:
    _attributes: { phpName: Product, isI18N: true, i18nTable: my_product_i18n }
    id:          { type: integer, required: true, primaryKey: true, autoincrement: true }
    price:       { type: float }

  my_product_i18n:
    _attributes: { phpName: ProductI18n }
    id:          { type: integer, required: true, primaryKey: true, foreignTable: my_product, foreignReference: id }
    culture:     { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }
    name:        { type: varchar, size: 50 }

Beachten Sie die Attribute isI18N und i18nTable in der ersten Tabelle, und die spezielle Spalte culture in der zweiten. Es handelt sich dabei um symfony-spezifische Erweiterungen für Propel.

Die Automatisierungen von symfony erlauben es Ihnen, ein solches Schema sehr viel schneller zu schreiben. Wenn die Tabelle, die die internationalisierten Daten enthält, den gleichen Namen wie die Haupttabelle mit angehängtem _i18n hat, und sie über eine Primärschlüssel-Spalte namens id verknüpft sind, dann können Sie die Angabe der Spalten id und culture in der _i18n-Tabelle sowie die speziellen I18n-Attribute in der Haupttabelle weglassen. Symfony wird diese selbst herleiten. Folglich ist das Schema in Listing 13-7 für symfony identisch zu dem in Listing 13-6.

Listing 13-7 - Beispielschema für I18n-Daten, Kurzschreibweise, in config/schema.yml

my_connection:
  my_product:
    _attributes: { phpName: Product }
    id:
    price:       float
  my_product_i18n:
    _attributes: { phpName: ProductI18n }
    name:        varchar(50)

Verwendung der erzeugten I18n-Objekte

Sobald die entsprechenden Modelklassen erzeugt worden sind (vergessen Sie nicht, symfony propel-build-model aufzurufen und den Cache mit symfony cc zu leeren, wenn Sie schema.yml verändert haben), können Sie die Klasse Product mit I18n-Unterstützung so verwenden, als handele es sich um eine einzelne Tabelle, wie in Listing 13-8 gezeigt.

Listing 13-8 - I18n-Objekte verwenden

[php]
$product = ProductPeer::retrieveByPk(1);
$product->setCulture('de');
$product->setName('Name des Produkts');
$product->save();

$product->setCulture('en');
$product->setName('Product name');
$product->save();

echo $product->getName();
 => 'Product name'

$product->setCulture('de');
echo $product->getName();
 => 'Name des Produkts'

Wenn Sie nicht jedes Mal die Culture setzen wollen, wenn Sie ein internationalisiertes Objekt verwenden, können Sie einfach die hydrate()-Methode überschreiben. In Listing 13-9 sehen Sie ein entsprechendes Beispiel.

Listing 13-9 - Überschreiben der hydrate()-Methode, um die Culture zu setzen, in myproject/lib/model/Product.php

[php]
public function hydrate(ResultSet $rs, $startcol = 1)
{
  parent::hydrate($rs, $startcol);
  $this->setCulture(sfContext::getInstance()->getUser()->getCulture());
}

Wenn Sie Abfragen über das Peerobjekt durchführen, können Sie die Ergebnisse auf Objekte beschränken, die eine Übersetzung in der aktuellen Culture haben, indem Sie die Methode doSelectWithI18n anstelle des üblichen doSelect verwenden, wie in Listing 13-10 gezeigt. Darüberhinaus wird diese Methode alle abhängigen I18n-Objekte gleichzeitig mit den regulären Objekten erzeugen, wodurch letztlich weniger Querys notwendig sind, um den gesamten Inhalt zu laden (in Kapitel 18 erfahren Sie mehr über die positiven Auswirkungen dieser Methode bezüglich der Performance).

Listing 13-10 - Objekte mit einem I18N-Kriterium abrufen

[php]
$c = new Criteria();
$c->add(ProductPeer::PRICE, 100, Criteria::LESS_THAN);
$products = ProductPeer::doSelectWithI18n($c, $culture);
// Der Parameter $culture ist optional
// Sofern keine Culture angegeben, wird die aktuelle des Users verwendet

Im Grunde sollen Sie niemals direkt die I18N-Objekte verwenden, sondern stattdessen jedes Mal, wenn Sie mit einem internationalisierten Objekt arbeiten, die Culture an das Model weiterreichen (oder sie vom Model ermitteln lassen).

Übersetzung der Benutzeroberfläche

Das Benutzerinterface muss für I18n-Anwendungen angepasst werden. Templates müssen in der Lage sein, Labels, Benachrichtigungen und Navigation in verschiedenen Sprachen anzuzeigen, jedoch mit der gleichen Präsentation. Symfony empfiehlt Ihnen, Ihre Templates in der Standardsprache zu schreiben, und die Übersetzung für alle vorkommenden Phrasen in einer Dictionary-Datei vorzuhalten. Somit müssen Sie Ihre Templates nicht jedesmal anpassen, wenn Sie eine Übersetzung bearbeiten, hinzufügen oder löschen.

Übersetzung konfigurieren

Templates sind standardmäßig nicht übersetzt, was bedeutet, dass Sie vor allem anderen zunächst einmal das entsprechende Feature in der settings.yml aktivieren müssen, wie in Listing 13-11 gezeigt.

Listing 13-11 - Übersetzung der Benutzeroberfläche aktivieren, in myapp/config/settings.yml

all:
  .settings:
    i18n: on

Verwenden des Übersetzungs-Helfers

Nehmen wir einmal an, Sie wollen eine Webseite in Deutsch und Französisch erstellen, wobei Deutsch die Standardsprache sein soll. Bevor Sie überhaupt daran gedacht hatten, die Seite zu übersetzen, haben Sie vermutlich Templates wie das in Listing 13-12 geschrieben.

Listing 13-12 - Ein einsprachiges Template

[php]
Willkommen auf unserer Webseite. Heute ist der <?php echo format_date(date()) ?>

Damit symfony die Phrasen eines Templates übersetzen kann, müssen sie zunächst als zu übersetzender Text identifiziert werden. Das ist Aufgabe des Helfers __() (zwei Unterstriche), Mitglied der Helfergruppe I18N. Alle Ihre Templates müssen die zu übersetzenden Phrasen in solche Funktionsaufrufe kapseln. Listing 13-12 kann nun so bearbeitet werden, dass es aussieht wie Listing 13-13 (wie Sie später im Abschnitt "Mit komplexen Übersetzungsanforderungen umgehen" sehen werden, gibt es sogar noch einen besseren Weg, den Übersetzungs-Helfer in diesem Beispiel aufzurufen).

Listing 13-13 - Ein für Mehrsprachigkeit vorbereitetes Template

[php]
<?php use_helper('I18N') ?>

<?php echo __('Willkommen auf unserer Webseite.') ?>
<?php echo __("Heute ist der ") ?>
<?php echo format_date(date()) ?>

TIP Wenn Ihre Anwendung die I18N-Helfergruppe auf jeder Seite verwendet, ist es vermutlich eine gute Idee, sie in die Liste der standard_helpers in der Datei settings.yml aufzunehmen, damit Sie nicht in jedem Template use_helper('I18N') schreiben müssen.

Dictionary-Dateien verwenden

Jedes Mal, wenn die Funktion __() aufgerufen wird, sucht symfony im Dictionary der aktuellen Benutzer-Culture nach einer Übersetzung für den übergebenen Parameter. Wenn es eine entsprechende Phrase findet, dann wird die Übersetzung zurückgegeben. Folglich basiert die Übersetzung der Benutzerschnittstelle auf einem Dictionary-File.

Die Dictionary-Dateien sind im XML Localization Interchange File Format (XLIFF, XML Lokalisierungsaustauschdateiformat) geschrieben, werden nach dem Muster messages.[sprachcode].xml benannt und im Verzeichnis i18n/ der Anwendung gespeichert.

XLIFF ist ein Standardformat, das auf XML basiert. Aufgrund seiner Bekanntheit können Sie Übersetzungstools von Drittanbietern verwenden, um den Text auf Ihrer Webseite herauszuziehen und ihn zu übersetzen. Anbieter von Übersetzungsdienstleistungen können mit dem Dateiformat umgehen und können eine ganze Seite übersetzen, indem Sie eine neue XLIFF-Datei hinzufügen.

TIP Zusätzlich zum XLIFF-Standard unterstützt symfony noch andere Backends für Dictionarys: gettext, MySQL, SQLite, and Creole. Lesen Sie die API-Dokumentation für weitere Information, wie diese Backends konfiguriert werden.

Listing 13-14 zeigt beispielhaft den XLIFF-Syntax anhand der Datei messages.en.xml, die notwendig ist, um Listing 13-13 ins Englische zu übersetzen.

Listing 13-14 - Ein XLIFF-Dictionary, in myapp/i18n/messages.en.xml

[xml]
<?xml version="1.0" ?>
<xliff version="1.0">
  <file orginal="global" source-language="de_DE" datatype="plaintext">
    <body>
      <trans-unit id="1">
        <source>Willkommen auf unserer Webseite.</source>
        <target>Welcome to our website.</target>
      </trans-unit>
      <trans-unit id="2">
        <source>Heute ist der </source>
        <target>Today's date is </target>
      </trans-unit>
    </body>
  </file>
</xliff>

Das Attribut source-language muss immer den vollständigen ISO-Code Ihrer Standard-Culture enthalten. Jede Übersetzung wird in einem trans-unit-Tag mit einer eindeutigen id geschrieben.

Für die Standard-Culture (in unserem Beispiel de_DE) werden die Phrasen nicht übersetzt, und somit werden die Parameter der __()-Aufrufe unverändert angezeigt. Das Ergebnis aus Listing 13-13 ist daher ähnlich dem aus Listing 13-12. Wenn allerdings die Culture auf en_US oder en_GB geändert wird, werden die Übersetzungen aus der Datei messages.en.xml und das Ergebnis schaut aus wie Listing 13-15.

Listing 13-15 - Ein übersetztes Template

[php]
Welcome to our website. Today's date is 
<?php echo format_date(date()) ?>

Wenn weitere Übersetzungen notwendig werden, erstellen Sie einfach eine neue Übersetzungs-Datei `messages.XX.xml` im gleichen Verzeichnis.

Verwalten von Dictionarys

Wenn die Datei messages.XX.xml zu lang und unübersichtlich wird, können Sie die Übersetzungen jederzeit in mehrere thematisch benannte Dictionary-Dateien aufteilen. Sie können also z.B. messages.fr.xml in diese drei Dateien im Anwendungs-Verzeichnis i18n/ aufteilen:

  • navigation.fr.xml
  • terms_of_service.fr.xml
  • search.fr.xml

Beachten Sie jedoch: sobald die Übersetzung nicht mehr in der regulären Datei messages.XX.xml aufgefunden werden kann, müssen Sie angeben, welches Dictionary benutzt werden soll. Sie übergeben diese Information in der Funktion __() als dritten Parameter. Um also einen String auszugeben, der im Dictionary navigation.fr.xml übersetzt wurde, schreiben Sie folgendes:

[php]
<?php echo __('Willkommen auf unserer Webseite.', null, 'navigation') ?>

Eine andere Möglichkeit, die Dictionarys zu organisieren, ist, sie nach Modulen aufzuteilen. Anstatt eine einzige Datei messages.XX.xml für die ganze Anwendung zu erzeugen, schreiben Sie einfach eine in jedes Verzeichnis modules/[module_name]/i18n/. Dies macht die Module unabhängiger von der gesamten Anwendung, was notwendig ist, wenn Sie sie z.B. als Plugins wiederverwenden wollen (siehe Kapitel 17).

Neu in der Entwicklungsversion

Weil das Bearbeiten von Dictionarys von Hand eine sehr fehleranfällige Sache ist, bietet symfony einen Task, der diesen Vorgang automatisiert. Der Task i18n-extract durchsucht eine komplette symfony-Anwendung und ermittelt alle Strings, die übersetzt werden müsesn. Als Parameter müssen die Anwendung und die Culture angegeben werden:

> php symfony i18n-extract frontend en

Standardmäßig verändert der Task Ihre Dictionarys nicht, er gibt nur die Anzahl der neuen und alten I18n-Strings aus. Damit die neuen Strings an Ihr Dictionary angehängt werden, müssen Sie die Option --auto-save angeben:

> php symfony i18n-extract --auto-save frontend en

Zusätzlich können Sie automatisch alte Strings löschen lassen, indem Sie die Option --auto-delete angeben:

> php symfony i18n-extract --auto-save --auto-delete frontend en

NOTE Derzeit hat der Task einige Einschränkungen: Er arbeitet nur mit dem Standard-Dictionary messages und nur mit den dateibasierten Backends (XLIFF und gettext), und es speichert bzw. löscht nur Strings in der Datei apps/myapp/i18n/messages.XX.xml.

Andere Elemente, die übersetzt werden müssen

Weitere Elemente, die möglicherweise übersetzt werden müssen:

  • Bilder, Textdokumente und einige andere Arten von eingebetteten Objekten können sich auch je nach Benutzer-Culture ändern. Als Beispiel betrachten wir ein Stück Text, das als Bild bereitgestellt wird, da es in einer speziellen Schriftart angezeigt werden soll. Hierfür können Sie Unterverzeichnisse mit dem Namen der entsprechenden Culture erstellen:

    [php] <?php echo image_tag($sf_user->getCulture().'/myText.gif') ?>

  • Fehlermeldungen aus Validierungsdateien werden automatisch durch einen Aufruf von __() ausgegeben, somit müssen Sie die Texte einfach nur in ein Dictionary schreiben, damit sie übersetzt werden.

  • Die Standardseiten von symfony (Seite nicht gefunden, Interner Serverfehler, Beschränkter Zugriff usw.) sind auf Englisch und müssen in einer I18n-Anwendung neu geschrieben werden. Sinnvollerweise erstellen Sie Ihr eigenes default-Modul in Ihrer Anwendung und verwenden __() in dessen Templates. Im Kapitel 19 erfahren Sie mehr, wie Sie diese Seiten anpassen können.

Mit komplexen Übersetzungsanforderungen umgehen

Die Übersetzung ist nur sinnvoll, wenn der Parameter von __() ein ganzer Satz ist. Manchmal jedoch müssen Sie Formatierungsangaben oder Variablen mit den Wörtern vermischen, und so könnten Sie auf die Idee verfallen, die Sätze in viele Häppchen zu zerteilen, wodurch der Helfer nur noch mit sinnentstellten Phrasen aufgerufen wird. Glücklicherweise bietet der __()-Helfer eine Ersetzungsfunktion auf Tokenbasis, die Sie dabei unterstützt, ein aussagekräftigen Dictionary zu erstellen, welches Übersetzer einfacher handhaben können. HTML-Formartierungen können Sie allerdings auch im Helfer-Aufruf belassen. Listing 13-16 zeigt ein Beispiel.

Listing 13-16 - Sätze mit Code übersetzen

[php]
// Basisbeispiel
Ein herzliches Willkommen allen unseren <b>neuen</b> Usern.<br />
Es sind derzeit <?php echo count_logged() ?> Personen online.

// Der schlechte Weg
<?php echo __('Ein herzliches Willkommen allen unseren') ?>
<b><?php echo __('neuen') ?></b>
<?php echo __('Usern') ?>.<br />
<?php echo __('Es sind derzeit') ?>
<?php echo count_logged() ?>
<?php echo __('Personen online') ?>.

// Der gute Weg zur Übersetzung
<?php echo __('Ein herzliches Willkommen allen unseren <b>neuen</b> Usern.') ?><br />
<?php echo __('Es sind derzeit %1% Personen online.', array('%1%' => count_logged())) ?>

In diesem Beispiel ist das Token %1%, aber es kann irgendeine Zeichenfolge sein, da die Ersetzungsfunktion des Translation-Helfers strtr() ist.

Ein gängiges Problem bei Übersetzungen ist die Verwendung von Pluralformen. Je nach der Anzahl der Resultate ändert sich der Text, aber je nach Sprache unterschiedlich. So ist beispielsweise der letzte Satz aus Listing 13-16 nicht korrekt, wenn count_logged() 0 oder 1 zurückgibt. Sie könnten nun zunächst den Rückgabewert dieser Funktion prüfen und daraufhin auswählen, welches Satzkonstrukt am besten passt, aber dies würde eine Menge zusätzlichen Code bedeuten. Außerdem haben verschiedene Sprachen unterschiedliche Grammatikregeln mit teilweise sehr komplexen Pluralbeugungen. Da diese Problem häufig auftritt, enthält symfony einen passenden Helfer namens format_number_choice(). Listing 13-17 zeigt die Verwendung des Helfers.

Listing 13-17 - Übersetzung eines Satzes abhängig von dem Wert der Parameter

[php]
<?php echo format_number_choice(
  '[0]Derzeit niemand online|[1]Es ist derzeit eine Person online|(1,+Inf]Es sind derzeit %1% Personen online', array('%1%' => count_logged()), count_logged()) ?>

Im ersten Argument stehen die diversen Textvarianten. Im zweiten (optionalen) Argument werden die Ersetzungsmuster übergeben, wie Sie es vom __()-Helfer kennen). Das dritte Argument ist die Zahl, anhand der bestimmt werden soll, welcher Text genommen wird.

Die Auswahlmöglichkeiten werden durch ein Pipe-Zeichen (|) getrennt, gefolgt von einer Auflistung der akzeptierten Werte gemäß folgender Syntax:

  • [1,2]: Passt auf Werte zwischen 1 und 2 (inklusive)
  • (1,2): Passt auf Werte zwischen 1 und 2 (exklusive 1 und 2)
  • {1,2,3,4}: Passt nur auf Werte in der Aufzählung
  • [-Inf,0): Passt auf Werte größer oder gleich der negativen Unendlichkeit und unter 0
  • {n: n % 10 > 1 && n % 10 < 5} pliki: Passt auf Werte wie 2, 3, 4, 22, 23, 24 (Nützlich für Sprachen wie Polnisch oder Russisch) Neu in der Entwicklungsversion

Alle nichtleeren Kombinationen von eckigen und runden Klammern werden akzeptiert.

Die Nachricht muss genau so in der XLIFF-Datei auftauchen, damit die Übersetzung korrekt funktioniert. Listing 13-18 zeigt ein Beispiel.

Listing 13-18 - XLIFF-Dictionary für einen String für format_number_choice()

...
<trans-unit id="3">
  <source>[0]Derzeit niemand online|[1]Es ist derzeit eine Person online|(1,+Inf]Es sind derzeit %1% Personen online</source>
  <target>[0]Nobody is logged|[1]There is 1 person logged|(1,+Inf]There are %1% persons logged</target>
</trans-unit>
...

SIDEBAR Einige Worte zu Zeichensätzen

Wenn Sie mit internationalisiertem Inhalt zu tun haben, führt das häufig zu Problemen mit den Zeichensätzen. Wenn Sie einen lokalisierten Zeichensatz verwenden, müssen Sie ihn ggf. ändern, wenn der Benutzer die Culture ändert. Außerdem können Templates in einem bestimmten Zeichensatz einige Zeichen aus einem anderen Zeichensatz nicht korrekt anzeigen.

Aus diesem Grund sollten Sie, sobald Sie mit mehr als einer Culture arbeiten, alle Templates als UTF-8 abspeichern, und das Layout muss den Inhalt mit diesem Zeichensatz ausgeben. Sie werden sicherlich keine unangenehmen Überraschungen haben, wenn Sie einfach immer mit UTF-8 arbeiten - und Sie ersparen sich eine Menge Kopfschmerzen.

Symfony-Anwendungen verwenden eine zentrale Einstellung für den Zeichensatz, in der Datei settings.yml. Wenn Sie diesen Parameter ändern, dann ändert sich der content-type-Header in allen HTML-Antworten.

all:
  .settings:
    charset: utf-8

Aufrufen des Übersetzungs-Helfers außerhalb von Templates

Nicht alle Texte, die in einer Seite angezeigt werden, kommen aus den Templates. Deshalb müssen Sie gelegentlich den Helfer __() in anderen Teilen Ihrer Anwendung aufrufen: In Actions, Filtern, Model-Klassen usw. Listing 13-19 zeigt, wie der Helfer innerhalb einer Action aufgerufen wird, indem die aktuelle Instanz des I18N-Objekts durch das Context-Singleton aufgerufen wird.

Listing 13-19 - Aufruf von __() in einer Action

[php]
$this->getContext()->getI18N()->__($text, $args, 'messages');

Zusammenfassung

Internationalisierung und Lokalisierung in Webanwendungen ist schmerzfrei, wenn Sie wissen, wie man die Benutzer-Culture verwendet. Die Helfer berücksichtigen die Einstellung, um korrekt formatierte Daten auszugeben, und lokalisierter Inhalt aus der Datenbank sieht so aus, als wäre es eine einfache Tabelle. Bezüglich der Übersetzung der Benutzerschnittstelle stellt der Helfer __() und das XLIFF-Dictionary sicher, dass Sie maximalst mögliche Flexibilität bei minimalem Aufwand haben.