How to handle the language setting of Yii

Hello!

I’m wondering how to deal with language setting of Yii, as my solution does not work completely.

Scenario:

My app has two languages - "en" and "bg". They could be "en_us" and "bg_bg", for simplicity I stick to the two-character codes.

I want all my URLs to be like /language-code/controller/action/param1/param2.

I had solved that by creating custom URL Manager Class:




		'urlManager'=>array(

			'class' => 'application.components.lang.MultiLanguageUrlManager',

			'urlFormat' => 'path', 

			'rules' => array(

				'<Language:\w{2}>/<controller:\w+>/<id:\d+>' => '<controller>/view', 

				'<Language:\w{2}>/<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>', 

				'<Language:\w{2}>/<controller:\w+>/<action:\w+>' => '<controller>/<action>',

				

				'<Language:\w{2}>/gii' => 'gii',

                '<Language:\w{2}>/gii/<controller:\w+>' => 'gii/<controller>',

                '<Language:\w{2}>/gii/<controller:\w+>/<action:\w+>' => 'gii/<controller>/<action>',

		)



And my URL Manager is:




class MultiLanguageUrlManager extends CUrlManager

{	

    public function parsePathInfo($pathInfo)

    {	

        parent::parsePathInfo($pathInfo);

        

		$urlLanguage = Yii::app()->getRequest()->getParam('Language');

		

		$language = null;

		if ($urlLanguage && in_array($urlLanguage, MultiLanguageUtil::getLanguageCodes()))

			$language = $urlLanguage;

		

		if (!isset($language) && isset($_COOKIE['Language']) && in_array($_COOKIE['Language'], MultiLanguageUtil::getLanguageCodes()))

			$language = $_COOKIE['Language']; 

		

		if (!isset($language))

			$language = $this->_defaultLanguage;

		

		Yii::app()->setLanguage($language);

		

		MultiLanguageUtil::setLanguageCookie($language);

		

		$url = Yii::app()->getRequest()->getUrl();

		preg_match('/^(?:\/)([a-z]{2})(?:\/)/', $url, $matches);

		if (!isset($matches[1]) || !in_array($matches[1], MultiLanguageUtil::getLanguageCodes()))

			Yii::app()->getRequest()->redirect('/' . $language . $url);

    }

	

	public function createUrl($route, $params = array(), $ampersand = '&')

	{

		if (!isset($params['Language']))

			$params['Language'] = Yii::app()->language;

		return parent::createUrl($route, $params, $ampersand);

	}

	

}



The problem with the above solution is that the URL Manager does not seem to get called when I use modules!

So I’ve created an admin and users module, but can’t use them as they fallback to the default app language (en).

Any suggestions how to do it, something like a bootstrap file where to put the setting of Yii’s language?

Thank you!

Hello!

Did you try to add rules like for gii?




'<Language:\w{2}>/admin' => 'admin',

'<Language:\w{2}>/admin/<controller:\w+>' => 'admin/<controller>',

'<Language:\w{2}>/admin/<controller:\w+>/<action:\w+>' => 'admin/<controller>/<action>',

'<Language:\w{2}>/users' => 'users',

'<Language:\w{2}>/users/<controller:\w+>' => 'users/<controller>',

'<Language:\w{2}>/users/<controller:\w+>/<action:\w+>' => 'users/<controller>/<action>',



@sprint - I had added them, just didn’t list them here so I don’t have too long post.

Well I solved it.

The above URL Manager was by idea of a guy that submitted an extension that does the above scenario, except that he did not save the language in a cookie and handled it in a bit different way.

The parsePathInfo() method in the URL Manager that he used to place his code didn’t have anything to do with the request parameters parse. It was just a method that was called after parseUrl() method, which extracts the parameters from URL. The parsePathInfo() is not called in case module is used. But the parseUrl() method is called always.

Now I moved my code to a newly created component. And I call it like this:




class MultiLanguageUrlManager extends CUrlManager

{


	public function parseUrl($pathInfo)

	{

		$result = parent::parseUrl($pathInfo);

		Yii::app()->getComponent('multiLanguageUtil');

		return $result;

	}

	

	public function createUrl($route, $params = array(), $ampersand = '&')

	{

		if (!isset($params['Language']))

			$params['Language'] = Yii::app()->language;

		return parent::createUrl($route, $params, $ampersand);

	}

}



My multiLanguageUtil component is:




<?php

class MultiLanguageUtil extends CApplicationComponent

{

	const LANGUAGE_COOKIE_EXPIRE_TIME = 2592000; // 30 days

	

	protected static  $_defaultLanguage = 'en';


	protected static $_languages = array(

		'en' => 'English', 

		'bg' => 'Български'

	);

	

	public function init()

	{

		$urlLanguage = Yii::app()->getRequest()->getParam('Language');

		

		$language = null;

		if ($urlLanguage && in_array($urlLanguage, MultiLanguageUtil::getLanguageCodes()))

			$language = $urlLanguage;

		

		if (!isset($language) && isset($_COOKIE['Language']) && in_array($_COOKIE['Language'], MultiLanguageUtil::getLanguageCodes()))

			$language = $_COOKIE['Language'];

		

		if (!isset($language))

			$language = $this->_defaultLanguage;

		

		Yii::app()->setLanguage($language);

		

		MultiLanguageUtil::setLanguageCookie($language);

		

		$url = Yii::app()->getRequest()->getUrl();

		preg_match('/^(?:\/)([a-z]{2})(?:\/)/', $url, $matches);

		if (!isset($matches[1]) || !in_array($matches[1], MultiLanguageUtil::getLanguageCodes()))

			Yii::app()->getRequest()->redirect('/' . $language . $url);

	}

	

	public static function getDefaultLanguage()

	{

		return self::$_defaultLanguage;

	}

	

	public static function getLanguages()

	{

		return self::$_languages;

	}


	public static function getLanguageCodes()

	{

		return array_keys(self::$_languages);

	}

	

	public static function setLanguageCookie($language)

	{

		$cookie = new CHttpCookie('Language', $language);

		$cookie->expire = time() + self::LANGUAGE_COOKIE_EXPIRE_TIME;

		Yii::app()->request->cookies->add('Language', $cookie);

	}

}



@Veseliq thank you!