rolandow
rolandow

Reputation: 1099

Set Locale in Symfony by GET param

I created a controller that sets the Security Token manually, according to encrypted GET parameters. I use this to create a remote login URL, that will perform a login when the user follows this link.

Now I would like to add the setting of the locale. When the Lang parameter is provided, it should set the locale. I added this to my controller:

$lang = strtolower($lang);
$this->getRequest()->getSession()->set('_locale', $lang);
$this->getRequest()->setLocale($lang);
$this->container->get('translator')->setLocale($lang);

The _locale variable is being set into the setting according to the development bar. The language file isn't loaded though, it falls back to the default language.

I read about creating a Listener to achieve this, but it seems to me that this is usefull when you want to provide the language in the URL. I don't want to add this into my Routing, I just want to set the locale when the session is created.

UPDATE:

I went for the 'simulate old beheaviour' solution, as provided by Symfony. Setting the Request Locale doesn't seem to work though. When I echo this in my Twig template, the values aren't equal: req lang: {{ app.request.locale }} session: {{ app.session.get('_locale') }}. The LocaleListener as posted below is working though, I checked this by inserting a die(), and also setting the locale of the Translator service seems to be working.

So by setting the locale of the translator, I got this working. I don't understand why though. Shouldn't the translator service use the request locale? Why do I need to set this manually?

Is the locale in the Request object ment for something else than translation?

<?php
namespace Mb\MyBundle\Listener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class LocaleListener implements EventSubscriberInterface
{
    private $translator;

    public function __construct($translator) {
        $this->translator = $translator;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();

        if (!$request->hasPreviousSession()) {
            return;
        }

        if (strlen( $request->getSession()->get('_locale') )) {
            $request->setLocale($request->getSession()->get('_locale'));
            $this->translator->setLocale($request->getSession()->get('_locale'));
        }
    }

    static public function getSubscribedEvents()
    {
        return array(
            // must be registered before the default Locale listener
            KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
        );
    }
}

And in my services.yml I have:

mb.locale.listener:
    class: Mb\MyBundle\Listener\LocaleListener
    arguments: [@translator]
    tags:An
      - { name: kernel.event_subscriber }

If somebody could explain me what's happening here, I'd be very happy :-)

Upvotes: 6

Views: 5836

Answers (2)

Vulovic Vukasin
Vulovic Vukasin

Reputation: 1748

This is what is working for me.

Had to lower the priority so that this is the last evenet that occurs, and had to always set the cookie from session.

Then, in a controller i get correct language. Also, I am setting language through an api call on the SessionInterface.

<?php

namespace App\EventSubscriber\Session;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class LocaleSubscriber implements EventSubscriberInterface
{
    /**
     * @var string $defaultLocale
     */
    private $defaultLocale;

    /**
     * LocaleSubscriber constructor.
     * @param string $defaultLocale
     */
    public function __construct($defaultLocale = 'en')
    {
        $this->defaultLocale = $defaultLocale;
    }

    /**
     * @param RequestEvent $event
     */
    public function onKernelRequest(RequestEvent $event)
    {
        $request = $event->getRequest();
        if (!$request->hasPreviousSession()) {
            return;
        }

        // if no explicit locale has been set on this request, use one from the session
        $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
    }

    /**
     * @return array
     */
    public static function getSubscribedEvents(): array
    {
        return array(
            // must be registered before (i.e. with a higher priority than) the default Locale listener
            KernelEvents::REQUEST => array(array('onKernelRequest', 0)),
        );
    }
}

Upvotes: 1

marrriva
marrriva

Reputation: 59

I had same problem and I wonder if it depends on order of listeners:

php bin/console debug:event-dispatcher shows

"kernel.request" event
----------------------
Order   Callable                                    Priority  
------------------------------------------------ ---------- 
#1      Symfony\Component\HttpKernel\EventListener\DebugHandlersListener::configure()           2048      
#2      Symfony\Component\HttpKernel\EventListener\DumpListener::configure()                    1024      
#3      Symfony\Component\HttpKernel\EventListener\ValidateRequestListener::onKernelRequest()   256       
#4      Symfony\Bundle\FrameworkBundle\EventListener\SessionListener::onKernelRequest()         128       
#5      Symfony\Component\HttpKernel\EventListener\FragmentListener::onKernelRequest()          48        
#6      Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelRequest()            32        
#7      Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelRequest()            16        
#8      Symfony\Component\HttpKernel\EventListener\TranslatorListener::onKernelRequest()        10        
#9      Symfony\Component\Security\Http\Firewall::onKernelRequest()                             8         
#10     AppBundle\Service\LocaleListener::onKernelRequest()                                     0         
#11     Symfony\Bundle\AsseticBundle\EventListener\RequestListener::onKernelRequest()           0         

and #10 is mine and should to after #7 LocaleListener and before #8 TranslatorListener so that's why I have to recall translator in my service.

Upvotes: 0

Related Questions