Zend Framework
October 2008 15

Zend Framework и многоязычность

Возникла у меня надобность создать многоязычный сайт используя ZF. Создал. Под катом расскажу как.

Значит, есть у нас условный сайт mysite.com, который переведен тремя зыками: украинским (uk), русским (ru) и английским (en). И тут приходит на сайт пользователь. Что мы обычно делаем? Или сразу показываем ему сайт на дефолтном языке, или сначала пытаемся определить, какой язык для него будет лучшим. Вот о втором варианте я хотел бы рассказать более подробно.

Современные браузеры (не берусь говорить о старых) передают серверу параметр HTTP_ACCEPT_LANGUAGE. У меня он равен “uk,ru;q=0.8,en-us;q=0.5,en;q=0.3″. Т.е. лучше всего я воспринимаю сайты на украинском или русском языке, а потом уже на английском, при этом отдаю предпочтение «американскому».

В ZF для того, чтобы определить какой же язык будет наиболее уместен можно использовать Zend_Locale. Например:

$locale = new Zend_Locale('auto');
$lang = $locale->getLanguage();


Но что если наш сайт не поддерживает этот язык? Нужно сделать проверку. Для этого в конфигурационном файле (я использую Zend_Config_Ini) сохраним набор локалей которые поддерживаются сайтом (с них потом можно будет вытянуть язык).

; allowed locales (first locale - default)
locales.uk = uk_UA
locales.ru = ru_RU
locales.en = en_GB


И пишем проверку (в bootstrap файле).

$locales = $config->locales->toArray();
$locale = new Zend_Locale('auto');

$lang = array_key_exists($locale->getLanguage(), $locales)
? $locale->getLanguage() : $config->locales->key();


Ок. Это работает. А как теперь сделать, чтобы mysite.com/uk/user/auth отображался на украинском, mysite.com/ru/user/auth — на русском, а mysite.com/user/auth — на том языке, который более всего подходит пользователю (или на дефолтном)? Для этого нужно переопределить основной роутер (для того чтобы он передавал параметр lang) и создать ещё один, который будет вытягивать язык из url (если он там есть):

// change default router
$frontController->getRouter()->addRoute('default',
new Zend_Controller_Router_Route(
':module/:controller/:action/*',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index',
'lang' => $lang
)
)
);

// add multilingual route
$frontController->getRouter()->addRoute('default_multilingual',
new Zend_Controller_Router_Route(
':lang/:module/:controller/:action/*',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index',
'lang' => $lang
),
array(
'lang' => '\w{2}'
)
)
);


Но и это ещё не все. Пользователь может попытаться открыть страницу mysite.com/de/user/auth, а наш сайт нихт шпрехен зе дойч… Вот засада. Что же делать? В общем для того, чтобы уже окончательно определиться на каком языке показывать сайт, создаём специальный helper (подсмотрено в книге «Zend Framework in Action»).

<?php

class Site_Controller_Action_Helper_Language extends Zend_Controller_Action_Helper_Abstract {

protected $_sDefaultLanguage;
protected $_aLocales;
protected $_sLanguagesDirectoryPath;

/**
* @param array $aLocales - Available locales
* @param string $sLanguagesDirectoryPath
*/
public function __construct(array $aLocales, $sLanguagesDirectoryPath) {
$this->_sLanguagesDirectoryPath = $sLanguagesDirectoryPath;
$this->_aLocales = $aLocales;
$this->_sDefaultLanguage = key($aLocales); // get first language
}

public function init() {
// try get current language from url
$sLang = $this->getRequest()->getParam('lang');

if(! array_key_exists($sLang, $this->_aLocales)) {
$sLang = $this->_sDefaultLanguage;
}

// generate path to the gettext language file
$sLanguageFilePath = $this->_sLanguagesDirectoryPath . '/'. $sLang . '/LC_MESSAGES/' . $sLang . '.mo';
if(! file_exists($sLanguageFilePath)) {
$sLanguageFilePath = $this->_sLanguagesDirectoryPath . '/' . $this->_sDefaultLanguage . '/LC_MESSAGES/' . $this->_sDefaultLanguage . '.mo';
$sLang = $this->_sDefaultLanguage;
}

// get current locale by current language
$sLocale = $this->_aLocales[$sLang];

// setup translate object
$oTranslate = new Zend_Translate('gettext', $sLanguageFilePath, $sLang);
Zend_Form::setDefaultTranslator($oTranslate); // translated Zend_Form

$this->_actionController->_locale = $sLocale;
$this->_actionController->_lang = $sLang;
$this->_actionController->_translate = $oTranslate;

$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->view->locale = $sLocale;
$viewRenderer->view->lang = $sLang;
$viewRenderer->view->translate = $oTranslate;
}
}


Этот helper делает последнюю проверку и пытается подгрузить нужный языковый файл. По адресу mysite.com/de/user/auth будет показываться украинская версия сайта. Ну и для того чтобы этот helper заработал, достаточно добавить две строки в наш bootstrap файл.

$languageHelper = new Site_Controller_Action_Helper_Language($locales, APPLICATION_PATH . '/languages');
Zend_Controller_Action_HelperBroker::addHelper($languageHelper);


В принципе все. Благодарю за внимание. Следующий топик будет посвящен Zend_Translate.
+8
5.2k 37
Comments 14