ZF: Zend_Date a polskie nazwy

Zadanie z użyciem Zend_Date: mając datę przykładowo 2011-01-24 wyświetlić ją jako 24 styczeń 2011 (co jest niepoprawne, ale w tym przypadku zleceniodawca tak sobie zażyczył).

Na początek tworzymy obiekt, który będzie zawierał naszą datę. Żeby wyświetlać polskie nazwy zainicjujemy locale = ‚pl_PL’

$data = new Zend_Date('2011-01-24', 'YMd', 'pl_PL');

Zakładając, że nie wymuszaliśmy formatowania daty jako ‚php’ i wykorzystujemy format ‚iso’ wyświetlamy w wymaganym formacie:

echo $data->get(Zend_Date::DAY) . ' '
     . $data->get(Zend_Date::MONTH_NAME) . ' '
     . $data->get(Zend_Date::YEAR);

Otrzymujemy: 24 stycznia 2011

Czyli niezupełnie to, o co chodziło. Dlaczego tak jest?

Odpowiedzi należy szukać w dokumentacji Zend_Locale i kodzie klasy Zend_Date. Zacznijmy od tej pierwszej: http://framework.zend.com/manual/en/zend.locale.functions.html (bazuję na wersji ZF 1.11.2)
W części dotyczącej szczegółów metody getTranslation() przy opisie typu ‚month’ można przeczytać:

Returns a translation for a month. You have to give the number of the month as integer value. It has to be between 1 and 12. If you want to receive data for other calendars, contexts or formats, then you must give an array instead of an integer with the expected values. The array has to look like this: array( ‚calendar’, ‚context’, ‚format’, ‚month number’). If you give only an integer then the default values are the ‚gregorian’ calendar, the context ‚format’ and the format ‚wide’. Use Zend_Date for simplicity

Czyli tłumaczenie domyślne używa ustawień, które są powyżej pogrubione.

Tylko co to znaczy? Zajrzyjmy do pliku pl.xml w katalogu Zend\Locale\Data i przejdźmy do węzła <calendar type=”gregorian”>

<calendar type="gregorian">
    <months>
        <monthContext type="format">
            <monthWidth type="abbreviated">
                <month type="1">sty</month>
                <month type="2">lut</month>
                ...
            </monthWidth>
            <monthWidth type="wide">
                <month type="1">stycznia</month>
                <month type="2">lutego</month>
                ...
            </monthWidth>
        </monthContext>
        <monthContext type="stand-alone">
            <monthWidth type="narrow">
                <month type="1">s</month>
                <month type="2">l</month>
                ...
            </monthWidth>
            <monthWidth type="wide">
                <month type="1">styczeń</month>
                <month type="2">luty</month>
                ...
            </monthWidth>
        </monthContext>
    </months>

Widać, że istnieją dwa węzły <monthContext> – „format” i „stand-alone”. Oba zawierają węzły <monthWidth="wide">, przy czym to w domyślnie używanej gałęzi calendar[@gregorian]/months/monthContext[@format]/monthWidth[@wide] widać wartość ‚stycznia’, a w gałęzi calendar[@gregorian]/months/monthContext[@stand-alone]/monthWidth[@wide] jest ‚styczeń’. Czyli interesuje nas ta druga, niestandardowa gałąź.

Jak to działa w Zend_Date. Odwołując się w Zend_Date do części daty przez get() wywoływana jest wewnętrzna metoda _toToken(), która z kolei wywołuje metodę _parseIsoToDate(). W tej metodzie widać, że wszystkie odwołania to tłumaczonych wartości odwołują się do wartości domyślnych: gregorian, format. Na przykładzie Zend_Date::MONTH_NAME:

return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month)));

Jak to się ma do opisanej wcześniej metody getTranslation() klasy Zend_Locale? Ona po prostu wywołuje Zend_Locale_Data::getContent().

Co zatem trzeba zrobić, żeby zamiast „stycznia” uzyskać „styczeń”? Niestety, nie da się wykorzystując samo Zend_Date(). Trzeba skorzystać z Zend_Locale::getTranslation() lub bezpośrednio Zend_Locale_Data::getContent():

$aFormat = array('gregorian', 'stand-alone', 'wide', $data->get(Zend_Date::MONTH_SHORT));
echo $data->get(Zend_Date::DAY) . ' '
     . Zend_Locale::getTranslation($aFormat, 'month', 'pl') . ' '
     . $data->get(Zend_Date::YEAR);

Dlaczego miesiąc określamy przez Zend_Date::MONTH_SHORT? Bo zwraca miesiąc bez wiodącego zera przy miesiącach jednocyfrowych – a takie są wartości atrybutów „type” elementów „month” w pliku pl.xml.

Na początku założyłem, że nie zmieniamy nic w formatowaniu dat w Zend_Date i wykorzystujemy domyślny format ‚iso’. Co jeśli wcześniej ustawiliśmy format ‚php’, np. poleceniem:

Zend_Date::setOptions(array(
    'format_type'   => 'php'
));

Wówczas nie będziemy mogli odwoływać się do części składowych daty wykorzystując stałe, np. Zend_Date::MONTH. Należy wtedy zastosować formatowanie znane z funkcji date():

$aFormat = array('gregorian', 'stand-alone', 'wide', $data->get('n'));
echo $data->get('d') . ' '
     . Zend_Locale::getTranslation($aFormat, 'month', 'pl') . ' '
     . $data->get('Y');

W określaniu formatu dajemy ‚n’, żeby uzyskać jednocyfrowy miesiąc bez wiodącego zera. Pozostałe składowe to ‚d’ – dzień z wiodącym zerem i ‚Y’ – czterocyfrowy rok.

Reklamy

3 uwagi do wpisu “ZF: Zend_Date a polskie nazwy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s