src/EventSubscriber/LocaleSubscriber.php line 21

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  4. use Symfony\Component\HttpKernel\Event\RequestEvent;
  5. use Symfony\Component\HttpKernel\KernelEvents;
  6. /**
  7.  * Based on https://symfony.com/doc/4.4/session/locale_sticky_session.html
  8.  * 
  9.  * 
  10.  */
  11. class LocaleSubscriber implements EventSubscriberInterface {
  12.     private $defaultLocale;
  13.     public function __construct($defaultLocale 'es') {
  14.         $this->defaultLocale $defaultLocale;
  15.     }
  16.     public function onKernelRequest(RequestEvent $event) {
  17.         $request $event->getRequest();
  18.         if (!$request->hasPreviousSession()) {
  19.             return;
  20.         }
  21.         // try to get language from the HTTP_ACCEPT_LANGUAGE
  22.         $locale $this->detect($request);
  23.         if ($locale) {
  24.             $request->getSession()->set('_locale'$locale);
  25.         }
  26.         //Retrieve locale value from session, if not, the default will be used
  27.         $request->setLocale($request->getSession()->get('_locale'$this->defaultLocale));
  28.         setLocale(LC_TIME$request->getSession()->get('_locale'$this->defaultLocale));
  29.     }
  30.     /**
  31.      * 
  32.      * @return type
  33.      */
  34.     public static function getSubscribedEvents(): array {
  35.         return [
  36.             // must be registered before (i.e. with a higher priority than) the default Locale listener
  37.             KernelEvents::REQUEST => [['onKernelRequest'20]],
  38.         ];
  39.     }
  40.     
  41.     /**
  42.      * Copied and adapted from golfandalucia.com
  43.      * 
  44.      * @param type $request
  45.      * @return type
  46.      */
  47.     private function detect($request): string {
  48.         $httpAcceptLanguageHeader $this->getHttpAcceptLanguageHeader($request);
  49.         if ($httpAcceptLanguageHeader == null) {
  50.             return 'es';
  51.         }
  52.         $locales $this->getWeightedLocales($httpAcceptLanguageHeader);
  53.         $sortedLocales $this->sortLocalesByWeight($locales);
  54.         $mappedLocales array_map(function ($weightedLocale) {
  55.             return $weightedLocale['locale'];
  56.         }, $sortedLocales);
  57.         
  58.         return (str_contains($mappedLocales[0], 'es')) ? 'es' 'en';
  59.     }
  60.     private function getHttpAcceptLanguageHeader($request) {
  61.         if (null !== ($request->server->get('HTTP_ACCEPT_LANGUAGE'))) {
  62.             return trim($request->server->get('HTTP_ACCEPT_LANGUAGE'));
  63.         } else {
  64.             return null;
  65.         }
  66.     }
  67.     private function getWeightedLocales($httpAcceptLanguageHeader) {
  68.         if (strlen($httpAcceptLanguageHeader) == 0) {
  69.             return [];
  70.         }
  71.         $weightedLocales = [];
  72.         // We break up the string 'en-CA,ar-EG;q=0.5' along the commas,
  73.         // and iterate over the resulting array of individual locales. Once
  74.         // we're done, $weightedLocales should look like
  75.         // [['locale' => 'en-CA', 'q' => 1.0], ['locale' => 'ar-EG', 'q' => 0.5]]
  76.         foreach (explode(','$httpAcceptLanguageHeader) as $locale) {
  77.             // separate the locale key ("ar-EG") from its weight ("q=0.5")
  78.             $localeParts explode(';'$locale);
  79.             $weightedLocale = ['locale' => $localeParts[0]];
  80.             if (count($localeParts) == 2) {
  81.                 // explicit weight e.g. 'q=0.5'
  82.                 $weightParts explode('='$localeParts[1]);
  83.                 // grab the '0.5' bit and parse it to a float
  84.                 $weightedLocale['q'] = floatval($weightParts[1]);
  85.             } else {
  86.                 // no weight given in string, ie. implicit weight of 'q=1.0'
  87.                 $weightedLocale['q'] = 1.0;
  88.             }
  89.             $weightedLocales[] = $weightedLocale;
  90.         }
  91.         return $weightedLocales;
  92.     }
  93.     /**
  94.      * Sort by high to low `q` value
  95.      */
  96.     private function sortLocalesByWeight($locales) {
  97.         usort($locales, function ($a$b) {
  98.             // usort will cast float values that we return here into integers,
  99.             // which can mess up our sorting. So instead of subtracting the `q`,
  100.             // values and returning the difference, we compare the `q` values and
  101.             // explicitly return integer values.
  102.             if ($a['q'] == $b['q']) {
  103.                 return 0;
  104.             }
  105.             if ($a['q'] > $b['q']) {
  106.                 return -1;
  107.             }
  108.             return 1;
  109.         });
  110.         return $locales;
  111.     }
  112. }