Hello everyone,
I’ve tried to make a compilation of everything in this thread and to make things work only with a behavior, without changing the model. So you don’t have to overload getters or setters in the model. Only to attach the behavior and define the defaultScope.
And of course create a new table in the database to store translations.
The table has this form by default (example for a base table named "post") :
postLang: l_id,post_id,lang_id,[list of attributes to translate prefixed by ‘l_’(configurable)]
The attributes to translate have to be also in the base table but with no prefix.
Here is the file : 2705
MultilingualBehavior.php
To attach the behavior to the model, use this piece of code (everything that is commented is default values):
public function behaviors() {
/*$table_name_chunks = explode('.', $this->tableName());
$simple_table_name = str_replace(array('{{', '}}'), '', array_pop($table_name_chunks));*/
return array(
'ml' => array(
'class' => 'application.components.MultilingualBehavior',
/*
'langClassName' => __CLASS__ . 'Lang', //example if model class name is 'Post' : 'PostLang'
'langTableName' => $simple_table_name . 'Lang', //example if table name is 'post' : 'postLang'
'langForeignKey' => $simple_table_name . '_id', //example if table name is 'post' : 'post_id'
'langField' => 'lang_id',
'localizedRelation' => 'i18n' . __CLASS__, //example if model class name is 'Post' : 'i18nPost'
'multilangRelation' => 'multilang' . __CLASS__, //example if model class name is 'Post' : 'multilangPost'
'dynamicLangClass' => true, //Set to true if you don't want to create a 'PostLang.php' in your models folder
'localizedPrefix' => 'l_', //In the lang table, localized attributes have to be prefixed with this to avoid collisions in some queries and allow search on translations
*/
'localizedAttributes' => array('slug', 'title'), //attributes of the model to be translated
'languages' => Yii::app()->params['translatedLanguages'], // array of your translated languages. Example : array('fr' => 'Français', 'en' => 'English')
'primaryLang' => Yii::app()->params['defaultLanguage'], //your main language. Example : 'fr'
),
);
}
In order to retrieve translated models by default, add this function in the model class :
public function defaultScope()
{
return $this->ml->localizedCriteria();
}
You also can modify the loadModel function of your controller as guillemc suggested in a previous post :
public function loadModel($id, $ml=false) {
if ($ml) {
$model = Post::model()->with('multilang')->findByPk((int) $id);
} else {
$model = Post::model()->findByPk((int) $id);
}
if ($model === null)
throw new CHttpException(404, 'The requested page does not exist.');
return $model;
}
and use it like this in the update action :
public function actionUpdate($id) {
$model = $this->loadModel($id, true);
...
}
Here is a very simple example for the form view :
<?php foreach (Yii::app()->params['translatedLanguages'] as $l => $lang) :
if($l === Yii::app()->params['defaultLanguage']) $suffix = '';
else $suffix = '_'.$l;
?>
<fieldset>
<legend><?php echo $lang; ?></legend>
<div class="row">
<?php echo $form->labelEx($model,'slug'); ?>
<?php echo $form->textField($model,'slug'.$suffix,array('size'=>60,'maxlength'=>255)); ?>
<?php echo $form->error($model,'slug'.$suffix); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'title'); ?>
<?php echo $form->textField($model,'title'.$suffix,array('size'=>60,'maxlength'=>255)); ?>
<?php echo $form->error($model,'title'.$suffix); ?>
</div>
</fieldset>
<?php endforeach; ?>
To enable search on translated fields, you can modify the search() function in the model like this :
public function search()
{
$criteria=new CDbCriteria;
//...
//here your criteria definition
//...
return new CActiveDataProvider($this, array(
'criteria'=>$this->ml->modifySearchCriteria($criteria),
//instead of
//'criteria'=>$criteria,
));
}
warning: the modification of the search criteria is based on a simple str_replace so it may not work properly under certain circumstances.
Hope this will help, it’s my first contribution so be cool please . And sorry for my poor english.