Локализация и плюрализация в PHP
Что такое локализация мы уже знаем. Что означает термин плюрализация?
Плюрализация
Плюрализация (pluralization) - придание чему-л. характера множественности, разнообразия на основе принципов плюрализма.
Singularize - образовывать форму единственного числа.
Так-то) Но, если просто, то этот термин подразумевает определение правильного окончания для слова в зависимости от численности, т.е. 1 депутат, 11 депутатов, 24 депутата..
Есть хороший ресурс, на котором собраны правила плюрализации для всех языков - Localization Guide (или тут). В таблице указаны:
- язык и его ISO обозначение;
nplurals
- это число форм, которые может принимать существительное;plural
- это правило-алгоритм, по которому можно выбрать нужную нам форму слова по указанному количеству;
Для Russian
(ru
) мы имеем 3 возможных формы (nplurals=3;
) и следующее правило:
plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
plural определяет нужную позицию в заранее подготовленном нами массиве слов и находится в . Например:
[депутат, депутата, депутатов][plural];
// Example:
n = 1 >> plural = 0 // депутат
n = 11 >> plural = 2 // депутатов
Внимание!
Исходя из этого важно понять, что ключи сообщений в файлах локализации могут содержать разное число pluralform
для разных языков. Для En
- 2 формы, а для Ru
- 3.
Symfony 2 и Laravel 4
В Symfony 2 для локализации и плюрализации используется компонент Translation
. Приведу пример описания plural
форм для слова яблоко
в словарях En
и Ru
:
// Resources/translations/messages.en.yml
apple: 'one apple | %count%apples'
// Resources/translations/messages.ru.yml
apple: '%count% яблоко | %count% яблока | %count% яблок'
Проверим?
// Внутри контроллера
$this->getRequest()->setLocale('ru_RU'); // en_US
$this->get('translator')->transChoice('apple', 11, ['%count%' => 11]); // 11 яблок
$this->get('translator')->transChoice('apple', 21, ['%count%' => 21]); // 21 яблоко
Внимание! Вы не сможете описать все plural
формы для русского языка через явные интервалы!
При описании plural
форм в словаре, по умолчанию используются стандартные правила определения формы. Но, если вы опишете свой диапазон интервалов - форма слова будет определяться только на основе ваших правил!
Синтаксис определения явных интервалов (Explicit Interval Pluralization) в компоненте Translation
не позволяет лаконично описать все формы склонения существительного для русского языка (и некоторых других). Так что используйте явные диапазоны только для En
. Хотя Вам это должно понадобиться крайне редко, как например:
1 год, 2-4 года, 5-20 лет..
Примечание для Laravel 4
Laravel 4 использует тот же компонент Translation
. Однако в Symfony 2 переменные для подстановки задаются в формате: %count% apple
, а в Laravel 4 через двоеточие :count apple
.
На написание статьи меня натолкнули костыль подсмотренный в одном проекте и этот комментарий.
К сожалению данный компонент не решает проблему склонения слова перед числительным:
остался 1 час
осталось 2 часа
Реализация на PHP
Пример реализации twig
-фильтра plural()
. Также можно использовать как нативную PHP ф-цию:
/**
* Detect & return the ending for the plural word
*
* @param integer $endings nouns or endings words for (1, 4, 5)
* @param array $number number rows to ending determine
*
* @return string
*
* @example:
* {{ ['Остался %d час', 'Осталось %d часа', 'Осталось %d часов']|plural(11) }}
* {{ count }} стат{{ ['ья','ьи','ей']|plural(count)
*/
function plural($endings, $number)
{
$cases = [2, 0, 1, 1, 1, 2];
$n = $number;
return sprintf($endings[ ($n%100>4 && $n%100<20) ? 2 : $cases[min($n%10, 5)] ], $n);
}
Другие библиотеки
Функция плюрализации: https://github.com/GrAndSE/phplural/blob/master/plural.php
Библиотека Inflector: https://github.com/ICanBoogie/Inflector (pluralize, singularize, camelize, underscore, humanize, titleize, ordinal, ordinalize)
#pluralization, #localization, #translate, #singularize