CakePhp:基于URL的国际化

时间:2011-09-27 09:30:58

标签: php cakephp internationalization routes url-routing

我的国际化问题很小:

我希望有一些网址如下:http://mywebsite/eng/controller/action/params ...

我发现了http://nuts-and-bolts-of-cakephp.com/2008/11/28/cakephp-url-based-language-switching-for-i18n-and-l10n-internationalization-and-localization/

这大部分时间都很好用。但我有一个案例没有预期的结果。

当我使用$ this-> Html->链接命名参数时,我没有得到我的好结构,但像http://mywebsite/controller/action/paramX:aaa/paramxY:bbb/language:eng

我认为这是一个路由问题,但我无法弄清楚出了什么问题?

非常感谢

2 个答案:

答案 0 :(得分:0)

这是因为cakephp在routes.php中找不到与此链接对应的路由。换句话说,您必须在routes.php文件中定义此路由

Router::connect('/:language/:controller/:action/:paramX/:paramY');

设置完成后,$ this-> Html->链接会输出一个不错的网址

答案 1 :(得分:0)

我终于这样做了: 我创建了一个自定义的CakeRoute,在这个cakeRoute中,我覆盖了“match”url和_writeUrl方法。

现在每件事都像魅力一样:)

对于那些被路线类强调的人:

    <?php
class I18nRoute extends CakeRoute {
/**
 * Constructor for a Route
 * Add a regex condition on the lang param to be sure it matches the available langs
 *
 * @param string $template Template string with parameter placeholders
 * @param array $defaults Array of defaults for the route.
 * @param string $params Array of parameters and additional options for the Route
 * @return void
 * @access public
 */
    public function __construct($template, $defaults = array(), $options = array()) {
        //$defaults['language'] = Configure::read('Config.language');
        $options = array_merge((array)$options, array(
            'language' => join('|', Configure::read('Config.languages'))
        ));
        parent::__construct($template, $defaults, $options);
    }

/**
 * Attempt to match a url array.  If the url matches the route parameters + settings, then
 * return a generated string url.  If the url doesn't match the route parameters false will be returned.
 * This method handles the reverse routing or conversion of url arrays into string urls.
 *
 * @param array $url An array of parameters to check matching with.
 * @return mixed Either a string url for the parameters if they match or false.
 * @access public
 */
    public function match($url) {
        if (empty($url['language'])) {
            $url['language'] = Configure::read('Config.language');
        }

        if (!$this->compiled()) {
            $this->compile();
        }
        $defaults = $this->defaults;

        if (isset($defaults['prefix'])) {
            $url['prefix'] = $defaults['prefix'];
        }

        //check that all the key names are in the url
        $keyNames = array_flip($this->keys);
        if (array_intersect_key($keyNames, $url) != $keyNames) {
            return false;
        }

        $diffUnfiltered = Set::diff($url, $defaults);
        $diff = array();

        foreach ($diffUnfiltered as $key => $var) {
            if ($var === 0 || $var === '0' || !empty($var)) {
                $diff[$key] = $var;
            }
        }

        //if a not a greedy route, no extra params are allowed.
        if (!$this->_greedy && array_diff_key($diff, $keyNames) != array()) {
            return false;
        }

        //remove defaults that are also keys. They can cause match failures
        foreach ($this->keys as $key) {
            unset($defaults[$key]);
        }
        $filteredDefaults = array_filter($defaults);

        //if the difference between the url diff and defaults contains keys from defaults its not a match
        if (array_intersect_key($filteredDefaults, $diffUnfiltered) !== array()) {
            return false;
        }

        $passedArgsAndParams = array_diff_key($diff, $filteredDefaults, $keyNames);
        list($named, $params) = Router::getNamedElements($passedArgsAndParams, $url['controller'], $url['action']);

        //remove any pass params, they have numeric indexes, skip any params that are in the defaults
        $pass = array();
        $i = 0;
        while (isset($url[$i])) {
            if (!isset($diff[$i])) {
                $i++;
                continue;
            }
            $pass[] = $url[$i];
            unset($url[$i], $params[$i]);
            $i++;
        }
/*
        //still some left over parameters that weren't named or passed args, bail.
        //We don't want this behavior, we use most of args for the matching, and if we have more, we just allow them as parameters
        if (!empty($params)) {
            return false;
        }*/

        //check patterns for routed params
        if (!empty($this->options)) {
            foreach ($this->options as $key => $pattern) {
                if (array_key_exists($key, $url) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
                    return false;
                }
            }
        }
        return $this->_writeUrl(array_merge($url, compact('pass', 'named')));
    }

    function _writeUrl($params) {
        if (isset($params['prefix'], $params['action'])) {
            $params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
            unset($params['prefix']);
        }

        if (is_array($params['pass'])) {
            $params['pass'] = implode('/', $params['pass']);
        }

        $instance =& Router::getInstance();
        $separator = $instance->named['separator'];

        if (!empty($params['named']) && is_array($params['named'])) {
            $named = array();
            foreach ($params['named'] as $key => $value) {
                $named[] = $key . $separator . $value;
            }
            $params['pass'] = $params['pass'] . '/' . implode('/', $named);
        }
        $out = $this->template;

        $search = $replace = array();
        foreach ($this->keys as $key) {
            $string = null;
            if (isset($params[$key])) {
                $string = $params[$key];
            } elseif (strpos($out, $key) != strlen($out) - strlen($key)) {
                $key .= '/';
            }
            $search[] = ':' . $key;
            $replace[] = $string;
        }
        $out = str_replace($search, $replace, $out);

        if (strpos($this->template, '*')) {
            $out = str_replace('*', $params['pass'], $out);
        }
        $out = str_replace('//', '/', $out);
        //Modified part: allows us to print unused parameters
        foreach($params as $key => $value){
            $found = false;
            foreach($replace as $repValue){
                if($value==$repValue){
                    $found=true;
                    break;
                }
            }
            if(!$found && !empty($value)){
                $out.="/$key:$value";
            }
        }
        return $out;
    }
}

你可以设置这样的路线:

Router::connect('/:language/:controller/*', array(), array('routeClass' => 'I18nRoute'));