Большинство приложений выполняют операции с учетом локали, такие как работа с текстами, датами, часовыми поясами и т. Д. Расширение PHP Intl предоставляет хороший API для доступа к широко известным функциям библиотеки ICU .
Установка
Расширение установлено по умолчанию на PHP 5.3 и выше. Вы можете найти его, выполнив следующую команду:
php -m | grep 'intl'
Если расширение отсутствует, вы можете установить его вручную, следуя руководству по установке . Если вы используете Ubuntu, вы можете напрямую запустить следующие команды.
sudo apt-get update
sudo apt-get install php5-intl
Если вы используете PHP7 на своем компьютере, вам нужно добавить PPA ( ppa:ondrej/php
# Add PPA
sudo add-apt-repository ppa:ondrej/php-7.0
# Update repository index
sudo apt-get update
# install extension
sudo apt-get install php7.0-intl
Форматирование сообщений
Большинство современных приложений создаются с учетом локализации. Иногда сообщение представляет собой простую строку с переменными заполнителями, в других случаях это сложная множественная строка.
Простые сообщения
Мы собираемся начать с простого сообщения, содержащего заполнитель. Заполнители — это шаблоны, заключенные в фигурные скобки. Вот пример:
var_dump(
MessageFormatter::formatMessage(
"en_US",
"I have {0, number, integer} apples.",
[ 3 ]
)
);
// output
string(16) "I have 3 apples."
Аргументы, передаваемые методу MessageFormatter::formatMessage
- Локаль сообщения.
- Строковое сообщение.
- Заполнители данных.
Заполнитель {0, number, integer}
number
integer
Мы также можем использовать именованные аргументы для заполнителей. Пример ниже выдаст тот же результат.
var_dump(
MessageFormatter::formatMessage(
"en_US",
"I have {number_apples, number, integer} apples.",
[ 'number_apples' => 3 ]
)
);
Разные языки имеют разные системы счисления, такие как арабский , индийский и т. Д.
Предыдущий пример ориентирован на локаль en_US
Давайте изменим его на ar
var_dump(
MessageFormatter::formatMessage(
"ar",
"I have {number_apples, number, integer} apples.",
[ 'number_apples' => 3 ]
)
);
string(17) "I have ٣ apples."
Мы также можем изменить его на бенгальский язык ( bn
var_dump(
MessageFormatter::formatMessage(
"bn",
"I have {number_apples, number, integer} apples.",
[ 'number_apples' => 3 ]
)
);
string(18) "I have ৩ apples."
Пока что мы работали только с числами. Давайте посмотрим на другие типы, которые мы можем использовать.
$time = time();
var_dump( MessageFormatter::formatMessage(
"en_US",
"Today is {0, date, full} - {0, time}",
array( $time )
) );
string(47) "Today is Wednesday, April 6, 2016 - 11:21:47 PM"
var_dump( MessageFormatter::formatMessage(
"en_US",
"duration: {0, duration}",
array( $time )
) );
string(23) "duration: 405,551:27:58"
Мы также можем прописать пропущенные числа.
var_dump( MessageFormatter::formatMessage(
"en_US",
"I have {0, spellout} apples",
array( 34 )
) );
string(25) "I have thirty-four apples"
Он также работает на разных языках. Вот пример использования арабского языка.
var_dump( MessageFormatter::formatMessage(
"ar",
"لدي {0, spellout} تفاحة",
array( 34 )
) );
string(44) "لدي أربعة و ثلاثون تفاحة"
тип аргумента | argStyle |
---|---|
число | целое число, валюта, проценты |
Дата | короткий, средний, длинный, полный |
время | короткий, средний, длинный, полный |
spellout | короткий, средний, длинный, полный |
порядковый | |
продолжительность |
плюрализация
Важной частью локализации нашего приложения является управление множественными сообщениями, чтобы сделать наш интерфейс как можно более интуитивным. Пример яблок выше сделает эту работу. Вот как должны выглядеть сообщения в этом случае.
- (
number_apples
- (
number_apples
- (
number_apples
var_dump( MessageFormatter::formatMessage(
"en_US",
'I have {number_apples, plural, =0{no apples} =1{one apple} other{# apples}}',
array('number_apples' => 10)
) );
// number_apples = 0
string(16) "I have no apples"
// number_apples = 1
string(16) "I have one apple"
// number_apples = 10
string(16) "I have 10 apples"
Синтаксис действительно прост, и большинство пакетов плюрализации используют этот синтаксис. Проверьте документацию для более подробной информации.
{data, plural, offsetValue =value{message}... other{message}}
-
data
-
plural
-
offsetValue
offset:value
Вычитает смещение из значения. -
=value{message}
Мы можем повторить эту часть несколько раз (=0{no apples} =1{one apple} =2{two apple}
-
other{message}
switch - case
Символ#
data
Выбор
В некоторых случаях нам нужно напечатать разные сообщения для каждого диапазона. Пример ниже делает это.
var_dump( MessageFormatter::formatMessage(
"en_US",
'The value of {0,number} is {0, choice,
0 # between 0 and 19 |
20 # between 20 and 39 |
40 # between 40 and 59 |
60 # between 60 and 79 |
80 # between 80 and 100 |
100 < more than 100 }',
array(60)
) );
string(38) "The value of 60 is between 60 and 79 "
В этом случае argType
choice
{value, choice, choiceStyle}
Официальное определение из документации ICU :
choiceStyle = number separator message ('|' number separator message)*
number = normal_number | ['-'] ∞ (U+221E, infinity)
normal_number = double value (unlocalized ASCII string)
separator = less_than | less_than_or_equal
less_than = '<'
less_than_or_equal = '#' | ≤ (U+2264)
Примечание . Разработчики ICU не рекомендуют использовать тип выбора.
Выбрать
Иногда нам нужно что-то вроде компонента выбора опции интерфейса. Страницы профиля используют это для обновления сообщений пользовательского интерфейса в соответствии с полом пользователя и т. Д. Вот пример:
var_dump( MessageFormatter::formatMessage(
"en_US",
"{gender, select, ".
"female {She has some apples} ".
"male {He has some apples.}".
"other {It has some apples.}".
"}",
array('gender' => 'female')
) );
string(19) "She has some apples"
Шаблон определяется следующим образом:
{value, select, selectStyle}
// selectStyle
selectValue {message} (selectValue {message})*
Аргумент message
Следующая часть объяснит сложный пример, где мы объединяем несколько шаблонов. Проверьте документацию ICU для более подробной информации.
Сложные случаи
До сих пор мы видели несколько простых примеров, таких как множественное число, выбор и т. Д. Некоторые случаи являются более сложными, чем другие. Документация ICU имеет очень хороший пример, иллюстрирующий это. Мы будем вставлять по частям, чтобы было проще понять.
var_dump( MessageFormatter::formatMessage(
"en_US",
"{gender_of_host, select, ".
"female {She has a party} ".
"male {He has some apples.}".
"other {He has some apples.}".
"}",
array('gender_of_host' => 'female', "num_guests" => 5, 'host' => "Hanae", 'guest' => 'Younes' )
) );
Это тот же пример, который мы использовали ранее, но вместо простого сообщения мы настраиваем его в зависимости от значения num_guests
var_dump( MessageFormatter::formatMessage(
"en_US",
"{gender_of_host, select, ".
"female {".
"{num_guests, plural, offset:1 ".
"=0 {{host} does not have a party.}".
"=1 {{host} invites {guest} to her party.}".
"=2 {{host} invites {guest} and one other person to her party.}".
"other {{host} invites {guest} and # other people to her party.}}}".
"male {He has some apples.}".
"other {He has some apples.}}",
array('gender_of_host' => 'female', "num_guests" => 5, 'host' => "Hanae", 'guest' => 'Younes' )
) );
Обратите внимание, что мы используем offset:1
num_guests
string(53) "Hanae invites Younes and 4 other people to her party."
Вот полный фрагмент этого примера.
var_dump( MessageFormatter::formatMessage(
"en_US",
"{gender_of_host, select, ".
"female {".
"{num_guests, plural, offset:1 ".
"=0 {{host} does not have a party.}".
"=1 {{host} invites {guest} to her party.}".
"=2 {{host} invites {guest} and one other person to her party.}".
"other {{host} invites {guest} and # other people to her party.}}}".
"male {".
"{num_guests, plural, offset:1 ".
"=0 {{host} does not have a party.}".
"=1 {{host} invites {guest} to his party.}".
"=2 {{host} invites {guest} and one other person to his party.}".
"other {{host} invites {guest} and # other people to his party.}}}".
"other {".
"{num_guests, plural, offset:1 ".
"=0 {{host} does not have a party.}".
"=1 {{host} invites {guest} to their party.}".
"=2 {{host} invites {guest} and one other person to their party.}".
"other {{host} invites {guest} and # other people to their party.}}}}",
array('gender_of_host' => 'female', "num_guests" => 5, 'host' => "Hanae", 'guest' => 'Younes' )
) );
Измените количество гостей, чтобы проверить все типы сообщений.
// num_guests = 2
string(55) "Hanae invites Younes and one other person to her party."
// num_guests = 1
string(34) "Hanae invites Younes to her party."
// num_guests = 0
string(28) "Hanae does not have a party."
Разбор сообщений
Там не так много, чтобы сказать о разборе сообщений; мы используем шаблон, который мы использовали для форматирования, чтобы извлечь данные из выходного сообщения.
$messageFormater = new MessageFormatter("en_US", 'I have {0, number}');
var_dump( $messageFormater->parse("I have 10 apples") );
array(1) {
[0]=>
int(10)
}
Проверьте документацию для более подробной информации о разборе сообщений.
Вывод
В этой вводной статье мы узнали о локализации наших сообщений с использованием расширения PHP Intl. Следующая часть будет посвящена форматированию чисел и дат, а также тому, как работать с календарями. Если у вас есть какие-либо вопросы о том, что мы уже рассмотрели, вы можете оставить их в комментариях ниже!