Zend_Translate чудова компонента Zend Framework для створення інтерфейсу перекладеного багатьма мовами. Я спробував підняти багатомовний інтерфейс використовуючи цей інструмент, але зіткнувся з певними архітектурними проблемами для вирішення яких мені випало поспілкуватися на Issue Tracker з Томасом Вейднером (Thomas Weidner) лідером команди інтернаціоналізації Zend Framework I18N. Але про все по порядку.
На етапі розробки/тестування багатомовного інтерфейсу хотілося вивести список фраз що не мають перекладу для поточної локалі (Locale).
Переглянувши вихідний код Zend_Translate_Adapter я зрозумів що Zend Framework не надає ніяких засобів для збору неперекладених фраз окрім скупого методу isTranslated().
Хотілося б щоб адаптер перекладів сам автоматично фіксував неперекладені фрази і давав можливість отримати їх перелік
Дивувало те що такої важливої функції ніхто ніде не обговорював/не розглядав і оскільки мої пошуки готового рішення не увінчалися успіхом – вирішив описати цю проблему детально в темі “Allow to build the list of untranslated message IDs” на Zend Framework Issue Tracker.
Я використовую Action Helper щоб додати необхідний функціонал до мого Front Page Controller-а.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * Initiate internationalization * * @return Trc_Initializer */ private function _initL10n() { $translate = new Zend_Translate('tmx', $this->_root . '/languages/general.tmx'); // get locale $locale = Zend_Registry::get('Zend_Locale'); $current_lang = $locale->getLanguage(); if (!$translate->isAvailable($current_lang)) { $locale->setLocale('en'); } $translate->setLocale($locale); // save locale state into user session $user = Wise_User_Session::getInstance(); $user->locale = $locale->getLanguage(); Zend_Registry::set('Zend_Translate', $translate); return $this; } |
Ініціалізований об’єкт Zend_Translate_Adapter_xxx зберігаю в реєстрі під зарезервованим за ним простором імен “Zend_Translate”.
Першим власним рішенням в мене було звертатися до Zend_Translate через написаний мною ViewHelper що має наступний вигляд:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /** * T (stands for Translation) Helper * * The main goal of this view helper is to collect the list * of untranslated Message Ids and provide them as an array */ class Zend_View_Helper_T { /** * The list of messageIds without translation for current locale * @var array */ static public $missedTranslations = null; /** * Zend_View * * @var Zend_View_Interface */ protected $_view = null; /** * Set the view object */ public function setView(Zend_View_Interface $view) { $this->_view = $view; } /** * Translates provided message Id * * You can give multiple params or an array of params. * If you want to output another locale just set it as last single parameter * Example 1: translate('%1\$s + %2\$s', $value1, $value2, $locale); * Example 2: translate('%1\$s + %2\$s', array($value1, $value2), $locale); * * @param string $messageid Id of the message to be translated * @return string Translated message */ public function T($messageid = null) { /** * Process the arguments */ $options = func_get_args(); array_shift($options); $count = count($options); $locale = null; if ($count > 0) { if (Zend_Locale::isLocale($options[($count - 1)], null, false) !== false) { $locale = array_pop($options); } } if ((count($options) === 1) and (is_array($options[0]) === true)) { $options = $options[0]; } /** * Get Zend_Translate_Adapter */ $translator = $this->_view->translate() // get Zend_View_Helper_Translate ->getTranslator(); // Get Zend_Translate_Adapter /** * Collect the list of untranslated Message Ids into array */ if (false === $translator->isTranslated($messageid)) { self::$missedTranslations[] = $messageid; } /** * Proxify the call to Zend_Translate_Adapter */ $message = $translator->translate($messageid, $locale); /** * If no any options provided then just return message */ if ($count === 0) { return $message; } /** * Apply options in case we have them */ return vsprintf($message, $options); } } |
Вище приведене рішення працює в мене і до тепер, однак недолік такого підходу в тому що при звертанні до Zend_Translate_Adapter безпосередньо (наприклад в Model або Controller Action, поза межами файлів представлення) – неперекладені фрагменти не потрапляють в наш чорний список
.
Томас Вейднер спочатку відхилив мою пропозицію ZF-5547, мотивуючи відповідь тим що єдиним найпрактичнішим рішенням є використання методу isTranslated().
Однак через два тижні він все таки видав нову редакцію Zend_Translate_Adapter що реалізовувала можливість використання Zend_Log для фіксування неперекладених фраз. Цей файл можна знайти в SVN репозиторії ось тут: svn://framework.zend.com/svn/framework/standard/incubator/library/Zend/Translate/Adapter.php, адаптувавши мою початкову ідею у відповідності до ідеології Zend Framework.
Зараз тестую новий функціонал. Результати тестування можна відслідковувати на Issue Tracker.

Почему не сделать просто статический метод, который будет реализововать приведенный вами пример?
Объект вида всегда можно получить через ViewRender
Ви праві! Так і треба було зробити, але варіант з View Helper мені тоді здався хорошим варіантом і я думав над оптимізацією оскільки була потреба лише в тимчасовому робочому рішенні – це перше і найпростіше що спало на думку.
Зараз я відмовився від view helper на користь експериментальної версії Zend_Translate в SVN інкубаторі з підтримкою потібного функціоналу.
До слова, вчора отримав повідомлення про те що запропонований функціонал одобрено dev-team але ще не одобрено з боку community. Є ймовірність що можливо нововведення може бути включено до дистрибутиву, якщо буде корисним спільноті zend framework. Тішуся дурницею як дитина, їй-богу
.
Побудова списку не перекладених фраз буде доступна в Zend Framework 1.8 !
Можна прочитати статтю Томаса на його персональному блозі