Як зробити локаль "липкою" під час сесії користувача

Дата оновлення перекладу 2023-06-22

Як зробити локаль "липкою" під час сесії користувача

Symfony зберагіає налаштування локалі у запиті, що означає, що це ж налаштування не зберігаєтьяс автоматично ("липко") для всіх запитів. Але ви можете зберігати локаль у сеісї так, щоб вона була використана у наступних запитах.

Створення LocaleSubscriber

Створіть нового підписника подій . Зазвичай, _locale використовується в якості параметра маршрутизації, щоб визначити локаль, хоча ви можете визначати правильну локаль так, як вам хочеться:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 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
{
    private $defaultLocale;

    public function __construct(string $defaultLocale = 'en')
    {
        $this->defaultLocale = $defaultLocale;
    }

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

        // спробуйте побачити, чи була локаль встановлена як параметр маршрутизації _locale
        if ($locale = $request->attributes->get('_locale')) {
            $request->getSession()->set('_locale', $locale);
        } else {
            // якщо для цього запиту не було чітко встановлено жодної локалі, використайте її з сесії
            $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            // повинен бути зареєстрований після слухача локалі за замовчуванням
            KernelEvents::REQUEST => array(array('onKernelRequest', 15)),
        ];
    }
}

Якщо ви використвуєте конфігурацію services.yml за замовчуванням , то ви закнічили! Symfony автоматично дізнається про підписаника подій та викличе метод onKernelRequest для кожного запиту.

Щоб побачити, як це працює, або встановіть ключ _locale у сесії вручну (наприклад, через маршрут і контролер "Змінити локаль"), або створіть маршрут з локаллю за замовчуванням .

Ви також можете сконфігурувати його чітко, щоб передати у default_locale :

1
2
3
4
5
6
7
8
# config/services.yaml
services:
    # ...

    App\EventSubscriber\LocaleSubscriber:
        arguments: ['%kernel.default_locale%']
        # розкоментуйте наступний рядок, якщо ви не використовуєте автоконфігурацію
        # tags: [kernel.event_subscriber]

Ось і все! Тепер відсвяткуйте, змінивши локаль користувача та побачивши, що вона "прилипає" у всьому запиті.

Памʼятайте, щоб отримати локаль користувача, завжди використовуйте метод Request::getLocale:

1
2
3
4
5
6
7
// з контролера...
use Symfony\Component\HttpFoundation\Request;

public function index(Request $request)
{
    $locale = $request->getLocale();
}

Установка локалі, засновуючись на побажаннях користувача

Ви можете захотіти покращити цю техніку та визначити локаль, засновуючись на сутності користувача, який виконав вхід. Однак, так як LocaleSubscriber викликається перед FirewallListener, який відповідає за управління аутентифікацією та установку мітки користувача у TokenStorage, у вас немає доступу до користувача, який виконав вхід.

Уявіть, що у вас є властивість locale у вашій сутності User і ви хочете використати це в якості локалі даного користувача. Щоб зробити це, ви можете підключитися до процесу виконання входу та оновити сесію користувача з цим значенням локалі до того, як він буде перенаправлений на свою першу стоінку.

Щоб зробити це, вам знадобиться підписник подій у події security.interactive_login:

// src/EventSubscriber/UserLocaleSubscriber.php namespace AppEventSubscriber;

use SymfonyComponentEventDispatcherEventSubscriberInterface; use SymfonyComponentHttpFoundationRequestStack; use SymfonyComponentSecurityHttpEventInteractiveLoginEvent; use SymfonyComponentSecurityHttpSecurityEvents;

/**
  • Зберігає локаль користувача у сесії після виконання входу.
  • Це може бути використано LocaleSubscriber пізніше.

*/

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', ]; }

}

Caution

Для того, щоб оновити мову одразу ж після того, як користувач змінив мовні побажання, вам також знадобиться оновити сесію, коли ви будете змінювати сутність User.