Yii Framework - Мультиязычность через URL | многоязычный сайт


Задача: организовать на сайте под управлением Yii Framework - мультиязычность.

Конечно в интернете полно информации на данную тему, даже готовых плагинов, но многие мне не понравились, некоторые вообще не удалось адекватно запустить.

Решил написать свой велосипед, постарался сделать его предельно простым и, как следствие, легко расширяемым.

Вот что получилось.

Для подключения мультиязычности выполняем следующее:

1. В директории /protected/components/ создаем файл - interceptorLanguageHttpRequest.php со следующим содержанием:

class interceptorLanguageHttpRequest extends CHttpRequest
{
    private $_requestUri;
 
    public function getRequestUri()
    {
        if ($this->_requestUri === null)
            $this->_requestUri = Lang::processLangInUrl(parent::getRequestUri());

        return $this->_requestUri;
    }
}

Задача данного файла перехватывать все приходящие ссылки и отдавать их на обработку в Lang::processLangInUrl(). Данный метод просматривает ссылку и ищет в ней префикс языка. Если префикс находится, то он активируется и удаляется из ссылки, что-бы не мешать дальнейшей работе приложения.

2. В директории /protected/components/ создаем файл -interceptorLanguageUrlManager.php со следующим содержанием:

class interceptorLanguageUrlManager extends CUrlManager
{
	// Перехватываю createUrl
    public function createUrl($route, $params=array(), $ampersand='&')
    {
        $url = parent::createUrl($route, $params, $ampersand);
        return Lang::addLangToUrl($url);
    }

	// Перехватываю createAbsoluteUrl
    public function createAbsoluteUrl($route, $params=array(), $ampersand='&')
    {
        $url = parent::createAbsoluteUrl($route, $params, $ampersand);
        return Lang::addLangToUrl($url);
    }
}

Данный файл перехватывает вызов createUrl() и createAbsoluteUrl() и отдает их под управление метода Lang::addLangToUrl(). Как вы уже поняли из названия метода - он добавляет префикс языка, если нужно.

3. В директории /protected/components/ создаем файл -Lang.php со следующим содержанием:

<?
/**
 * Обработка ссылок сайта.
 * Добавление языкового префикса
 * или удаление (с перехватом и изменением Yii::app()->language )
 */
class Lang
{

    public static function enabled()
    {
        return count(Yii::app()->params['translatedLanguages']) > 1;
    }

	// проверяю ссылку, вынимаю префикс языка
	// и отправляю далее без префикса
    public static function processLangInUrl($url)
    {
        if (self::enabled())
        {
            $domains = explode('/', ltrim($url, '/'));

			$lang = Yii::app()->params['defaultLanguage'];
			for ($i=0; $i<count($domains); $i++) {
				if ( in_array($domains[$i], array_keys(Yii::app()->params['translatedLanguages'])) ) {
					$lang = $domains[$i];	// Язык найден!
				}
			}
			Yii::app()->setLanguage($lang);
			$url = str_replace('/'.$lang.'/', '/', $url);	// просто убиру его из ссылки, если он там есть
        }

        return $url;
    }


	// добавляю в ссылку префикс
    public static function addLangToUrl($url)
    {
        if (self::enabled())
        {
			if ( Yii::app()->getLanguage() != Yii::app()->params['defaultLanguage'] ) {
				$work_dir = str_replace('index.php', '', $_SERVER['SCRIPT_NAME']);
				$url = str_replace($work_dir, '/', $url);
				$url = $work_dir . Yii::app()->getLanguage() . $url;
			}
        }
        return $url;
    }


	// Формирую строку языка.
	public function t( $message = '', $params = array() ) {
		$res = '';
		$lang = Yii::app()->getLanguage();
		$LangDictionary = Yii::app()->params['LangDictionary'];


		if ( !empty($LangDictionary[ $message ]) ) {

			if ( !empty( $LangDictionary[ $message ][ $lang ] ) ) {
				$res = $LangDictionary[ $message ][ $lang ];	// Если нужный язык найден
			}
			else
			{
				$res = $LangDictionary[ $message ][ Yii::app()->params['defaultLanguage'] ];	// Если нужный язык не найден, то юзаю дефолтный
			}

			// Расставляю параметры
			if ( count( $params ) )	{
				foreach ( $params as $key => $val )	{
					$res = str_replace('%'.$key.'%', $val, $res);
				}
			}
			// *** все возможные параметры стоят
		}
		else
		{
			$res = '<b>Error:</b> Can`t find "' . $message . '" param.';
		}

		return $res;
	}


}

А в этом файле описывается работа всех необходимых методов. Ещё здесь имеется метод t(), к которому вернемся чуть позже.

Дело осталось за малым - подключить все эти компоненты и можно их использовать.

4. Отправляется в /protected/config/main.php и вносим следующие изменения:

<?
'components'=>array(

	...

	// Добавляем это
	'request' => array(
		'class'=>'interceptorLanguageHttpRequest', // Для перехвата языкового префикса
	),

	'urlManager' => array(
		// И это
		'class'=>'interceptorLanguageUrlManager', // Для добавления в ссылку языкового префикса
		...
	),
),


// А так-же добавляем параметры
'params' => array(

	...

	'defaultLanguage' => 'ru',		// Язык по умолчанию
	'translatedLanguages' => array(	// Список языков поддерживаемых сервисом
		'ru' => 'Русский',
		'en' => 'English',
	),
	'LangDictionary' => include('protected/config/LangDictionary.php'),	// Сам словарь языков

),

Тут думаю все понятно без пояснений. Стоит добавить что осталось добавить сам файл с языками. Лежать он будет например в /protected/config/LangDictionary.php.

return array(

	'Hello' => array( 
		'ru' => 'Привет мир', 
		'en' => 'Hello world', 
	),
	'Params' => array( 
		'ru' => 'Это тестовая строка с параметрами А: %param1% и В: %param2%.', 
		'en' => 'Test string with params A: %param1% and B: %param2%', 
	),
	
	...
);

Где именно разместить данный файл,можете решить сами. Мне было удобнее в конфигурационной директории.

Отдельно стоит отметить дополнительный функционал метода Lang::t(). Вторым параметром можно отправить массив с "параметрами" строки. В случае с "Это тестовая строка с параметрами А: %param1% и В: %param2%.", параметры обрамленные в знак процента будут заменены на параметры из массива отправленного в Lang::t('type', array('param1'=>'test_A', 'param2'=>'test_B')).

Теперь создадим тестовый экшн для проверки:

<?
public function actionIndex()
	{
		echo '<P>Сформированный URL - <b>'.Yii::app()->request->getUrl().'</b> (языкового префикса не должно быть)</p>';
		echo '<P>Установленный язык - <b>'.Yii::app()->language.'</b></p>';
		echo '<P>Тест создания ссылки - <b>'.Yii::app()->createAbsoluteUrl('site/index', array('id'=>1)).'</b></p>';
		echo '<P>Тест перевода строки - <b>'.Lang::t('Hello').'</b></p>';
		echo '<P>Тест 2 перевода строки - <b>'.Lang::t('Params', array('param1' => 'Test A', 'param2' => 'Test B')).'</b></p>';
	}

Вот и увидим следующий результат:

Сформированный URL - / (языкового префикса не должно быть)
Установленный язык - en
Тест создания ссылки - http://site.ru/en/site/index.html?id=1
Тест перевода строки - Hello world
Тест 2 перевода строки - Test string with params A: Test A and B: Test B

В результате получаем систему для настройки мультиязычности на Yii Framework, которую довольно просто дорабатывать под свои потребности.

 


Тэги:

Комментарии: 0

Прокомментировать »

 
 
 

Прокомментировать

 
 
Сообщение *
 
Проверочный код *
 
 
 
Яндекс.Метрика