6

我正在尝试根据存储在数据库中的当前用户偏好设置语言环境。

因此,我们的 User 类有一个 getPreferredLanguage,它返回一个语言环境标识('en'、'fr_FR' 等)。

我考虑过以下方法:

  • 注册一个订阅 KernelEvents::REQUEST 事件的“语言环境”侦听器服务。
  • 此服务可以访问安全上下文(通过其构造函数)
  • 此服务的 onKernelRequest 方法尝试从安全上下文中获取用户,获取用户的首选语言环境,并将其设置为请求的语言环境。

不幸的是,这不起作用。当调用“语言环境”侦听器服务的 onRequestEvent 方法时,安全上下文没有令牌。似乎上下文侦听器在很晚的阶段被调用(优先级为 0),并且不可能告诉我的“语言环境”侦听器在安全上下文之前运行。

有谁知道如何解决这种方法,或建议另一种方法?

4

3 回答 3

2

您可能对我在此答案中发布的语言环境侦听器感兴趣:Symfony2 语言环境检测:不考虑会话中的 _locale

编辑:如果用户在个人资料中更改了他的语言,那没问题。如果您正在使用 FOSUserBundle(主),则可以挂钩配置文件编辑成功事件。否则在您的配置文件控制器中,如果您使用的是自制系统。这是 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);
    }
}

并在 services.yml

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

对于多个浏览器中的多个会话没有问题,因为每个新会话都需要新的登录。嗯,好的,不是在更改语言之后,因为只会更新当前会话。但是您可以修改 LanguageListener 来支持这一点。
如果管理员更改语言的情况应该是微不足道的。

于 2013-05-18T12:36:36.940 回答
0

如果您通过 Google 获得此答案,我目前正在使用此解决方案。

    <?php

namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;

class SetLocaleEventSubscriber implements EventSubscriberInterface
{

    private Security $security;
    private TranslatorInterface $translator;

    public function __construct(Security $security, TranslatorInterface $translator)
    {
        $this->security = $security;
        $this->translator = $translator;
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::CONTROLLER => [
                ['setLocale', 1]
            ]
        ];
    }

    public function setLocale(ControllerEvent $event)
    {
        if (!$event->isMasterRequest()) {
            return;
        }
        $request = $event->getRequest();
        /**
         * @var \App\Entit\User
         */
        $user = $this->security->getUser();

        if ($user) {;
            $request->setLocale($user->getLocale());
            $this->translator->setLocale($user->getLocale());
        }
    }
}
于 2020-06-04T15:08:59.640 回答
0

为了实现这一点,您需要在事件上设置一个事件订阅者,其Kernel::REQUEST优先级高于文档中所示的默认 Locale 侦听器

此时,很遗憾,您将无法访问当前登录的用户,因为这是在 Locale 侦听器之后触发的另一个 Symfony 事件中设置的。

但是,您可以访问会话。

解决方案是在成功登录后将用户的语言环境保存在会话中,然后在会话的请求中设置语言环境。

// src/EventSubscriber/UserLocaleSubscriber.php
namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
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 $requestStack;

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

    public function onInteractiveLogin(InteractiveLoginEvent $event)
    {
        $user = $event->getAuthenticationToken()->getUser();

        if (null !== $user->getLocale()) {
            $this->requestStack->getSession()->set('_locale', $user->getLocale());
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin',
        ];
    }
}
// src/EventSubscriber/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
{
    public function onKernelRequest(RequestEvent $event)
    {
        $request = $event->getRequest();

        if ($request->getSession()) {
            // Set user's locale from session
            if ($locale = $request->getSession()->get('_locale')) {
                $request->setLocale($locale);
            }
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            // must be registered before (i.e. with a higher priority than) the default Locale listener
            KernelEvents::REQUEST => [['onKernelRequest', 20]],
        ];
    }
}
于 2022-01-11T07:28:09.183 回答