04. Мультиязычность с Zend_Translate и создание помощников действий.

    Теперь решил, что не плохо было бы рассмотреть поддержку мультиязычности с использованием Zend Framework, т.к. эта часть мануала не переведена на русский язык, покрайней мере пока (версия 1.7.4 - 2009-01-31). Если задача не имеет особых требований, то осмелюсь заявить, что нижеописанный способ поможет понять основные моменты работы с Zent_Translate.
    Сразу хочу сказать, что если не хватит сил на эту тему или мультиязычность не нужна, можно пропустить все, что тут написано, просто скачать исходник без поддержки модуля locale и перейти к следующей статье. Но все же про создание помощников действий почитать рекомендую, еще пригодится.

    Опять же придеться освещать сразу 2 темы в рамках одной статьи, но так вышло, что в нашем случае они связаны. Конечно же можно добиться того же результата и без использования некоторых компонентов - это же в конце концов фрэймворк, но здесь речь о ZF так что идем дальше.
    Локализация приложения это не только перевод текста на различные языки, но и конвертация единиц измерений, разные форматы дат, валюта. Сейчас займемся только переводом текста, но не будем забывать о масштабируемости и по-этому нужно создать нечто подобное отдельному модулю, который можно будет включить/отключить, без труда добавить функционал. Неплохим решением стало - создание помощника.

    Создание помощника действий (Action Helper).


    По пунктам:

    1. Создать класс-наследник от Zend_Controller_Action_Helper_Abstract;
    2. Так же, как мы поступали с помощниками видов, дать имя классу и сохранить файл, следуя соглашениям по именованию ZF.

    lib/Divo/Helper/Action/Locale.php

require_once 'Zend/Controller/Action/Helper/Abstract.php';
require_once('Zend/Translate.php');

class Divo_Helper_Action_Locale extends Zend_Controller_Action_Helper_Abstract
{
    public function __construct() 
    {    }

    public function direct()
    {
    
    }
}

    При вызове хелпера из контроллера, по умолчанию выполняется метод direct(). __construct выполняется только при первом вызове помощника.

    4. Указать приложению, где лежат помощники. На всякий случай сделаем это в загрузочном файле:

    www/index.php

Zend_Controller_Action_HelperBroker::addPath(LIBPATH.'/Divo/Helper/Action', 'Divo_Helper_Action');

    Первый параметр - путь, второй - префикс классов.

    Все теперь помощник доступен во всех контроллерах, обратиться можно следующим образом:

$this->_helper->locale(); // Выполняется метод Divo_Helper_Action_Locale::direct()

    Вернемся к Zend_Translate.


    Нам нужно что бы страницы на разных языках имели уникальный URI. Если страница сайта на русском и английском языках будет доступна по одному и тому же адресу, то поисковые системы смогут проиндексировать только одну версию. Выбираем реализацию поддоменами, по-этому нам понадобится поддомен с кодом языка (например en.zf-demo.2developers.net для английского), а русский будет по умолчанию на основном домене.
    Изменим файл конфигурации, добавив в него настройки модуля locale:

    app/config.ini

[locale]
; вкл/выкл
enabled = true
; по умолчанию тот который без поддомена
default = ru

[languages] ; поддерживаемые языки
ru = Русский
en = English

    Теперь изменим класс нашего помощника:

    lib/Divo/Helper/Action/Locale.php

require_once 'Zend/Controller/Action/Helper/Abstract.php';
require_once('Zend/Translate.php');

class Divo_Helper_Action_Locale extends Zend_Controller_Action_Helper_Abstract
{
    public $config;
    
    public function __construct() {
        $this->config = Divo_Controller::divoLoadConfig('config.ini', 'locale');
    }

    public function direct()
    {
        $path = APPPATH.'/includes/locale/';
        
        /* Если в URI есть поддомен из 2 букв 
           Внимание! регулярное выражение составлено с учетом того что приложение на домене, 3-го уровня
            если же основной домен, второго уровня например 2developers.net - 
                нужно использовать такое выражение "/([a-z]{2})\..*\..{2,5}/"   */
        if (preg_match("/([a-z]{2})\..*\..{2,5}/", HOST, $sub)) {
            $lang = $sub[1];
        } else {
            $lang = $this->config->default;
        }
        
        $obj = new Zend_Translate('gettext', $path.$lang.'.mo', $lang);            

        return $obj;
    }

}

    В конструкторе загружаются настройки из файла конфигурации, мы создавали метод Divo_Controller::divoLoadConfig() в прошлой статье.

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

    lib/Divo/Controller.php

добавить аттрибут класса для хранения объекта

/** @var object - Zend_Translate Модуль Locale */
protected $translate;

и изменить метод init(), что бы он выглядел следующим образом:

public function init()
{
    // первое, что сделаем - загрузим настройки
    $this->config = $this->divoLoadConfig();
    require_once 'Zend/Registry.php';
    Zend_Registry::set('Zend_Config', $this->config);
    
    // Если каталог www расположен не в корне сервера (см. 11 строка www/index.php)
    if (BASEURL !== "") {
        $this->getRequest()->setBaseUrl(BASEURL.'/');
    }
    
    /** Настройки вида */
    // Указываем где искать скрипты вида
    $this->view->setScriptPath(APPPATH.'/views/');
    // Путь к помощникам видов
    $this->view->setHelperPath(LIBPATH.'/Divo/Helper/View', 'Divo_Helper_View');
    // Берем из настроек разделитель для составных заголовков
    $this->view->headTitle()->setSeparator($this->config->view->title_separator);
    
    // Запустить layout
    $this->_divoStartLayout();
    
    // Включить модуль locale, если необходимо
    if ($this->config->locale->enabled == true) {
        /** Модуль Locale Execute time: 0.022301 sec. */
        $this->translate = $this->_helper->locale();
        Zend_Registry::set('Zend_Translate', $this->translate);
        //на заметку: время выполнения этого кода 0.012301 сек.
    }

    $this->divoInit();
}

    А сейчас самое интересное, не знаю с чего начать :)

    Gettext и файлы перевода


    Нужно утилитой gettext собрать все строковые выражения в файлах проекта т.к. это отдельная тема, я не буду описывать как это сделать, уже и так много написано об инструментах для перевода, но файл перевода в итоге должен получится примерно такой:

    app/includes/locale/all.po
# zf-demo.2Developers.net
# Copyright (C) 2009 2Developers.net
# This file is distributed under the same license as the zf-demo.2Developers.net package.
# Vladimir , 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-02-09 01:50+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: RU \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: /var/www/htdocs/~app/controllers/IndexController.php:12
msgid "Текст главной страницы"
msgstr "Текст главной страницы"

#: /var/www/htdocs/~app/views/layout.phtml:8
#: /var/www/htdocs/~app/views/layout.phtml:18
msgid "Демо-сайт"
msgstr ""

#: /var/www/htdocs/~app/views/layout.phtml:19
msgid "Только для примера"
msgstr ""

#: /var/www/htdocs/~app/views/layout.phtml:22
msgid "Главная"
msgstr ""

#: /var/www/htdocs/~app/views/layout.phtml:23
msgid "О сайте"
msgstr ""

#: /var/www/htdocs/~app/views/index/about.phtml:1
msgid "Страница с текстом о сайте и может быть контактной формой."
msgstr ""

#: /var/www/htdocs/~app/views/index/index.phtml:2
msgid "демо, тест, ZF, фрэймворк, PHP"
msgstr ""

#: /var/www/htdocs/~app/views/index/index.phtml:2
msgid "Демо-сайт. Разработано с использованием Zend Framework"
msgstr ""

#: /var/www/htdocs/~app/views/index/index.phtml:2
msgid "Главная страница"
msgstr ""

    Следующим шагом будет скомпилировать файл перевода. В линуксе это делается командой: msgfmt ПУТЬ/all.po -o ПУТЬ/ru.mo
    Если у вас нет возможности все это сделать, скачайте архив приложенный к этому посту, получите скомпилированные файлы, положите их в app/includes/locale/ и можно пропустить следующий пункт.

    Теперь добавим в файл all.po строки с переводом на английский (можно сделать это с помощью какой нибудь утилиты в KDE например KBabel):

# zf-demo.2Developers.net
# Copyright (C) 2009 2Developers.net
# This file is distributed under the same license as the zf-demo.2Developers.net package.
# Vladimir , 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-02-09 01:50+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: RU \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: /var/www/htdocs/~app/controllers/IndexController.php:12
msgid "Текст главной страницы"
msgstr "Content of the main page"

#: /var/www/htdocs/~app/views/layout.phtml:8
#: /var/www/htdocs/~app/views/layout.phtml:18
msgid "Демо-сайт"
msgstr "Demo-site"

#: /var/www/htdocs/~app/views/layout.phtml:19
msgid "Только для примера"
msgstr "Only for example"

#: /var/www/htdocs/~app/views/layout.phtml:22
msgid "Главная"
msgstr "Home"

#: /var/www/htdocs/~app/views/layout.phtml:23
msgid "О сайте"
msgstr "About"

#: /var/www/htdocs/~app/views/index/about.phtml:1
msgid "Страница с текстом о сайте и может быть контактной формой."
msgstr "The page with description of the site and maybe with contact form"

#: /var/www/htdocs/~app/views/index/index.phtml:2
msgid "демо, тест, ZF, фрэймворк, PHP"
msgstr "demo, test, ZF, Framework, PHP"

#: /var/www/htdocs/~app/views/index/index.phtml:2
msgid "Демо-сайт. Разработано с использованием Zend Framework"
msgstr "Demo-site. Powered by Zend Framework"

#: /var/www/htdocs/~app/views/index/index.phtml:2
msgid "Главная страница"
msgstr "Main page"

    И компилируем в app/includes/locale/en.mo

    С этого момента все строки в контроллерах, необходимо выводить через объект $this->translate. Например взять строку "Текст главной страницы" в app/controllers/IndexController.php:12


$this->view->assign("message", "Текст главной страницы");

    нужно заменить на:

$this->view->assign("message", $this->translate->_("Текст главной страницы"));

    Теперь вы можете увидеть эту строку на русском по адресу zf-demo.2developers.net и на английском по адресу en.zf-demo.2developers.net

    Но самое главное, что большинство строк приходится на скрипты видов, благо в ZF уже есть ViewHelper - translate, пользуемся следующим образом:
    например app/views/layout.phtml строка 8

$this->headTitle('Демо-сайт');

    изменяем на:

$this->headTitle($this->translate('Демо-сайт'));

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


Прикрепленные файлы:

Демо-сайт без поддержки мультиязычности (Загрузок: 65)
Демо-сайт с поддержкой мультиязычности (Загрузок: 117)
Файлы перевода (Загрузок: 66)

Добавлена: 08-02-2009 | Изменена: 20-02-2009 | Пользователем: djaarf | Просмотров: 3483

Комментарии

Alex 20-02-2009 23:56
Все время ошибку выдает /var/www/htdocs/zf-demo/lib/Divo/Helper/Action/Locale.php on line 18
djaarf 21-02-2009 01:50
Да поправил, спасибо! Нужно создавать объект класса Zend_Translate и первым аргументом передавать адаптер и он сам все сделает, а не так как я, сразу объект адаптера создал:


$obj = new Zend_Translate_Gettext($path.$lang.'.mo');


$obj = new Zend_Translate('gettext', $path.$lang.'.mo', $lang);

Alex 21-02-2009 07:27
Ага, по мануалу сделал уже тоже


Оставить комментарий



Капча *

Captcha

Комментарий будет опубликован после проверки модератором

Для подсветки синтаксиса исходный код следует обрамлять следующими тэгами
<pre><code class="синтаксис" >код</code></pre>
Подерживаются следующие: cpp php javascript sql html-xml css ini