2013-05-03 111 views
5

我试图实现一个检测用户首选语言(考虑Accept-Language标题)的LocaleListener并将其存储在会话中以避免检查每个请求。我已经开发了下面的代码来实现: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不应该考虑存储在session('_ 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 } 

哦,你必须在config.yml定义一个未定义的fallback_language得到它的工作。

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

谢谢@Pazi。我有两个关于你的代码片段的问题:1)在每个请求中设置语言环境是否是一个好想法?我试图避免在会话中存储区域设置。 2)你在哪里设置了你的语言环境?你的方法$ user-> getLanguage()返回什么? – 2013-05-03 14:00:29

+0

在我的项目中没有问题。我也从另一个来源获得了这个片段,但是我不知道这个url了。可以修改它以仅在会话中使用'_locale'。在过去,我介绍了这一点,它没有奏效。'$ user-> getLanguage()'在我的用户实体中是简单的语言字段,'因为我的用户可以独立于浏览器语言环境来决定使用Web应用程序的语言。 – 2013-05-03 17:21:12

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)表示,其还可以现场存储在会话。它不是自动的吗?或者应该报告一个错误? “也可以将会话区域存储在会话中,而不是每个请求的基础上。如果这样做,每个后续请求都将具有此区域设置。” – 2013-05-03 14:05:14

+0

@hugomn请注意这个引用:“如果你这样做,**每个后续请求将有这个地方。**”而我们不是在谈论子请求,是不是?所以它不会工作。 – 2013-05-03 14:34:35

+0

我没有明白。那么这意味着symfony在会话中不会考虑后续请求中的关键_locale? – 2013-05-05 04:43:43