6

我正在尝试实现一个 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') 中的值来定义请求语言环境吗?这是正确的行为吗?我怎样才能做到这一点?

4

2 回答 2

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"
于 2013-05-03T09:59:50.213 回答
7

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

  • 恢复保存语言环境的旧方法。您可以在升级文件中阅读如何执行此操作
  • 编辑 LocaleListener 以将语言环境存储在请求中:

    if (!$request->attributes->has('locale')) {
        $request->setLocale(...);
    }
    
于 2013-05-03T07:49:36.920 回答