Подводные камни интернационализации в CakePHP
Подводные камни интернационализации в CakePHP
Появилась у меня не так давно необходимость сделать интернационализации одного моего проекта, а именно реализацию механизма переключения языков (в моем случае – русский и английский языки). В итоге, попались мне несколько подводных камней, информацией о которых я и хотел бы поделиться. Дело в том, что на решение этих «камешков» у меня ушло некоторое количество времени: поиск на stackoverflow, мануалы teknoid'а, компиляция с иными источниками.
Итак, на book.cakephp.org, вроде бы, все прекрасно объясняется, все просто, как дважды два, но вот некоторых деталей там нет.
Весь перевод осуществляется с помощью вызова функции
__()
. Не буду объяснять, как она работает, это можно найти в вышеупомянутом book.cakephp.org, но первые грабли, на которую я наступил — это то, что при вызове этой функции, происходил сразу же вывод строки, переданной ей. Чтобы избежать моментального echo
в этой функции, надо передавать параметр 'true'
сразу после определения строки: __('string', true)
. Это приведет к тому, что переведенная строка будет возвращена return
'ом, а не echo
.Вторые грабли — невозможность использования функции
__()
в моделях (валидация как пример), при попытке использовать оную, выдается непонятная сразу ошибка (весьма пространная). Точнее, использовать можно, но для этого надо переопределить метод invalidate()
. Кстати говоря, это описано в cook book, но, судя по выдаче гугла, вопрос возникает крайне часто. Лично я не стал переопределять метод и попросту в представлении добавил параметр 'error'
, в котором можно интернационализировать строки без костылей:$form->input('login', array(
'size' => '66',
'maxlength' => '32',
'label' => false,
'error' => array(
'notempty' => __('Поле логина не заполнено', true),
'between' => __('Логин должен состоять минимум из 3 символов и не превышать 64 символа', true),
'alphaNumeric' => __('Поле логина должно состоять из латинских/кириллических букв и/или чисел', true),
),
)),
),
Третья очень часто встречаемая проблема — невозможность интернационализации строк, больших, чем 1014 символов, и, поэтому, придется попросту подключать свой отдельный переведенный шаблон для каждого используемого на сайте языка. В нашем случае, это представления в layout'ах.
Четвертая проблема возникла при использовании PoEdit. PoEdit — это необходимый редактор для перевода сгенерированного с помощью консольного приложения
'cake i18n extract'
.pot файла (в котором как раз и содержится перевод строк). Дело в том, что не удавалось сохранить переведенный файл, PoEdit ругался на неизвестные мне две ошибки. В итоге оказалось, что нужно заменить по этой таблице для каждого языка, перейдя по «Каталог — Настройки — Формы множественного числа», две переменные.Пятая проблема также касается PoEdit. Дело в том, что он создает .mo файл, помимо .po (да — да, сгенерированный кейком .pot надо переименовать в .po, читаем поваренную книгу), который имеет больший приоритет, но он пуст, и, при чтении языковой папки, кейк будет читать пустой файл, что неблагополучно скажется на переводе, а, точнее, на его отсутствие. Для фикса, просто удалите .mo файл, он никому не нужен.
Ну, и, наконец, шестая проблема. Для тестирования перевода, я пытался использовать следующий код, засунутый в core.php (вроде как должно было бы работать):
Configure::write('Config.language', 'eng');
На самом деле, такой код в core.php работать не будет, его надо кидать в bootstrap.php, тогда все будет хорошо.
Постепенно, обнаружил еще одну маленькую ошибочку, которую могут допустить те, кто использует мануал teknoid'а (http://nuts-and-bolts-of-cakephp.com/2008/11/28/cakephp-url-based-language-switching-for-i18n-and-l10n-internationalization-and-localization/).
Дело в том, что при создании коллбэка в AppController (от него в приложении наследуют все контроллеры, а тот, в свою очередь, наследует от Controller, поэтому его используют для выполнения неких глобальных для всех контроллеров системы действий), который содержит в себе вызов функции смены языка, будут баги, в случае если пользователь не перейдет по маске роута с указанием языка, а попробует перейти напрямую на
“:controller/:action”
, то переменная конфигурации языка по умолчанию не будет храниться в сессии и куках, а это значит, что обозначенная выше работа с текстами, в которых более 1000 символов, через языковые шаблоны, попросту будет выдавать кучу ошибок. Поэтому необходимо вставить считывание текущего языка по умолчанию и записывать его при определенных условиях в сессию/куки:else if(!$this->Session->check('Config.language') and !$this->Cookie->read('lang'))
{
$this->Session->write('Config.language', Configure::read('Config.language'));
$this->Cookie->write('lang', Configure::read('Config.language'), null, '20 days');
}
В принципе, это наиболее часто встречаемые ошибки и проблемы, которые можно встретить при интернационализации в CakePHP, хотя некоторые из них упомянуты в cake book, но на практике это совсем другое, ибо эти самые упоминания весьма смутны.
К сожалению, информации в гугле крайне мало по ошибкам, и два потраченных вечера, я думаю, стоят того, чтобы поделиться накопленной информацией со всеми, кто читает сей текст.
Так что, спасибо за внимание! Очень надеюсь, что такая «скомпилированная» версия дополнений к интернационализации в CakePHP кому то еще поможет.
1 комментарий