DbHelp.ru
Маленький Yii блог
Комментарии
DeD: Запрацювало тільки після заміни if (isset($_GET['root'])) на if...
Denis: Если что- можете поюзать полный код уроков: https://github.com/d...
Гость: www.youtube.com/watch?v=vZqNhOsaHRU - ролик по проекту DruYiid
Mj: Мдааа так было интересно, ех... Но лучше поздно чем нико...
Mj: Добавте оповещание по email



Сервер Ultima Online - Forest Wars (от создателя данного блога)

Многоязычность субдоменов и URL-правила

Рубрика: Перевод Cookbook

Оцените эту статью:

Рейтинг: 0.00 (0)
25 Дек. 2009
Опубликовать в Twitter Написать в Facebook Опубликовать в своем блоге livejournal.com

Yii Framework Blog img http://dbhelp.rucookbook Это руководство предназначено для более-менее продвинутых пользователей. Если вы только что начали работу с Yii Framework-ом, вам стоит вернутся на эту страницу позднее :-)

---

 

Некоторые размышления

В Yii мы обычно определяем статические правила маршрутизации (url-rules) в основном конфигурационном файле. В настоящее время в Yii нет встроенной поддержки субдоменов и динамических маршрутов. При разработке многоязычного приложения, вы обычно определяете url-правила на английском языке, независимо от языка клиента. Это хорошо работает, но для профессиональных сайтов и порталов — вы можете использовать совершенно другой подход!

Давайте представим что мы создаем сайт на двух языках (английском и немецком). Правила для страницы «контакты» скорее всего выглядело бы следующим образом:

<?php
...
 
'components' => array(
  'urlManager' => array(
    'rules' => array(
      'contact' => 'site/contact',
    ),
  ),
),
 
...
?>

Доступ к странице мы могли бы получить по ссылке:

http://www.example.com/contact

Теперь подумаем как сделать вот так:

http://en.example.com/contact  
http://de.example.com/kontakt

Как вы видите, мы используем субдомен — как определитель языка пользователя (EN – для английскойго, DE – для немецкого) и слово «Контакт» как url-правило. Как я уже говорил ранее, такой подход Yii не поддерживает.

Прежде чем я покажу вам решение — ознакомтесь со всеми недостатками и приемуществами. Оцените самостоятельно стоит ли использовать данный подход для ваших приложений.

Недостатки

  • Если вы используете субдомены для размещения основной информации на них, это скорее всего приведет к падению вашего PageRank основного домена. (например example.com вероятно пострадает)
  • Google заявляет что лучше использовать домен верхнего уровня вместо субдоменов. Так что если вы являетесь владельцем example.com , example.de – тогда вы не должны использовать данный подход. Но вы конечно можете переписать часть кода под работы с доменами верхнего уровня, вместо субдоменов.
  • Для небольших сайтов нет смысла использовать данный подход. Реальное приемущество вы получите на веб-сайтах с посещаемостью не меньше чем 10 000 уникалов в сутки.

 

Приемущества

 

  • Вы можете развить ваш сайт в реальный многоязычный портал, как например YouTube, и проверять статистику с одно аккаунта Google Analytics для разных субдоменов.
  • Google будет отображать ссылки (http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=47334) для каждого языка. Это правильнее с точки зрения SEO
  • Пользователи будут счастливы :)

 

Решение

Создадим новый компонент, который будет включать в себя все необходимые свойства и функции:

<?php
 
class I18n extends CApplicationComponent
{
 
    public $supportedLanguages;
    public $urlRulesPath;
    public $activeLanguage;
 
    public function init()
    {
 
        if (true === (bool)preg_match("/^(?<protocol>(http|https):\/\/)(((?<languageCode>[a-z]{2})\.)*)((.*\.)*(?<domain>.+\.[a-z]+))$/", Yii::app()->request->hostInfo, $matches))
        {
 
            if (2 !== strlen($matches['languageCode']) && false !== ($language = $this->isSupportedLanguage($matches['languageCode'])))
            {
                $this->activeLanguage = $language;  
            }
            else
            {
 
                $this->activeLanguage = $this->guessClientLanguage();
 
                $redirectUrl = "{$matches['protocol']}{$this->activeLanguage['code']}.{$matches['domain']}";
 
            }
 
        }
        else
        {
            throw new CException("Unable to parse host info - please request this page with a domain (eg http://example.com/) instead of an ip-address!");
        }
 
        Yii::app()->setLanguage($this->activeLanguage['code']);
 
        Yii::app()->urlManager->rules = include("{$this->urlRulesPath}/{$this->activeLanguage['code']}.php");
 
        if (false !== Yii::app()->urlManager->cacheID && null !== ($cache = Yii::app()->getComponent(Yii::app()->urlManager->cacheID)))
        {
            $keyPrefix = $cache->keyPrefix;
            $cache->keyPrefix = "{$keyPrefix}.{$this->activeLanguage['code']}";
            Yii::app()->urlManager->init();
            $cache->keyPrefix = $keyPrefix;                 
        }
        else
        {
            Yii::app()->urlManager->init();
        }
 
        if (true === isset($redirectUrl))
        {
            Yii::app()->request->redirect($redirectUrl);
        }
 
    }
 
    public function guessClientLanguage()
    {
 
        if (false === isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) || false === (bool)preg_match("/([a-z]{2}+)[-_][A-z]{2}+/", $_SERVER['HTTP_ACCEPT_LANGUAGE'], $match) || false === ($language = $this->isSupportedLanguage($match[1])))
        {
            if (false === ($language = $this->getFallbackLanguage()))
            {
                throw new CException("Unable to return the fallback language - please set it in config!");
            }
        }
 
        return $language;
 
    }
 
    public function getFallbackLanguage()
    {
 
        foreach ($this->supportedLanguages as $supportedLanguage)
        {
            if (true === isset($supportedLanguage['fallback']) && true === $supportedLanguage['fallback'])
            {
                return $supportedLanguage;
            }
        }
 
        return false;
 
    }
 
    public function isSupportedLanguage($languageCode)
    {
 
        foreach ($this->supportedLanguages as $supportedLanguage)
        {
            if ($supportedLanguage['code'] === $languageCode)
            {
                return $supportedLanguage;
            }
        }
 
        return false;
 
    }
 
}
 
?>

В основной конфигурации мы добавим этот компонент в массив предварительной загрузки:

<?php
...
 
preload => array('log', 'i18n'),
 
...
?>

Еще нам требуется добавить компонент в тело конфигурационнго файла, с описанием основных параметров работы:

<?php
...
 
'components' => array(
  'i18n' => array(
    'class' => 'I18n',
    'urlRulesPath' => dirname(__FILE__) . '/i18n/urlRules',
    'supportedLanguages' => array(
      array('code' => 'en', 'name' => 'english', 'fallback' => true),
      array('code' => 'de', 'name' => 'german'),
    ),
  ),
),
 
...
?>

Файлы правил маршрутизации (protected/i18n/urlRules/*.php ) должны иметь примерно следующий формат:

<?php
 
/* ../protected/i18n/urlRules/de.php */
 
return array(
  'kontakt' => 'site/contact',
)

Вывод

Не стесняйтесь поделиться своими мыслями и замечаниями! Спасибо.

 



Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
Другие yii статьи:

  1. Первым делом необходимо объявить переменную в моделе для хранения имени файла . Также стоит незабыть указать правило валидации (в ... "Как загружать файлы с помощью модели?"

  2. Эта статья устарела т.к. была написана для yii версии 1.0.х; Если вы используете более новую версию - у вас могут ... "Урок 4 : Создаем отдельную страницу для постов (тем)"

  3. Серия рецентов "By Example" пытается предоставить для разработчиков примеры использования самых распостраненных действий в Yii. Учимся использовать CHtml::dropDownList() на ... ""By Example" : CHtml - dropDownList()"

[guest] Гость

Было сказано: Пятница, 22 Январь 2010

Было бы не плохо правила брать из базы

NickSun

Было сказано: Пятница, 18 Июнь 2010

Че-то не могу понять куда это писать:

<?php
...

preload => array('log', 'i18n'),

...
?>

NickSun

Было сказано: Пятница, 18 Июнь 2010

Разобрался уже. В config/main.php нужно

[guest] Maxx

Было сказано: Суббота, 19 Июнь 2010

угу

NickSun

Было сказано: Понедельник, 21 Июнь 2010

Кстати походу косяк в кукбуке :)
Сначала регуляркой ищем два символа языка: (?<languageCode>[a-z]{2}), а потом перед тем как поменять язык проверяем чтоб не дай Бог язык оказался длинной в 2 символа: if (2 !== strlen($matches['languageCode']) ...
Может все-таки нужно 2 == strlen($matches['languageCode']) ?

[guest] kitt

Было сказано: Понедельник, 12 Июль 2010

Как насчет национальных символов в UTF8 в урлах и правилах к ним?
Что то вроде:


...

'components' => array(
'urlManager' => array(
'rules' => array(
'Контакты' => 'site/contact',
'Дневники/<username:\w+>'=>'diary/user'
),
),
),

...



У меня preg_match('/^\w+$/u','РусскиеБуквы') возращает 0.
И соотвественно компоненты CUrlManager и CUrlRule, завязанные на них не отрабатывают с русскими буквами в УРЛах.

Ось убунту 10.04, apache2+mod_php, системная локаль utf8. Уже не знаю куда копать(((
Если кто вкурсе - черканите на xzombi@ya.ru

[guest] zolter

Было сказано: Вторник, 13 Июль 2010

У меня

'Контакты' => 'site/contact',

проходит вполне нормально

[guest] DropSQL

Было сказано: Четверг, 12 Август 2010

У меня preg_match('/^\w+$/u','РусскиеБуквы') возращает 0.

Потому что \w+ - содержит только латиницу.

[guest] butch

Было сказано: Четверг, 09 Сентябрь 2010

'РусскиеБуквы' должны быть в utf8 кодировке, тогда php \w будет воспринимать правильно

[guest] butch

Было сказано: Четверг, 09 Сентябрь 2010

Только что проверил :) действительно \w работает только с латиницей.

Для Unicode \w нужно заменить можно на \p{L}

preg_match("/^\p{L}+$/u", "РусскиеБуквы")

http://www.php.net/manual/en/regexp.reference.unicode.php

[guest] Maxx

Было сказано: Четверг, 09 Сентябрь 2010

О пасибки

[guest] Гость

Было сказано: Понедельник, 07 Февраль 2011

Sposibo

[guest] Гость

Было сказано: Среда, 04 Сентябрь 2013

Оставить комментарий


Код:
Имя: