Le impostazioni internazionali predefinite di Symfony2 nel routing

Ho un problema con il routing e l’internazionalizzazione del mio sito creato con Symfony2.
Se definisco percorsi nel file routing.yml, in questo modo:

example: pattern: /{_locale}/example defaults: { _controller: ExampleBundle:Example:index, _locale: fr } 

Funziona bene con URL come:

 mysite.com/en/example mysite.com/fr/example 

Ma non funziona con

 mysite.com/example 

Potrebbe essere che i segnaposto opzionali siano consentiti solo alla fine di un URL?
Se sì, quale potrebbe essere una soluzione ansible per la visualizzazione di un URL come:

 mysite.com/example 

in una lingua predefinita o reindirizzando l’utente a:

 mysite.com/defaultlanguage/example 

quando visita:

 mysite.com/example. ? 

Sto cercando di capirlo, ma senza successo finora.

Grazie.

Se qualcuno è interessato, sono riuscito a inserire un prefisso sul mio routing.yml senza utilizzare altri pacchetti.

Quindi ora, questi URL funzionano:

 www.example.com/ www.example.com//home/ www.example.com/fr/home/ www.example.com/en/home/ 

Modifica la tua app/config/routing.yml :

 ex_example: resource: "@ExExampleBundle/Resources/config/routing.yml" prefix: /{_locale} requirements: _locale: |fr|en # put a pipe "|" first 

Quindi, nella tua app/config/parameters.yml , devi configurare una locale

 parameters: locale: en 

Con questo, le persone possono accedere al tuo sito Web senza inserire impostazioni locali specifiche.

Puoi definire più pattern come questo:

 example_default: pattern: /example defaults: { _controller: ExampleBundle:Example:index, _locale: fr } example: pattern: /{_locale}/example defaults: { _controller: ExampleBundle:Example:index} requirements: _locale: fr|en 

Dovresti essere in grado di ottenere lo stesso tipo di cose con le annotazioni:

 /** * @Route("/example", defaults={"_locale"="fr"}) * @Route("/{_locale}/example", requirements={"_locale" = "fr|en"}) */ 

Spero possa aiutare!

Questo è quello che utilizzo per il rilevamento e il reindirizzamento automatico delle impostazioni internazionali, funziona bene e non richiede lunghe annotazioni di routing:

routing.yml

La rotta locale gestisce la radice del sito Web e quindi ogni altra azione del controller viene anteposta alla locale.

 locale: path: / defaults: { _controller: AppCoreBundle:Core:locale } main: resource: "@AppCoreBundle/Controller" prefix: /{_locale} type: annotation requirements: _locale: en|fr 

CoreController.php

Questo rileva la lingua dell’utente e reindirizza al percorso di tua scelta. Io uso la casa come predefinito in quanto è il caso più comune.

 public function localeAction($route = 'home', $parameters = array()) { $this->getRequest()->setLocale($this->getRequest()->getPreferredLanguage(array('en', 'fr'))); return $this->redirect($this->generateUrl($route, $parameters)); } 

Quindi, le annotazioni del percorso possono essere semplicemente:

 /** * @Route("/", name="home") */ public function indexAction(Request $request) { // Do stuff } 

Ramoscello

L’impostazione localeAction può essere utilizzata per consentire all’utente di modificare le impostazioni internazionali senza allontanarsi dalla pagina corrente:

 {{ targetLanguage }} 

Pulito e semplice!

La soluzione di LocalRewriteListener di Joseph Astrahan funziona tranne per route con parametri a causa di $routePath == "/{_locale}".$path)

Esempio: $routePath = "/{_locale}/my/route/{foo}" è diverso da $path = "/{_locale}/my/route/bar"

Ho dovuto usare UrlMatcher (link a Symfony 2.7 api doc) per abbinare il percorso reale con l’url.

Modifico isLocaleSupported per l’utilizzo del codice locale del browser (es: fr -> fr_FR). Uso le impostazioni internazionali del browser come chiave e le impostazioni internazionali del percorso come valore. Ho un array come questo array(['fr_FR'] => ['fr'], ['en_GB'] => 'en'...) (vedi il file parametri di seguito per maggiori informazioni)

I cambiamenti :

  • Controlla se il locale indicato nella richiesta è suportato. In caso contrario, utilizzare le impostazioni internazionali predefinite.
  • Cerca di abbinare il percorso con la raccolta del percorso dell’app. Se non fai niente (l’app lancia un 404 se la rotta non esiste). Se sì, redirect con le impostazioni internazionali corrette nel parametro route.

Ecco il mio codice. Funziona per qualsiasi percorso con o senza parametri. Questo aggiunge la locale solo quando {_local} è impostato sulla rotta.

File di routing (nel mio caso, quello in app / config)

 app: resource: "@AppBundle/Resources/config/routing.yml" prefix: /{_locale}/ requirements: _locale: '%app.locales%' defaults: { _locale: %locale%} 

Il parametro nel file app / config / parameters.yml

 locale: fr app.locales: fr|gb|it|es locale_supported: fr_FR: fr en_GB: gb it_IT: it es_ES: es 

services.yml

 app.eventListeners.localeRewriteListener: class: AppBundle\EventListener\LocaleRewriteListener arguments: ["@router", "%kernel.default_locale%", "%locale_supported%"] tags: - { name: kernel.event_subscriber } 

LocaleRewriteListener.php

 router = $router; $this->routeCollection = $router->getRouteCollection(); $this->defaultLocale = $defaultLocale; $this->supportedLocales = $supportedLocales; $this->localeRouteParam = $localeRouteParam; $context = new RequestContext("/"); $this->matcher = new UrlMatcher($this->routeCollection, $context); } public function isLocaleSupported($locale) { return array_key_exists($locale, $this->supportedLocales); } public function onKernelRequest(GetResponseEvent $event) { //GOAL: // Redirect all incoming requests to their /locale/route equivalent when exists. // Do nothing if it already has /locale/ in the route to prevent redirect loops // Do nothing if the route requested has no locale param $request = $event->getRequest(); $baseUrl = $request->getBaseUrl(); $path = $request->getPathInfo(); //Get the locale from the users browser. $locale = $request->getPreferredLanguage(); if ($this->isLocaleSupported($locale)) { $locale = $this->supportedLocales[$locale]; } else if ($locale == ""){ $locale = $request->getDefaultLocale(); } $pathLocale = "/".$locale.$path; //We have to catch the ResourceNotFoundException try { //Try to match the path with the local prefix $this->matcher->match($pathLocale); $event->setResponse(new RedirectResponse($baseUrl.$pathLocale)); } catch (\Symfony\Component\Routing\Exception\ResourceNotFoundException $e) { } catch (\Symfony\Component\Routing\Exception\MethodNotAllowedException $e) { } } public static function getSubscribedEvents() { return array( // must be registered before the default Locale listener KernelEvents::REQUEST => array(array('onKernelRequest', 17)), ); } } 

C’è la mia soluzione, rende questo processo più veloce!

controller:

 /** * @Route("/change/locale/{current}/{locale}/", name="locale_change") */ public function setLocaleAction($current, $locale) { $this->get('request')->setLocale($locale); $referer = str_replace($current,$locale,$this->getRequest()->headers->get('referer')); return $this->redirect($referer); } 

Ramoscello:

 
  • {{ language.locale }}
  • Symfony3

     app: resource: "@AppBundle/Controller/" type: annotation prefix: /{_locale} requirements: _locale: en|bg| # put a pipe "|" last 

    Ho una soluzione completa a questo che ho scoperto dopo alcune ricerche. La mia soluzione presuppone che tu voglia che ogni percorso abbia una localizzazione di fronte ad essa, anche il login. Questo è stato modificato per supportare Symfony 3, ma credo che funzionerà ancora in 2.

    Questa versione presuppone anche che si desideri utilizzare le impostazioni internazionali del browser come impostazioni internazionali predefinite se si spostano su un percorso come / admin, ma se si spostano su / en / admin sapranno utilizzare le impostazioni locali. Questo è il caso per esempio # 2 sotto.

    Quindi per esempio:

     1. User Navigates To -> "/" -> (redirects) -> "/en/" 2. User Navigates To -> "/admin" -> (redirects) -> "/en/admin" 3. User Navigates To -> "/en/admin" -> (no redirects) -> "/en/admin" 

    In tutti gli scenari, le impostazioni locali verranno impostate correttamente come vuoi che vengano utilizzate nel tuo programma.

    È ansible visualizzare la soluzione completa di seguito che include come farlo funzionare con login e sicurezza, altrimenti la versione breve probabilmente funzionerà per voi:

    Versione completa

    Symfony 3 Reindirizza tutte le rotte alla versione corrente delle impostazioni internazionali

    Versione breve

    Per far sì che il caso n. 2 nei miei esempi sia ansible, devi farlo utilizzando un lister httpKernal

    LocaleRewriteListener.php

     router = $router; $this->routeCollection = $router->getRouteCollection(); $this->defaultLocale = $defaultLocale; $this->supportedLocales = $supportedLocales; $this->localeRouteParam = $localeRouteParam; } public function isLocaleSupported($locale) { return in_array($locale, $this->supportedLocales); } public function onKernelRequest(GetResponseEvent $event) { //GOAL: // Redirect all incoming requests to their /locale/route equivlent as long as the route will exists when we do so. // Do nothing if it already has /locale/ in the route to prevent redirect loops $request = $event->getRequest(); $path = $request->getPathInfo(); $route_exists = false; //by default assume route does not exist. foreach($this->routeCollection as $routeObject){ $routePath = $routeObject->getPath(); if($routePath == "/{_locale}".$path){ $route_exists = true; break; } } //If the route does indeed exist then lets redirect there. if($route_exists == true){ //Get the locale from the users browser. $locale = $request->getPreferredLanguage(); //If no locale from browser or locale not in list of known locales supported then set to defaultLocale set in config.yml if($locale=="" || $this->isLocaleSupported($locale)==false){ $locale = $request->getDefaultLocale(); } $event->setResponse(new RedirectResponse("/".$locale.$path)); } //Otherwise do nothing and continue on~ } public static function getSubscribedEvents() { return array( // must be registered before the default Locale listener KernelEvents::REQUEST => array(array('onKernelRequest', 17)), ); } } 

    Per capire come funziona, consulta l’interfaccia del sottoscrittore dell’evento nella documentazione di symfony.

    Per triggersre l’ascoltatore è necessario configurarlo nel tuo services.yml

    services.yml

     # Learn more about services, parameters and containers at # http://symfony.com/doc/current/book/service_container.html parameters: # parameter_name: value services: # service_name: # class: AppBundle\Directory\ClassName # arguments: ["@another_service_name", "plain_value", "%parameter_name%"] appBundle.eventListeners.localeRewriteListener: class: AppBundle\EventListener\LocaleRewriteListener arguments: ["@router", "%kernel.default_locale%", "%locale_supported%"] tags: - { name: kernel.event_subscriber } 

    Infine questo si riferisce alle variabili che devono essere definite nel file config.yml

    config.yml

     # Put parameters here that don't need to change on each machine where the app is deployed # http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration parameters: locale: en app.locales: en|es|zh locale_supported: ['en','es','zh'] 

    Infine, devi assicurarti che tutti i tuoi percorsi inizino con / {locale} per ora. Un esempio di questo è sotto il mio controller.php predefinito

     get('translator')->trans('Symfony is great'); // replace this example code with whatever you need return $this->render('default/index.html.twig', [ 'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'), 'translated' => $translated ]); } /** * @Route("/admin", name="admin") */ public function adminAction(Request $request) { $translated = $this->get('translator')->trans('Symfony is great'); // replace this example code with whatever you need return $this->render('default/index.html.twig', [ 'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'), 'translated' => $translated ]); } } ?> 

    Nota i requisiti requirements={"_locale" = "%app.locales%"} , questo fa riferimento al file config.yml in modo che devi solo definire quei requisiti in un posto per tutti i percorsi.

    Spero che questo aiuti qualcuno 🙂

    Io uso annotazioni e lo farò

     /** * @Route("/{_locale}/example", defaults={"_locale"=""}) * @Route("/example", defaults={"_locale"="en"}, , requirements = {"_locale" = "fr|en|uk"}) */ 

    Ma per il modo yml, prova qualche equivalente …

    Forse l’ho risolto in un modo ragionevolmente semplice:

     example: path: '/{_locale}{_S}example' defaults: { _controller: 'AppBundle:Example:index' , _locale="de" , _S: "/" } requirements: _S: "/?" _locale: '|de|en|fr' 

    Curioso del giudizio dei critici … Un caro saluto, Greg

     root: pattern: / defaults: _controller: FrameworkBundle:Redirect:urlRedirect path: /en permanent: true 

    Come configurare un reindirizzamento su un’altra rotta senza un controller personalizzato

    Penso che potresti semplicemente aggiungere un percorso come questo:

     example: pattern: /example defaults: { _controller: ExampleBundle:Example:index } 

    In questo modo, la locale sarà l’ultima impostazione locale selezionata dall’utente o la locale predefinita se le impostazioni locali dell’utente non sono state impostate. Si potrebbe anche aggiungere il parametro “_locale” ai “valori predefiniti” nella propria configurazione di routing se si desidera impostare un locale specifico per / esempio:

     example: pattern: /example defaults: { _controller: ExampleBundle:Example:index, _locale: fr } 

    Non so se c’è un modo migliore per farlo.