symfony2: how to parameter localization so we can

2019-08-05 12:53发布

In my symfony2 application, I have set up JMSI18nRoutingBundle : http://jmsyst.com/bundles/JMSI18nRoutingBundle

I have the following config:

jms_i18n_routing:
    default_locale: fr
    locales: [fr, en]
    strategy: prefix_except_default

I have set up a controller action to change the locale:

/**
 * @Route("/public/change_locale/{locale}", name="change_locale", requirements={"locale" = "fr|en"})
 * @Template(":Core/Admin:test.html.twig")
 * @param Request $request
 * @param string $locale
 * @return array
 */
public function changeLocaleAction(Request $request, $locale)
{
    $request->setLocale($locale);
    $this->get('session')->set('_locale', $locale);

    return $this->redirectToRoute('home');
}

I figured out that the locale was not persisted in the session. And for a reason I don't understand, the locale is not automatically used when generating routes in twig. So I have come to build a listener to reassign the locale to the request and the session but still, it's not working properly, I can't simply change my locale from 'fr' to 'en' and have all routes of my layout point to routes containing the 'en' locale parameter

What am I missing in the process of implementing this bundle ?

My listener:

<?php

namespace AppBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class LocaleListener
{
    private $container;

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

    public function setLocale(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }

        $request = $event->getRequest();
        if (!$request->hasPreviousSession()) {
            $request->setLocale($request->getPreferredLanguage($this->container->getParameter('jms_i18n_routing.locales')));
            return;
        }

        // on essaie de voir si la locale a été fixée dans le paramètre de routing _locale
        if ($locale = $request->attributes->get('_locale')) {
            $request->getSession()->set('_locale', $locale);
            $request->setLocale($locale);
        } else {
            // si aucune locale n'a été fixée explicitement dans la requête, on utilise celle de la session
            $request->setLocale($request->getSession()->get('_locale', $this->container->getParameter('jms_i18n_routing.default_locale')));
        }


}
}

EDIT1 :

It turns out it is working if I add the _locale parameter to all my route in all my templates. But I'd be very happy to avoid this, and the bundle documentation says the locale of the request context is used in case we don't specify the parameter: http://jmsyst.com/bundles/JMSI18nRoutingBundle/master/usage Well, in my experience this feature of the bundle isnot working properly

I don't want to edit all my routes to add the _locale parameter :

Recettes professionnelles

EDIT2:

Digging into it, I first tried to overwrite the path function of twig. It works, my template path now take into account the locale if I add a locale parameter in the path function.

However, this is not the right way to go.

I found out that the JMSi18nRoutingBundle extends the symfony Router which makes a call to $this->context.

The context which does not seem to be null does not have the locale parameter. I might need to change this in my listener... any idea?

1条回答
家丑人穷心不美
2楼-- · 2019-08-05 13:25

I was on the right path with my last edit: the request context parameter _locale has tobe defined too :

My listener becomes :

<?php

namespace AppBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Routing\RequestContext;

class LocaleListener
{
    /**
     * @var RequestContext
     */
    private $context;
    private $locales;
    private $defautLocales;

    public function __construct(RequestContext $context, $locales, $defautLocales)
    {
        $this->context = $context;
        $this->locales = $locales;
        $this->defautLocales = $defautLocales;
    }

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

        if (!$request->hasPreviousSession()) {
            $request->setLocale($request->getPreferredLanguage($this->locales));
            return;
        }

        // on essaie de voir si la locale a été fixée dans le paramètre de routing _locale
        if ($locale = $request->attributes->get('_locale')) {
            $request->getSession()->set('_locale', $locale);
        } else {
            // si aucune locale n'a été fixée explicitement dans la requête, on utilise celle de la session
            $locale = $request->getSession()->get('_locale', $this->defautLocales);
        }

        $request->setLocale($locale);
        $this->context->setParameter('_locale', $locale);

    }
}

And the definition:

locale_listener:
    class: %locale_listener.class%
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: setLocale, priority: 17}
    arguments: [@router.request_context, '%jms_i18n_routing.locales%', '%jms_i18n_routing.default_locale%']
查看更多
登录 后发表回答