Symfony2 неправильное обнаружение локали?
Следуя руководству Symfony2 о translation, я обнаружил, что неверный локаль из заголовков http (хранится в $this->get('session')->getLocale()
) неверен (отправлено it, выведенный ru):
Host localhost User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv: 7.0.1) Gecko/20100101 Firefox/7.0.1 Принять текст /html, application/xhtml + xml, application/xml; q = 0.9,/; q = 0.8 Accept-Language it-it, it; q = 0.8, en-us; q = 0.5, en; q = 0.3
Это нормальное поведение? Или я должен что-то сделать, чтобы получить локализацию из коробки?
Ответы
Ответ 1
Сегодня я более подробно посмотрел на код, потому что у меня была та же проблема, что и у вас, и кажется, что язык исходит от Session::getLocale()
. Но Symfony2 никогда не вызывает Session::setLocale()
и устанавливает член locale
объекта Session
. Поиск google для "symfony2 session setlocale" приводит к этим § документации
Итак, я закончил работу над этой строкой над контроллером, над которым работал, и он работал:
$this->getRequest()->getSession()->setLocale(
$this->getRequest()->getPreferredLanguage());
Теперь я предполагаю, что это неприемлемо, потому что вы не собираетесь добавлять это поверх каждого контроллера. Кроме того, это не должно выполняться для каждого запроса, это должно быть сделано только для первого, когда у пользователя нет сеанса. Если кто-нибудь знает, как это сделать, не стесняйтесь редактировать этот ответ.
Ответ 2
для HTTP-Standard вы должны использовать другой 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'));
}
если вам нужно сделать это для любой страницы, вам в основном нужно будет сделать то же самое, но внутри Listener для kernel.request
-Event. Чтобы быть надежно вызванным после того, как этот маршрут был выполнен, вы должны установить 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));
}
}
P.S. я не совсем уверен, что этот код действительно работает, но он должен дать общее представление о том, как это можно сделать.
Ответ 3
Вы можете зарегистрировать прослушиватель, как показано ниже:
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);
}
}
(gist)
Сразу после этапа настройки рамочного сеанса:
<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>
(gist)
Ответ 4
Я написал 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);
}
}