Итак, в прошлый раз разговор был о Symfony. Сегодня речь пойдет о Akelos. Кто не в курсе Akelos, скажу лишь то, что этот фреймворк является полным клоном RoR с единственным отличием – написан он на PHP. Правда ли это для вопросов интернационализации я не знаю. Но как бы то ни было все равно посмотрим, что Akelos нам приготовил.
Пару слов о документации
Как таковой для Akelos ее нет. Есть пару отписок, небольшой Readme, плюс сгенерированная с помощью phpxref дока и демонстрационный скринкаст. Все. Может быть в этом плане разработчик понадеялся на прошлый опыт с Ruby On Rails. Не знаю, но факт, как говорится, на лицо и с этим следует смириться. В оправдание могу сказать, что фреймворк достаточно само документированный и разобраться как и что происходит не составляет особого труда. Исходники благо открыты для любого применения.
Интернационализация интерфейса, сообщений и тд
Здесь Akelos ничем примечательным от Symfony не отличается. Если помните в Symfony для проблемы поддержки нескольких языков и стран использовался параметр Culture ( язык_СТРАНА в двухбуквенных кодах). Akelos используют более простую модель. В файле config задаются разрешенные локали, которые можно увидеть в банальном HTTP-заголовке «Accept-Language» (например, «ru, en_us»). После того как настроены необходимые языки Akelos будет самостоятельно создавать и следить за словарями для этих языков с помощью специального метода t() или специальных тегов _{} в виде.
Каждый раз когда вызываются эти методы, фреймворк, во-первых, обновит словарь, если переданного слова или фразы не будет в словаре, и, во-вторых, при выводе возьмет перевод слова или фразы из словаре, соответствующему выбранной локали.
Для того, чтобы сменить локаль достаточно в URL добавить код языка. Например, вот так будет выглядить классическая строка с доступными языками:
<div align="right">
<?php echo $url_helper->link_to($controller->t('en'), array('lang' => 'en')) ?> |
<?php echo $url_helper->link_to($controller->t('de'), array('lang' => 'de')) ?> |
<?php echo $url_helper->link_to($controller->t('ru'), array('lang' => 'ru')) ?> |
</div>
Это все. Akelos по щелчку на ссылку прибавит к URL выбранный язык. И даже более того, во-всех ссылках, созданных с помощью link_to(), отобразится изменения, связанные с выбором языка. Ни о чем разработчику беспокоится не приходится.
Что касается словарей, то никого XML подобия вы не встретите. Обыкновенные ассоциативные массивы:
$dictionary = array();
$dictionary['Pages'] = 'Страницы';
$dictionary['OK'] = 'OK';
$dictionary['Cancel'] = 'Отмена';
Локализация содержимого
Если с интернационализацией интерфейса все очень просто и понятно, то почему же должно быть по-другом с содержимым подумали разработчики и упростили работу нам до безобразия.
Для начала следует обьявить что твоя любимая модель имеет многоязыковую структуру и что даже несколько столбцов в соответствующей ей таблицы из базы данных имеет перевод на другие языки мира. Как это делается? А вот так:
function up_1()
{
$this->createTable('pages', "
id,
en_title,
de_title,
ru_title,
en_body text,
de_body text,
ru_body text
");
}
Все это естественно должно находится в инсталлере приложения. Как видите, в одной таблице мы имеет сразу же и английский, и немецкий, и русский вариант заголовка и текста страницы. Ну что же, разработчики доупрощались настолько, что нарушили святые нормальные формы старика Кодда, так ревностно оберегаемые математиками и профессорам ВУЗов. Мне если честно, такой поворот событий тоже не очень нравится. Не правильно это по единственной простой причине – если не все страницы могут быть переведены на все три языка, то на что будет похожа наша таблица? Пустое пространство – это не есть хорошо и все-таки следует беречь ресурсы данные нам Богом.
Ну оставим и пойдем дальше. Дальше никаких сюрпризов не ожидается. Все те же get- и set-методы автоматом подхватываются фрейморков. И мы просто лениво наслаждаться тем, что мир прекрасен и чуден, и все так хорошо и просто. На всякий случай приведу пример как же это делается:
Контроллер:
$this->Page->setAttribute('title', $this->params['title']);
$this->Page->setAttribute('body', $this->params['body']);
$this->Page->save();
Вид:
<h1>En</h1>
<p>
<label for=“page_title”>_{Title}</label><br />
<?php echo $form_helper->text_field(‘title’, ‘en’)?>
</p>
<p>
<label for=“page_body”>_{Body}</label><br />
<?php echo $form_helper->text_area(‘body’, “en”) ?>
</p>
<h1>Ru</h1>
<p>
<label for=“page_title”>_{Title}</label><br />
<?php echo $form_helper->text_field(‘title’, ‘ru’)?>
</p>
<p>
<label for=“page_body”>_{Body}</label><br />
<?php echo $form_helper->text_area(‘body’, ‘ru’) ?>
</p>
Модель (инсталлер):
$this->createTable('pages', "
id,
en_title,
ru_title,
en_body text,
ru_body text
");
И все. Красота да и только.
Выводы
Akelos прост на уровня интуитивного понимания. Конечно хранение в одной таблицы сразу всех версий контента не очень красиво. Гораздо приятным в этом отношении выглядит Symfony, которые как заядлый отличник старается все время вытянуть на пятерку.
Но и у Symfony есть свои недостатки, которые, как мне кажется, все-таки сглаживаются на больших проектах. Взять хотя бы тот же XML для словарей. Его неудобно писать вручную. Но кто знает, возможно на большом сайте такой необходимости уже и не будет, так как можно будет использовать генерирующие XLIFF программы.
По большому счету, что Akelos, что Symfony — без разницы. Все они используют ту же модель – хеллпер, словарь, ORM, автоматом подхватывающие get- и set-методы.
Надеюсь, что это небольшая обзорная статья в чем-то поможет в реализации многоязычных приложения самостоятельно. Курс и направление движения есть. Существуют ли какие-либо другие варианты? Наверняка существуют. Если мне что-нибудь интересного в этом плане попадется, обязательно напишу.
В следующей статье я планирую немножко развить эту тему и немножко отойти к другой. Меня интересует ORM-фреймворк Doctrine. Что за вкусности там есть, опять же поддержка интернационализации, удобно ли пользоваться, насколько эффективен для применения «один разработчик – небольшой приложение». Словом, не буду загадывать – все равно сами все увидите.

