1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 21816 -->
4 <sect1 id="zend.locale.introduction">
5 <title>Wprowadzenie</title>
8 <classname>Zend_Locale</classname> to odpowiedź frameworka na pytanie: "Jak jedna aplikacja
9 może być używana na całym świecie?". Większość odpowie: "To proste. Wystarczy przetłumaczyć
10 wszystkie napisy na inne języki.". Jednak użycie prostych tabel mapujących frazy jednego
11 języka na drugi nie jest wystarczające. Różne regiony mogą mieć różne konwencje dotyczące
12 imion, nazwisk, zwrotów grzecznościowych, formatu liczb, dat, czasu, waluty itp.
17 <ulink url="http://en.wikipedia.org/wiki/Internationalization_and_localization">Lokalizacja
18 i internacjonalizacja</ulink>. Zwroty te często są przedstawiane skrótowo jako odpowiednio
19 <emphasis>L10n</emphasis> oraz <emphasis>I18n</emphasis>. Internacjonalizacja zakłada
20 przystosowanie do użycia systemu niezależnie od specjalnych wymogów
21 charakterystycznych dla użytkowników
22 w zakresie języka, regionu, sposobu zapisu liczb, konwencji finansowych, dat i czasu.
23 Lokalizacja określa dodanie do systemu funkcjonalności obsługujących określone wymogi
24 dotyczące języka, konwencji dat, czasu, waluty, nazw, symboli, sortowania itp.
25 <code>L10n</code> i <code>I18n</code> uzupełniają się nawzajem. Zend Framework udostępnia
26 ich obsługę poprzez szereg komponentów. M. in.:
27 <classname>Zend_Locale</classname>, <classname>Zend_Date</classname>,
28 <classname>Zend_Measure</classname>, <classname>Zend_Translate</classname>,
29 <classname>Zend_Currency</classname>, and <classname>Zend_TimeSync</classname>.
33 <title>Zend_Locale i setlocale()</title>
36 W <ulink url="http://php.net/setlocale">dokumentacji PHP</ulink> można przeczytać, że
37 funkcja <methodname>setlocale()</methodname> nie jest bezpieczna wątkowo (thread-safe)
38 ponieważ działa w zasięgu procesu a nie wątku. To oznacza, że w środowisku
39 wielowątkowym może dojść do sytuacji w której locale ulegnie zmianie pomimo braku
40 odwołań do funkcji <methodname>setlocale()</methodname> w skrypcie.
41 To, z kolei, może prowadzić do nieoczekiwanych rezultatów działania programu.
45 Podczas używania <classname>Zend_Locale</classname> takie ograniczenia nie występują
46 ponieważ klasa <classname>Zend_Locale</classname> jest całkowicie niezależna od funkcji
47 <acronym>PHP</acronym> <methodname>setlocale()</methodname>.
51 <sect2 id="zend.locale.whatislocalization">
52 <title>Co to jest lokalizacja</title>
55 Lokalizacja oznacza, że aplikacja (lub strona) może być używana przez różnych
56 użytkowników, którzy mówią w różnych językach. Jednak przetłumaczenie napisów
57 to tylko jedno z wielu zagadnień z tym związanych. W Zend Framework składają
61 <itemizedlist mark='opencircle'>
64 <classname>Zend_Locale</classname> - Główna klasa wspierająca locale dla
65 pozostałych komponentów Zend Framework.
71 <classname>Zend_Translate</classname> - Tłumaczenie łańcuchów znaków.
77 <classname>Zend_Date</classname> - Lokalizacja dat, czasów.
83 <classname>Zend_Calendar</classname> - Lokalizacja kalendarzy (ze wsparciem
84 dla systemów kalendarzy innych niż Gregoriański)
90 <classname>Zend_Currency</classname> - Lokalizacja walut.
96 <classname>Zend_Locale_Format</classname> - Przetwarzanie i generowanie
97 zlokalizowanych liczb.
103 <classname>Zend_Locale_Data</classname> - Pozyskiwanie zlokalizowanej formy
104 standardowych łańcuchów znaków - nazw państw, języków i
105 <ulink url="http://unicode.org/cldr/">innych z <acronym>CLDR</acronym></ulink>.
111 <code>TODO</code> - Lokalizacja porządków sortowania
117 <sect2 id="zend.locale.whatis">
118 <title>Czym jest locale</title>
121 Każdy użytkownik komputera używa locale, nawet wtedy gdy o tym nie myśli. Aplikacje
122 nie posiadające obsługujące wielu zestawów językowych przeważnie wspierają
123 jedno określone locale (locale autora). Kiedy klasa lub funkcja używają lokalizacji,
124 mówi się że jest świadoma locale. W jaki sposób kod "wie" jakiego locale użytkownik
129 Łańcuch znaków lub obiekt identyfikujący locale daje klasie
130 <classname>Zend_Locale</classname> i jej klasom pochodnym dostęp do informacji
131 dotyczących języka oraz regionu, których użytkownik się spodziewa.
132 Na podstawie tych informacji dokonywane jest poprawne formatowanie, normalizacja
137 <sect2 id="zend.locale.representation">
138 <title>Jak locale są reprezentowane</title>
141 Identyfikatory locale składają się z informacji dotyczących języka użytkownika oraz
142 preferowanego/podstawowego regionu geograficznego (np. stan, województwo, land).
143 Łańcuchy identyfikatorów locale używane w Zend Framework przestrzegają międzynarodowych
144 standardów dotyczących skrótów języków i regionów. Zapisane są jako
145 <code>język_REGION</code>. Obie części są utworzone z liter znaków wchodzących w skład
146 <acronym>ASCII</acronym>.
151 W przeciwieństwie do popularnego osądu istnieją identyfikatory locale składające
152 się z więcej niż 2 liter. Dodatkowo istnieją języki i regiony których skróty
153 również są zawarte w więcej niż 2 literach. Mając to na uwadze, należy wystrzegać
154 się własnoręcznego wydobywania oznaczenia języka czy regionu z pełnego\
155 identyfikatora locale. Zamiast tego należy skorzystać z
156 <classname>Zend_Locale</classname>. W przeciwnym przypadku efekty działania kodu
157 mogą okazać się niespodziewane.
162 Użytkownik z USA może spodziewać się języka angielskiego (<code>English</code>)
163 oraz regionu <constant>USA</constant>. Daje to identyfikator locale: "en_US".
164 Użytkownik w Niemczech będzie się spodziewał języka niemieckiego
165 (<code>Deutsch</code>) oraz regionu Niemcy (<code>Deutschland</code>) co da
166 locale "de_DE". Aby zasięgnąć szczegółowych informacji o konkretnym
167 identyfikatorze locale do użytku w Zend Framework należy zapoznać się z <ulink
168 url="http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html">listą
169 identyfikatorów locale</ulink>.
172 <example id="zend.locale.representation.example-1">
173 <title>Wybranie konkretnego locale</title>
175 <programlisting language="php"><![CDATA[
176 $locale = new Zend_Locale('de_DE'); // Język niemiecki _ Niemcy
181 Użytkownik z Niemiec przebywający w Ameryce mógłby oczekiwać języka
182 <code>Deutsch</code> i regionu <constant>USA</constant> ale podobne niestandardowe
183 połączenia nie są wspierane w takim stopniu jak pełnoprawne locale. Jeśli podana
184 zostanie nieprawidłowa kombinacja to nastąpi automatyczne odrzucenie kodu regionu.
185 Dla przykładu, "de_IS" zostałoby ograniczone do "de" a "xh_RU" - do "xh" ponieważ
186 żadna z tych kombinacji nie jest poprawna. Dodatkowo, jeśli język podanej kombinacji
187 nie jest wspierany (np. "zz_US") lub nie istnieje to zostanie użyte domyślne locale
188 "root", które ma domyślny zestaw definicji międzynarodowych oznaczeń dat, czasów,
189 liczb, walut itp. Proces odrzucania kodu regionu zależy również od żądanych informacji.
190 Niektóre kombinacje języków i regionów mogą być odpowiednie dla określonego
191 rodzaju danych (np. dat) ale nie dla innych (np. format waluty).
195 Należy mieć na uwadze zmiany historyczne ponieważ komponenty Zend Framework mogą nie
196 być "świadome" częstych zmian stref czasowych na przestrzeni lat w wielu regionach.
197 Przykładowo, <ulink url="http://www.statoids.com/tus.html"> pod tym linkiem widać
198 historyczną listę szeregu zmian</ulink> jakich dokonywały rządy w stosunku do
199 występowania tzw. czasu letniego a nawet obowiązującej strefy czasowej. Przez to,
200 podczas obliczeń na datach, komponenty Zend Framework nie będą brały tych zmian pod
201 uwagę. Zamiast tego zwrócony zostanie rezultat wynikający z użycia strefy czasowej
202 wg. obecnych zasad dotyczących czasu letniego i strefy czasowej konkretnego regionu.
206 <sect2 id="zend.locale.selection">
207 <title>Wybranie odpowiedniego locale</title>
210 W większości przypadków <code>new Zend_Locale()</code> automatycznie wybierze poprawne
211 locale zachowując uprzywilejowanie w stosunku do danych udostępnionych przez
212 przeglądarkę użytkownika. W przypadku użycia
213 <code>new Zend_Locale(Zend_Locale::ENVIRONMENT)</code> pierwszym źródłem informacji
214 o locale stanie się konfiguracja serwera hostingowego tak jak opisano niżej.
217 <example id="zend.locale.selection.example-1">
218 <title>Automatyczny wybór locale</title>
220 <programlisting language="php"><![CDATA[
221 $locale = new Zend_Locale();
223 // domyślne zachowanie, tak samo jak wyżej
224 $locale1 = new Zend_Locale(Zend_Locale::BROWSER);
226 // preferencja ustawień serwera
227 $locale2 = new Zend_Locale(Zend_Locale::ENVIRONMENT);
229 // perferencja ustawień frameworka
230 $locale3 = new Zend_Locale(Zend_Locale::FRAMEWORK);
235 Algorytm automatycznego szukania locale używany przez <classname>Zend_Locale</classname>
236 używa trzech źródeł danych:
241 const <constant>Zend_Locale::BROWSER</constant> - Przeglądarka użytkownika
242 przy każdym żądaniu, dostarcza informacji, które przekładane są na zmienną
243 globalną <acronym>PHP</acronym> o nazwie
244 <varname>$_SERVER['HTTP_ACCEPT_LANGUAGE']</varname>.
245 Jeśli brak jest odpowiedniego locale to następnym źródłem branym pod
246 uwagę jest <constant>ENVIRONMENT</constant> i w ostateczności
247 <constant>FRAMEWORK</constant>.
253 const <constant>Zend_Locale::ENVIRONMENT</constant> - <acronym>PHP</acronym>
254 udostępnia locale serwera hostingowego poprzez wewnętrzną funkcję
255 <methodname>setlocale()</methodname>. Jeśli brak jest odpowiedniego locale
256 to kolejnym źródłem branym pod uwagę staje się
257 <constant>FRAMEWORK</constant> i w ostateczności
258 <constant>BROWSER</constant>.
264 const <constant>Zend_Locale::FRAMEWORK</constant> - W momencie, w którym
265 Zend Framework będzie miał wystandaryzowany sposób określania
266 domyślnych wartości komponentów (cecha jeszcze niedostępna) wtedy użycie
267 tej stałej spowoduje wybranie locale na podstawie tych domyślnych wartości.
268 W przypadku braku odpowiedniego locale kolejnym źródłem branym pod uwagę
269 będzie <constant>ENVIRONMENT</constant> i na końcu
270 <constant>BROWSER</constant>.
277 <sect2 id="zend.locale.selection.automatic">
278 <title>Użycie automatycznego locale</title>
281 <classname>Zend_Locale</classname> oferuje trzy dodatkowe locale. Nie należą one
282 do żadnego języka ani regionu. Są to locale "automatyczne" co oznacza, że działają
283 na podobnej zasadzie co metoda <methodname>getDefault()</methodname> ale bez potrzeby
284 tworzenia instancji. Locale "automatyczne" mogą być użyte w każdym momencie, w którym
285 możliwe byłoby zdefiniowanie locale w standardowy sposób. Dzięki temu można ich używać
286 w łatwy sposób np. w sytuacji pracy z locale udostępnianym przez przeglądarkę.
290 Istnieją trzy rodzaje takich locale, których zachowanie nie jest standardowe:
294 <code>'browser'</code> - klasa <classname>Zend_Locale</classname> powinna
295 użyć informacji dostarczanych przez przeglądarkę użytkownika. Te dane są
296 udostępniane przez <acronym>PHP</acronym> w globalnej zmiennej
297 <varname>$_SERVER['HTTP_ACCEPT_LANGUAGE']</varname>.
301 Jeśli przeglądarka użytkownika informuje o więcej niż jednym locale
302 <classname>Zend_Locale</classname> użyje pierwszego z listy. W przypadku
303 nie podania żadnego locale przez przeglądarkę (lub gdy skrypt jest
304 uruchomiony z linii poleceń) zostanie użyte "automatyczne" locale
305 <code>'environment'</code>.
311 <code>'environment'</code> - klasa <classname>Zend_Locale</classname>
312 powinna brać pod uwagę informacje przekazane przez serwer hostingowy.
313 Są one udostępnione przez <acronym>PHP</acronym> poprzez wewnętrzną funkcję
314 <methodname>setlocale()</methodname>.
318 Jeśli środowisko serwera informuje o więcej niż jednym locale
319 <classname>Zend_Locale</classname> użyje pierwszego z listy. W przypadku
320 nie podania żadnego locale zostanie użyte "automatyczne" locale
321 <code>'browser'</code>.
327 <code>'auto'</code> - klasa <classname>Zend_Locale</classname> powinna
328 automatycznie wykryć locale, które nadaje się do użycia. W pierwszej
329 kolejności będzie próbować znaleźć locale użytkownika, w przypadku
330 niepowodzenia pod uwagę brane będzie środowisko serwera hostingowego.
334 Jeśli nie uda się wykryć locale, klasa rzuci wyjątek i powiadomi o
341 <example id="zend.locale.selection.automatic.example-1">
342 <title>Użycie automatycznego locale</title>
344 <programlisting language="php"><![CDATA[
345 // bez automatycznej detekcji
346 //$locale = new Zend_Locale(Zend_Locale::BROWSER);
347 //$date = new Zend_Date($locale);
349 // z automatyczną detekcją
350 $date = new Zend_Date('auto');
355 <sect2 id="zend.locale.defaultlocale">
356 <title>Użycie domyślnego locale</title>
359 W niektórych środowiskach automatyczna detekcja locale nie jest możliwa. Można się tego
360 spodziewać w przypadku uruchomienia skryptu z linii poleceń lub gdy przeglądarka
361 użytkownika nie ma zdefiniowanego języka a domyślnym locale serwera hostingowego
362 jest 'C' lub inne niestandardowe locale.
366 W takim przypadku <classname>Zend_Locale</classname> rzuci wyjątek z informacją o
367 niepowodzeniu w automatycznym wykryciu locale. Istnieją dwa wyjścia z tej sytuacji.
368 Pierwszym jest ręczne ustawienie nowego locale, drugim - zdefiniowanie domyślnego
372 <example id="zend.locale.defaultlocale.example-1">
373 <title>Obsługa wyjątków locale</title>
375 <programlisting language="php"><![CDATA[
378 $locale = new Zend_Locale('auto');
379 } catch (Zend_Locale_Exception $e) {
380 $locale = new Zend_Locale('de');
383 // w modelu/kontrolerze
384 $date = new Zend_Date($locale);
389 To podejście ma jedną wadę. Wymusza ustawienie obiektu locale poprzez
390 <classname>Zend_Locale</classname> w każdej klasie. W przypadku używania wielu klas
391 może to stanowić duży problem.
395 Od Zend Framework 1.5 istnieje o wiele lepszy sposób na obsługę takiej sytuacji.
396 Można ustawić domyślne locale za pomocą statycznej metody
397 <methodname>setDefault()</methodname>. Oczywiście każde nieznane lub źle sformułowane
398 locale również spowoduje rzucenie wyjątku. <methodname>setDefault()</methodname>
399 powinna być wywołana przed uruchomieniem dowolnej klasy używającej
400 <classname>Zend_Locale</classname>. Tak jak w poniższym przykładzie:
403 <example id="zend.locale.defaultlocale.example-2">
404 <title>Ustawienie domyślnego locale</title>
406 <programlisting language="php"><![CDATA[
408 Zend_Locale::setDefault('de');
410 // w modelu/kontrolerze
411 $date = new Zend_Date();
416 W przypadku niepowodzenia automatycznego wykrycia locale użyte zostanie locale
417 <emphasis>de</emphasis>. W przeciwnym przypadku - klasa użyje wykrytego locale.
421 <sect2 id="zend.locale.interoperate">
422 <title>Klasy ZF "świadome" locale</title>
425 Klasy, które są "świadome" locale w Zend Framework polegają na
426 <classname>Zend_Locale</classname> w kwestii automatycznego wybrania locale na
427 zasadach opisanych wcześniej. Np. w aplikacji webowej Zend Framework, utworzenie
428 obiektu klasy <classname>Zend_Date</classname> bez podania locale spowoduje, że
429 powstały obiekt będzie miał locale ustawione na podstawie przeglądarki użytkownika.
432 <example id="zend.locale.interoperate.example-1">
433 <title>Format daty domyślnie dostosowuje się do przeglądarki</title>
435 <programlisting language="php"><![CDATA[
436 $date = new Zend_Date('2006',Zend_Date::YEAR);
441 Aby zmienić domyślne zachowanie i zmusić komponenty Zend Framework "świadome" locale
442 do użytku określonego locale (obojętnie od ustawień przeglądarki użytkownika) należy
443 podać nazwę locale w trzecim argumencie konstruktora.
446 <example id="zend.locale.interoperate.example-2">
447 <title>Zmiana domyślnego wykrywania locale</title>
449 <programlisting language="php"><![CDATA[
450 $usLocale = new Zend_Locale('en_US');
451 $date = new Zend_Date('2006', Zend_Date::YEAR, $usLocale);
452 $temp = new Zend_Measure_Temperature('100,10',
453 Zend_Measure::TEMPERATURE,
459 Jeśli jest wiadomo, że wiele obiektów powinno użyć określonego locale to należy się
460 upewnić, że będą miały to locale określone. Dzięki temu można uniknąć dodatkowego
461 czasu pracy skryptu wynikającego z wyszukiwania odpowiedniego locale.
464 <example id="zend.locale.interoperate.example-3">
465 <title>Optymalizacja wydajności dzięki określeniu locale</title>
467 <programlisting language="php"><![CDATA[
468 $locale = new Zend_Locale();
469 $date = new Zend_Date('2006', Zend_Date::YEAR, $locale);
470 $temp = new Zend_Measure_Temperature('100,10',
471 Zend_Measure::TEMPERATURE,
477 <sect2 id="zend.locale.frameworkwidelocale">
478 <title>Locale obowiązujące w całej aplikacji</title>
481 Zend Framework umożliwia zdefiniowanie locale obowiązującego w całej aplikacji.
482 Polega to na wywołaniu obiektu klasy <classname>Zend_Locale</classname> i umieszczeniu
483 go w rejestrze z kluczem 'Zend_Locale'. Dzięki temu ta instancja będzie używana we
484 wszystkich klasach "świadomych" locale Zend Framework. Ten sposób umożliwia
485 ustawienie locale w rejestrze i uwolnienie się od potrzeby zwracania uwagi na to
486 zagadnienie. Ustawione locale zostanie automatycznie użyte we wszystkich przypadkach.
487 Przykładowe użycie znajduje się w poniższym przykładzie:
490 <example id="zend.locale.frameworkwidelocale.example">
491 <title>Użycie locale obowiązującego w całej aplikacji</title>
493 <programlisting language="php"><![CDATA[
495 $locale = new Zend_Locale('de_AT');
496 Zend_Registry::set('Zend_Locale', $locale);
498 // w modelu lub kontrolerze
499 $date = new Zend_Date();
500 // print $date->getLocale();
501 echo $date->getDate();
506 <sect2 id="zend.locale.formatoptions">
507 <title>Zend_Locale_Format::setOptions(array $options)</title>
510 Opcja 'precision' służy do obcięcia lub wydłużenia liczby. Wartość '-1' wyłącza
511 możliwość modyfikacji ilości liczb po przecinku. Opcja 'locale' jest pomocna podczas
512 przetwarzania liczb i dat z użyciem separatorów oraz nazw miesięcy.
513 Opcja formatów dat 'format_type' umożliwia wybór pomiędzy standardem
514 <acronym>CLDR</acronym>/ISO oraz wyrażeniami funkcji <acronym>PHP</acronym> date().
515 Opcja 'fix_date' umożliwia podanie formatu liczb do użytku z metodą
516 <methodname>toNumber()</methodname> (więcej informacji znajduje się w rozdziale
517 <xref linkend= "zend.locale.number.localize"/>).
521 Opcja 'date_format' może być użyta do określenia domyślnego formatu daty ale należy
522 zachować ostrożność przy używaniu <methodname>getDate()</methodname>,
523 <methodname>checkdateFormat()</methodname> and <methodname>getTime()</methodname>.
524 Aby ich pomyślnie używać należy umieścić w ich opcjach następującą tablicę:
525 array('date_format' => null, 'locale' => $locale).
528 <example id="zend.locale.formatoptions.example-1">
529 <title>Daty przyjmują domyślny format przeglądarki</title>
531 <programlisting language="php"><![CDATA[
532 Zend_Locale_Format::setOptions(array('locale' => 'en_US',
534 'format_type' => 'php'));
539 Aby uzyskać standardowe definicje locale można użyć stałej
540 <constant>Zend_Locale_Format::STANDARD</constant>. Ustawienie w opcji
541 <code>date_format</code> na <constant>Zend_Locale_Format::STANDARD</constant> spowoduje
542 użycie standardowej definicji formatu zawartej w bieżącym locale. Umieszczenie tej
543 stałej w opcji <code>number_format</code> spowoduje użycie standardowego
544 formatu liczb z bieżącego locale. Ustawienie stałej w opcji <code>locale</code>
545 spowoduje użycie standardowego locale dla środowiska bądź przeglądarki.
548 <example id="zend.locale.formatoptions.example-2">
549 <title>Użycie standardowych definicji w metodzie setOptions()</title>
551 <programlisting language="php"><![CDATA[
552 Zend_Locale_Format::setOptions(array('locale' => 'en_US',
553 'date_format' => 'dd.MMMM.YYYY'));
554 // nadpisanie globalnego formatu daty
555 $date = Zend_Locale_Format::getDate('2007-04-20',
556 array('date_format' =>
557 Zend_Locale_Format::STANDARD);
559 // globalne ustawienie standardowego locale
560 Zend_Locale_Format::setOptions(array('locale' => Zend_Locale_Format::STANDARD,
561 'date_format' => 'dd.MMMM.YYYY'));
566 <sect2 id="zend.locale.cache">
567 <title>Przyspieszenie Zend_Locale i jej klas pochodnych</title>
570 Można przyspieszyć działanie klasy <classname>Zend_Locale</classname> i jej klas
571 pochodnych poprzez użycie <classname>Zend_Cache</classname>. W przypadku używania
572 <classname>Zend_Locale</classname> osiągnąć to można za pomocą statycznej
573 metody <methodname>Zend_Locale::setCache($cache)</methodname>.
574 Klasę <classname>Zend_Locale_Format</classname> można przyspieszyć używając opcji
576 <classname>Zend_Locale_Format::setOptions(array('cache' => $adapter));</classname>.
577 Jeśli używane są obie klasy należy ustawić cache jedynie dla
578 <classname>Zend_Locale</classname>. W przeciwnym przypadku ostatni ustawiony cache
579 nadpisze wcześniejszy. Dla ułatwienia istnieją również statyczne metody
580 <methodname>getCache()</methodname>, <methodname>hasCache()</methodname>,
581 <methodname>clearCache()</methodname> oraz <methodname>removeCache()</methodname>.
585 Jeśli deweloper nie ustawi własnoręcznie cache'u <classname>Zend_Locale</classname>
586 automatycznie zrobi to za niego. W niektórych sytuacjach może zajść potrzeba rezygnacji
587 z użycia cache'u, nawet za cenę wydajności. Wtedy należy użyć statycznej metody
588 <methodname>disableCache(true)</methodname>. Oprócz wyłączenia ewentualnego wcześniej
589 ustawionego cache'u (bez usuwania jego zawartości) metoda ta zapobiega generowaniu
590 cache'u (jeśli nie był wcześniej ustawiony).