Lokalizowanie dat z Zend Framework
Wczoraj na Planecie PHP znalazłem wpis Locale-Sensitive Dates in PHP. Autorka opisuje zagadnienie obsługi dat, w kontekście ich tłumaczenia na różne języki. Proponowanym rozwiązaniem jest skorzystanie z kombinacji funkcji setlocale oraz strftime. Nie jest to jednak rozwiązanie idealne, gdyż wymaga, aby środowisko, w którym działa aplikacja, obsługiwało wybrany zestaw znaków. W dyskusji zaproponowałem rozwiązanie oparte o Zend Framework, które chciałbym pokrótce przedstawić.
Do obsługi dat wykorzystamy Zend_Date, zaś ich lokalizację powierzymy Zend_Locale.
Przygotowanie środowiska
Nim przystąpimy do zabawy datami należy przygotować środowisko. W tym celu ze strony projektu pobieramy najnowszą wersję frameworka (w chwili pisania artykułu mamy do dyspozycji stabilną wersję 1.6.2 oraz niestabilną 1.7.0) i rozpakowujemy. Następnie tworzymy plik date.php i przygotowujemy ZF do działania:
< ?php header( 'Content-type: text/html; charset=utf-8' ); // ścieżka define( 'DS', DIRECTORY_SEPARATOR ); define(' APPLICATION_PATH', realpath( dirname( __FILE__ ) ) ); set_include_path( APPLICATION_PATH . DS . '3rd_party' . DS . PATH_SEPARATOR . get_include_path() ); // autoload require_once "Zend/Loader.php"; Zend_Loader::registerAutoload(); // ustawiam strefę czasową- wymagane przez Zend_Date! date_default_timezone_set( 'Europe/Warsaw' ); ?>
Najważniejsza jest linia 6, w której definiujemy katalog, gdzie ZF powinien szukać swoich klas. Tak przygotowani możemy rozpocząć walkę z lokalizowaniem dat!
Zend_Locale
ZF posiada rozbudowaną obsługę l10n i i18n. która oprócz obsługi tłumaczeń pozwala na prostą obsługę walut, formatów zapisu liczb, jednostek miary oraz – co najbardziej nas interesuje – daty. Framework dystrybuowany jest z dość rozbudowaną biblioteką tłumaczeń, obsługującą nazwy dni, miesięcy, najczęściej spotykane formaty dat itp. Dzięki temu używanie Zend_Locale staje się banalnie proste i sprowadza się do 1 linijki:
< ?php $locale = new Zend_Locale( 'pl_PL' ); ?>
Twórcy ZF poszli jednak dalej, pozwalając w prosty sposób dostosowywać się do języka używanego przez użytkownika, pobierając tą informację z jego przeglądarki. Przykładowy kod, wraz z obsługą wyjątku, gdy wybrany język nie jest obsługiwany przez ZF, jest równie trywialny jak poprzedni przykład:
< ?php try { $locale = new Zend_Locale( Zend_Locale::BROWSER ); } catch( Zend_Locale_Exception $e ) { $locale = new Zend_Locale( 'pl_PL' ); } ?>
Warto wspomnieć jeszcze o możliwości wykorzystania Zend_Cache, aby przyspieszyć działanie aplikacji (lokalizacje trzymane są w pliku XML).
Zend_Date
Zend_Date pozwala w prosty sposób operować datami- parsować, prezentować w różnych formatach, dodawać i odejmować. Co ważne- operacje nie są ograniczone do zakresu unix epoch! Przykładowe wykrozystanie Zend_Date:
< ?php echo new Zend_Date(); // wyświetli aktualną datę w predefiniowanym formacie echo new Zend_Date( '2008-11-03 8:34:40' ); // wyświetli podaną datę w predefiniowanym formacie ?>
A jak do tego wszystkiego ma się Zend_Locale? Sprzężenie obu modułów jest zadaniem trywialnie prostym:
< ?php // polska lokalizacja echo new Zend_Date( new Zend_Locale( 'pl_PL' ) ); // wyświetli aktualną datę w formacie Y-m-d H:i:s ?>
Predefiniowana data zależna jest od wybranej lokalizacji, co ma znaczenie choćby w kwestii podawania godzin (format 12 lub 24 godzinny). Poniżej zamieszczam kilka przykładów użycia Zend_Date wraz z Zend_Locale. Dodam tylko, że domyślnie Zend_Date przyjmuje wyświetla daty w formacie zgodnym z ISO, to zachowanie można jednak zmienić, co uczyniłem w niniejszym przykładzie:
< ?php // format daty będę podawał zgodnie z formatem PHP, a nie ISO Zend_Date::setOptions( array( 'format_type' => 'php' ) ); // polska lokalizacja $locale = new Zend_Locale( 'pl_PL' ); echo new Zend_Date( $locale ); // wyświetli aktualną datę w formacie Y-m-d H:i:s $date = new Zend_Date( '2008-11-03 8:34:40', $locale ); echo $date->toString( 'l, j F, Y, H:i' ); // wyświetli: poniedziałek, 3 listopada, 2008, 08:34 // angielska lokalizacja $locale = new Zend_Locale( 'en_EN' ); echo new Zend_Date( $locale ); // wyświetli aktualną datę w formacie M j, Y g:i:s A ?>
Automatyzacja zadań
Dalej nie pozostaje już nic innego jak tylko rozpropagować informacje o używanej lokalizacji na inne komponenty. Dokumentacja ZF wskazuje Zend_Registry jako najprostszy sposób by tego dokonać:
< ?php Zend_Registry::set('Zend_Locale',$locale); ?>
Jednak w ostatniej stabilnej wersji ZF (1.6.2) nie doszukałem się odwołania do Zend_Registry wewnątrz Zend_Locale czy Zend_Date, co powoduje, że i tak instancję Zend_Locale należy przesyłać jawnie. Mam nadzieję, że nadchodzące wydanie (1.7) zmieni coś w tej kwestii. Osoby zainteresowane tematem odsyłam do dokumentacji ZF po więcej szczegółów.
A jak sprawic, zeby Zend nie wyswietlil nazwy miesiaca w postaci:
stycznia
tylko:
styczeń
?? Probuje, probuje i jakos nie bardzo wiem jak.