При написании одного проекта, возникла необходимость в организации мультиязычности на сайте. Причем количество языков не должно ограничиваться двумя и URL должны быть человеко-понятные и SEO оптимизированные. Тоесть ссылки на сайте должны быть вида:
http://mysupersite.ru/ru/contacts для русского языка
http://mysupersite.ru/en/contacts для английского языка
Так как опыт у меня не очень большой, я начал вопрошать гугл. Вариантов, как оказалось, достаточно много, однако из всех мне приглянулся один вариант, который я использовал и слегка модифицировал.
1. Расширяем CUrlManager.
Создаем файл 'components/UrlManager.php' со следующим содержимым:
<?php
class UrlManager extends CUrlManager
{
public function createUrl($route,$params=array(),$ampersand='&')
{
if (!isset($params['language'])) {
if (Yii::app()->user->hasState('language'))
Yii::app()->language = Yii::app()->user->getState('language');
else if(isset(Yii::app()->request->cookies['language']))
Yii::app()->language = Yii::app()->request->cookies['language']->value;
$params['language']=Yii::app()->language;
}
return parent::createUrl($route, $params, $ampersand);
}
}
?>
Согласно нашему условию, выбранный язык должен быть частью URL. Это значит, что $_GET['language'] должен быть определен. Для реализации этого мы переопределяем функцию createUrl() класса CUrlManager. Если язык в строке не указан, тогда мы его ищем в переменной сессии, затем в кукисах, и если до этого пользователь не менял язык то устанавливаем язык приложения по умолчанию. И затем формируем правильную строку URL уже с языком как параметр.
2. Редактируем наш Controller
Добавляем следующий код в 'components/Controller.php'
<?php
public function __construct($id,$module=null){
parent::__construct($id,$module);
// If there is a post-request, redirect the application to the provided url of the selected language
if(isset($_POST['language'])) {
$lang = $_POST['language'];
$MultilangReturnUrl = $_POST[$lang];
$this->redirect($MultilangReturnUrl);
}
// Set the application language if provided by GET, session or cookie
if(isset($_GET['language'])) {
Yii::app()->language = $_GET['language'];
Yii::app()->user->setState('language', $_GET['language']);
$cookie = new CHttpCookie('language', $_GET['language']);
$cookie->expire = time() + (60*60*24*365); // (1 year)
Yii::app()->request->cookies['language'] = $cookie;
}
else if (Yii::app()->user->hasState('language'))
Yii::app()->language = Yii::app()->user->getState('language');
else if(isset(Yii::app()->request->cookies['language']))
Yii::app()->language = Yii::app()->request->cookies['language']->value;
}
public function createMultilanguageReturnUrl($lang='en'){
if (count($_GET)>0){
$arr = $_GET;
$arr['language']= $lang;
}
else
$arr = array('language'=>$lang);
return $this->createUrl('', $arr);
}
?>
Мы расширяем конструктор класса и добавляем язык для приложения. Так как все контроллеры будут наследоваться с этого контроллера, язык приложения будет установлен явно на каждый запрос.
Если не установленYii::app()->language явно для каждого запроса в URL, он будет браться из конфигурационного файла приложения. Если же он не указан в конфигурационном фале, он будет идентичен Yii::app()->sourceLanguage, который по умолчанию 'en_us'.
Все эти параметры можно изменить в конфигурационном файле protected\config\main.php
'sourceLanguage'=>'en',
'language'=>'ru',
3. Создаем Language Selector Widget
Создаем файл в 'components/widgets/LanguageSelector.php' со следующим содержимым:
<?php
class LanguageSelector extends CWidget
{
public function run()
{
$currentLang = Yii::app()->language;
$languages = Yii::app()->params->languages;
$this->render('languageSelector', array('currentLang' => $currentLang, 'languages'=>$languages));
}
}
?>
И вьюху для нашего виджета 'components/widgets/views/languageSelector.php':
<div id="language-select">
<?php
if(sizeof($languages) < 4) { // если языков меньше четырех - отображаем в строчку
// Если хотим видить в виде флагов то используем этот код
foreach($languages as $key=>$lang) {
if($key != $currentLang) {
echo CHtml::link(
'<img src="/images/'.$key.'.gif" title="'.$lang.'" style="padding: 1px;" width=16 height=11>',
$this->getOwner()->createMultilanguageReturnUrl($key)); };
}
// Если хотим в виде текста то этот код
/*
$lastElement = end($languages);
foreach($languages as $key=>$lang) {
if($key != $currentLang) {
echo CHtml::link(
$lang,
$this->getOwner()->createMultilanguageReturnUrl($key));
} else echo '<b>'.$lang.'</b>';
if($lang != $lastElement) echo ' | ';
}
*/
}
else {
// Render options as dropDownList
echo CHtml::form();
foreach($languages as $key=>$lang) {
echo CHtml::hiddenField(
$key,
$this->getOwner()->createMultilanguageReturnUrl($key));
}
echo CHtml::dropDownList('language', $currentLang, $languages,
array(
'submit'=>'',
)
);
echo CHtml::endForm();
}
?>
</div>
Для отображения флагов, необходимо разместить в папке /images/ указатели языков с именами типа en.gif, ru.gif, ua.gif, md.gif.
4. Размещаем Widget на сайте
Добавлем следующий код внутри header-div в 'views/layouts/main.php'
<div id="language-selector" style="float:right; margin:5px;">
<?php
$this->widget('application.components.widgets.LanguageSelector');
?>
</div>
5. Редактируем Конфигурационный файл приложения
<?php
'components'=>array(
...
'request'=>array(
'enableCookieValidation'=>true,
'enableCsrfValidation'=>true,
),
'urlManager'=>array(
'class'=>'application.components.UrlManager',
'urlFormat'=>'path',
'showScriptName'=>false,
'rules'=>array(
'<language:(ru|ua|en)>/' => 'site/index',
'<language:(ru|ua|en)>/<action:(contact|login|logout)>/*' => 'site/<action>',
'<language:(ru|ua|en)>/<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<language:(ru|ua|en)>/<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<language:(ru|ua|en)>/<controller:\w+>/<action:\w+>/*'=>'<controller>/<action>',
),
),
),
'params'=>array(
'languages'=>array('ru'=>'Русский', 'ua'=>'Українська', 'en'=>'English'),
),
?>
6. Добавляем .htaccess
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
Вот вроде бы и все. У меня заработало и глюков пока не замечено. На вопросы отвечу.
Информацию почти всю взял отсюда: SEO-conform Multilingual URLs + Language Selector Widget (i18n)