2013-05-03 4 views
5

Я пытаюсь реализовать LocaleListener, который определяет предпочтительный язык пользователя (учитывая заголовок Accept-Language) и сохраняет его в сеансе, чтобы избежать проверки его на каждый запрос. Я разработал код ниже для достижения этой цели:Определение локали Symfony2: не считая _locale в сеансе

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

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

    $preferredLocale = $request->getPreferredLanguage($this->availableLocales); 

    if ($this->container->has('session')) { 
     $session = $this->container->get('session'); 
     if (!$session->has('_locale')) { 
      $session->set('_locale', $preferredLocale); 
     } 
    } else { 
     $request->setLocale($preferredLocale); 
    } 
} 

код работает, предпочтительный язык хранится в сессии, но Symfony не рассматривает локаль, хранящийся в сессии для перевода строк. В моем случае, мой любимый язык был «pt_BR», и когда я бежать:

{{ app.request.locale }} 

Symfony убегает «ан». Не следует ли symfony рассматривать значение, сохраненное в сеансе ('_ locale'), для определения локали запроса? Это правильное поведение? Как я могу это сделать?

ответ

15

Вот рабочий язык слушателя. второй способ - изменить язык на пользовательские настройки, которые пользователь выбирает. Вы можете опустить этот метод, если у вашего пользователя нет возможности определить свой язык.

<?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; 
    } 

    /** 
    * kernel.request event. If a guest user doesn't have an opened session, locale is equal to 
    * "undefined" as configured by default in parameters.ini. If so, set as a locale the user's 
    * preferred language. 
    * 
    * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event 
    */ 
    public function setLocaleForUnauthenticatedUser(GetResponseEvent $event) 
    { 
     if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { 
      return; 
     } 
     $request = $event->getRequest(); 
     if ('undefined' == $request->getLocale()) { 
      if ($locale = $request->getSession()->get('_locale')) { 
       $request->setLocale($locale); 
      } else { 
       $request->setLocale($request->getPreferredLanguage()); 
      } 
     } 
    } 

    /** 
    * security.interactive_login event. If a user chose a language in preferences, it would be set, 
    * if not, a locale that was set by setLocaleForUnauthenticatedUser remains. 
    * 
    * @param \Symfony\Component\Security\Http\Event\InteractiveLoginEvent $event 
    */ 
    public function setLocaleForAuthenticatedUser(InteractiveLoginEvent $event) 
    { 
     $user = $event->getAuthenticationToken()->getUser(); 

     if ($lang = $user->getLanguage()) { 
      $this->session->set('_locale', $lang); 
     } 
    } 
} 

в вашем services.yml:

services: 
    acme.language.interactive_login_listener: 
     class: Acme\UserBundle\EventListener\LanguageListener 
     calls: 
      - [ setSession, [@session] ] 
     tags: 
      - { name: kernel.event_listener, event: security.interactive_login, method: setLocaleForAuthenticatedUser } 

    acme.language.kernel_request_listener: 
     class: Acme\UserBundle\EventListener\LanguageListener 
     tags: 
      - { name: kernel.event_listener, event: kernel.request, method: setLocaleForUnauthenticatedUser } 

Ой, а вы должны определить неопределенную fallback_language в config.yml, чтобы заставить его работать.

framework: 
    translator:  { fallback: "undefined" } 
    default_locale: "en" 
+0

Спасибо, @Pazi. У меня есть два вопроса о вашем фрагменте: 1) это хорошая идеа, чтобы установить локаль в каждом запросе? Я пытался избежать этого сохранения локали в сеансе. 2) Где вы установили свой язык во время сеанса? Что возвращает ваш метод $ user-> getLanguage()? –

+0

В моем проекте это не проблема. Я получил этот фрагмент из другого источника, но я больше не знаю URL. Можете ли вы изменить его, чтобы использовать только '_locale' в сеансе. Раньше, когда я ввел это, он не сработал.'$ user-> getLanguage()' просто поле языка в моей пользовательской сущности, потому что мои пользователи могут решить, на каком языке использовать веб-приложение, независимо от языкового стандарта браузеров. –

7

Начиная с symfony 2.1, язык не сохраняется в сеансе, а в запросе. Что вы можете сделать, чтобы решить эту проблему:

  • восстановить старый способ сохранения локали. Вы можете прочитать, как сделать это в upgrade file
  • редактировать в LocaleListener хранить локаль в запросе:

    if (!$request->attributes->has('locale')) { 
        $request->setLocale(...); 
    } 
    
+0

код [Официальная документация] (http://symfony.com/doc/2.1/book/translation.html#handling-the-user-s-locale) говорит, что его также можно хранить локаль в сессии , Разве это не автоматическое? Или нужно сообщить об ошибке? «Также возможно сохранить локаль в сеансе, а не на основе запроса. Если вы сделаете это, каждый последующий запрос будет иметь этот язык». –

+0

@hugomn, пожалуйста, обратите внимание на этот цитат: «Если вы сделаете это, ** каждый последующий запрос будет иметь этот язык. **« И мы не говорим о запросе на суб, не так ли? Так что это не сработает. –

+0

Я не понял. Значит, это означает, что symfony не рассматривает ключевую _locale в сеансе для последующих запросов? –

Смежные вопросы