为 CakePHP 中的每个 URL 添加前缀

发布于 2024-08-12 11:50:09 字数 1650 浏览 4 评论 0原文

在 CakePHP 中向每个 URL 添加前缀(例如语言参数)的最简洁方法是什么?

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

它需要使用“真实”前缀,例如 admin,理想情况下,裸 URL /controller/action 可以重定向到 /DEFAULT-LANGUAGE/controller/action

它现在在我的改装应用程序中工作,但它是一种黑客,我需要在大多数链接中手动包含语言参数,这不好。

因此,问题是双重的:

  • 构造路由的最佳方法是什么,以便默认情况下隐式包含语言参数,而不必为每个新定义的路由指定语言参数?
    • Router::connect('/:controller/:action/*', ...) 应隐式包含前缀。
    • 该参数应位于 $this->params['lang'] 中或类似的位置,以便在 AppController::beforeFilter() 中进行计算。
  • 如果没有明确指定,如何让 Router::url() 自动在 URL 中包含前缀?
    • Router::url(array('controller' => 'foo', 'action' => 'bar')) 应返回 /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 一样。这足够了吗?

What's the cleanest way to add a prefix to every URL in CakePHP, like a language parameter?

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

It needs to work with "real" prefixes like admin, and ideally the bare URL /controller/action could be redirected to /DEFAULT-LANGUAGE/controller/action.

It's working in a retro-fitted application for me now, but it was kind of a hack, and I need to include the language parameter by hand in most links, which is not good.

So the question is twofold:

  • 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.
    • The parameter should be available in $this->params['lang'] or somewhere similar to be evaluated in 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
    • Since Controller::redirect(), Form::create() or even Router::url() directly need to have the same behavior, overriding every single function is not really an option. Html::image() for instance should produce a prefix-less URL though.

The following methods seem to call Router::url.

  • Controller::redirect
  • Controller::flash
  • Dispatcher::__extractParams via Object::requestAction
  • Helper::url
  • JsHelper::load_
  • JsHelper::redirect_
  • View::uuid, but only for a hash generation

Out of those it seems the Controller and Helper methods would need to be overridden, I could live without the JsHelper. My idea would be to write a general function in AppController or maybe just in bootstrap.php to handle the parameter insertion. The overridden Controller and Helper methods would use this function, as would I if I wanted to manually call Router::url. Would this be sufficient?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

做个少女永远怀春 2024-08-19 11:50:09

这基本上是我最终为解决这个问题而实现的所有代码(至少我认为这就是全部;-)):

/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< /strong>

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 使用默认语言(在我的例子中是日语),而像 /eng/controller/action 这样的 URL 则使用替代语言。这个逻辑可以在router_url_language()函数中很容易地改变。

为此,我还需要为每个路由定义两条路由,一条包含 /:language/ 参数,另一条不包含。至少我不知道如何以另一种方式做到这一点。

This is essentially all the code I implemented to solve this problem in the end (at least I think that's all ;-)):

/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}'));

This allows default URLs like /controller/action to use the default language (JPN in my case), and URLs like /eng/controller/action to use an alternative language. This logic can be changed pretty easily in the router_url_language() function.

For this to work I also need to define two routes for each route, one containing the /:language/ parameter and one without. At least I couldn't figure out how to do it another way.

指尖上的星空 2024-08-19 11:50:09

IRC 的 rchavik 建议使用此链接:CakePHP 基于 URL 的 i18n 和 l10n 国际化和本地化语言切换

一般来说,似乎覆盖 Helper::url 可能是解决方案。

rchavik from IRC suggested this link: CakePHP URL based language switching for i18n and l10n internationalization and localization

In general, it seems that overriding Helper::url might be the solution.

别靠近我心 2024-08-19 11:50:09

一种更简单的方法可能是将所选语言存储在 cookie 中,然后不必重写所有 URL。您还可以自动检测用户的浏览器语言。

但是,搜索引擎不太可能识别各种语言,并且如果有人尝试共享链接,您也会丢失该语言。

但喜欢您发布的完整解决方案,非常全面,谢谢。 :-)

An easier way might be to store the chosen language in a cookie and then not have to rewrite all the URLs. You could also potentially detect the user's browser language automatically.

However, search engines would be unlikely to pickup the various languages and you'd also lose the language if someone tried to share the link.

But love the full solution you posted, very comprehensive, thanks. :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文