Добавление префикса к каждому URL в CakePHP

Какой самый простой способ добавить префикс к каждому URL-адресу в CakePHP, например, языковой параметр?

http://example.com/en/controller/action
http://example.com/ru/admin/controller/action

Он должен работать с «настоящими» префиксами, такими как admin, и в идеале голый URL-адрес /controller/action может быть перенаправлен на /DEFAULT-LANGUAGE/controller/action.

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

Так что вопрос двоякий:

  • What's the best way to structure Routes, so the language parameter is implicitly included by default without having to be specified for each newly defined Route?
    • Router::connect('/:controller/:action/*', ...) should implicitly include the prefix.
    • Параметр должен быть доступен в $this->params['lang'] или где-то подобном для оценки в AppController::beforeFilter().
  • How to get Router::url() to automatically include the prefix in the URL, if not explicitly specified?
    • Router::url(array('controller' => 'foo', 'action' => 'bar')) should return /en/foo/bar
    • Поскольку Controller::redirect(), Form::create() или даже Router::url() напрямую должны иметь одинаковое поведение, переопределение каждой отдельной функции на самом деле не вариант. Html::image(), например, должен создавать URL-адрес без префикса.

Следующие методы, кажется, вызывают Router::url.

  • Controller::redirect
  • Controller::flash
  • Dispatcher::__extractParams через Object::requestAction
  • Helper::url
  • JsHelper::load_
  • JsHelper::redirect_
  • View::uuid, но только для генерации хэша

Из них кажется, что методы Controller и Helper должны быть переопределены, я мог бы жить без JsHelper. Моя идея заключалась бы в том, чтобы написать общую функцию в AppController или, может быть, только в bootstrap.php для обработки вставки параметров. Переопределенные методы Controller и Helper будут использовать эту функцию, как и я, если бы захотел вручную вызвать Router::url. Будет ли этого достаточно?


person deceze♦    schedule 25.11.2009    source источник


Ответы (3)


rchavik из IRC предложил эту ссылку: localization/" rel="noreferrer">Переключение языка на основе URL-адреса CakePHP для интернационализации и локализации i18n и l10n

В общем, кажется, что переопределение Helper::url может быть решением.

person Joe Phillips    schedule 25.11.2009
comment
И, согласно комментариям, переопределение AppController::url сделает это для контроллеров. Пока все хорошо, есть что-нибудь еще? Другие части вызывают Router::url напрямую? - person deceze♦; 25.11.2009

Это, по сути, весь код, который я реализовал для решения этой проблемы в конце (по крайней мере, я думаю, что это все ;-)):

/config/bootstrap.php

define('DEFAULT_LANGUAGE', 'jpn');

if (!function_exists('router_url_language')) {
    function router_url_language($url) {
        if ($lang = Configure::read('Config.language')) {
            if (is_array($url)) {
                if (!isset($url['language'])) {
                    $url['language'] = $lang;
                }
                if ($url['language'] == DEFAULT_LANGUAGE) {
                    unset($url['language']);
                }
            } else if ($url == '/' && $lang !== DEFAULT_LANGUAGE) {
                $url.= $lang;
            }
        }

        return $url;
    }
}

/config/core.php

Configure::write('Config.language', 'jpn');

/app_helper.php

class AppHelper extends Helper {

    public function url($url = null, $full = false) {
        return parent::url(router_url_language($url), $full);
    }

}

/app_controller.php

class AppController extends Controller {

    public function beforeFilter() {
        if (isset($this->params['language'])) {
            Configure::write('Config.language', $this->params['language']);
        }
    }

    public function redirect($url, $status = null, $exit = true) {
        parent::redirect(router_url_language($url), $status, $exit);
    }

    public function flash($message, $url, $pause = 1) {
        parent::flash($message, router_url_language($url), $pause);
    }

}

/config/routes.php

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
Router::connect('/:language/', array('controller' => 'pages', 'action' => 'display', 'home'), array('language' => '[a-z]{3}'));
Router::connect('/:language/pages/*', array('controller' => 'pages', 'action' => 'display'), array('language' => '[a-z]{3}'));
Router::connect('/:language/:controller/:action/*', array(), array('language' => '[a-z]{3}'));

Это позволяет URL-адресам по умолчанию, таким как /controller/action, использовать язык по умолчанию (JPN в моем случае), а URL-адресам, таким как /eng/controller/action, использовать альтернативный язык. Эту логику можно довольно легко изменить в функции router_url_language().

Чтобы это работало, мне также нужно определить два маршрута для каждого маршрута, один с параметром /:language/, а другой без него. По крайней мере, я не мог понять, как это сделать по-другому.

person deceze♦    schedule 10.12.2009
comment
Отличный ответ, это действительно помогло мне. - person gacrux; 16.12.2010
comment
@gacrux Обратите внимание, что это должно быть намного проще в Cake 1.3, который включает настраиваемые префиксы. Вышесказанное относится к Cake 1.2, который знал только префикс one. :) - person deceze♦; 16.12.2010

Более простым способом может быть сохранение выбранного языка в файле cookie, а затем не нужно переписывать все URL-адреса. Вы также можете автоматически определить язык браузера пользователя.

Однако маловероятно, что поисковые системы будут использовать различные языки, и вы также потеряете язык, если кто-то попытается поделиться ссылкой.

Но мне нравится полное решение, которое вы опубликовали, очень всеобъемлющее, спасибо. :-)

person Simon East    schedule 28.09.2012
comment
Проблема с языковыми переключателями без URL связана с поисковыми системами. Они будут когда-либо индексировать только один язык или получат кучу своих трусиков, если увидят разный контент по одному и тому же URL-адресу. Это действительно работает только для частных (только для входа) областей вашего сайта. - person deceze♦; 28.09.2012
comment
О, да, это хороший момент. Я обновлю свой ответ, чтобы отметить это. - person Simon East; 28.09.2012