Локализация

делаю проект и по ходу разбираюсь в документации. сайт будет на 3-х

языках англ.(En), русский(Ru), испанский(Es). вроде в документации по

этой теме пробелы.

вот актуальные вопросы:

  1. как сконфигурировать языки?

  2. как выбор языков "играет" в строке запроса ($_GET['lang'])?

  3. выбор актуального сообщения на текущем языке.

  4. как вывести на форме ввода сразу 3 перевода (например, слово "Название")?

Локализацией плотно не занимался, скажу что занаю, остальное надо у Qiang спрашивать на английском форуме. Если тебе сложно на англ. я могу спросить и перевести сюда, но это будет долго, время перевода+время "врубиться" в ответ.

Итак:

  1. Перевод делается методом Yii::t(string $category, string $message, array $params=array ( ), string $source=NULL) и происходит в том случае, когда исходный язык и целевой язык различаются. Исходный язык задается с помощью свойства sourceLanguage. Конфигурируется так же как и любое другое свойство приложения - через конфиг. Целевой язык (на котором пользователь просматривает сайт) содержится в свойстве language приложения. Его т тоже можешь задать по дефолту, а после обработки параметров устанавливать как тебе надо. Чтобы его устанавливать, можно подписаться на событие onbeginRequest приложения. Подробнее про события - в разделе Компонент.

Для каждого языка тебе надо выбрать метод перевода - база, gettext, просто пхп-файлы. Я пробовал только последний. Он по умолчанию и идет.

Файлы перевода ложить сюда:/protected/messages/LocaleID/CategoryName.php

LocaleID - это то, что пишется в свойстве language. Для русского будет ru_RU, для английского великобритании - en_GB, для сша - en_US, посмотри код нужных тебе локалей.

  1. Немного не понял вопрос. Я думаю. речь идет о том, как установить текущий язык? Это делается ручками. Либо подписываешся на событие, как  писал выше, либо создаешь фильтр, который переключает текущий язык. Например, в зависимости от $_GET. Можно например и в куках, тут только твоя фантазия. Про фильтры смотри в разделах Контроллер и Создание дополнений (англ).

  2. Вызываешь Yii::t(); там где надо получить выводимое сообщение. Это, кстати написано в разделе интернационализации. Там есть три пункта, которые надо сделать, чтобы локализовать приложение

  3. А вот это проблема. Не знаю, думал ли об этом Qiang, когда создавал движок. Сам спросишь на форуме или мне спросить? Ну "через задницу" - понятно - переключаем локаль и выводим. И так 3 раза, потом возвращаем в исходное. Но это глупо, надо как-то поумнее. А вообще-то я редко встречал хорошие сайты, где одновременно несколько языков было бы. Обычно юзеру дается вариант переключить язык и потом выводишь ему на выбранном языке. Но проблема остается, спорить не буду.

Резюме: Внимательнее перечитай раздел локализации. По №4 спроси на общем форуме, я не знаю. Если еще непонятки - давай, будем решать.

Доброго времени суток!

Подготавливаюсь перенести проект на yii framework.

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

framework\YiiBase.php



	public static function t($category,$message,$params=array(),$source=null,$language=null)


	{


		if(self::$_app!==null)


		{


			if($source===null)


				$source=$category==='yii'?'coreMessages':'messages';


			if(($source=self::$_app->getComponent($source))!==null)


				$message=$source->translate($category,$message,$language);


		}


		if($params===array())


			return $message;


		if(isset($params[0])) // number choice


		{


			$message=CChoiceFormat::format($message,$params[0]);


			unset($params[0]);


		}


		return $params!==array() ? strtr($message,$params) : $message;


	}


framework\i18n\CMessageSource.php



	public function translate($category,$message,$language=null)


	{


        if($language!==null)


            return $this->translateMessage($category,$message,$language);


		else if(($lang=Yii::app()->getLanguage())!==$this->getLanguage())


			return $this->translateMessage($category,$message,$lang);


		else


			return $message;


	}


Вызываем так:



echo Yii::t('category', 'word', null, null, 'en_us');


echo Yii::t('category', 'word', null, null, 'ru_ru');


Надеюсь, в скором времени Квонг как-то решит данную проблему.

Обовите свн, qiang сказал что уже пофиксил эту штуку, я не проверял.

Хех, быстро сработано. Спасибо, Костя.

Я тоже вот на днях столкнулся с этим, решил отложить, а тут это и пофиксили :)

Ну я попросил - он сделал :)

Мне вот интересно, кем он работает если может опен-сорс проектом постоянно заниматься…

Документация еще не обновлена, кто посмотри как сделано - скажете как юзать?

Quote

Мне вот интересно, кем он работает если может опен-сорс проектом постоянно заниматься...

Мне тоже. Вы спросите у него  :)

Quote

Документация еще не обновлена, кто посмотри как сделано - скажете как юзать?

Вы говорите про четвертую проблему? Чтобы через Yii::t() вывести перевод для определенного языка? Посмторел SVN v756, ничего не поменялось, связанное с переводами.

UPDATE:

В SVN v769 изменения добавлены. Спасибо.

/**

 * Translates a message to the specified language.


 * Starting from version 1.0.2, this method supports choice format (see {@link CChoiceFormat}),


 * i.e., the message returned will be chosen from a few candidates according to the given


 * number value. This feature is mainly used to solve plural format issue in case


 * a message has different plural forms in some languages.


 * @param string message category. Please use only word letters. Note, category 'yii' is


 * reserved for Yii framework core code use. See {@link CPhpMessageSource} for


 * more interpretation about message category.


 * @param string the original message


 * @param array parameters to be applied to the message using <code>strtr</code>.


 * Starting from version 1.0.2, the first parameter can be a number without key.


 * And in this case, the method will call {@link CChoiceFormat::format} to choose


 * an appropriate message translation.


 * @param string which message source application component to use.


 * Defaults to null, meaning using 'coreMessages' for messages belonging to


 * the 'yii' category and using 'messages' for the rest messages.

* @param string the target language. If null (default), the {@link CApplication::getLanguage application language} will be used.

 * This parameter has been available since version 1.0.3.</strong>


 * @return string the translated message


 * @see CMessageSource


 */


public static function t($category,$message,$params=array(),$source=null,<strong class='bbc'>$language=null</strong>)

Не стал заводить нову тему. Спрошу здесь!

Сейчас тоже начал разбираться с тем как перевести проект на Yii на разные языки.

С настройками языков (sourceLanguage и language) кажется разобрался.

Так вот вопрос…я правильно понял что для обеспечения многоязычности - необходимо все строковые константы заменить на вызов Yii::t().

Т.е. если в модели я пишу так:



   public function attributeLabels()


    {


        return array(


            'id'         => 'идентификатор',


            'firstName'  => 'Имя',


            'lastName'   => 'Фамилия',


            'secondName' => 'Отчество',


            'password'   => 'Пароль',


            'status'     => 'Статус',


            'accessLevel' => 'Уровень доступа'


        );


    }


то это необходимо заменить на



   public function attributeLabels()


    {


        return array(


            'id'         => Yii::t(....)


            'firstName'  => Yii::t(....),


            'lastName'   => Yii::t(....),


            'secondName' => Yii::t(....),


            'password'   => Yii::t(....),


            'status'     => Yii::t(....),


            'accessLevel' => Yii::t(....)


        );


    }


аналогично и во view для вывода статичных сообщений.

Я прав?? Или что-то не так понял??

Все верно, именно так :)

Предлагаю обсудить еще один вопрос.

А именно,если файл с переводом - это простой php файл, содержащий массив сообщений, то в случае большого сайта - размер такого файла, и следовательно занимаемый им объем - будет велик. Следовательно целесообразно разделить его на несколько более мелких.

Как это правильнее и структурнее сделать??

У меня есть следующие варианты:

  1. Оставить все в одном файле - (не подходит)

  2. Создавать файлы перевода для каждого контроллера и его представлений (view)

  3. Создать один общий файл перевода (для каких то общеупотребительных терминов), а так же создавать файлы для каждого контроллера

Может есть еще какие то варианты??

Я думаю, проще всего разбить по контроллерам. А для перевода по кнтексту есть первый параметр в методе Yii::t().

Так я как раз и хотел - использовать контекст в качестве имени контроллера

пример

Yii:t('User','имя')

где User - это название файла перевода и одновременно название контроллера, сообщения которого переводятся.

ага, только с маленькой буквы. Так же как в пути к контроллеру, соблюдая соглашения (http://www.yiiframework.com/doc/guide/ru/basics.convention)

И плюс еще не забудь, Yii выдает стандартные сообщения. Где-то они там у него уже переведены, но надо в фреймворке смотреть и проверять русскую грамматику - мало ли как перевели, а тебе проект сдавать. /yii/messages/ru/yii.php

Ну конечно же  ;)

Quote

1. как сконфигурировать языки?
  1. как выбор языков "играет" в строке запроса ($_GET['lang'])?

  2. выбор актуального сообщения на текущем языке.

  3. как вывести на форме ввода сразу 3 перевода (например, слово "Название")?

1.  организация папок см. скриншот. в файле конфигурации:

[tt]…

'sourceLanguage'=>'ru_ru',

'language'=>'ru_ru',

…[/tt]

3.  [tt]Yii::t(‘admin.label’,‘Дата’);[/tt]

4.  [tt]Yii::app()->messages->translate(‘admin.label’,‘Название’,‘en_us’);[/tt]

2.

Quote

можно подписаться на событие onbeginRequest приложения. Подробнее про события - в разделе Компонент
- нельзя. еще не пропарсена строка запроса. (можно организовать это вручную, но овчинка выделки не стоит, дублируется)

что бы языки "заиграли" в запросе GET, в конфигурации прописал так:

[tt]        'urlManager'=>array(

          'rules'=>array(

// localhost/EN/news, либо localhost/ES/news

              '<lang:(EN|ES)>/news/<id:\d+>'=>'news',

              '<lang:(EN|ES)>/news'=>'news/table',

              '<lang:(EN|ES)>/news/page/<id:\d+>'=>'news/page',

              '<lang:(EN|ES)>/news/add'=>'news/add',

              '<lang:(EN|ES)>/news/edit/<id:\d+>'=>'news/edit',

              '<lang:(EN|ES)>/news/delete/<id:\d+>'=>'news/delete',

// русский, язык по умолчанию  localhost/news

              'news/<id:\d+>'=>'news',

              'news'=>'news/table',

              'news/page/<id:\d+>'=>'news/page',

              'news/add'=>'news/add',

              'news/edit/<id:\d+>'=>'news/edit',

              'news/delete/<id:\d+>'=>'news/delete',

[/tt]возможно можно шаблон прописать и короче для "пустого"

русского языка, но не силен в регулярных дебрях, сорри

на данный момент перестал работать контроллер по умолчанию,

типа: localhost/ , localhost/EN.  чешу репу…

дописываем в конфиг и заработало:

  [tt] '<lang:(EN|ES)>'=>'контроллер по умолчанию',

'<lang:(EN|ES)>'=>'',  //либо пустую строку[/tt]


формирование ссылок в системе пока сделал так:

[tt]//  localhost/EN/news, либо localhost/ES/news, либо localhost/news

$lang = (isset($_GET['lang']) ? array('lang'=>$_GET['lang']) : array());

$id = array('допустим_GET_парамерт_id'=>$row['id']);

$this->createUrl('имя_экшана', array_merge($lang, $id));[/tt]


установка языка в системе и формирование ссылок.

  • в контроллерах использ. внешний фильтр:

[tt]    public function filters()

    {

        return array(

            'accessControl', // perform access control for CRUD operations

            array(

                'application.filters.InitLang',  //создать папку private/filters

            ),

        );

    }

[/tt]

  • файл InitLang.php:

[tt]class InitLang extends CFilter

{

    protected function preFilter($filterChain)

    {

        $_GET['lang'] = (isset($_GET['lang']) ? $_GET['lang'] : 'RU');

        switch ($_GET['lang']) {

            case 'EN':

                Yii::app()->language = 'en_us';

                Yii::app()->params['lang'] = array('lang'=>$_GET['lang']);  // запомнить в конфигурации

                break;

            case 'ES':

                Yii::app()->language = 'es_es';

                Yii::app()->params['lang'] = array('lang'=>$_GET['lang']);

                break;

            //default:  - инициализировано в кунфигурации

            //    Yii::app()->language = 'ru_ru';

            //    Yii::app()->params['lang'] = array();

        }

        return true; // false - в случае когда следует запретить выполнение экшна

    }

    protected function postFilter($filterChain)

    {

        // код, выполянемый после запуска экшна

    }

}[/tt]

  • конфигурация:

[tt]    'params'=>array(

        'adminEmail'=>'webmaster@example.com', // this is used in contact page

        'lang'=>array(), //для ссылок, filter InitLang, пустой array() для 'RU'

        …[/tt]

  • формирование ссылок в системе:

$params = array_merge(Yii::app()->params['lang'], array('id'=>$row['id']));

$this->createUrl('edit', $params);


это все. спасабо всем кто принял обсуждение в топике

Quote

Quote

можно подписаться на событие onbeginRequest приложения. Подробнее про события - в разделе Компонент
- нельзя. еще не пропарсена строка запроса. (можно организовать это вручную, но овчинка выделки не стоит, дублируется)

А знаешь, мне кажется в тыщу раз проще именно подписаться на это событие :) Тогда:

  1. Избегаешь таких сложных правил в урл менеджере

  2. Вообще можешь не учитывать язык там (потому что после парсинга, а фактически просто считывания первых 3х символов запроса, ты язык просто убираешь, пусть Yii самостоятельно разбирает дальше)

  3. Проблема с "пустым" языком решается элементарно

А как насчет записывать выбранный язык не в параметры приложения (которые в теории не должны сохраняться от запроса к запросу. А если и сохраняются - то для всех юзеров), а в Yii::app()->user->lang='EN' для зарегистрированных и в сессии - для незарегистрированных. Доступ к сессии - тоже через свойство CWebApplication, посмотри доки.

По поводу конфигурации можешь еще глянуть мое дополнение для сохранения конфига в базе - http://www.yiiframew…ension/dbparam/