Урок 5 : Многоязычность
Рубрика: Создаем блог вместе
10 Июн. 2009Эта статья устарела т.к. была написана для yii версии 1.0.х; Если вы используете более новую версию - у вас могут возникнуть ошибки из-за несовместимости. Обычно ответы на все вопросы работы на 1.1.х были описаны в комментариях ниже статьи.
Я надеюсь вы согласитесь со мной что каждый серьезный сайт (проект) должен поддерживать многоязычность. Мы с вами не имеем право навязывать пользователю язык на котором он должен смотреть наш сайт. Пока наш блог проект не зашел слишком далеко - стоит оглянуться и заняться интернационализацией...
А вы уже читали "Урок 4 : Создаем отдельную страницу для постов (тем)"? Если нет, тогда дальше читать не стоит :)
Хочу обратить внимание что Yii отлично поддерживает интернационализацию (I18N) и что перевести проект на другие языки проблем не составит.
Первым делом в конфиг файле надо указать текущий язык скриптов проекта (на каком языке у нас будут написаны исходники), ну и сразу можем указать какой язык на сайте будет по умолчанию.
Заходим в protected/config/main.php и добавляем две строчки:
<?php
return array(
...
'sourceLanguage' => 'ru',
'language' => 'en',
...
- sourceLanguage - язык скриптов.
- language - язык нашего сайта по умолчанию
Я выбрал английский язык по умолчанию чтобы видеть разницу в проделанной работе.
Теперь заходим в protected и создаем там папку messages. В папке messages создаем папку en, а в папке en создаем файл main.php:
<?php
return array(
'русский вариант' => 'английский вариант',
);
В этом самом файле мы и делаем все переводы нашего сайта на английский язык. К примеру сюда же кидаются переводы для кнопочек, элементов форм и прочей фигни. В народе файл messages/en/main.php называют словарём. Таких словарей у нас может быть много и использовать их будем в зависимости от ситуации.
Я взял на себя смелость немного перевести элементы блога и файл messages/en/main.php у меня теперь выглядит следующим образом:
<?php
return array(
'Перейти к странице:' => 'Select page:',
);
Так получилось что в тех скриптах блога что мы с вами уже написали - только одна русская фраза фигурирует в отображении (post/index.php), её я и перевёл. Все остальные наши данные выводятся с базы данных и в переводе на данном этапе не нуждаются.
Теперь давайте откроем файл views/post/index.php и укажем там что фразу "Перейти к странице" надо переводить (если язык пользователя не русский).
Все переводы осуществляются одной командой:
Yii::t("словарь", "что_переводим")
Как вы понимаете что б перевести фразу "Перейти к странице:" нам достаточно указать:
Yii::t("main", "Перейти к странице:");
- Первым параметром мы указали название нашего рабочего словаря (messages/en/main.php)
- Второй параметр - это фраза которую надо переводить.
Теперь после небольшой теории - переходим к практике.
Файл views/post/index.php до интернационализации:
<table border="0" width="100%" cellpadding="10" cellspacing="10">
<?php
if (!empty($posts))
foreach ($posts as $key => $val) {
$this->renderPartial('_list',array(
'post'=>$val,
));
}
?>
</table>
<?php $this->widget('CLinkPager',array(
'pages'=>$pages,
'maxButtonCount' => 5,
'header' => '<b>Перейти к странице:</b><br><br>',
)); ?> Файл views/post/index.php после интернационализации:
<table border="0" width="100%" cellpadding="10" cellspacing="10">
<?php
if (!empty($posts))
foreach ($posts as $key => $val) {
$this->renderPartial('_list',array(
'post'=>$val,
));
}
?>
</table>
<?php $this->widget('CLinkPager',array(
'pages'=>$pages,
'maxButtonCount' => 5,
'header' => '<b>'.Yii::t("main", "Перейти к странице:").'</b><br><br>',
)); ?> Изменилась всего одна строчка. Старая фраза просто обернулась методом Yii::t.
На этом наше с вами участие заканчивается. Дальше Yii сама проверяет какой язык пользователем был выбран на сайте.
Давайте рассмотрим как работает на простых примерах
- Если язык пользователя совпадает с языком скриптов (указанно в config/main.php) - тогда перевод не осуществляется. Т.е. на экран выводиться просто фраза которая указана вторым параметром в Yii::t.
- Если язык пользователя английский - Yii открывает словарь main (messages/en/main.php) и ищет в нём фразу указанную вторым параметром. Если такой фразы не найдено - выводиться оригинальное название на родном языке. Если фраза найдена - значит она и подставляется при выводе.
- Если у пользователя выбран язык для которого мы не писали перевода (к примеру язык "ua", а папки messages/ua нет) тогда на экран будет выведена фраза на оригинальном языке скриптов
Вот в принципе и все премудрости которые надо знать.
В дальнейшем при разработке я сразу буду использовать Yii::t, так что больше к тому "откуда растут ноги" мы возвращаться не будем.
Вкратце про интернационализацию я уже писал тут, но еще больше вы можете прочитать в официальной документации на русском языке!
Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
- Поздравляю всех с выходом Yii Framework 1.1 beta
next
Список изменений
Загрузить версию 1.1 beta
... "Yii PHP framework 1.1 beta"
- Вот и порадовали нас новой версией любимого фреймворка. Хотелось бы отметить что на этот раз исправлений ошибок оказалось меньше чем ... "Yii PHP framework 1.0.9"
- Сегодня обнаружил что Sam Dark как и обещал перевел интерисующюю практически всех часть документации про RBAC.
next
Благодаря таким людям - ... "Перевод : Аутентификация и авторизация (RBAC)"

[guest] corpix
Было сказано: Четверг, 11 Июнь 2009
Как по мне...тк способ не удобен...я лучше переназначу папку с вьюхами, чем буду вызывать по множеству раз функции и хранить все сообщения на сайте централизованно

[adm] zolter
Было сказано: Четверг, 11 Июнь 2009
Тут вы не правы. Если переводом занимаеться не разработчик (так и должно быть) тогда переводчику врядли будет удобно получить в качестве материала исходники всех вьюх и искать в них текст что б переводить. Мне кажеться намного удобнее переводчику кинуть обычный практически текстовый файл словаря где он без каких либо знаний html-а поймет где надо переводить и куда что вставлять :)

[guest] Гость
Было сказано: Четверг, 11 Июнь 2009
Как считаете оправдано использование пространств имен в этой функции (Yii::t)?
Я сейчас склоняюсь к тому, чтобы написать враппер с простым именем, например "__" для замены
<?php echo Yii::t('main',
И "_" для использования без echo.

[adm] zolter
Было сказано: Четверг, 11 Июнь 2009
А есть ли в этом смысл? Только в том чтобы визуально было красивее? Мне кажется это лишняя затрата своего времени, хотя кому как нравится :) Плюс к этому, судя по вашему примеру - вы лишитесь такой возможности как использовать любое кол-во словарей, а не только main.
В самой работе использование словарей очень полезно.

[guest] Гость
Было сказано: Четверг, 11 Июнь 2009
я не очень понял, как быть с большими статичными текстами на страницах ?
их тоже в словарь совать ?

[adm] zolter
Было сказано: Четверг, 11 Июнь 2009
Нет. Словари используются только для перевода статических элементов на странице (название кнопок, колонок в таблицах, всякие системные ошибки и сообщения, поля в формах и тп).
В принципе вы можете использовать данный способ и для перевода большого статического текста, но лучше для этого наверно использовать БД. т.е. в базе хранить версии текста на разных языках и в зависимости от выбранного пользовательского языка - тащить нужный текст с базы.

corpix
Было сказано: Пятница, 12 Июнь 2009
2 zolter
Да, если передавать тексты переводчику, то словари безусловно удобней =)

[guest] kaiser Zaido
Было сказано: Воскресенье, 12 Июль 2009
На мой взгшял, вы не отметили в статье момент о том как же пользователь может указать что желает видеть блог на английском языке.
Т.е. как пользователю блога переключится с русского на английский

[adm] zolter
Было сказано: Воскресенье, 12 Июль 2009
По этой теме просто уже написана статья в кукбуку. Скорее всего скоро просто займусь её переводом и опубликую ссылку в уроке на неё. Спасибо что напомнили!
Кстати ссылка на неё - http://www.yiiframework.com/doc/cookbook/26/ (англ.)

[guest] Гость
Было сказано: Вторник, 13 Октябрь 2009
Скажите, пожалуйста, а что делать, если мне приходят данные в виде ключей массива, а мне надо получить "перевод" этих ключей согласно файлам в каталогах messages/ru messages/en.
Вот у меня есть такой массив грубо говоря
array("key1", "key2", "key3");
и переводы:
ru:
"key1" => "Русский key1",
"key2" => "Русский key2",
"key3" => "Русский key3"
en:
"key1" => "English key1",
"key2" => "English key2",
"key3" => "English key3"
если я пишу просто Yii::t("main", $key) - то он так и выводит "key1", так как считает что это написано уже на русском. Можно ли как-нибудь сфорсировать перевод?

[guest] Maxx
Было сказано: Вторник, 13 Октябрь 2009
Для англ.рус перевода надо всего 1 словарь делать. ненадо два отдельных. Первое значение - текущее название, второе - которое должно быть в случае выбора англ. языка.
Посмотрите еще раз урок, там об этом говорится. Некаких key1,key2 ненадо

[guest] Гость
Было сказано: Среда, 14 Октябрь 2009
Я бы рад от них избавиться, но они приходят из внешней среды.
Для всех остальных констант - я использую именно то, что сказано в уроке. Но для этой маленькой части - я имею только константы и их сопоставление каждому языку.
Я не могу вбить их напряму, так как не знаю какие именно и в каком порядке эти константы ко мне попадут. Я просто знаю как каждая константа должна переводиться на каждый язык.
Может ли Yii помочь мне в этом?

[guest] Нянька
Было сказано: Суббота, 31 Октябрь 2009
>> [guest] Гость
ну ни Сукин ли ты сын??
нет конечно...

[guest] Гость
Было сказано: Суббота, 13 Март 2010
Не получается вывести русский язык.
Беру стандартный testdrive - заменяю там английские слова на русские - буквы вообще не выводятся. Если просто добавляю русскую букву к английскому слову - все слово пропадает.
Что я делаю не так?

[guest] Гость
Было сказано: Суббота, 13 Март 2010
спасибо за урок, появился один вопрос, у меня модуль news как сделать перевод если у меня словарный файл хранится тут
\protected\modules\news\messages\main.php
как мне прописать в строчке
Yii::t("main", "Перейти к странице:");
в первом параметре что нужно указать чтобы со слаться в модуль?
как я понимаю сейчас он ищит тут
\protected\messages\main.php

[guest] Гость
Было сказано: Суббота, 13 Март 2010
ой, забыл указать директорию ru/
вот так
\protected\modules\news\messages\ru\main.php
\protected\messages\ru\main.php
просто при написании комментария забыл прописать ru/
В файлах всё в порядке.

[guest] Гость
Было сказано: Суббота, 13 Март 2010
вопрос ещё открытый подскажите как прописать тут
Yii::t("main", "Перейти к странице:");
чтобы файл читался отсюда
\protected\modules\news\messages\ru\main.php
?

[guest] Гость
Было сказано: Воскресенье, 14 Март 2010
всё разобрался, подсказали на другом форуме
http://www.yiiframework.com/forum/index.php?/topic/7443-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d0%b8/page__view__findpost__p__39721
просто нужно было указать название модуля
Yii::t('NewsModule.news', 'title');

[guest] Гость
Было сказано: Воскресенье, 14 Март 2010
и ещё вот, немного поискав на основном форуме Yii
http://www.yiiframework.com/forum/index.php?/topic/6623-failed-to-get-i18n-working-please-help/page__hl__/messages/__fromsearch__1

[guest] Гость
Было сказано: Воскресенье, 14 Март 2010
ага, для этого выложил ссылки. А вопрос у меня появился только тогда как решил сделать модули, до этого даже как-то и не задумывался. Теперь остаётся сделать плагин под смарти, так чтобы было удобно просто и понятно. Что то вроде этого
{t lang="news.title"}где news модуль а следом за точкой словарное слово что нужно перевести. Но это пока обдумываю как лучше)

[guest] alex3d
Было сказано: Воскресенье, 14 Март 2010
> [guest] Гость
> Было сказано: Суббота, 13 Март 2010
> Не получается вывести русский язык.
> Беру стандартный testdrive - заменяю там английские слова на > русские - буквы вообще не выводятся.
У меня была таже фигня - ниче понять не мог... погуглил и нашел что надо вставить в config/main.php например после:
'name'=>'My Demo App...',вот это:
'charset'=>'windows-1251',

[guest] Гость
Было сказано: Воскресенье, 14 Март 2010
сразу е понял о чём речь)
вообщем проблема та же самая была, исправил след. образом, в файле .htaccess прописал такую строчку
AddDefaultCharset utf-8
и всё стало в порядке

[guest] alex3d
Было сказано: Понедельник, 15 Март 2010
Захотел вставить комбо-бокс переключения языков как в статье из cookbook/26, но там очень сжато написано - даже не показано как виджет вставить - из комментов только понял. Там же в комментариях прочитал что компонент "MyController" (который я поместил в папку components) лучше запихнуть в "аутолоад" - чтоб ненадо было каждый раз все компоненты вызывать через "extends MyController". окошко с языками показывается, параменты сессии не передаются и не присваиваются переменной app()->language. Такое ощущение что init() от MyController не вызывается вообще... Но ведь должен? если в конфиге у меня
'import'=>array(
'application.models.*',
'application.components.*',
),значит всё файлы что в папке components будут автоматом вызыватся? т.е. init() обязательно исполнится? Или я неправильно понял что такое поставить в "аутолоад"?
И второй вопрос - все что присваивается в конфиге (main.php) исполняется только 1 раз при входе на сайт? я к тому что
'sourceLanguage' => 'ru',
'language' => 'en',не будет ли каждый раз сбрасывать параметр app()->language на "en"?

[guest] Artem
Было сказано: Четверг, 25 Март 2010
А как локализовать стандартные сообщения?
Например которые выводятся при валидации формы.
У Вас такие есть :)
Please fix the following input errors:
* Логин содержит недопустимые символы.

[adm] zolter
Было сказано: Четверг, 25 Март 2010
Свое сообщение указывается параметром 'message'. Т.е. в rules мое правило выглядит вот так:
array('login', 'match', 'pattern' => '/^[A-Za-z0-9А-Яа-я\_\-\s,]+$/u','message' => 'Логин содержит недопустимые символы.'),

[guest] Artem
Было сказано: Пятница, 26 Март 2010
Вы меня не поняли. Я имел ввиду другой текст. Как локализовать его?
Please fix the following input errors: - вот этот текст не переведён.

[guest] Гость
Было сказано: Вторник, 13 Апрель 2010
Добрый день, а кто нибудь использовал gettext в качестве источника сообщений? не могу разобраться в какую директорию подкладывать файлы перевода.. с пом poedit сгенерировал файл category1.po и category1.mo.
В конфигах
'components'=>array(
...
'messages'=>array(
'class'=>'CGettextMessageSource',
'useMoFile'=>1,
),...
вызываю $test = Yii::t('category1', 'some key');
файлы перевода лежат тут protected\messages\en\category1.mo
и protected\messages\ru\category1.mo
в результате перевода не получаю(, другие источники сообщений отрабатывают отлично.

[guest] almix
Было сказано: Четверг, 15 Апрель 2010
решил проблему,(слегка некорректно по моему правда).
в файле CGettextMoFile.php
function load()
...
закоментил
//if(($pos=strpos($id,chr(4)))!==false && substr($id,0,$pos)===$context)
// {
// $id=substr($id,$pos+1);
$message=$this->readString($fr,$targetLengths[$i],$targetOffsets[$i]);
$messages[$id]=$message;
// }
по всей видимости тут проблема с utf-8.
и прописал в main.php -> 'catalog'=>'category1'
'messages'=> array(
'class'=> 'CGettextMessageSource',
'catalog'=>'category1'
),
после этого переводы из mo файлов стали отрабатывать корректно. Если у кого то есть более корректный способ решения, отпишите плиз.

[adm] zolter
Было сказано: Четверг, 15 Апрель 2010
вместо substr нужно mb_substr поставить и думаю заработает

[guest] yolf
Было сказано: Понедельник, 14 Июнь 2010
Как по мне - не удобно хранить текст во вьюхах. Проще сделать как в хотел человек в комменте за прошлый год - юзать ключи.
Потому сделал следующий костыль:
в конфиге sourceLanguage присваивается какая ни будь левая локаль, например abc, в словарях пишем:
en/main.php - 'key1'=>'hello world'
ru - 'key1' => 'привет мир'
И в переопределенном контроллере в init_e проверяем Пост, сессию. Если там языка нет - то запихиваем в сессию и в app->language тот - который хотим юзать по умолчанию.
Метод несколько кривой, но лично мне проще во вьюхе написать:
Yii::t('main', 'btnSaveText');
чем вместо btnSaveTest печатать готовый текст.

[guest] Гость
Было сказано: Четверг, 03 Февраль 2011
Товарищи, а от куда ж берётся этот язык пользователя?
Нигде не указано о том как его устанавливать, как его передавать, например, в урле.
Он просто где-то есть... Но где?
Да, например, браузер передаёт желаемый язык пользователя соответственно настройкам - это ли то, о чём идёт речь?
А что, если пользователь хочет изменить язык?

[guest] zolter
Было сказано: Пятница, 04 Февраль 2011
Язык один раз выбираем на странице. Затем уже сохраняем в сессию к пример и берем оттуда, если он небыл отдельно передан в URL страницы. Тут уже дело фантазии как бы.

[guest] V1dun
Было сказано: Суббота, 25 Июнь 2011
Автоматический перевод сообщений из ядра Yii будет при выставлении опций:
'language'=>'ru',
'components'=>array(
'coreMessages'=>array(
'language'=>'en',
),
),

[guest] Гость
Было сказано: Четверг, 11 Август 2011
Здравствуйте, хочу построить мультиязычность через gettext и столкнулся с проблемой, что POedit при сканировании проекта выберает для перевода не текст, а словарь, т.е Yii::t('словарь','текст') выберает только первый аргумент функции.
В Poedit во вкладке Ключевые слова добавил t.
Буду очень благодарен за помошь!!!

[guest] Гость
Было сказано: Пятница, 09 Декабрь 2011
Все очень просто: используйте как ключевое слово t:2
(2 указывает на использование второго параметра)


