src/EventSubscriber/LocaleSubscriber.php line 31
<?php
namespace App\EventSubscriber;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleSubscriber implements EventSubscriberInterface
{
private array $allowedLanguages = ['fr', 'en'];
public function __construct(private readonly EntityManagerInterface $em, private string $defaultLocale = 'fr') {
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
$token = unserialize($request->getSession()->get('_security_main'));
// Get navigator language
$browserLang = $this->detectBrowserLang($request);
// Set local by url, by session, by navigator, by default
$locale = $request->get('_locale');
// @codeCoverageIgnoreStart
if ($locale && $this->languageIsAllowed($locale)) {
$request->getSession()->set('_locale', $locale);
$request->setLocale($locale);
} elseif (($locale = $request->getSession()->get('_locale')) && ($this->languageIsAllowed($locale))) {
// If no explicit locale has been set on this request, use one from the session
$request->setLocale($locale);
} elseif (!empty($browserLang)) {
$request->setLocale($browserLang);
} else {
$request->setLocale($this->defaultLocale);
}
// @codeCoverageIgnoreEnd
// Save locale to user data
if ($token && $token->getUser() && ($token->getUser() instanceof User) && $token->getUser()->getLocale() != $request->getLocale()) {
/** @var User $user */
$user = $this->em->getRepository(User::class)->findOneBy(['email' => $token->getUser()->getEmail()]);
$user->setLocale($request->getLocale());
$this->em->flush();
}
}
/**
* Detect Browser language and return lang
*/
private function detectBrowserLang($request): string
{
$result = [];
$browserLang = '';
// ex : $acceptLanguage = fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7 : languages priority separate by ','
$acceptLanguageBrowser = $request->headers->get('accept-language');
foreach (explode(',', $acceptLanguageBrowser) as $acceptLanguage) {
preg_match('/^(([a-zA-Z]+)(-([a-zA-Z]+)){0,1})(;q=([0-9.]+)){0,1}/', $acceptLanguage, $matches);
if (isset($matches[1])) {
$result[$matches[1]] = [
'lng_base' => strtolower($matches[2]),
'lng' => $matches[1],
'priority' => (float)(isset($matches[6]) ? $matches[6] : 1)
];
}
}
if (!empty($result)) {
// Sort by preference
uasort($result, function ($a, $b) {
return $a['priority'] < $b['priority'];
});
// Get first occurrence
foreach ($result as $lang) {
if ($this->languageIsAllowed($lang['lng_base'])) {
$browserLang = $lang['lng_base'];
break;
}
}
}
return $browserLang;
}
// @codeCoverageIgnoreStart
public static function getSubscribedEvents(): array
{
return [
// Must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 20]],
];
}
// @codeCoverageIgnoreEnd
private function languageIsAllowed($lang): bool
{
return in_array($lang, $this->allowedLanguages);
}
}