2009-11-25 60 views
20

向CakePHP中的每个URL(如语言参数)添加前缀的最简单方法是什么?向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,但仅用于一个散列生成

在这些似乎控制器和帮助器的方法将需要重写,我可以生活没有JsHelper。我的想法是在AppController中编写一个通用函数,或者可能只是在bootstrap.php中处理参数插入。重写的Controller和Helper方法将使用此函数,因为如果我想手动调用Router::url。这会足够吗?从IRC

回答

14

这是基本上所有我为了解决到底这个问题(至少我认为这是所有;-))代码:

/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在我的情况)以及像/eng/controller/action这样的URL来使用交替一种语言。这个逻辑可以在router_url_language()函数中很容易地改变。

对于这个工作我还需要定义为每个路由两条路线,一个包含/:language/参数,一个没有。至少我不知道如何做另一种方式。

+0

很好的答案,这真的帮助了我。 – gacrux 2010-12-16 03:25:45

+2

@gacrux请注意,这应该是蛋糕1.3复杂得多,其中包括可定制的前缀。上述内容适用于Cake 1.2,它只知道一个*前缀。 :) – deceze 2010-12-16 03:26:37

0

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

然而,搜索引擎不太可能拾取各种语言,你也就会失去了语言,如果有人试图分享链接。

但是爱你的贴,很全面的完整的解决方案,谢谢。 :-)

+1

用“URL-少”语言切换的问题是搜索引擎。他们只会索引单一语言,或者如果他们在同一个网址上看到不同的内容,他们就会将他们的内裤捆绑在一起。这只适用于您网站的私人(仅限登录)区域。 – deceze 2012-09-28 04:57:44

+0

哦,是的,这是一个很好的观点。我会更新我的答案,注意这一点。 – 2012-09-28 04:58:50