Einführung
Zend_Locale ist die Antwort des Frameworks auf die Frage "Wie kann die selbe Anwendung
auf der ganzen Welt verwendet werden?". Die meisten Leute werden sagen "Das ist einfach. Lasst uns alle
Ausgaben in die unterschiedlichsten Sprachen übersetzen". Aber, eine einfache Übersetzungstabelle die
Phrasen von einer Sprache in die andere übersetzt ist nicht genug. Verschiedene Regionen haben auch
unterschiedliche Regeln für Vornamen, Nachnamen, Titel, Format von Nummern, Daten, Zeiten, Währungen usw.
Was wir benötigen ist
Lokalisierung
und die vergleichbare
Internationalisierung
. Beide werden oft abgekürzt zu L10n und I18n. Internationalisierung bezeichnet
mehr die Benutzung von Systemen für die spezielle Benutzung durch eindeutige Gruppen wie zum Beispiel
Sprachübersetzung, Unterstützung von lokalen Konventionen für Plurale, Daten, Zeiten, Währungen, Namen,
Symbolen, Sortierungen, Reihungen und viele mehr. L10n und I18n sind einander
sehr ähnlich. Zend Framework bietet Unterstützung für diese Konventionen durch eine Kombination von
Komponenten wie Zend_Locale, Zend_Date, Zend_Measure, Zend_Translate, Zend_Currency und Zend_TimeSync.
Zend_Locale und setLocale()
Die Dokumentation von PHP sagt das
setlocale() nicht Threadsicher ist weil es pro Prozess behandelt wird und nicht
pro Thread. Das bedeutet das man in multithreaded Umgebungen das Problem bekommen kann, das sich
das Gebietsschema (Locale) ändert wärend das Skript diese Änderung nie selbst durchgeführt hat.
Deswegen kann es zu unerwarteten Ergebnissen kommen wenn man setLocale() in seinen
Skripts verwendet.
Wenn Zend_Locale verwendet wird hat man diese Einschränkungen nicht, da
Zend_Locale weder von PHP's setlocale() abhängig ist, noch irgendwie
mit Ihr gekoppelt ist.
Was ist Lokalisierung
Lokalisierung bedeutet das eine Anwendung (oder Homepage) von verschiedenen Benutzer verwendet werden
kann die unterschiedliche Sprachen sprechen. Aber wie bereits angedeutet heißt Lokalisierung mehr
als nur die Übersetzung von Zeichenketten. Es beinhaltet
Zend_Locale - Unterstützung für Gebietsschemata welche Unterstützung für
Lokalisierungen von anderen ZF Komponenten bieten.
Zend_Translate - Übersetzung von Zeichenketten.
Zend_Date - Lokalisierung von Daten und Zeiten.
Zend_Calendar - Lokalisierung von Kalendern (Unterstützung für nicht Gregorianische Kalendersysteme)
Zend_Currency - Lokalisierung von Währungen.
Zend_Locale_Format - Erkennen und erzeugen von lokalisierten Zahlen.
Zend_Locale_Data - Empfangen von lokalisierten Standard Übersetzungen für
Länder, Sprachen und mehr aus der CLDR
.
TODO - Lokalisierung von Sammlungen
Was ist ein Gebietsschema?
Jeder Computer benutzt Gebietsschemata, selbst wenn Sie es nicht wissen. Anwendungen welche keine
Unterstützung für Lokalisierung bieten, unterstützen zumindest genau ein Gebietsschema (das
Gebietsschema des Authors). Wenn eine Klasse oder Funktion Lokalisierung verwendet sagen wir sie ist
Lokalisierbar. Aber wie weiß der Code welches Gebietsschema ein Benutzer erwartet ?
Eine Gebietsschema Zeichenkette oder Objekt welches ein unterstütztes Gebietsschema identifiziert, gibt
Zend_Locale und dessen Unterklassen Zugriff auf Informationen über die Sprache und
Region welche der Benutzer erwartet. Formatierungen, Normalisierungen und Konvertierungen werden
anhand dieser Informationen durchgeführt.
Wodurch werden Gebietsschemata repräsentiert?
Eine Gebietsschema Zeichenkette besteht aus Informationen über die Sprache des Benutzers und die
bevorzugte/primäre geographische Region (z.B. Staat oder Region von seinem Zuhause oder Arbeitsplatz).
Die Gebietsschema Zeichenkette welche im Zend Framework benutzt werden sind international definierte
Standard Abkürzungen von Sprachen und Regionen. Sie werden geschrieben als sprache_REGION.
Beide Teile, sowohl Sprache als auch Region, werden mit Buchstaben, ASCII Zeichen, abgekürzt.
Man muß darauf achten das nicht nur Gebietsschemata mit 2 Zeichen existieren wie die meisten
Leute denken. Es gibt auch Sprachen und Regionen die nicht nur mit 2 Zeichen abgekürzt werden.
Deswegen sollte man die Region und Sprache NICHT selbst trennen, sondern Zend_Locale verwenden
um die Sprache oder Region von einem Gebietsschema String zu trennen. Andernfalls kann es zu
unerwartetem Verhalten im eigenen Code kommen wenn man versucht das selbst zu machen.
Ein Benutzer von den USA würde die Sprache Englisch und die Region USA
erwarten, beschrieben durch das Gebietsschema "en_US". Ein Benutzer von Deutschland würde die Sprache
Deutsch und die Region Deutschland erwarten, beschrieben durch das
Gebietsschema "de_DE". Hier findest Du eine
Liste von vordefinierten Sprachen und Kombinationen von Regionen
wenn ein bestimmtes Gebietsschema im Zend Framework ausgewählt werden muß.
Auswählen eines speziellen Gebietsschemas
Ein deutscher Benutzer in Amerika würde die Sprache Deutsch und die region USA
erwarten, aber diese nicht-standardmäßigen Mischungen werden nicht als direkt als "Gebietsschema"
unterstützt und erkannt. Wird stattdessen eine ungültige Kombination benutzt, dann wird Sie automatisch
gekürzt, indem die Region entfernt wird. Zum Beispiel würde "de_IS" zu "de" gekürzt werden, und "xh_RU"
würde zu "xh" gekürzt werden, weil keiner dieser Kombinationen gültig ist. Zusätzlich, wenn die Sprache
nicht unterstützt wird (z.B. "zz_US") oder diese nicht existiert, dann wird ein Standard "root"
Gebietsschema benutzt. Dieses "root" Gebietsschema hat Standarddefinitionen für international bekannte
Repräsentationen von Daten, Zeiten, Nummern, Währungen usw. Der Prozess der Kürzung hängt von der
gewünschten Information ab, weil einige Kombinationen von Sprache und Region für eine gewisse Art von
Informationen gültig sind (z.B. Daten) aber für andere nicht (z.B. Währungs Formate).
Achtung vor historischen Änderungen oder dem Versuch die verschiedenen Änderungen der Zeitzonen die
im Laufe der langen Zeit in den vielen Regionen gemacht wurden, da ZF Komponenten darüber nichts
wissen. Zum Beispiel kann hier eine historische Liste
mit dutzenden Änderungen von Regierungen angesehen werden und ob eine Region Sommer-/Winterzeit
unterstützt und sogar in welche Zeitzone eine bestimmte geographische Region gehört. Das bedeutet, wenn
Datumsberechnungen gemacht werden, wird die Berechnung welche durch die ZF Komponenten durchgeführt wird,
nicht an diese Änderungen angepasst. Stattdessen wird die korrekte Uhrzeit benutzt, welche für die aktuell
benutzte Zeitzone angegeben wurde, wobei moderne Regeln für Sommer-/Winterzeit und Zeitzonen Zuordnung
anhand von geographischen Regionen verwendet werden.
Auswahl des richtigen Gebietsschemas
In den meisten Situationen wird new Zend_Locale() automatisch das richtige
Gebietsschema auswählen, wobei die Informationen benutzt werden welche der Webbrowser des
Benutzers zur Verfügung stellt. Wenn statt dessen new Zend_Locale(Zend_Locale::ENVIRONMENT
benutzt wird, dann werden die Informationen vom Betriebsystem des hostenden Servers, wie anbei
beschrieben, dafür genommen.
Automatische Auswahl des Gebietsschemas
Der Suchalgorithmus, welcher von Zend_Locale für die automatische Auswahl des
Gebietsschemas verwendet wird beherrscht drei Informationsquellen:
const Zend_Locale::BROWSER - Der Webbrowser des Benutzer welcher die
Informationen mit jeder Anfrage schickt. Diese wird von PHP durch die globale Variable
HTTP_ACCEPT_LANGUAGE veröffentlicht. Wenn kein passendes
Gebietsschema gefunden wurde, dann wird mit ENVIRONMENT gesucht und
als letztes mit FRAMEWORK gesucht.
const Zend_Locale::ENVIRONMENT - PHP veröffentlicht das Gebietsschema
des hostenden Servers über die interne PHP Funktion setlocale(). Wenn
kein passendes Gebietsschema gefunden wurde, dann wird mit FRAMEWORK
und als letztes mit BROWSER gesucht.
const Zend_Locale::FRAMEWORK - Wenn Zend Framework einen standartisierten
Weg zur Verfügung stellt um für Komponenten Standardwerte zu definieren (das ist geplant
aber noch nicht realisiert), dann wird die Verwendung dieser Konstante das
Gebietsschema anhand dieser Standardwerte auswählen. Wenn kein passendes Gebietsschema
gefunden wurde, dann wird mit ENVIRONMENT und als letztes mit
BROWSER gesucht.
Verwenden automatischer Gebietsschemata
Zend_Locale bietet drei zusätzliche Gebietsschemata. Diese Gebietsschemata gehören
nicht zu irgendeiner Sprache oder Region. Es sind "automatische" Gebietsschemata was bedeutet das
Sie den gleichen Effekt wie die Methode getDefault() haben, aber ohne die negativen
Effekte wie die Erstellung einer Instanz. Diese "automatischen" gebietsschemata können überall
verwendet werden, wo auch standard Gebietsschemata verwendet werden können, und für die
Definition eines Gebietsschemas, kann auch die String Repräsentation verwendet werden. Das bietet
Einfachheit für Situationen wo mit Gebietsschemas gearbeitet wird die vom Browser geliefert
werden.
Es gibt drei Gebietsschemata mit leicht unterschiedlichem Verhalten:
'browser' - Zend_Locale soll mit den Informationen arbeiten
die durch den Web Browser des Benutzers geliefert werden. Sie werden von PHP in der
globalen Variable HTTP_ACCEPT_LANGUAGE veröffentlicht.
Wenn ein Benutzer mehr als ein Gebietsschema in seinem Browser anbietet, wird
Zend_Locale das erste gefundene Gebietsschema verwenden. Wenn der
Benutzer kein Gebietsschema liefert oder das Skript von der Kommandozeile aufgerufen
wird, wird automatisch das Gebietsschema 'environment' verwendet und
zurückgegeben.
'environment' - Zend_Locale soll mit den Informationen arbeiten
welche vom Host Server geliefert werden. Sie werden vom PHP über die interne Funktion
setlocale() veröffentlicht.
Wenn eine Umgebung mehr als ein Gebietsschema anbietet, wird Zend_Locale
das erste gefundene Gebietsschema verwenden. Wenn der Host kein Gebietsschema anbietet
wird automatisch das Gebietsschema 'browser' verwendet und zurückgegeben.
'auto' - Zend_Locale soll automatisch jedes beliebige
Gebietsschema erkennen mit dem gearbeitet werden kann. Zuerst wird nach dem
Gebietsschema des Benutzers gesucht und anschließend, wenn das nicht erfolgreich war,
nach dem Gebietsschema des Hosts.
Wenn kein Gebietsschema gefunden werden konnte, wird eine Ausnahme geworfen und
bekanntgeben das die automatische Erkennung fehlgeschlagen ist.
Verwenden automatischer Gebietsschemata
Verwenden eines Standard Gebietsschemas
In einigen Umgebungen ist es nicht möglich automatisch ein Gebietsschema zu erkennen. Man kann
dieses Verhalten zum Beispiel sehen wenn eine Anfrage von der Kommandozeile kommt, oder der
anfragende Browser kein Sprachtag gesetzt hat und zusätzlich der Server das Standardgebietsschema
'C' gesetzt hat oder ein anderes propäritäres Gebietsschema.
In solchen Fällen wirft Zend_Locale normalerweise eine Ausnahme mit einer Nachricht,
das die automatische Erkennung des Gebietsschemas nicht erfolgreich war. Es gibt zwei Optionen
um diese Situation handzuhaben. Entweder durch das Setzen eines neuen Gebietsschemas per Hand, oder
der Definition eines Standardgebietsschemas.
Handhabung von Ausnahmen für Gebietsschemas
Aber das hat einen großen negativen Effekt. Man muß das Gebietsschema-Objekt in jeder Klasse
setzen die Zend_Locale verwendet. Das kann sehr unhandlch sein wenn mehrere Klassen
verwendet werden.
Seit Zend Framework Release 1.5 gibt es einen viel besseren Weg um das handzuhaben. Man kann
ein Standard Gebietsschema mit der statischen setDefault() Methode setzen. Natürlich
wird jedes unbekannte oder nicht voll qualifizierte Gebietsschema eine Ausnahme werden.
setDefault() sollte der erste Aufruf sein bevor irgendeine Klasse initiiert wird
die Zend_Locale verwendet. Siehe das folgende Beispiel für Details:
Setzen eines Standardgebietsschemas
Im Fall das kein Gebietsschema erkannt wird, wird automatisch das Gebietsschema
de verwendet. Andernfalls wird das erkannte Gebietsschema
verwendet.
ZF lokalisierbare Klassen
Im ZF sind lokalisierbare Klassen von Zend_Locale abhängig um ein Gebietsschema
automatisch auszuwählen, wie im oberen Abschnitt geschrieben. Das Erstellen eines Datums durch
Verwendung von Zend_Date ohne die Angabe eines Gebietsschemas führt als Ergebnis zu
einem Objekt mit einem Gebietsschema, basierend auf den Informationen welche durch den Webbrowser des
Benutzers zur Verfügung gestellt werden.
Daten verwenden das aktuelle Gebietsschema des Web Benutzers
Um dieses Standardverhalten zu übergehen, und die eine lokalisierbare ZF Komponente dazu zu bringen
ein spezielles Gebietsschema zu benutzen welches unabhängig vom Gebietsschema des Besucher der
Webseite ist, muß als dritter Parameter im Konstruktor das Gebietsschema angegeben werden.
Übergehen der Auswahl des standardmäßigen Gebietsschemas
Wenn viele Objekte benutzt werden die alle das gleiche Gebietsschema verwenden, sollte das
Gebietsschema explizit definiert werden, um die zusätzliche Arbeit des Objekts durch die
Eruierung des Standardmäßigen Gebietsschemas zu verringern.
Optimierung der Geschwindigkeit durch Benutzung eines Standard Gebietsschemas
Anwendungsweites Gebietsschema
Zend Framework erlaubt die Verwendung eines Anwendungsweiten Gebietsschemas. Man kann einfach eine
Instanz von Zend_Locale in der Registry mit dem Schüssel 'Zend_Locale' setzen.
Dann wird diese Instanz in allen Klassen vom Zend Framework die Gebietsschemata verwenden selbst
verwendet. Auf diesem Weg wird eine Instanz in der Registry gesetzt und dann kann man das weitere
Setzen vergessen. Sie wird automatisch in allen anderen Klassen verwendet. Siehe das folgende
Beispiel für die richtige Verwendung:
Verwendung eines anwendungsweiten Gebietsschemas
getLocale();
echo $date->getDate();
]]>
Zend_Locale_Format::setOptions(array $options)
Die Option 'precision' wird benutzt um einen Wert zu verkürzen oder mit extra Ziffern zu strecken.
Ein Wert von '-1' verhindert die Veränderung der Anzahl an Ziffern im Nachkomma-Teil des Wertes.
Die 'locale' Option hilft wenn Nummern und Daten analysiert werden und hierbei Trennzeichen oder
Monatsnamen verwendet werden. Die Datumsformat Option 'format_type' wählt zwischen CLDR/ISO
Datumsdefinitionen und PHP's date() Definitionen. Die Option 'fix_date' erlaubt oder verhindert eine
Automatik welche versucht falsche Daten zu korrigieren. Die Option 'number_format' definiert ein
Standard Format für Nummern bei Verwendung der Funktion toNumber(). (siehe
).
Die Option 'date_format' kann verwendet werden um ein Standard Datumsformat zu definieren. Aber Achtung
bei der Verwendung von getDate(), checkDateFormat() und getTime() nach der Verwendung von setOptions()
mit einem 'date_format'. Um diese vier Methoden mit einem Standard Datumsformat für ein Gebietsschema
zu benutzen, muß array('date_format' => null, 'locale' => $locale) in deren Optionen angegeben werden.
Daten die das richtige Gebietsschema des Web Benutzers verwenden
'en_US',
'fix_date' => true,
'format_type' => 'php'));
]]>
Um mit den Standarddefinitionen eines Gebietsschemas zu arbeiten kann die Konstante
Zend_Locale_Format::STANDARD verwendet werden. Das Setzen der Konstante Zend_Locale_Format::STANDARD
für 'date_format' benutzt die Standarddefinition des aktuellen Gebietsschemas. Das Setzen für
'number_format' benutzt das Standard Nummernformat dieses Gebietsschemas. Und das Setzen für 'locale'
verwendet das Standard Gebietsschema des Servers oder Browsers.
Verwendung von STANDARD Definitionen für setOptions()
'en_US',
'date_format' => 'dd.MMMM.YYYY'));
// Überladen des global gesetzten Datumsformats
$date = Zend_Locale_Format::getDate('2007-04-20',
array('date_format' =>
Zend_Locale_Format::STANDARD);
// Überladen des global gesetzten Standard Gebietsschemas
Zend_Locale_Format::setOptions(array('locale' => Zend_Locale_Format::STANDARD,
'date_format' => 'dd.MMMM.YYYY'));
]]>
Zend_Locale und dessen Subklassen schneller machen
Zend_Locale und dessen Subklassen können durch die Verwendung von
Zend_Cache schneller gemacht werden. Man sollte die statische Methode
Zend_Locale::setCache($cache) verwenden wenn man Zend_Locale benutzt.
Zend_Locale_Format kann schneller gemacht werden indem die Option
cache innerhalb von
Zend_Locale_Format::setOptions(array('cache' => $adapter)); aufgerufen wird. Wenn beide
Klassen verwendet werden sollte nur für Zend_Locale ein Cache gesetzt werden, da der
zuletzt gesetzte Cache den vorher gesetzten Cache überschreibt. Der Bequemlichkeit halber gibt es
auch die statischen Methoden Zend_Locale::getCache(), hasCache(),
clearCache() und removeCache().