As seen in this post, Yii doesn't enforce how language is set and maintained within the session.
According to that post, the preferred method is to create a base controller which implements code for maintaining the language state. That Controller is then used in your code instead of CControler (by defing your classes with "class ... extends MyController")
Here's my method of implementing this idea:
components/MyController.php
<?php
class MyController extends CController
{
function init()
{
parent::init();
$app = Yii::app();
if (isset($_POST['_lang']))
{
$app->language = $_POST['_lang'];
$app->session['_lang'] = $app->language;
}
else if (isset($app->session['_lang']))
{
$app->language = $app->session['_lang'];
}
}
}
?>
You can use a custom made Widget to let the user select language:
components/LangBox.php
<?php
class LangBox extends CWidget
{
public function run()
{
$currentLang = Yii::app()->language;
$this->render('langBox', array('currentLang' => $currentLang));
}
}
?>
components/views/langBox.php
<?php echo CHtml::form(); ?>
<div id="langdrop">
<?php echo CHtml::dropDownList('_lang', $currentLang, array(
'en_us' => 'English', 'is_is' => 'Icelandic'), array('submit' => '')); ?>
</div>
<?php echo CHtml::endForm(); ?>
See also ¶
- Here is another approach using behaviors.
why component instead of controller?
Because the file is auto required from /components, whereas it isn't in /controllers
You can simplify quite a lot...
function change_language() { if (isset($_POST['lang'])) Yii::app()->session['lang'] = $_POST['lang']; if (isset(Yii::app()->session['lang'])) Yii::app()->language = Yii::app()->session['lang']; }
cookies
You could also store the preferred language in a cookie, instead of the session, and then retrieve it on every page load and on the language selection page.
user session and behaviour
You can enhance this language managment.
Is possible to write a behavior for the application that will set the language, without any needs to create a masterclass for all controllers
<?php /** * ApplicationConfigBehavior is a behavior for the application. * It loads additional config paramenters that cannot be statically * written in config/main */ class ApplicationConfigBehavior extends CBehavior { /** * Declares events and the event handler methods * See yii documentation on behaviour */ public function events() { return array_merge(parent::events(), array( 'onBeginRequest'=>'beginRequest', )); } /** * Load configuration that cannot be put in config/main */ public function beginRequest() { if ($this->owner->user->getState('applicationLanguage')) $this->owner->language=$this->owner->user->getState('applicationLanguage'); else $this->owner->language='en'; } }
As you see, I took the actual language by the user state. For save the language I created a special action in SIteController:
/** * set the application language or the theme according to the choice of the user */ public function actionSettings() { if (isset($_POST['language'])) Yii::app()->user->setState('applicationLanguage',$_POST['language']); $this->redirect($_POST['url']); }
Behavior
Just for other folks, who maybe was struggling with Yii's documentation too when they were trying to find out how and where to put application behavior.
So 1st step is to put file with class ApplicationConfigBehavior to the protected/components directory.
And 2nd step is to add to your config in protected/config/main.php
'behaviors' => array('ApplicationConfigBehavior')
Easy, huh? But it took me quite a while to figure this out...
p.s. Thanks to zaccaria for the hint on how to run some piece of code before all requests without overriding controller class.
re: user session and behaviour
After re-reading this wiki, I advice anyone to use a mixed approach:
Use behavior instead of init of the model, but use the method displayed in the article (reading the input directly in the onInit) instead of following my example of another action.
This approach is quite better than mine.
If anyone will do this "mixed approach" with success and test it, can please update the article with a definitive, tested, version?
Original post
the original forum post isn't available anymore.
elaborate version
I use a more elaborate version of the code posted here to also do stuff like language validation etc. The concept is still a model/component/behavior bundle
private function setLanguage(){ if (isset( $_POST['_lang']) && $this->validateLang( $_POST['_lang'] )){ $this->setDisplayedLangProperties( $_POST['_lang'] ); Yii::app()->request->redirect( Menu::model()->getLangDefaultMenu()->menuUrl ); // the previous line is only needed in cases where the content displayed can only be displayed in one language. }elseif( Yii::app()->user->getState('displayedLanguage') === null ){ $this->setDisplayedLangProperties( 'en' ); // if no language has been set set the default language }elseif( Yii::app()->user->getState('displayedLanguage') !== null ){ $this->setDisplayedLangProperties( Yii::app()->user->getState('displayedLanguage')->iso2 ); // in case the language is already set and no change is needed just keep the settings alive } }
validateLang() is just a function that returns true if the passed argument is a valid language tag. setDisplayedLangProperties just gets a lang model and sets it as a user state, this way everything in the application can get a refference to the displayed language model and use it ( because some times the two char iso code just isnt enough )
Thanks
Thanks for this wiki, very helpful. In addition, I defaulted the language with the preferred language (= first value coming from the HTTP_ACCEPT_LANGUAGE element) :
if (isset($_POST['_lang'])) { $app->language = $_POST['_lang']; $app->session['_lang'] = $app->language; } else if (isset($app->session['_lang'])) { $app->language = $app->session['_lang']; } else { // 'fr_FR' becomes 'fr' $app->language = substr(Yii::app()->getRequest()->getPreferredLanguage(),0,2); $app->session['_lang'] = substr(Yii::app()->getRequest()->getPreferredLanguage(),0,2); }
translation using database
Hi,
How can we implement translation using database.I want to give translation option to my site and when someclick on french then action translate the english value by fetching its french translated value from database.
Thanks
re Narender Negi
Use CDbMessageSource
Language in URL
How do you store language in URL ? For example "example.com/de/site/index" ?
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.