Локализация и плюрализация в PHP

Категория: 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

категория: PHP