Виникла в мене потреба створити багатомовний сайт використовуючи Zend Framework. Створив :). Нижче розкажу як.
Значить маємо умовний сайт http://mysite.com, який перекладено трьома мовами українською (uk), російською (ru) і англійською (en). Приходить на наш сайт користувач. Що ми зазвичай робимо? Або показуємо йому сайт з мовою по замовчуванню (в нас буде українська), або спробуємо спочатку визначити яка ж мова буде для нього кращою. На другому варіанті зупинюся детальніше.
Сучасні браузери (не берусь говорити про старі) передають серверу параметр HTTP_ACCEPT_LANGUAGE. В мене там “uk,ru;q=0.8,en-us;q=0.5,en;q=0.3”. Це значить, що краще за все я сприймаю сайти на українській, або російській мові, а потім вже на англійській, при цьому надаю перевагу “американській версії” :).
В Zend Framework для того, щоб визначити яка ж мова буде найбільш вдалою можна використати 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(); |
А як зробити, щоб http://mysite.com/uk/user/auth відображався на українській, http://mysite.com/ru/user/auth – на російській, а http://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}' ) ) ); |
Але й це ще не все. Юзер може спробувати перейти за адресою http://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; } } |
Цей хелпер робить останню перевірку і підвантажує потрібний мовний файл. Наприклад, для url http://mysite.com/de/user/auth сайт буде відображатись на українській мові.
Для того, щоб хелпер запрацював, достатньо додати в наш bootstrap файл дві стрічки:
$languageHelper = new Site_Controller_Action_Helper_Language($locales, APPLICATION_PATH . '/languages'); Zend_Controller_Action_HelperBroker::addHelper($languageHelper); |
Ну ніби все :). Дякую за увагу.
Небольшое такое дополнение: если в Zend_Translate вы будете скармливать CSV файлы в UTF-8 – то для адекватного русского Вам понадобится выставить локаль ручками:
setlocale(LC_ALL, ‘ru_RU.UTF-8’);
Anton Shevchuk, а почему сразу в конфиге-то локаль не выставить? Это сразу избавит от всех возможных проблем.
Обычно так и делается.
Степан, добавил ваш блог в новоиспеченный каталог
http://zendframework.ru/links/russian
Дня доброго!
Возникла необходимость в реализации данной “идеи” и я нашел Вашу статью. Прочитал на рус. и на укр:).
Все ОК, но …
| Для того, щоб хелпер запрацював, достатньо додати в наш bootstrap файл дві стрічки: |
И вот тут я прописываю в bootstrap’е (в одно из _initFunction() )
$languageHelper = new Zend_Controller_Action_Helper_Language($locales, APPLICATION_PATH.’/languages’);
Zend_Controller_Action_HelperBroker::addHelper($languageHelper);
также явно указываю и путь где лежат эти ActionHelper’ы по типу:
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH.’/controllers/helpers’);
и в итоге получаю ошибочку, что:
Fatal error: Class ‘Zend_Controller_Action_Helper_Language’ not found in X:/…/htdocs\bvcom_ZF\application\Bootstrap.php on line 65
Не могли бы Вы мне подсказать, что я делаю не так ? Оно так уперлось, что даже разговаривать со мной не хочет, а обратиться за помощью толком не к кому.
P.S.: Пробовал и в ./library ложить сам helper, но тоже что-то не сильно соглашается.
Спасибо, Павел!
Видимо не настроен автолоадер для хелперов. Я уже не помню как это точно делается т.к. довольно давно использовал ZF. Попробуйте погуглить http://www.google.com.ua/search?gcx=w&sourceid=chrome&client=ubuntu&channel=cs&ie=UTF-8&q=zend+framework+helpers+loader