Symfony2错误的区域设置检测?

时间:2011-10-05 02:31:12

标签: symfony localization translation

关于translation的Symfony2指南后,我发现来自http标头的推断区域设置(存储在$this->get('session')->getLocale()中)是错误的(发送,推断 en ):

  

主机localhost用户代理Mozilla / 5.0(Windows NT 6.1; WOW64;   rv:7.0.1)Gecko / 20100101 Firefox / 7.0.1   接受text / html,application / xhtml + xml,application / xml; q = 0.9, / ; q = 0.8   接受语言it-it,it; q = 0.8,en-us; q = 0.5,en; q = 0.3

这是正常行为吗?或者我应该设置一些东西,以使本地化开箱即用?

4 个答案:

答案 0 :(得分:7)

我今天更仔细地查看了代码,因为我遇到了与您相同的问题,而且该语言似乎来自Session::getLocale()。但Symfony2从不调用Session::setLocale(),并设置locale对象的Session成员。谷歌搜索“symfony2 session setlocale”会导致this § of the documentation

所以我最终将这一行放在我正在处理的控制器之上,并且它起作用了:

$this->getRequest()->getSession()->setLocale(
    $this->getRequest()->getPreferredLanguage());

现在我想这是不可接受的,因为你不会在每个控制器的顶部添加它。此外,这不应该针对每个请求执行,只应在第一个请求时完成,此时用户还没有会话。如果有人知道该怎么做,请随时编辑这个答案。

答案 1 :(得分:4)

根据HTTP-Standard,您应该为每个翻译版本的页面使用不同的URL。剩下的是一个简单的操作,它将从请求中推断出最佳使用的区域设置并重定向到相应的页面:

/**
 * @Route("/")
 */
public function localeRedirectAction() {
    /* @var $request \Symfony\Component\HttpFoundation\Request */
    /* @var $session \Symfony\Component\HttpFoundation\Session */
    $req = $this->getRequest();
    $session = $this->get('session');

    $session->setLocale($req->getPreferredLanguage(array('de', 'en')));

    return $this->redirect($this->generateUrl('home'));
}

如果您需要为任何页面执行此操作,您基本上需要执行相同操作,但在kernel.request - 事件的监听器中。为了在路由匹配器完成它之后可靠地调用它,你应该将监听器的priority设置为值< 0:

# services.yml
services:
  my_locale_listener:
    class: Namespace\LocaleListener
    tags: [{ name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: -255 }]
    arguments: [ @service_container, [ 'en', 'fr', 'de', 'es', 'it' ] ]

听众会看起来像这样:

class LocaleListener {
    public function __construct($container, $availableLocales) {
        $this->container = $container;
        $this->availableLocales = $availableLocales;
    }

    public function onKernelRequest(GetResponseEvent $e) {
        $req = $e->getRequest();
        $locale = $req->getPreferredLanguage($this->availableLocales);

        // generate a new URL from the current route-name and -params, overwriting
        // the current locale
        $routeName = $req->attributes->get('_route');
        $routeParams = array_merge($req->attributes->all(), array('_locale' => $locale));
        $localizedUrl = $this->container->get('router')->generateUrl($routeName, $routeParams);

        $e->setResponse(new RedirectResponse($localizedUrl));
    }
}

P.S。我并不完全相信这段代码确实有效,但它应该就如何做到这一点给出一个基本的想法。

答案 2 :(得分:1)

您可以注册听众,如下所示:

use Symfony\Component\DependencyInjection\ContainerInterface;

use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;

class LocaleListener
{
    private $container;
    private $defaultLocale;

    public function __construct(ContainerInterface $container, $defaultLocale = 'nl')
    {
        $this->container = $container;
        $this->defaultLocale = $defaultLocale;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }

        if (!$this->container->has('session')) {
            return;
        }

        $session = $this->container->get('session');
        $session->setLocale($this->defaultLocale);
    }
}

gist

在框架会话设置阶段之后:

<service id="my.event_listener.locale_listener" class="MyBundle\MyEventListener\LocaleListener">
    <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="100" />
    <argument type="service" id="service_container" />
</service>

gist

答案 3 :(得分:0)

我编写了一个LocaleListener,它不会将您重定向到特定于语言环境的URL,但它会为您设置语言环境设置;)

services.yml中的代码

services:
    acme.demobundle.listener.request:
        class: Namespace\LocaleListener
        tags: [{ name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: -255 }]
        arguments: [ @service_container, [ 'en', 'fr', 'de', 'it', 'es' ] ]

和实际的监听器:

class LocaleListener
{
    protected $container;
    protected $availableLocales;

    public function __construct(\Symfony\Component\DependencyInjection\Container $container, $availableLocales) {
        $this->container = $container;
        $this->availableLocales = $availableLocales;
    }

    public function onKernelRequest(GetResponseEvent $e) {
        $req = $e->getRequest();
        $locale = $req->getPreferredLanguage($this->availableLocales);
        $session = $this->container->get('session');
        $session->setLocale($locale);
    }
}