You are viewing revision #2 of this wiki article.
This is the latest version of this article.
You may want to see the changes made in this revision.
Task Definition ¶
So, you need localised urls made simple that follow the Yii framework guidelines?
- http://example.com/terms-and-conditions (english)
- http://example.com/impressum (german)
- http://example.com/mentions-legales (french)
It's actually pretty simple to do!
This How-To assumes the following ¶
- You know how to use Yii framework
- You know how to use the translations generator
- You know how to use the Yii::t(...) function
Identifying the problem ¶
The simplest solution to just translate them in the config UrlManager component right?
'urlManager' => array(
'urlFormat' => 'path',
'showScriptName' => false,
'caseSensitive' => true,
'rules'=>array(
Yii::t('routes', '/terms-and-conditions') => '/site/index/termsAndConditions',
// ..... more routing here....
// .... and the default MVC routing rules here...
),
),
This way you will even get your routes translation file auto updated when you generate translations via the Yii cli script!
It sounds good doesn't it?!
However, this will NOT work because your translator is initialized after your configuration array is evaluated!
Solution ¶
Bootstrap your Yii (as recommended by Qiang Xue)
Create a file Yii.php in the protected.components folder and create a class called Yii extending the YiiBase
class Yii extends YiiBase
{
}
At the moment Yii::createComponent allows you to pass in constructor arguments as extra arguments in the function. However we want to pass in extra arguments through our configuration array (we will need this for our super simplified UrlRule component later) This is perfectly fine since you can't have variable with numeric names in PHP.
Our overload looks like this (copy/paste from the createComponent source with a couple of extra lines of code).
class Yii extends YiiBase
{
/**
* Creates an object and initializes it based on the given configuration.
*
* The specified configuration can be either a string or an array.
* If the former, the string is treated as the object type which can
* be either the class name or {@link YiiBase::getPathOfAlias class path alias}.
* If the latter, the 'class' element is treated as the object type,
* and the rest of the name-value pairs in the array are used to initialize
* the corresponding object properties.
*
* Any additional parameters passed to this method will be
* passed to the constructor of the object being created.
*
* @param mixed $config the configuration. It can be either a string or an array.
* @return mixed the created object
* @throws CException if the configuration does not have a 'class' element.
*/
public static function createComponent($config)
{
if(is_string($config))
{
$type=$config;
$config=array();
}
elseif(isset($config['class']))
{
$type=$config['class'];
unset($config['class']);
}
else
throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
if(!class_exists($type,false))
$type=Yii::import($type,true);
if(($n=func_num_args())>1)
{
$args=func_get_args();
if($n===2)
$object=new $type($args[1]);
elseif($n===3)
$object=new $type($args[1],$args[2]);
elseif($n===4)
$object=new $type($args[1],$args[2],$args[3]);
else
{
unset($args[0]);
$class=new ReflectionClass($type);
// Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+
// $object=$class->newInstanceArgs($args);
$object=call_user_func_array(array($class,'newInstance'),$args);
}
}
else
{
$args=array();
foreach($config as $k => $v)
if (is_int($k)) {
$args[] = $v;
unset($config[$k]);
}
$n = count($args);
if ($n===0)
$object=new $type;
elseif ($n===1)
$object = new $type($args[0]);
elseif($n===2)
$object = new $type($args[0], $args[1]);
elseif($n===3)
$object = new $type($args[0], $args[1], $args[2]);
}
foreach($config as $key=>$value)
$object->$key=$value;
return $object;
}
}
Of course we now need to use our Bootstrapping class instead of the default empty class provided by the framework. To do this we need to go to our public folder and edit the index.php
// your $yii variable should point to our newly created bootstrapping file
$yii = dirname(__FILE__).'/protected/components/Yii.php';
Finally, in the protected.components create a new Url rule component as following
class LocalisedUrlRule extends CUrlRule {
public function __construct($pattern, $route) {
parent::__construct($route, Yii::t('routes', $pattern));
}
}
In the end ¶
If you modified everything correctly you can now write things like the following in your main.php config file
'urlManager' => array(
'urlFormat' => 'path',
'showScriptName' => false,
'caseSensitive' => true,
'rules'=>array(
// FYI: translation here takes place just to have the script generate the translation string automatically
array('class' => 'protected.components.LocalisedUrlRule', Yii::t('routes', '/terms-and-conditions'), '/site/termsAndConditions'),
// ..... more routing here....
// .... and the default MVC routing rules here...
),
),
The implementation is rather easy and by updating your translations you can always easily modify the localized routes (which are auto-generated) in the routes.php translations file.
Nice Tip
Thank you for this amazing tip about localisation
What was changed in Yii class
Could you mark (with comments?) what was changed in original
Yii::createComponent
? This would make article more clear.Looks nice
But when I tried it I'm only getting blank screen after trying to access anything. Not sure what I need to do in order for the bootstrapped file to run (1.1.16).
EDIT: Nevermind. I just forget to require the YiiBase.php file in the bootstrap.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.