【问题标题】:Zend Framework URL based translation routesZend Framework 基于 URL 的翻译路由
【发布时间】:2012-08-29 13:52:53
【问题描述】:

我正在尝试在 Zend Framework 中实现基于 URL 的翻译,以便我的网站对 SEO 友好。这意味着除了默认路由之外,我还需要像下面这样的 URL。

zend.local/en/module
zend.local/en/controller
zend.local/en/module/controller
zend.local/en/controller/action

以上是我现在遇到的问题;其余的应该没问题。我添加了一个控制器插件,它获取 lang 参数,以便我可以在 preDispatch 方法中设置语言环境和翻译对象。以下是我的一些路线(存储在 .ini 文件中):

; Language + module
; Language + controller
resources.router.routes.lang1.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.lang1.route = "(^[a-zA-Z]{2})/(\w+$)"
resources.router.routes.lang1.defaults.controller = index
resources.router.routes.lang1.defaults.action = index
resources.router.routes.lang1.map.1 = "lang"
resources.router.routes.lang1.map.2 = "module"


; Language + module + controller
; Language + controller + action
resources.router.routes.lang2.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.lang2.route = "(^[a-zA-Z]{2})/(\w+)/(\w+$)"
resources.router.routes.lang2.defaults.module = default
resources.router.routes.lang2.defaults.action = index
resources.router.routes.lang2.map.1 = "lang"
resources.router.routes.lang2.map.2 = "controller"
resources.router.routes.lang2.map.3 = "action"

正如 cmets 所指出的,多个 URL 结构将匹配相同的路由,这使我的应用程序无法正确解释格式。例如,以下两个 URL 将被 lang1 路由匹配:

zend.local/en/mymodule
zend.local/en/mycontroller

在第一个 URL 中,“mymodule”用作模块名称,这是正确的。但是,在第二个 URL 中,“mycontroller”用作模块名称,这不是我想要的。在这里,我希望它使用“默认”模块和“mycontroller”作为控制器。这同样适用于之前的lang2 路由。所以我不知道如何区分URL是/en/module还是/en/controller的结构。

为了解决这个问题,我在我的控制器插件中尝试了以下代码。

// Get module names as array
$dirs = Zend_Controller_Front::getInstance()->getControllerDirectory();
$modules = array_keys($dirs);

// Module variable contains a module that does not exist
if (!in_array($request->getModuleName(), $modules)) {
   // Try to use it as controller name instead
   $request->setControllerName($request->getModuleName());
   $request->setModuleName('default');
}

这在我测试的场景中运行良好,但是我必须做一些类似的事情来使lang2 路由工作(这可能涉及扫描目录以获取控制器列表)。这似乎是一个糟糕的解决方案,所以如果可能的话,我很想只用路由(或不那么“hacky”的简单代码)来完成所有这些。例如,我可以在每次我想要/en/controller 的时候制作路线,但这是一种我宁愿不采用的折衷方案。所以,如果有人知道如何解决这个问题,或者知道另一种方法来完成同样的事情,我会全力以赴!

【问题讨论】:

  • URI 中总是有 lang 吗?我的意思是,没有像 localhost/module/controller = deafult-lang = en 这样的默认语言
  • @Keyne 如果 URL 中未指定语言,则将在我的控制器插件中设置默认语言。在这种情况下,将使用默认路由,并且一切正常。
  • 我已经发布了答案,但我不确定您的 lang2 路线。在我的回答中,我刚刚在一个路由中添加了 lang 部分,并让默认模块路由完成它的工作。如果我做对了,请告诉我。

标签: php zend-framework url-routing zend-translate


【解决方案1】:

我在这里重现了您的问题并提出了以下内容(但不使用配置文件):

路由器

/**
 * Initializes the router
 * @return Zend_Controller_Router_Interface
 */
protected function _initRouter() {
    $locale = Zend_Registry::get('Zend_Locale');

    $routeLang = new Zend_Controller_Router_Route(
        ':lang',
        array(
        'lang' => $locale->getLanguage()
        ),
        array('lang' => '[a-z]{2}_?([a-z]{2})?')
    );

    $frontController  = Zend_Controller_Front::getInstance();
    $router = $frontController->getRouter();

    // Instantiate default module route
    $routeDefault = new Zend_Controller_Router_Route_Module(
        array(),
        $frontController->getDispatcher(),
        $frontController->getRequest()
    );

    // Chain it with language route
    $routeLangDefault = $routeLang->chain($routeDefault);

    // Add both language route chained with default route and
    // plain language route
    $router->addRoute('default', $routeLangDefault);

    // Register plugin to handle language changes
    $frontController->registerPlugin(new Plugin_Language());

    return $router;
}

插件

/**
 * Language controller plugin
 */
class Plugin_Language extends Zend_Controller_Plugin_Abstract
{
    /**
     * @var array The available languages
     */
    private $languages = array('en', 'pt');

    /**
     * Check the URI before starting the route process
     * @param Zend_Controller_Request_Abstract $request
     */
    public function routeStartup(Zend_Controller_Request_Abstract $request)
    {
        $translate = Zend_Registry::get('Zend_Translate');
        $lang = $translate->getLocale();

        // Extracts the URI (part of the URL after the project public folder)
        $uri = str_replace($request->getBaseUrl() . '/', '', $request->getRequestUri());
        $langParam = substr($uri, 0, 3);

        // Fix: Checks if the language was specified (if not, set it on the URI)
        if((isset($langParam[2]) && $langParam[2] !== '/') || !in_array(substr($langParam, 0, 2), $this->languages)) { {
            $request->setRequestUri($request->getBaseUrl() . '/' . $lang . "/" . $uri);
            $request->setParam('lang', $lang);
        }
    }
}

基本上,在模块默认路由中应用语言设置的路由链。作为修复,我们确保 URI 将包含用户遗漏的语言。

您需要调整它,因为我使用的是Zend_Registry::get('Zend_Locale')Zend_Registry::get('Zend_Translate')。将其更改为应用上的实际键。

至于 lang 路线:[a-z]{2}_?([a-z]{2})? 它将允许像我这样的语言:pt_BR

让我知道它是否对你有用。

【讨论】:

  • 感谢您的回答。我希望你不介意我在 pastebin 上写了我的评论;我发现不可能用这么少的字符做出适当的解释。 Please see my comment here.
  • 没问题,我已经读过了。我们在 url 中包含语言参数的部分(如果未指定)对最终用户是透明的。它就好像它是可选的一样(我们需要它以便它可以工作)。用户不会看到它被注入,浏览器上的 URL 将保持不变。 IIRC,只有两个缺失的部分:一个是覆盖 Zend_Locale 语言,另一个是将此代码“翻译”成配置文件。明白了吗?
  • 这里似乎一切正常。我会弄清楚如何将其放入配置文件并尽快发布。
  • 我曾经有简单的自定义路由,例如/register,默认为/default/user/register。这些路由存储在配置文件中。但是,随着新的语言路线到位,这不再起作用。我怀疑它与加载路线的顺序有关。在您的路由之后在引导程序中添加路由将使其工作如果我将其更改为/:lang/register,要求为'lang' => '[a-z]{2}_?([a-z]{2})?'(因为现在所有请求都将具有一种语言)。关于如何避免我的所有路线和使用配置的任何想法?
  • 你做到了吗?还在寻求帮助?
猜你喜欢
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
  • 2012-02-22
相关资源
最近更新 更多