遵循有关 translation 的 Symfony2 指南,我发现从 http 标头推断的语言环境(存储在
$this->get('session')->getLocale()
中)是错误的(发送 it,推断 en):
主机本地主机用户代理 Mozilla/5.0(Windows NT 6.1;WOW64; 版本:7.0.1) 壁虎/20100101 火狐/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
这是正常行为吗?或者我应该设置一些东西以便本地化开箱即用?
我今天更彻底地研究了代码,因为我遇到了和你一样的问题,而且看来该语言来自
Session::getLocale()
。但 Symfony2 从不调用 Session::setLocale()
,而是设置 locale
对象的 Session
成员。谷歌搜索“symfony2 session setlocale”会导致文档的这§
所以我最终把这条线放在我正在处理的控制器顶部,并且它起作用了:
$this->getRequest()->getSession()->setLocale(
$this->getRequest()->getPreferredLanguage());
现在我想这是不可接受的,因为您不会将其添加到每个控制器之上。另外,不应对每个请求都执行此操作,而应仅在用户还没有会话时对第一个请求执行此操作。如果有人知道如何做到这一点,请随时编辑此答案。
根据 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'));
}
如果您需要对任何页面执行此操作,则基本上需要执行相同的操作,但要在
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));
}
}
附注我并不完全相信这段代码确实有效,但它应该给出如何完成此操作的基本想法。
您可以像下面这样注册监听器:
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>
(要点)
我编写了一个 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);
}
}