Reputation: 31
I'm trying to change the user locale with Symfony from a field "locale" in the database. I read the Symfony manual (how to sticky a session for example), but nothing works in my application. Translator still gets the default locale...
I created listeners, subscribers... to dynamically change the locale, but as they are loaded before the firewall listener, I'm unable to change the current value.
I tried to change the priority subscriber, but I lost the user entity. I tried to set locale request in controllers, but I think it's too late.
I don't want to add locales in URLs.
Here my subscriber - listener - code:
public function onKernelRequest(RequestEvent $event)
{
$user = $this->tokenStorage->getToken()->getUser();
$request = $event->getRequest();
$request->setLocale($user->getLocale());
}
In subscribers, I added:
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => [['onKernelRequest', 0]],
];
}
Here, my full code:
framework.yml:
default_locale: fr
services.yml:
parameters:
locale: 'fr'
app_locales: fr|en|
translation.yml:
framework:
default_locale: '%locale%'
translator:
paths:
- '%kernel.project_dir%/translations'
fallbacks:
- '%locale%'
LocaleSubscriber.php:
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleSubscriber implements EventSubscriberInterface
{
private $defaultLocale;
public function __construct($defaultLocale = 'en')
{
$this->defaultLocale = $defaultLocale;
}
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
if (!$request->hasPreviousSession()) {
return;
}
// try to see if the locale has been set as a _locale routing parameter
if ($locale = $request->attributes->get('_locale')) {
$request->getSession()->set('_locale', $locale);
} else {
// if no explicit locale has been set on this request, use one from the session
$request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
}
}
public static function getSubscribedEvents()
{
return [
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 20]],
];
}
}
UserLocaleSubscriber.php
// src/EventSubscriber/UserLocaleSubscriber.php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
/**
* Stores the locale of the user in the session after the
* login. This can be used by the LocaleSubscriber afterwards.
*/
class UserLocaleSubscriber implements EventSubscriberInterface
{
private $session;
public function __construct(SessionInterface $session)
{
$this->session = $session;
}
public function onInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
if (null !== $user->getLocale()) {
$this->session->set('_locale', $user->getLocale());
}
}
public static function getSubscribedEvents()
{
return [
SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin',
];
}
}
Ex controller annotation:
/**
* @Route("/user/locale", name="user_locale", requirements={"_locale" = "%app.locales%"})
* @Route("/{_locale}/user/locale", name="user_locale_locale", requirements={"_locale" = "%app.locales%"})
*/
Upvotes: -1
Views: 12116
Reputation: 19
debug:event kernel.request
.UserLocaleSubscriber
is executed right after the firewall listener.TranslatorInterface
and manually set the translator locale.// src/EventSubscriber/UserLocaleSubscriber.php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Stores the locale of the user in the session after the
* login. This can be used by the LocaleSubscriber afterwards.
*/
class UserLocaleSubscriber implements EventSubscriberInterface
{
private $session;
private $translator;
public function __construct(SessionInterface $session, TranslatorInterface $translator)
{
$this->session = $session;
$this->translator = $translator;
}
public function onInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
if (null !== $user->getLocale()) {
$this->translator->setLocale($user->getLocale());
}
}
public static function getSubscribedEvents()
{
return [
SecurityEvents::INTERACTIVE_LOGIN => ['onInteractiveLogin', 7]
];
}
}
Upvotes: 1
Reputation: 4144
It's hard to help without seeing the full code you are using.
Symfony has it's own LocaleListener as well. Make sure your's is executed first.
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 20]],
];
}
Upvotes: -2