Symfony2错误的现场检测?

Symfony2错误的现场检测?,symfony,localization,translation,Symfony,Localization,Translation,根据Symfony2指南,我发现从http头推断出的区域设置(存储在$this->get('session')->getLocale())是错误的(发送it,推断en): 主机本地主机用户代理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 接受语言吧,它吧;q=0.8,在美国

根据Symfony2指南,我发现从http头推断出的区域设置(存储在
$this->get('session')->getLocale()
)是错误的(发送it,推断en):

主机本地主机用户代理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 接受语言吧,它吧;q=0.8,在美国;q=0.5,en;q=0.3


这是正常的行为吗?或者我应该设置一些东西来让本地化工作开箱即用吗?

我今天更彻底地研究了代码,因为我遇到了与您相同的问题,而且语言似乎来自
会话::getLocale()
。但是Symfony2从不调用
Session::setLocale()
,而是设置
Session
对象的
locale
成员。谷歌搜索“symfony2会话setlocale”会导致

所以我把这条线放在我正在工作的控制器上,它起作用了:

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

现在我想这是不可接受的,因为你不会把它添加到每个控制器上。另外,不应该对每个请求都这样做,只应该在用户还没有会话时对第一个请求这样做。如果有人知道如何做到这一点,请随意编辑此答案。

您可以像下面这样注册听众:

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);
    }
}
()

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

<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>


)

根据HTTP标准,您应该为页面的每个翻译版本使用不同的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'));
}
如果需要对任何页面执行此操作,基本上也需要执行相同的操作,但要在
内核.request
-事件的侦听器中执行。为了在路由匹配器完成工作后可靠地调用,您应该将侦听器的
优先级设置为<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));
    }
}

顺便说一句,我并不完全相信这段代码是否真的有效,但它应该给出如何实现这一点的基本想法。

我编写了一个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);
    }
}

我找到了一个名为
Symfony\Component\HttpFoundation\Request::getPreferredLanguage()
的方法,如果该方法有效,则应调用该方法,但在代码中找不到对此函数的任何调用。我认为你应该提交一份错误报告。@greg0ire如果我不确定这是错误的行为,我就不能报告错误……你永远不能100%确定,因为这没有记录在案,报告错误似乎没有那么糟糕。另外,你肯定会得到你的问题的答案(也是一个好答案)。别害羞+对于你的问题,这是正确的行为。默认区域设置是在config.yml中指定的,而不是由浏览器发送的。实际上,您可以修改它以获取请求对象并使用getPreferredLocale方法,但我喜欢这个想法。