2 · курс
0%
Главная/🧩Специальные темы

43Интернационализация

language и sourceLanguage, Yii::t() с параметрами, множественным числом, select, number и date (ICU MessageFormat), источники переводов PhpMessageSource/DbMessageSource/GettextMessageSource, извлечение сообщений командой message, переводы представлений и модулей, локаль форматтера.

⏱ ~5 мин 📚 1 глава руководства

I18n в Yii — это три вещи: язык приложения (Yii::$app->language), перевод сообщений через Yii::t() с форматированием ICU и локализация вывода дат/чисел через formatter. Строки пишутся на исходном языке (обычно английском), переводы хранятся в файлах или БД по категориям.

Языки#

PHP
'sourceLanguage' => 'en-US',     // на каком языке написаны строки в коде (по умолчанию en-US)
'language' => 'ru-RU',           // язык вывода; можно менять во время выполнения
PHP
// например, по настройке пользователя или заголовку Accept-Language
Yii::$app->language = 'ru-RU';
Yii::$app->language = Yii::$app->request->getPreferredLanguage(['en-US', 'ru-RU', 'de']);

Код языка — IETF: en, en-US, ru-RU, zh-Hans-CN. Если для ru-RU перевода нет, будет искаться ru.

Yii::t()#

PHP
echo Yii::t('app', 'This is a string to translate!');
echo Yii::t('app', 'Hello, {username}!', ['username' => $username]);
echo Yii::t('app', 'Price: {0}', [$price]);                             // позиционные — {0}, {1}
echo Yii::t('app', 'Balance: {0, number, currency}', [$amount]);        // формат числа через ICU
echo Yii::t('app', 'Today is {0, date, short}', [time()]);
echo Yii::t('app', 'Hello', [], 'de');                                  // явный язык

Категория (app) — группа сообщений; yii зарезервирована для фреймворка, расширения используют свои (yii/bootstrap...). Если строка не переведена, вернётся исходная (и сработает событие missingTranslation).

Множественное число#

PHP
echo Yii::t('app', 'There {n, plural, =0{are no cats} =1{is one cat} other{are # cats}}!', ['n' => $n]);

Формы для русского перевода — one, few, many, other (правила CLDR):

PHP
'There {n, plural, =0{are no cats} =1{is one cat} other{are # cats}}!' =>
    'На диване {n, plural, =0{нет кошек} one{# кошка} few{# кошки} many{# кошек} other{# кошки}}!',

# — число, =0 — точное значение. Также {n, plural, offset:1 …} и {n, selectordinal, one{#st} two{#nd} few{#rd} other{#th}}.

Выбор по значению#

PHP
echo Yii::t('app', '{name} is {gender, select, female{she} male{he} other{it}} and loves Yii!', [
    'name' => 'Alexander',
    'gender' => 'male',
]);

Числа, даты, порядковые#

PHP
Yii::t('app', '{n, number}', ['n' => 1234.5]);                 // 1 234,5 (ru)
Yii::t('app', '{n, number, percent}', ['n' => 0.42]);
Yii::t('app', '{n, number, #,##0.00}', ['n' => 1234.5]);        // свой паттерн
Yii::t('app', '{d, date, long}', ['d' => time()]);              // short | medium | long | full | паттерн
Yii::t('app', '{t, time, short}', ['t' => time()]);
Yii::t('app', '{n, spellout}', ['n' => 42]);                    // forty-two
Yii::t('app', '{n, ordinal}', ['n' => 42]);                     // 42nd

Всё это MessageFormatter расширения intl; без intl доступны только простые подстановки, plural и select.

Источники переводов#

config/web.phpPHP
'components' => [
    'i18n' => [
        'translations' => [
            'app*' => [                                     // категории app, app/error, app/mail…
                'class' => 'yii\i18n\PhpMessageSource',
                'basePath' => '@app/messages',              // messages/ru-RU/app.php
                'sourceLanguage' => 'en-US',
                'fileMap' => [
                    'app' => 'app.php',
                    'app/error' => 'error.php',
                ],
                // 'forceTranslation' => true,   // переводить, даже если language == sourceLanguage
                // 'on missingTranslation' => [TranslationEventHandler::class, 'handleMissingTranslation'],
            ],
            '*' => ['class' => 'yii\i18n\PhpMessageSource'],   // остальное — по умолчанию @app/messages
        ],
    ],
],
messages/ru-RU/app.phpPHP
return [
    'This is a string to translate!' => 'Это строка для перевода!',
    'Hello, {username}!' => 'Привет, {username}!',
    'not translated yet' => '',        // пустая — вернётся исходная
];
PhpMessageSource
PHP-массивы basePath/<язык>/<категория>.php; самый быстрый и простой
DbMessageSource
таблицы source_message и message (миграция @yii/i18n/migrations); переводы редактируются в админке
GettextMessageSource
файлы .po/.mo, инструменты переводчиков

Ключ app* — маска по префиксу. Переводы фреймворка (yii) уже есть на десятках языков — категорию yii настраивать не нужно.

Извлечение сообщений#

Консоль
./yii message/config-template @app/messages/config.php    # шаблон конфигурации
./yii message/config --languages=ru-RU,de --messagePath=@app/messages @app/messages/config.php
./yii message @app/messages/config.php                    # просканировать код, обновить файлы переводов

Команда находит все вызовы Yii::t() (и \Yii::t, $this->t в шаблонах — настраивается translator), создаёт файлы для каждого языка, помечает удалённые строки @@…@@, сортирует. Для БД — 'format' => 'db', для gettext — 'po'.

Переводы в разных местах#

PHP
// модели: подписи и ошибки
public function attributeLabels() { return ['username' => Yii::t('app', 'Username')]; }
['username', 'required', 'message' => Yii::t('app', '{attribute} is required')],

// представления: целые файлы — views/site/ru-RU/about.php выберется автоматически для language = ru-RU
// (устарело с 2.0.x, лучше Yii::t внутри представлений)

// виджеты и модули — своя категория и регистрация переводов
class Module extends \yii\base\Module
{
    public function init()
    {
        parent::init();
        $this->registerTranslations();
    }

    public function registerTranslations()
    {
        Yii::$app->i18n->translations['modules/users/*'] = [
            'class' => 'yii\i18n\PhpMessageSource',
            'sourceLanguage' => 'en-US',
            'basePath' => '@app/modules/users/messages',
            'fileMap' => ['modules/users/validation' => 'validation.php', 'modules/users/form' => 'form.php'],
        ];
    }

    public static function t($category, $message, $params = [], $language = null)
    {
        return Yii::t('modules/users/' . $category, $message, $params, $language);
    }
}
// Module::t('form', 'Save')

Локаль форматтера и прочее#

  • Yii::$app->formatter->locale по умолчанию = language — даты и числа локализуются автоматически.
  • Yii::$app->language влияет на Html::tag('html', …, ['lang' => …]) — задавайте lang в layout из Yii::$app->language.
  • RTL-языки: Yii::$app->formatter не решает вёрстку — используйте класс dir="rtl" в layout по языку.
  • URL с языком (/ru/site/about) — свой UrlManager или правило с параметром <lang:(ru|en)> и установка языка в beforeAction/bootstrap; готовые расширения: codemix/yii2-localeurls.
Проверь себя5

Исходную строку Hello и вызовет событие missingTranslation у источника.

one, few, many (и other); =0/=1 — для точных значений.

@app/messages/ru-RU/app.php.

./yii message/config для конфигурации, затем ./yii message config.php.

Зарегистрировать источник в Yii::$app->i18n->translations под своей категорией (обычно в init() модуля) и использовать эту категорию в Yii::t().