From a05ea3927722c2db3a1ad521a45250dd0bd59b0f Mon Sep 17 00:00:00 2001 From: jo66 Date: Mon, 26 Nov 2018 17:38:34 +0100 Subject: [PATCH 1/3] Implement locale switcher --- docs/images/locale_switcher.png | Bin 0 -> 34205 bytes docs/index.rst | 6 +- docs/reference/global_locale_switcher.rst | 62 +++++++++++++++ src/Controller/LocaleController.php | 35 +++++++++ src/EventSubscriber/LocaleSubscriber.php | 73 ++++++++++++++++++ src/EventSubscriber/UserLocaleSubscriber.php | 67 ++++++++++++++++ src/Resources/config/routes.yaml | 4 + .../translations/SonataAdminBundle.de.xlf | 11 +++ .../translations/SonataAdminBundle.en.xlf | 11 +++ .../translations/SonataAdminBundle.es.xlf | 11 +++ .../translations/SonataAdminBundle.fr.xlf | 11 +++ .../translations/SonataAdminBundle.hu.xlf | 11 +++ .../translations/SonataAdminBundle.it.xlf | 11 +++ .../translations/SonataAdminBundle.pl.xlf | 11 +++ .../translations/SonataAdminBundle.ru.xlf | 11 +++ src/Resources/views/standard_layout.html.twig | 45 +++++++++++ 16 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 docs/images/locale_switcher.png create mode 100644 docs/reference/global_locale_switcher.rst create mode 100644 src/Controller/LocaleController.php create mode 100644 src/EventSubscriber/LocaleSubscriber.php create mode 100644 src/EventSubscriber/UserLocaleSubscriber.php create mode 100644 src/Resources/config/routes.yaml create mode 100644 src/Resources/translations/SonataAdminBundle.de.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.en.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.es.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.fr.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.hu.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.it.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.pl.xlf create mode 100644 src/Resources/translations/SonataAdminBundle.ru.xlf create mode 100644 src/Resources/views/standard_layout.html.twig diff --git a/docs/images/locale_switcher.png b/docs/images/locale_switcher.png new file mode 100644 index 0000000000000000000000000000000000000000..066ff8cf187d5c383597505d671318123c21a801 GIT binary patch literal 34205 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 + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\TranslationBundle\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RedirectResponse; + +/** + * Locale controller. + * + * @author Jonathan Vautrin + */ +final class LocaleController +{ + /** + * Switch current locale. + * + * @return RedirectResponse + */ + public function index(Request $request, string $locale): RedirectResponse + { + $request->getSession()->set('_locale', $locale); + return new RedirectResponse($request->headers->get('referer', '/')); + } +} diff --git a/src/EventSubscriber/LocaleSubscriber.php b/src/EventSubscriber/LocaleSubscriber.php new file mode 100644 index 00000000..829b3910 --- /dev/null +++ b/src/EventSubscriber/LocaleSubscriber.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\TranslationBundle\EventSubscriber; + +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Locale subscriber. + * + * @author Jonathan Vautrin + */ +class LocaleSubscriber implements EventSubscriberInterface +{ + /** + * The default locale. + * + * @var string + */ + private $defaultLocale; + + /** + * @param string $defaultLocale + */ + public function __construct(string $defaultLocale = 'en') + { + $this->defaultLocale = $defaultLocale; + } + + /** + * Kernel request. + * + * @param GetResponseEvent $event + */ + 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)); + } + } + + /** + * Subscribed events. + * + * @return array + */ + public static function getSubscribedEvents() + { + return array( + // must be registered before (i.e. with a higher priority than) the default Locale listener + KernelEvents::REQUEST => array(array('onKernelRequest', 20)), + ); + } +} diff --git a/src/EventSubscriber/UserLocaleSubscriber.php b/src/EventSubscriber/UserLocaleSubscriber.php new file mode 100644 index 00000000..e8fae3fe --- /dev/null +++ b/src/EventSubscriber/UserLocaleSubscriber.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\TranslationBundle\EventSubscriber; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; +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. + * + * @author Jonathan Vautrin + */ +class UserLocaleSubscriber implements EventSubscriberInterface +{ + /** + * The default locale. + * + * @var SessionInterface + */ + private $session; + + /** + * @param SessionInterface $session + */ + public function __construct(SessionInterface $session) + { + $this->session = $session; + } + + /** + * Interactive login. + * + * @param InteractiveLoginEvent $event + */ + public function onInteractiveLogin(InteractiveLoginEvent $event) + { + $user = $event->getAuthenticationToken()->getUser(); + + if (null !== $user->getLocale()) { + $this->session->set('_locale', $user->getLocale()); + } + } + + /** + * Subscribed events. + * + * @return array + */ + public static function getSubscribedEvents() + { + return array( + SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin', + ); + } +} diff --git a/src/Resources/config/routes.yaml b/src/Resources/config/routes.yaml new file mode 100644 index 00000000..5b0c527d --- /dev/null +++ b/src/Resources/config/routes.yaml @@ -0,0 +1,4 @@ +locale: + path: /locale/{locale} + defaults: + _controller: Sonata\TranslationBundle\Controller\LocaleController::index diff --git a/src/Resources/translations/SonataAdminBundle.de.xlf b/src/Resources/translations/SonataAdminBundle.de.xlf new file mode 100644 index 00000000..668f2860 --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.de.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Sprachen + + + + diff --git a/src/Resources/translations/SonataAdminBundle.en.xlf b/src/Resources/translations/SonataAdminBundle.en.xlf new file mode 100644 index 00000000..55c45c41 --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.en.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Languages + + + + diff --git a/src/Resources/translations/SonataAdminBundle.es.xlf b/src/Resources/translations/SonataAdminBundle.es.xlf new file mode 100644 index 00000000..148010a4 --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.es.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Idiomas + + + + diff --git a/src/Resources/translations/SonataAdminBundle.fr.xlf b/src/Resources/translations/SonataAdminBundle.fr.xlf new file mode 100644 index 00000000..565358cf --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.fr.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Langues + + + + diff --git a/src/Resources/translations/SonataAdminBundle.hu.xlf b/src/Resources/translations/SonataAdminBundle.hu.xlf new file mode 100644 index 00000000..9ecab2c9 --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.hu.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Nyelvek + + + + diff --git a/src/Resources/translations/SonataAdminBundle.it.xlf b/src/Resources/translations/SonataAdminBundle.it.xlf new file mode 100644 index 00000000..d05d43bc --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.it.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Le lingue + + + + diff --git a/src/Resources/translations/SonataAdminBundle.pl.xlf b/src/Resources/translations/SonataAdminBundle.pl.xlf new file mode 100644 index 00000000..47a2b6cf --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.pl.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Języki + + + + diff --git a/src/Resources/translations/SonataAdminBundle.ru.xlf b/src/Resources/translations/SonataAdminBundle.ru.xlf new file mode 100644 index 00000000..ae317af7 --- /dev/null +++ b/src/Resources/translations/SonataAdminBundle.ru.xlf @@ -0,0 +1,11 @@ + + + + + + languages_title + Языки + + + + diff --git a/src/Resources/views/standard_layout.html.twig b/src/Resources/views/standard_layout.html.twig new file mode 100644 index 00000000..d1e8f19e --- /dev/null +++ b/src/Resources/views/standard_layout.html.twig @@ -0,0 +1,45 @@ +{# + +This file is part of the Sonata package. + +(c) Thomas Rabaix + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. + +#} + +{% extends '@SonataAdmin/standard_layout.html.twig' %} + +{% block sonata_top_nav_menu %} + {{ parent() }} + +{% endblock %} From 37b4f15965f02cd59098ebd1dcdb4cc8ce0a6301 Mon Sep 17 00:00:00 2001 From: jo66 Date: Tue, 27 Nov 2018 10:02:51 +0100 Subject: [PATCH 2/3] Some improvements following change requests --- src/Controller/LocaleController.php | 2 +- src/EventSubscriber/LocaleSubscriber.php | 19 +++++++------------ src/EventSubscriber/UserLocaleSubscriber.php | 12 +++--------- src/Resources/config/routes.yaml | 2 +- src/Resources/views/standard_layout.html.twig | 4 +++- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/Controller/LocaleController.php b/src/Controller/LocaleController.php index ec84f288..6b962fe7 100644 --- a/src/Controller/LocaleController.php +++ b/src/Controller/LocaleController.php @@ -27,7 +27,7 @@ final class LocaleController * * @return RedirectResponse */ - public function index(Request $request, string $locale): RedirectResponse + public function index(Request $request, $locale) { $request->getSession()->set('_locale', $locale); return new RedirectResponse($request->headers->get('referer', '/')); diff --git a/src/EventSubscriber/LocaleSubscriber.php b/src/EventSubscriber/LocaleSubscriber.php index 829b3910..a62fc684 100644 --- a/src/EventSubscriber/LocaleSubscriber.php +++ b/src/EventSubscriber/LocaleSubscriber.php @@ -20,11 +20,9 @@ * * @author Jonathan Vautrin */ -class LocaleSubscriber implements EventSubscriberInterface +final class LocaleSubscriber implements EventSubscriberInterface { /** - * The default locale. - * * @var string */ private $defaultLocale; @@ -32,14 +30,12 @@ class LocaleSubscriber implements EventSubscriberInterface /** * @param string $defaultLocale */ - public function __construct(string $defaultLocale = 'en') + public function __construct($defaultLocale = 'en') { $this->defaultLocale = $defaultLocale; } /** - * Kernel request. - * * @param GetResponseEvent $event */ public function onKernelRequest(GetResponseEvent $event) @@ -52,22 +48,21 @@ public function onKernelRequest(GetResponseEvent $event) // 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)); + return; } + + // if no explicit locale has been set on this request, use one from the session + $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale)); } /** - * Subscribed events. - * * @return array */ public static function getSubscribedEvents() { return array( // must be registered before (i.e. with a higher priority than) the default Locale listener - KernelEvents::REQUEST => array(array('onKernelRequest', 20)), + KernelEvents::REQUEST => [['onKernelRequest', 20]], ); } } diff --git a/src/EventSubscriber/UserLocaleSubscriber.php b/src/EventSubscriber/UserLocaleSubscriber.php index e8fae3fe..276b4244 100644 --- a/src/EventSubscriber/UserLocaleSubscriber.php +++ b/src/EventSubscriber/UserLocaleSubscriber.php @@ -22,11 +22,9 @@ * * @author Jonathan Vautrin */ -class UserLocaleSubscriber implements EventSubscriberInterface +final class UserLocaleSubscriber implements EventSubscriberInterface { /** - * The default locale. - * * @var SessionInterface */ private $session; @@ -40,8 +38,6 @@ public function __construct(SessionInterface $session) } /** - * Interactive login. - * * @param InteractiveLoginEvent $event */ public function onInteractiveLogin(InteractiveLoginEvent $event) @@ -54,14 +50,12 @@ public function onInteractiveLogin(InteractiveLoginEvent $event) } /** - * Subscribed events. - * * @return array */ public static function getSubscribedEvents() { - return array( + return [ SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin', - ); + ]; } } diff --git a/src/Resources/config/routes.yaml b/src/Resources/config/routes.yaml index 5b0c527d..34d2fcc5 100644 --- a/src/Resources/config/routes.yaml +++ b/src/Resources/config/routes.yaml @@ -1,4 +1,4 @@ -locale: +sonata.translation.locale: path: /locale/{locale} defaults: _controller: Sonata\TranslationBundle\Controller\LocaleController::index diff --git a/src/Resources/views/standard_layout.html.twig b/src/Resources/views/standard_layout.html.twig index d1e8f19e..a1bb6b16 100644 --- a/src/Resources/views/standard_layout.html.twig +++ b/src/Resources/views/standard_layout.html.twig @@ -31,7 +31,9 @@ file that was distributed with this source code. {% for locale in sonata_translation_locales %} {% endfor %} From fab249ff46695f95c811f93c11e7115dc3e16284 Mon Sep 17 00:00:00 2001 From: jo66 Date: Tue, 27 Nov 2018 10:16:18 +0100 Subject: [PATCH 3/3] LocaleController => LocaleAction --- .../LocaleController.php => Action/LocaleAction.php} | 6 +++--- src/Resources/config/routes.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/{Controller/LocaleController.php => Action/LocaleAction.php} (88%) diff --git a/src/Controller/LocaleController.php b/src/Action/LocaleAction.php similarity index 88% rename from src/Controller/LocaleController.php rename to src/Action/LocaleAction.php index 6b962fe7..4b21bc91 100644 --- a/src/Controller/LocaleController.php +++ b/src/Action/LocaleAction.php @@ -9,18 +9,18 @@ * file that was distributed with this source code. */ -namespace Sonata\TranslationBundle\Controller; +namespace Sonata\TranslationBundle\Action; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; /** - * Locale controller. + * Locale action. * * @author Jonathan Vautrin */ -final class LocaleController +final class LocaleAction { /** * Switch current locale. diff --git a/src/Resources/config/routes.yaml b/src/Resources/config/routes.yaml index 34d2fcc5..a4497dc4 100644 --- a/src/Resources/config/routes.yaml +++ b/src/Resources/config/routes.yaml @@ -1,4 +1,4 @@ sonata.translation.locale: path: /locale/{locale} defaults: - _controller: Sonata\TranslationBundle\Controller\LocaleController::index + _controller: Sonata\TranslationBundle\Action\LocaleAction::index