📜 ⬆️ ⬇️

Yii and multilingual site. Correct URL and flexibility


When writing one project, it became necessary to organize multilingualism on the site. Moreover, the number of languages ​​should not be limited to two, and the URL should be human-friendly and SEO optimized. Ie links on the site should be of the form:
http://mysupersite.ru/ru/contacts for the Russian language
http://mysupersite.ru/en/contacts for the English language
Since my experience is not very big, I began to ask Google. As it turned out, there are a lot of options, but of all I liked one option that I used and slightly modified.

1. Extend CUrlManager.


Create the file 'components / UrlManager.php' with the following contents:
<?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); } } ?> 

According to our condition, the selected language should be part of the URL. This means that $ _GET ['language'] must be defined. To implement this, we override the createUrl () function of the CUrlManager class. If the language in the string is not specified, then we are looking for it in the session variable, then in the cookies, and if the user has not changed the language before, we set the default application language. And then we form the correct URL string already with the language as a parameter.

2. Editing our Controller


Add the following code to '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); } ?> 


We extend the class constructor and add the language for the application. Since all controllers will be inherited from this controller, the application language will be set explicitly for each request.
If Yii :: app () -> language is not set explicitly for each request in the URL, it will be taken from the application configuration file. If it is not specified in the configuration file, it will be identical to Yii :: app () -> sourceLanguage, which is by default 'en_us'.
All these parameters can be changed in the protected \ config \ main.php configuration file.
 'sourceLanguage'=>'en', 'language'=>'ru', 

3. Create a Language Selector Widget


Create a file in 'components / widgets / LanguageSelector.php' with the following contents:
 <?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)); } } ?> 

')
And the view for our widget '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> 

To display flags, it is necessary to place in the / images / folder of languages ​​with names like en.gif, ru.gif, ua.gif, md.gif.

4. We place Widget on the site


Add the following code inside the header-div to 'views / layouts / main.php'
 <div id="language-selector" style="float:right; margin:5px;"> <?php $this->widget('application.components.widgets.LanguageSelector'); ?> </div> 

5. Edit the application configuration file


 <?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. Add .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 


That seems to be all. It worked for me and glitches have not yet been noticed. I will answer questions.
I took most of the information from here: SEO-conform Multilingual URLs + Language Selector Widget (i18n)

Source: https://habr.com/ru/post/139689/


All Articles