2013-05-03 13 views
5

Sto provando ad implementare un LocaleListener che rileva la lingua preferita dell'utente (considerando l'intestazione Accept-Language) e lo memorizza in sessione per evitare di controllarlo ogni richiesta. Ho sviluppato il codice qui sotto per ottenere questo risultato:Rilevamento locale Symfony2: non considerando _locale in sessione

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

Il codice funziona, la lingua preferita viene memorizzato in sessione, ma symfony non sta prendendo in considerazione il locale memorizzato nella sessione di tradurre le stringhe. Nel mio caso, la mia lingua preferita era 'pt_BR' e quando scappo:

{{ app.request.locale }} 

symfony fuoriesce 'en'. Symfony non dovrebbe considerare il valore memorizzato nella sessione ('_ locale') per definire le impostazioni locali della richiesta? È un comportamento corretto? Come posso farlo?

risposta

15

Ecco un ascoltatore lingua di lavoro. il secondo metodo consiste nel cambiare la lingua in base alle preferenze dell'utente, scelta dall'utente. Puoi omettere questo metodo, se il tuo utente non ha la possibilità di definire la propria lingua.

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

nel 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 } 

Oh, e si deve definire un fallback_language indefinito in config.yml per farlo funzionare.

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

Grazie, @Pazi. Ho due domande sul tuo frammento di codice: 1) è una buona idea quella di impostare il locale in ogni richiesta? Ho cercato di evitare questa memorizzazione locale in sessione. 2) Dove hai impostato la tua locale in sessione? Cosa restituisce il tuo metodo $ user-> getLanguage()? –

+0

Nel mio progetto non c'è problema. Ho preso questo frammento anche da un'altra fonte, ma non conosco più l'url .. Puoi modificarlo per usare solo il _ _locale' nella sessione. In passato, come ho introdotto questo, non aveva funzionato.'$ user-> getLanguage()' è un campo linguistico semplice nella mia entità utente, perché i miei utenti possono decidere in quale lingua utilizzare l'applicazione web, indipendentemente dalle impostazioni internazionali del browser. –

7

A partire da symfony 2.1, le impostazioni internazionali non vengono memorizzate nella sessione, ma nella richiesta. Che cosa puoi fare per risolverlo:

  • ripristinare il vecchio modo di salvare la locale. Si può leggere come fare questo nel upgrade file
  • modificare il localeListener per memorizzare le impostazioni internazionali nella richiesta:

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

Il [documentazione ufficiale] (http://symfony.com/doc/2.1/book/translation.html#handling-the-user-s-locale) dice che la sua anche possibile memorizzare locale in sessione . Non è automatico? O dovrebbe essere segnalato un bug? "È anche possibile memorizzare le impostazioni internazionali nella sessione anziché su base per richiesta. Se si esegue questa operazione, ogni richiesta successiva avrà questa impostazione internazionale." –

+0

@hugomn si prega di notare questo citare: "Se lo fai, ** ogni richiesta successiva avrà questa localizzazione. **" E non stiamo parlando di sub richiesta, no? Quindi non funzionerà. –

+0

Non ho capito. Quindi significa che symfony non considera la chiave _locale in sessione per le richieste successive? –

Problemi correlati