我正在尝试实现检测用户首选语言的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')中的值来定义请求语言环境吗?这是正确的行为吗?我怎么能做到这一点?
答案 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开始,语言环境不存储在会话中,而是存储在请求中。你可以做些什么来解决它:
编辑LocaleListener以将语言环境存储在请求中:
if (!$request->attributes->has('locale')) {
$request->setLocale(...);
}