symfony 2 set locale based on user preferences sto

2019-04-08 00:26发布

问题:

I am trying to set the locale based on the current user's preferences which are stored in the DB.

Our User class therefore has a getPreferredLanguage which returns a locale identify ('en', 'fr_FR', etc.).

I've considered the following approach:

  • register a "locale" listener service that subscribes to the KernelEvents::REQUEST event.
  • this service has access to the security context (via its constructor)
  • this service's onKernelRequest method attempts to get the user from the security context, get the user's preferred locale, and set it as the request's locale.

Unfortunately, this doesn't work. When the "locale" listener service's onRequestEvent method is invoked, the security context does not have a token. It seems that the context listener is invoked at a very late stage (with a priority of 0), and it is impossible to tell my "locale" listener to run before the security context.

Does anyone know how to fix this approach, or suggest another one?

回答1:

You may be interested in the locale listener, which I posted in this answer: Symfony2 locale detection: not considering _locale in session

Edit: If a user changes his language in the profile, it's no problem. You can hook into profile edit success event if you're are using FOSUserBundle (master). Otherwise in your profile controller, if you're using a self made system. Here is a example for FOSUserBundle:

<?php
namespace Acme\UserBundle\EventListener;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ChangeLanguageListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return array(
                FOSUserEvents::PROFILE_EDIT_SUCCESS => 'onProfileEditSuccess',
        );
    }

    public function onProfileEditSuccess(FormEvent $event)
    {
        $request = $event->getRequest();
        $session = $request->getSession();
        $form = $event->getForm();
        $user = $form->getData();
        $lang = $user->getLanguage();

        $session->set('_locale', $lang);
        $request->setLocale($lang);
    }
}

and in the services.yml

services:
    acme.change_language:
        class: Acme\UserBundle\EventListener\ChangeLanguageListener
        tags:
            - { name: kernel.event_subscriber }

for multiple sessions in multiple browser is no problem, as every new session requires a new login. Hmm, ok, not after changing the language, as only the current session would be updated. But you can modify the LanguageListener to support this.
And the case if an admin changes the language should be insignificant.