DbHelp.ru
Маленький Yii блог
Комментарии
Wa1deMar: У меня при регестрации выбивает ошибку Пользователь н...
Гость: а где исходники? http://www.yii.dbhelp.ru/files/step8/blog-8.zip
Гость: так я выставил N=1 и получается что роботу надо раз 10 про...
r-bezhenar: Не знал куда написать. Подскажите пожалуйста как лучш...
TranceSmile: Конечно так удобней. Чем выводить всю модель.



Сервер 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. Последние пару дней я проводил небольшие технические работы на блоге, но всё не было времени запостить тему про всё что ... "Обновление на DbHelp.ru"

  2. Давайте сегодня немного поработаем со всевозможными настройками которые нам предоставляет стандартный класс для работы с капчей (CCaptcha). next Давайте для начала ... "Изменяем нашу каптчу (captcha)"

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

[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

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


Код:
Имя: