Статьи

Локализация дат, валюты и номеров с помощью Php-Intl

Первая часть этой серии была знакомством с расширением PHP Intl и с тем, как локализовать сообщения вашего приложения. В этой части мы узнаем о локализации чисел, дат, календарей и аналогичных сложных данных. Давайте начнем!

Иллюстрация глобус

Локализация Десятичных

Это может показаться странным, но одна из моих главных проблем, когда форматирование чисел работает с десятичными точками, так как они отличаются от места к месту. Проверьте Википедию для более подробной информации о различных вариациях десятичных знаков.

Стиль
1,234,567.89
1234567,89
1234567,89
1234567 · 89
1.234.567,89
1˙234˙567,89
12,34,567.89
1’234’567.89
1’234’567,89
1.234.567’89
123,4567.89

Расширение PHP Intl имеет NumberFormatter который занимается локализацией чисел:

 $numberFormatter = new NumberFormatter( 'de_DE', NumberFormatter::DECIMAL ); var_dump( $numberFormatter->format(123456789) ); $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DECIMAL ); var_dump( $numberFormatter->format(123456789) ); $numberFormatter = new NumberFormatter( 'ar', NumberFormatter::DECIMAL ); var_dump( $numberFormatter->format(123456789) ); $numberFormatter = new NumberFormatter( 'bn', NumberFormatter::DECIMAL ); var_dump( $numberFormatter->format(123456789) ); 
 string(11) "123.456.789" string(11) "123,456,789" string(22) "١٢٣٬٤٥٦٬٧٨٩" string(30) "১২,৩৪,৫৬,৭৮৯" 

Первый параметр — это код локали, а второй — стиль форматирования. В этом случае мы форматируем десятичные числа.

Стили форматирования

Стили форматирования описывают, как наши числа должны быть отформатированы: десятичное, валюта, длительность и т. Д. Проверьте список доступных стилей форматирования в документации. Давайте попробуем несколько примеров для разных стилей:

 $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DECIMAL ); $numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2); var_dump( $numberFormatter->format(1234.56789) ); $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DECIMAL ); $numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2); var_dump( $numberFormatter->format(1234) ); 
 string(8) "1,234.57" string(8) "1,234.00" 

При указании атрибута дробной части значение округляется в большую сторону в режиме вверх. Мы можем изменить это, указав стиль округления.

 $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DECIMAL ); $numberFormatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 2); $numberFormatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_CEILING); var_dump($numberFormatter->format(1234.5678) ); $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DECIMAL ); $numberFormatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 2); $numberFormatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_DOWN); var_dump($numberFormatter->format(1234.5678) ); 
 string(8) "1,234.57" string(8) "1,234.56" 

Параметры spellout и duration из первой части также можно использовать здесь со следующими параметрами:

 $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DURATION ); var_dump( $numberFormatter->format(123) ); $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::SPELLOUT ); var_dump( $numberFormatter->format(123) ); 
 string(4) "2:03" string(24) "one hundred twenty-three" 

Мы также можем анализировать строки, чтобы получить от них отформатированное значение:

 $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::DURATION ); var_dump( $numberFormatter->parse("4:03") ); $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::SPELLOUT ); var_dump( $numberFormatter->parse("one hundred") ); 
 float(243) float(100) 

Несмотря на то, что мы можем полностью сделать наше приложение независимым от языка, мы должны переключаться между языками, чтобы проверить различные изменения.

Локализация валют

Форматирование чисел как валют не сильно отличается, мы только меняем тип форматирования и добавляем код валюты.

 $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::CURRENCY ); var_dump( $numberFormatter->formatCurrency(1234.56789, "USD" ) ); 
 string(9) "$1,234.57" 

Мы можем избежать ввода кода валюты для каждой локали, вызвав метод NumberFormatter экземпляре NumberFormatter .

 $numberFormatter = new NumberFormatter( 'en_US', NumberFormatter::CURRENCY ); var_dump( $numberFormatter->formatCurrency(1234.56789, $numberFormatter->getSymbol(NumberFormatter::INTL_CURRENCY_SYMBOL)) ); $numberFormatter = new NumberFormatter( 'fr_FR', NumberFormatter::CURRENCY ); var_dump( $numberFormatter->formatCurrency(1234.56789, $numberFormatter->getSymbol(NumberFormatter::INTL_CURRENCY_SYMBOL)) ); 
 string(9) "$1,234.57" string(14) "1 234,57 €" 

Мы можем использовать атрибуты, которые мы упоминали ранее ( $numberFormatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 2); ), также с валютами.

Часовые пояса

Перед использованием календарей PHP Intl нам нужно освежить время в часовых поясах и попробовать быстрый пример:

Часовой пояс — это регион, в котором соблюдается единое стандартное время для юридических, коммерческих и социальных целей. Часовые пояса, как правило, следуют границам стран и их подразделений, потому что для районов, находящихся в тесной коммерческой или иной связи, удобно сохранять одно и то же время.

— Википедия

Класс IntlTimeZone отвечает за создание и управление часовыми поясами . Это ничем не отличается от часовых поясов в классе DateTimeZone :

 $timezone = IntlTimeZone::createDefault(); var_dump($timezone, $timezone->getDisplayName()); $timezone = IntlTimeZone::countEquivalentIDs("GMT"); var_dump($timezone); $timezone = IntlTimeZone::createTimeZone("GMT"); var_dump($timezone); 
 object(IntlTimeZone)#1 (4) { ["valid"]=> bool(true) ["id"]=> string(3) "UTC" ["rawOffset"]=> int(0) ["currentOffset"]=> int(0) } string(3) "GMT" int(10) object(IntlTimeZone)#1 (4) { ["valid"]=> bool(true) ["id"]=> string(3) "GMT" ["rawOffset"]=> int(0) ["currentOffset"]=> int(0) } 

Календари

Расширение PHP Intl имеет приятный, выразительный API для выполнения операций календаря :

 $calendar = IntlCalendar::createInstance(); var_dump($calendar->getTimeZone()->getId()); 
 string(3) "UTC" 

Метод createInstance принимает часовой пояс (из предыдущего раздела) и код локали. Мы также можем создать экземпляр календаря из экземпляра DateTime .

 $calendar = IntlCalendar::fromDateTime( (new DateTime) ); 

Мы можем сделать все виды сравнений между календарными датами.

 $calendar1 = IntlCalendar::fromDateTime( DateTime::createFromFormat('jM-Y', '11-Apr-2016') ); $calendar2 = IntlCalendar::createInstance(); $durationFormatter = new NumberFormatter( 'en_US', NumberFormatter::DURATION ); $diff = $calendar1->fieldDifference($calendar2->getTime(), IntlCalendar::FIELD_MILLISECOND); var_dump( $calendar1->equals($calendar2), $diff, $durationFormatter->format( $diff ) ); 
 bool(true) int(595) string(4) "9:55" 

Важное примечание : наша переменная calendar1 fieldDifference к значению diff , поэтому после fieldDifference метода fieldDifference календари fieldDifference . Помните об этой изменчивости при использовании этих классов!

Константа IntlCalendar::FIELD_MILLISECOND определяет тип сравнения, год, месяц, неделю и т. Д. Проверьте полный список в документации .

Если вы уже использовали пакет briannesbitt/carbon , возможно, вам понравился выразительный синтаксис для навигации по датам. Мы можем сделать то же самое, используя класс IntlCalendar .

 $calendar1 = IntlCalendar::createInstance(); var_dump(IntlDateFormatter::formatObject($calendar1)); $calendar1->add(IntlCalendar::FIELD_MONTH, 1); var_dump(IntlDateFormatter::formatObject($calendar1)); $calendar1->add(IntlCalendar::FIELD_DAY_OF_WEEK, 1); var_dump(IntlDateFormatter::formatObject($calendar1)); $calendar1->add(IntlCalendar::FIELD_WEEK_OF_YEAR, 1); var_dump(IntlDateFormatter::formatObject($calendar1)); 
 string(25) "Apr 12, 2016, 12:06:22 AM" string(25) "May 12, 2016, 12:06:22 AM" string(25) "May 15, 2016, 12:06:22 AM" string(25) "May 22, 2016, 12:06:22 AM" 

Проверьте документацию для более подробной информации и примеров.

Вывод

В этой серии из двух частей мы обнаружили расширение PHP Intl и библиотеку ICU. Расширение все еще содержит некоторые другие части, такие как Collators , Spoofchecker , UConverter и т. Д. Мы сосредоточимся на них в последующих публикациях, но пока, если у вас есть какие-либо вопросы или комментарии, оставьте их ниже!