Symfony session cannot be retrieve in twig - php

I'm trying to make a two language app with symfony2.
I'm using Doctrine behavior and A2lixtranslationformbundle.
I have a listener which listen to change the locale:
namespace George\CoreBundle\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleListener implements EventSubscriberInterface
{
private $defaultLocale;
public function __construct($defaultLocale = 'en')
{
$this->defaultLocale = $defaultLocale;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$request->hasPreviousSession()) {
return;
}
// try to see if the locale has been set as a _locale routing parameter
//if ($locale = $request->attributes->get('_locale')) {
if ($locale = $request->get('_locale')) {
$request->getSession()->set('_locale', $locale);
} else {
// if no explicit locale has been set on this request, use one from the session
$request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
}
}
public static function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
In the twig template i want to retrieve the translation trough the session param to see what locale we have:
{{ entity.translate(app.session.get('_locale')).title }}
But the app.session.get('_locale') does not return nothing. What is the problem why the session in the twig do not get this property i have test it in the listener everything looks fine.

In order to retrive the locale in twig you can use the following snippet
{{ app.request.locale }}
for your case will be
{{ entity.translate(app.request.locale).title }}

Related

Manage locale with Symfony3 LocaleSubscriber

I've some troubles in using locale parameter with Symfony 3. I've tried a lot of things that I've found on Stack, but nothing seems to work.
I've followed the official documentation : https://symfony.com/doc/current/session/locale_sticky_session.html
LocaleSubscriber.php
<?php
namespace AppBundle\EventSubscriber;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\HttpKernel;
class LocaleSubscriber implements EventSubscriberInterface
{
private $defaultLocale;
public function __construct($defaultLocale = 'en')
{
$this->defaultLocale = $defaultLocale;
}
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
return;
}
$request = $event->getRequest();
if (!$request->hasPreviousSession()) {
return;
}
// try to see if the locale has been set as a _locale routing parameter
if ($locale = $request->get('_locale')) {
$request->set('_locale', $locale);
} else {
$request->set('_locale', $this->defaultLocale);
}
}
public static function getSubscribedEvents()
{
return array(
// must be registered after the default Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
config.yml
framework:
#esi: ~
translator: { fallbacks: ['%locale%'] }
service.yml
AppBundle\EventSubscriber\LocaleSubscriber:
arguments: ['%kernel.default_locale%']
tags: [kernel.event_subscriber]
AdminController
namespace AdminBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class AdminController extends Controller
{
public function homeAction(Request $request)
{
var_dump($request->getLocale());
var_dump($request->get('_locale'));
return $this->render('AdminBundle:home:home.html.twig');
}
}
HTML Links :
<li>FR</li>
<li>EN</li>
Problem : When I try to switch of language, the parameter _locale is changed but the text don't switch language. "testfr" must be "testen" according to my messages.en.yml.
My var_dump when I click on the "FR" link : string(2) "fr" string(2) "fr"
My var_dump when I click on the "EN" link : string(2) "fr" string(2) "en"
I guess it is not normal..
If someone can help me, that would be nice and can remove a headache.
Thanks
Edit : The translator takes the "locale" parameter, which doesn't change when I click on one of theses links. I'm still investigating.
Finally, found the problem :
if (!$request->hasPreviousSession()) {
return;
}
Just comment this part of the code, and all is fine now.

Symfony override _locale parameter

I have created a custom LocaleListener:
class LocaleListener implements EventSubscriberInterface
{
public function onKernelRequest(GetResponseEvent $event)
{
if ($request->getSession()->get("language")) {
$lang = $request->getSession()->get("language");
} else {
$lang = $request->getPreferredLanguage(array("de", "en"));
}
$request->getSession()->set('_locale', $lang);
$request->setLocale($request->getSession()->get('_locale', $lang));
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
I get the language code from session (if exists) or from browser. Now I would like to correct / manipulate the route. I am using _locale in my router to set the language code (en or de). Now I would like override the user's choice.
For example, the language code in the LocaleListener is de. The user does now request the url which _locale = en (example: /en instead of automatically /de).
How can I force to set the users _locale to my result form the LocaleListener outside of every controller, with a listener or an other solution?
In this case you need to add RedirectResponse
$event->setResponse(new RedirectResponse($request->getBaseUrl().'/'.$locale.'/'.($params ? '?'.http_build_query($params) : '')));
or use JMSI18nRoutingBundle https://github.com/schmittjoh/JMSI18nRoutingBundle

Symfony 2, switching language does not work

I wonder why when I click the links on the view to switch the language it doesn't work. If I set default locale to en or km, it will show English language or Khmer language respectively. What wrong with me, I can not click links below to switch the language? Please help me ! Many thanks in advanced for any answer.
In the view
<div class="col-sm-3 language-switcher">
English |
ខ្មែរ
</div>
routing.yml
ngs_locale:
path: locale/{locale}
defaults: { _controller: NGSHomeBundle:Locale:locale }
LocaleController.php
namespace NGS\HomeBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class LocaleController extends Controller
{
public function localeAction(Request $request, $locale)
{
/** ======== dump ========== **/
dump($locale); //"km"
$request->getSession()->set('_locale', $locale);
/** ======== dump ========== **/
dump($request->getLocale()); //"en"
$referer = $request->headers->get('referer');
/** ======== dump ========== **/
dump($referer);die; // null
if (empty($referer)) {
throw $this->createNotFoundException('ngs_not_found');
}
return $this->redirect($referer);
}
}
LocaleListener.php
namespace NGS\HomeBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class LocaleListener implements EventSubscriberInterface
{
private $defaultLocale;
public function __construct($defaultLocale = 'en')
{
$this->defaultLocale = $defaultLocale;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$request->hasPreviousSession()) {
return;
}
// try to see if the locale has been set as a _locale routing parameter
if ($locale = $request->attributes->get('_locale')) {
$request->getSession()->set('_locale', $locale);
} else {
// if no explicit locale has been set on this request, use one from the session
$request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
}
}
public static function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
Service.yml
services:
ngs_home.locale_listener:
class: NGS\HomeBundle\EventListener\LocaleListener
arguments: ["%kernel.default_locale%"]
tags:
- { name: kernel.event_subscriber }
Now, I fixed my problem:
First, I changed the link: from locale to _locale
<div class="col-sm-3 language-switcher">
English |
ខ្មែរ
</div>
Second, I changed routing.yml, locale to _locale
ngs_locale:
path: locale/{_locale}
defaults: { _controller: NGSHomeBundle:Locale:locale
Third, I changed LocaleController.php. Removed $locale parameter and then get $locale by $request->getLocale();
public function localeAction(Request $request)
{
$locale = $locale = $request->getLocale();
$request->getSession()->set('_locale', $locale);
$referer = $request->headers->get('referer');
if (empty($referer)) {
throw $this->createNotFoundException('ngs_not_found');
}
return $this->redirect($referer);
}
Fourth, I add DependencyInjection for HomeBundle DependencyInjection \Configuration.php and DependencyInjection \NGSHomeExtension.php
That's it !

change locale symfony 2.3

I just began with symfony
I'm trying to build a multilang website but I have a problem to change the locale
I read some posts and I read the documentation about this but the locale don't change, I try:
public function indexAction()
{
$this->get('session')->set('_locale', 'fr');
$request = $this->getRequest();
$locale = $request->getLocale();
return $this->render('PhoneMainBundle:Default:index.html.twig',array('locale'=>$locale));
}
but the value in $locale is always 'en' (my default locale)
I also try
public function indexAction()
{
$this->get('session')->set('_locale', 'fr');
$request = $this->getRequest();
$request->setLocale('fr');
$locale = $request->getLocale();
return $this->render('PhoneMainBundle:Default:index.html.twig',array('locale'=>$locale));
}
In this case $locale is fr but the translations are always from messages.en.yml
I'd like in a first time to detect the user locale using $_SERVER['HTTP_ACCEPT_LANGUAGE'], maybe using a listner on each page actualisation ?
and after I will create a route to change the locale
But I 'd like to find a way to change the locale.
Thanks for your help
Based on this and this answers.
LanguageListener.php:
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LanguageListener
{
private $session;
public function setSession(Session $session)
{
$this->session = $session;
}
public function setLocale(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
$request->setLocale($request->getPreferredLanguage(array('en', 'de')));
}
}
services.yml:
acme.language.kernel_request_listener:
class: Acme\UserBundle\EventListener\LanguageListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: setLocale }
About wrong locale detection in twig, there could be a lot of different causes. Search through the SO, you'll definitely find the answer. Make sure that your '_local' var is defined right, make sure that you put your languages files in the right place, etc. FInally, read again the last version of the documentation: http://symfony.com/doc/current/book/translation.html
I however added this to make it more dynamic
services.yml
services:
acme.language.kernel_request_listener:
class: Acme\UserBundle\EventListener\LanguageListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: setLocale }
arguments: [ #router, #service_container ]
LanguageListener.php:
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LanguageListener
{
private $session;
private $container;
private $router;
public function __construct($router, $container)
{
// ...
$this->router= $router;
$this->container = $container;
}
public function setSession(Session $session)
{
$this->session = $session;
}
public function setLocale(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
$request->setLocale($request->getPreferredLanguage($this->container->parameters['jms_i18n_routing.locales']));
}
}
Just to be able to get the parameters and values from config.yml.
Regards,
Wick
If for example your default locale is french, except for one controller you want to have the default locale set to english can do that:
routing.yml
desktop_comingsoonpage:
resource: "#RemmelComparabusBundle/Controller/ComingsoonpageController.php"
defaults: { _locale: en }
type: annotation
more info : Symfony doc

symfony 2 set locale based on user preferences stored in DB

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?
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.
If you reach this answer through Google, I am currently using this solution.
<?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());
}
}
}
In order to achieve this, you need to setup an event subscriber on the Kernel::REQUEST event with a higher priority than the default Locale listener as indicated in the documentation
At this time, you will unfortunately not be able to access to the current logged in user because this is something set in another Symfony event triggered after the Locale listener.
However, you can access to the session.
The solution is to save the user's locale in the session just after a successful login, and then set the locale in the request from the session.
// 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]],
];
}
}

Categories