如何操作用户的Locale

3.4 版本
维护中的版本

当前用户的locale被存在请求中,可以通过 Request 对象访问到:

1
2
3
4
5
6
use Symfony\Component\HttpFoundation\Request;
 
public function indexAction(Request $request)
{
    $locale = $request->getLocale();
}

要设置用户的locale,你可能希望创建一个自定义的事件监听,以便它在系统的其他部分(比如translator)需要它之前就被设置好:

1
2
3
4
5
6
7
public function onKernelRequest(GetResponseEvent $event)
{
    $request = $event->getRequest();
 
    // some logic to determine the $locale
    $request->setLocale($locale);
}

参考 把locale信息“粘连”到用户的Session周期中 以了解更多内容。

在控制器中使用 $request->setLocale() 来设置locale以便左右translator实在是太迟了。可以通过监听 (如上), URL (见下文) 或是直接对 translator 服务来调用 setLocale()

下文的 Locale 和 URL 小节有讲到通过路由来设置locale。

Locale和URL 

由于你可以把locale存到用户的session中,根据用户的locale,它可能会尝试使用相同的URL来显示不同语言的资源。例如,http://www.example.com/contact 可以对某个用户显示英语内容,但对另一个用户有显示法语的。不幸的是,这会粗暴破坏互联网的一个基本原则:即,特定的URL要对用户返回相同的资源,不管是什么(语种的)用户。进一步搞砸问题的是,哪个版本的内容可以被搜索引擎检索到?

一个很好的策略是,把locale包容到URL之中。通过使用一个特殊的 _locale 参数(parameter),该策略已为路由系统完整支持:

1
2
3
4
5
6
# app/config/routing.yml
contact:
    path:     /{_locale}/contact
    defaults: { _controller: AppBundle:Contact:index }
    requirements:
        _locale: en|fr|de
1
2
3
4
5
6
7
8
9
10
11
12
<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">
 
    <route id="contact" path="/{_locale}/contact">
        <default key="_controller">AppBundle:Contact:index</default>
        <requirement key="_locale">en|fr|de</requirement>
    </route>
</routes>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
 
$collection = new RouteCollection();
$collection->add('contact', new Route(
    '/{_locale}/contact',
    array(
        '_controller' => 'AppBundle:Contact:index',
    ),
    array(
        '_locale' => 'en|fr|de',
    )
));
 
return $collection;

当使用特殊的 _locale 路由参数时,匹配到的locale将 自动设置到Request对象中 然后可以透过 getLocale() 方法来取出。换言之,如果一个用户访问的URI是 /fr/contact,那么locale fr 将自动地被设置为当前请求的locale。

现在你可以使用locale来创建路由,用于程序中的其他需要翻译的页面。

参考 如何在路由中使用服务容器的参数 来了解如何避免在全部路由中写死 _locale 条件(requirement)。

设置默认的Locale 

若无法确定用户的locale怎么办?在框架中配置好 default_locale,即可确保用户在每一次请求中皆已被设置locale:

1
2
3
# app/config/config.yml
framework:
    default_locale: en
1
2
3
4
5
6
7
8
9
10
11
12
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
    <framework:config default-locale="en" />
</container>
1
2
3
4
// app/config/config.php
$container->loadFromExtension('framework', array(
    'default_locale' => 'en',
));

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)