Yii2 интернационализация PHP, db, gettext начальная настройка

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

Речь пойдет только об инициализации самого процесса. Сам же процесс отлично описан в официальном полном руководстве по Yii2. Прочитайте, пожалуйста, официальное руководство прежде чем продолжить.

Способы хранения словарей

Способов хранения словарей всего три:

  • PhpMessageSource — хранение словаря в виде PHP-массива;
  • GettextMessageSource — хранение словаря в виде gettext файлов .po и .mo;
  • DbMessageSource — хранение словаря в базе данных.

Каждый из способов имеет определенные преимущества. Я использую второй и третий в зависимости от ситуации.

Например, если все переводы фиксированы и/или приложение планируется распространять, то использую gettext, так как в данном случае очень удобно при помощи po-редактора отредактировать все переводы и скомпилировать mo-файлы. Эти файлы будут распространяться вместе с приложением, что очень удобно. Пользователю приложения нет надобности изменять эти переводы в будущем, так что такой способ мне подходит больше.

Если же разрабатываемое приложение, например, будет находиться в единственном экземпляре на сервере и будет доступно только определенной группе людей и эти люди должны регулярно вносить какие-либо изменения в переводы, например, при добавлении каких-то новых объектов в приложение через сам интерфейс приложения (добавление новых дополнительных полей для информации о товаре), то удобней использовать хранение словаря в базе данных и редактировать его используя ActiveRecord в любое время через интерфейс приложения.

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

Способ хранения указывается в конфигурационном файле в компонентах. Компонента, отвечающая за интернационализацию называется i18n. Следующий фрагмент показывает, как выглядит фрагмент конфигурационного файла:

'components' => [
    'i18n' => [
        'translations' => [
            'app*' => [
                'class' => 'yii\i18n\PhpMessageSource',
                // каталог, где будут располагаться словари
                'basePath' => '@app/messages',
                // исходный язык, на котором изначально
                // написаны фразы в приложении
                'sourceLanguage' => 'en-US',
            ],
        ],
    ],
],

Вместо класса PhpMessageSource можно указать GettextMessageSource или DbMessageSource.

Этот пример взят из официального руководства. Вся интересующая информация находится там в полном объеме. Дублировать здесь ее не буду.

Инициализация сборщика

Прежде чем начать собственно перевод, необходимо сформировать конфигурационный файл для сборщика словарей переводов. Предположим, что в Вашем приложении уже имеется несколько вызовов метода Yii::t(‘категория’, ‘текст на исходном языке’) и нам нужно собрать все эти вызовы и на их основе построить словарь для каждого нужного нам языка перевода. Сборщик просканирует все файлы, как это указано в его конфигурации, и сформирует необходимые словари. Так как категорий может быть несколько, то и словарей на каждый язык может быть несколько.

Теперь нам нужно сформировать конфигурационный файл для сборщика. Для этого находясь в каталоге приложения выполним:

./yii message/config @app/config/messages.php

Если Вам нужен расширенный файл с множеством поясняющих комментариев, то вместо вышеприведенной команды выполните следующую:

./yii message/config-template @app/config/messages.php

Результатом выполнения в обоих случаях будет созданный файл конфигурации сборщика по указанному пути.

Пример того, как выглядит такой файл для сборщика в файлы gettext .po:

<?php
return [
    'color' => null,
    'interactive' => true,
    'sourcePath' => '@app',
    // здесь нужно перечислить языки перевода
    'languages' => ['ru-RU', 'uk-UA'],
    'translator' => 'Yii::t',
    'sort' => false,
    'removeUnused' => false,
    'markUnused' => true,
    'except' => [
        '.svn',
        '.git',
        '.gitignore',
        '.gitkeep',
        '.hgignore',
        '.hgkeep',
        '/messages',
        '/BaseYii.php',
    ],
    'only' => [
        '*.php',
    ],
    'ignoreCategories' => [],
    // ----------------------------------------
    // Для хранения словаря в файлах gettext PO
    'format' => 'po',
    'messagePath' => '@app/messages',
    'catalog' => 'messages',
    'overwrite' => true,
];

В данном примере используется gettext и файлы .po и .mo. Название каталога переводов, полученное в итоге, будет messages.po

Все параметры кажутся очевидными. Если нужно вместо gettext использовать другие способы хранения, укажите вместо выделенной части массива следующее:

Для хранения в базе данных:

return [
    . . .
    // ----------------------------------------
    // Для хранения словаря в базе данных
    'format' => 'db',
    // ОПЦИОНАЛЬНО: компонент подключения к БД
    'db' => 'db',
    // ОПЦИОНАЛЬНО: название таблицы с исходными сообщениями
    'sourceMessageTable' => '{{%source_message}}',
    // ОПЦИОНАЛЬНО: название таблицы с переводами
    'messageTable' => '{{%message}}',
];

Для хранения в виде массива в файлах PHP:

return [
    . . .
    // -----------------------------------------
    // Для хранения словаря в виде массива php
    'format' => 'php',
    'messagePath' => '@app/messages',
    'overwrite' => true,
];

Отредактируйте конфигурационный файл сборщика необходимым Вам образом.

Экстракция сборщиком фраз в словарь переводов

Если словарь будет храниться в виде массива в файлах .php или в формате gettext в файлах .po, то при выполнении процедуры экстракции всех фраз в словарь все необходимые файлы будут созданы, однако с базой данных такого не произойдет — таблицы для хранения словарей необходимо предварительно создать при помощи следующей миграции:

./yii migrate --migrationPath='@yii/i18n/migrations'

Теперь все готово к экстракции всех фраз из метода Yii::t() по всех указанных файлах проекта в словарь. Для этого достаточно выполнить следующую команду с указанием файла конфигурации сборщика:

./yii message/extract @app/config/messages.php

Через некоторое время база данных или файлы .po или .php будут наполнены (или обновлены) всеми необходимыми фразами для перевода.

Осуществление переводов

Gettext .po .mo

Полученные файлы .po в нашем случае будут находиться в каталогах:

/
|
+--messages
   |
   +--ru-RU
   |  |
   |  +--messages.po
   |
   +--uk-UA
      |
      +--messages.po

Каталоги ru-RU и uk-UA, а также файлы messages.po внутри них, если не существуют, то будут созданы автоматически сборщиком при выполнении команды message/extract.

Для редактирования этих файлов можно использовать любой редактор кода, так как файлы .po имеют простую текстовую структуру, однако мне нравится специальная утилита Poedit, которую я и использую. При сохранении перевода (файла .po) эта утилита автоматически компилирует файл .mo, которые фактически и используется gettext.

Если Вы используете простой текстовый редактор, то после редактирования файла .po, Вам придется его скомпиллировать вручную в файл .mo. Для этого можно воспользоваться утилитой msgfmt из пакета gettext в Linux, FreeBSD и других UNIX-подобных системах.

Чтобы выполнить рекурсивно компилляцию всех файлов, расположенных в подкаталогах основного каталога переводов, находясь в каталоге messages выполните следующую команду:

find . -name \*.po -execdir msgfmt messages.po -o messages.mo \;

Массивы PHP

Структура каталогов и файлов php с переводами немного отличается от gettext. Для каждой категории перевода формируется свой файл .php. Если в Вашем приложении используются, например, категории app и user, то получим следующую структуру:

/
|
+--messages
   |
   +--ru-RU
   |  |
   |  +--app.php
   |  +--user.php
   |
   +--uk-UA
      |
      +--app.php
      +--user.php

Если эти каталоги и файлы не существуют на момент запуска сборщика, то они будут созданы автоматически.

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

Заключение

Тема интернационализации в Yii2 для меня новая. Я писал эту статью попутно разбираясь с интернационализацией, поэтому в статье могут быть некоторые неточности.

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

Удачной разработки!

Добавить комментарий