Search code examples
symfonylocaleevent-listenersonata-user-bundle

User locale does not work at first request


My website is running Symfony, master version. So far, I was able to use the LocalListener logic from the website, with a slight difference due to code not being compatible with my version. (I think) I only simplified the onKernelRequest method this way:

public function onKernelRequest(GetResponseEvent $event)
{
    $request = $event->getRequest();
    if (!$request->hasPreviousSession()) {
        return;
    }

    if ($locale = $request->get('_locale')) {
        $request->getSession()->set('_locale', $locale);
    }
    $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
}

That way, I could put up a simple language selector on my page, using these paths, and the new language would apply at the first request. (it would not happen if I left the "else" condition)

Then I wanted to take account of the locale stored in user accounts, in case the user is logged in and has specified a locale in his or her profile. So I added this piece of code in the function :

public function onKernelRequest(GetResponseEvent $event)
{
    $request = $event->getRequest();
    if (!$request->hasPreviousSession()) {
        return;
    }

    $token = $this->container->get('security.context')->getToken();
    if (is_object($token)) {
    $user = $token->getUser();
    if (is_object($user)) {
        $userlocale = $user->getLocale();
        if ($userlocale) {
        $request->getSession()->set('_locale', $userlocale);
        $request->setLocale($userlocale);
        return;
        }
    }
}

    if ($locale = $request->get('_locale')) {
        $request->getSession()->set('_locale', $locale);
    }
    $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
}

(EDIT: sorry for poor indentation, somehow stackoverflow does not want to indent it properly...)

Basically it checks if a user is logged in, and if there is, if he or she has set a locale, and if they have, sets the locale to the user locale instead. Now this works, but... not instantly. Whenever I log in or change my locale in my profile, the next page I get to is still in the previously set locale. Only when I load a new page does it change its translations properly, and stays that way for the next requests.

So here is my question: is there something I am supposed to add to make this change occur on those post-login and post-profile-edit requests?


Solution

  • Well thanks to Elnur I decided to go back to my jms_i18n solution (see comments in Elnur's answer), and I found this question that helped me build my own solution. So I switched from an EventSubscriber extended class to a simple "unextended" class of my own. Here is the working code:

    <?php
    //src/myApp/MainBundle/EventListener/LocaleListener.php
    namespace myApp\MainBundle\EventListener;
    
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Symfony\Component\HttpKernel\HttpKernelInterface;
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Symfony\Component\HttpFoundation\Cookie;
    
    class LocaleListener
    {
      private $container;
    
      public function __construct(ContainerInterface $container)
      {
        $this->container = $container;
      }
    
      public function onKernelRequest(GetResponseEvent $event)
      {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
          return;
        }
        $request = $event->getRequest();
        if ($request->getRequestFormat() !== 'html') {
          return;
        }
    
        $token = $this->container->get('security.context')->getToken();
        if (is_object($token)) {
          $user = $token->getUser();
          if (is_object($user)) {
            $userlocale = $user->getLocale();
            if ($userlocale && $userlocale != $request->get('_locale')) {
              $parmArray = $request->get('_route_params');
              $parmArray['_locale'] = $userlocale;
    
              $redirectResponse = new RedirectResponse( $this->container->get('router')->generate($request->get('_route'), $parmArray) );
              $redirectResponse->headers->setCookie( new Cookie('b_locale', $userlocale, time() + 2592000) );
    
              $event->setResponse( $redirectResponse );
            }
          }
        }
      }
    }
    

    And here is how to register it in services :

    # app/config/config.yml
    services:
        myapp_main.locale_listener:
            class: myApp\MainBundle\EventListener\LocaleListener
            arguments: ["@service_container"]
            tags:
                - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
    

    Many thanks to Elnur for changing my mind.