I18N And Urls

Hey there,

I’m writing some translatable urls. Default choice to translate would be to go through Yii::t(…) but at the point of initialisation (app config) the Yii::t is called before the language is set. According to this, I have two options, either “manually” import the array for my routes and just use the array at that point outside Yii::t and B, create a custom url rule for I18n rules.

Before getting into details about either method, has anyone figured how to do it in a different way? Any ideas?

i.e.

en_us => /search

de => /suche

etc.

Probably you may take some ideas from this wiki article

Eventually I did the following to have translatable urls with full support of the CUrlRule expressions

Step1.

Yii Bootstrap - I override the createComponent function. The create component is very nicely written but, since we know for sure variables with the name $0, $1, etc are not allowed, I modified it to treat integer keys as arguments it needs to pass to the constructor (to overcome the issue with how CUrlManager instantiates the CUrlRule




<?php

// Adjust the path to your YiiBase according to your Yii folder structure - mine is modified <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/wink.gif' class='bbc_emoticon' alt=';)' />

require(dirname(__FILE__).'/../../yii/YiiBase.php');

class Yii extends YiiBase

{

    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

        {

            // This is the code I added to it. The rest is the original createComponent function replacing the $object=new $type;

            $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]);

        }

        // My code ends here


        foreach($config as $key=>$value)

            $object->$key=$value;


        return $object;

    }

}



Step 2.

The above modification allowed me to actually extend the CUrlRule and create the LocalisedUrlRule




<?php

class LocalisedUrlRule extends CUrlRule {

    public function __construct($pattern, $route) {

        parent::__construct($route, Yii::t('routes', $pattern));

    }

}



Step 3.

So, in my config I could generate urls like this




'urlManager'=>array(

	'rules'=>array(

                // Dedicated urls - SEO friendly front-end (localised)

                // FYI: translation here takes place just to have the script generate the translation string automatically. At this point the Yii::t will always return the original text (i.e. /contact) regardless the language setting

                array('class' => 'LocalisedUrlRule', Yii::t('routes', '/contact'), '/contact/index'),

	),

),



The above is sufficient for the parseUrl functionality. The createUrl is not tested yet and not sure if it’s going to work perfectly.

Comments and ideas are always welcomed!