Symfony2语言环境检测:不考虑会话中的_locale

时间:2013-05-03 02:51:28

标签: symfony localization translation locale

我正在尝试实现检测用户首选语言的LocaleListener(考虑Accept-Language标头)并将其存储在会话中以避免每次请求都检查它。我已经开发了下面的代码来实现这个目标:

public function onKernelRequest(GetResponseEvent $event) {
    $request = $event->getRequest();

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

    $preferredLocale = $request->getPreferredLanguage($this->availableLocales);

    if ($this->container->has('session')) {
        $session = $this->container->get('session');
        if (!$session->has('_locale')) {
            $session->set('_locale', $preferredLocale);
        }
    } else {
        $request->setLocale($preferredLocale);
    }
}

代码正在运行,首选语言存储在会话中,但symfony不考虑存储在会话中的语言环境来翻译字符串。就我而言,我的首选语言是'pt_BR',当我逃跑时:

{{ app.request.locale }}

symfony正在逃避'en'。 symfony不应该考虑存储在session('_ locale')中的值来定义请求语言环境吗?这是正确的行为吗?我怎么能做到这一点?

2 个答案:

答案 0 :(得分:15)

这是一个工作语言监听器。第二种方法是将语言更改为用户选择的用户首选项。如果您的用户无法定义其语言,则可以省略此方法。

<?php

namespace Acme\UserBundle\EventListener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class LanguageListener
{
    private $session;

    public function setSession(Session $session)
    {
        $this->session = $session;
    }

    /**
     * kernel.request event. If a guest user doesn't have an opened session, locale is equal to
     * "undefined" as configured by default in parameters.ini. If so, set as a locale the user's
     * preferred language.
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     */
    public function setLocaleForUnauthenticatedUser(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }
        $request = $event->getRequest();
        if ('undefined' == $request->getLocale()) {
            if ($locale = $request->getSession()->get('_locale')) {
                $request->setLocale($locale);
            } else {
                $request->setLocale($request->getPreferredLanguage());
            }
        }
    }

    /**
     * security.interactive_login event. If a user chose a language in preferences, it would be set,
     * if not, a locale that was set by setLocaleForUnauthenticatedUser remains.
     *
     * @param \Symfony\Component\Security\Http\Event\InteractiveLoginEvent $event
     */
    public function setLocaleForAuthenticatedUser(InteractiveLoginEvent $event)
    {
        $user = $event->getAuthenticationToken()->getUser();

        if ($lang = $user->getLanguage()) {
            $this->session->set('_locale', $lang);
        }
    }
}

在您的services.yml中:

services:
    acme.language.interactive_login_listener:
        class: Acme\UserBundle\EventListener\LanguageListener
        calls:
            - [ setSession, [@session] ]
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: setLocaleForAuthenticatedUser }

    acme.language.kernel_request_listener:
        class: Acme\UserBundle\EventListener\LanguageListener
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: setLocaleForUnauthenticatedUser }

哦,你必须在config.yml中定义一个未定义的fallback_language才能使它工作。

framework:
    translator:      { fallback: "undefined" }
    default_locale:  "en"

答案 1 :(得分:7)

从symfony 2.1开始,语言环境不存储在会话中,而是存储在请求中。你可以做些什么来解决它:

  • 恢复保存区域设置的旧方法。您可以在upgrade file
  • 中了解如何执行此操作
  • 编辑LocaleListener以将语言环境存储在请求中:

    if (!$request->attributes->has('locale')) {
        $request->setLocale(...);
    }