2011-10-26 46 views
26

我的路由和Symfony2構建的網站國際化有問題。
如果我定義在routing.yml中的文件路徑,如:Symfony2路由中的默認語言環境

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

它正常工作與像URL:

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

但不與工作

mysite.com/example 

難道只有在URL末尾才允許使用可選的佔位符?
如果是的話,這可能是用於顯示URL像一個可能的解決方案:當他參觀

mysite.com/defaultlanguage/example 

:在默認語言

mysite.com/example 

或將用戶重定向到

mysite.com/example. ? 

我試圖弄清楚,但迄今沒有成功。

謝謝。

+0

你能解決這個問題? –

+0

我沒有在我的網站上實施任何有關默認本地的解決方案。在我們走向國際的時候,我可能不得不這樣做,我會報告我們在這裏實施的解決方案。我剛剛閱讀了答案,@mattexx似乎是最好的/更清潔的答案。我不知道你可以爲一個控制器定義多個路由。 –

回答

-3

我想你可以簡單地添加這樣的路線:

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

這樣,如果用戶區域尚未設置的語言環境是由用戶選擇的最後一個區域,或者默認的語言環境。

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

我不知道是否有更好的方法來做到這一點:你也可能會在「_locale」參數,如果你想設置一個特定的區域設置/例如添加到您的路由配置的「默認」 。

+0

您是否嘗試過這種解決方案?這裏的模式不包含任何語言環境,我認爲它不起作用。 –

0

我使用註釋,我會做

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

但對陽明路,嘗試一些等價...

+1

有關信息,有關語言環境的一些更改正在爲V2.1提供。區域設置只會在請求中,不會在會話中使用 https://github.com/symfony/symfony/commit/74bc699b270122b70b1de6ece47c726f5df8bd41 – webda2l

+1

我不想使用相同的URL以多種不同的語言顯示資源用戶的區域設置。我想使用默認網址以網站默認語言顯示資源。例如,這就是蘋果在他們的網站上做的:http://apple.com =>美國「默認」版本; http://apple.com/uk:uk版本; http://apple.com/fr:法文版等 –

11

可以定義多個模式是這樣的:

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

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

你應該能夠通過註釋實現相同的排序:

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

希望有所幫助!

+1

它有幫助。然而,帶註釋的較低的一個對我來說不起作用。爲什麼? – mario

+1

可能你忘了'使用Sensio \ Bundle \ FrameworkExtraBundle \ Configuration \ Route;' – Jhonne

+0

請確保你使用不同的路由名稱 – amiroff

6

這是我使用自動區域設置檢測和重定向,它工作得很好,不需要冗長的路由註釋:

的routing.yml

locale路線處理網站的根目錄,然後每個其他控制器操作都預置了語言環境。

locale: 
    path:/
    defaults: { _controller: AppCoreBundle:Core:locale } 

main: 
    resource: "@AppCoreBundle/Controller" 
    prefix: /{_locale} 
    type: annotation 
    requirements: 
    _locale: en|fr 

CoreController.php

此檢測用戶的語言和重定向到您所選擇的路線。因爲這是最常見的情況,所以我把家用作默認設置。

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

    return $this->redirect($this->generateUrl($route, $parameters)); 
} 

然後,路線註釋可以僅僅是:

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

嫩枝

的localeAction可以用來允許用戶更改語言環境,而不從當前頁面導航離去:

<a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': targetLocale })) }}">{{ targetLanguage }}</a> 

Clean &簡單!

+0

不過這樣一來自動重定向到與區域的鏈接: www.example.com/en www.example.com/fr 但www.example。com沒有顯示。 我們正在試圖做的是完全一樣的運行www.symfony.com網站: 如果我去www.example.com則使用默認的語言環境 如果我去www.example.com/fr採用FR區域 如果我去www.example.com/en的區域使用EN 望着symfony的網站,並在該文件第一章的路線也規定,如果我去www.example.com和所有其他路線沒有指定他使用默認區域設置的地方而無需更改網址! – Lughino

+1

夠公平的。這種方法使得語言環境總是在URL中,我個人不介意。尤其是它使註解保持簡單並且與語言環境設置完全分離。 –

+0

但是不解決問題。 然而最優解決方案! – Lughino

2

有我的解決方案,它使這個過程更快!

控制器:

/** 
* @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); 
} 

嫩枝:

<li {% if app.request.locale == language.locale %} class="selected" {% endif %}> 
    <a href="{{ path('locale_change', { 'current' : app.request.locale, 'locale' : language.locale }) }}"> {{ language.locale }}</a> 
</li> 
18

如果有人有興趣,我成功地把一個前綴我routing.yml,而無需使用其他包。

所以,現在,放入系統網址的工作:

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

編輯您的app/config/routing.yml

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

然後,在你app/config/parameters.yml,你必須建立一個區域

parameters: 
    locale: en 

隨着這樣,人們可以訪問您的網站,而無需輸入特定的區域設置。

+7

不幸的是,這不起作用:www.example.com//home/ url應該是www.example.com/home/,它不會以這種方式工作。 – amiroff

1

我有一個完整的解決方案,我發現一些研究後。我的解決方案假定您希望每條路線在其前面都有語言環境,甚至登錄。這被修改爲支持Symfony 3,但我相信它仍然可以在2中工作。

此版本還假定您希望使用瀏覽器區域設置作爲默認區域設置,如果它們轉到/ admin之類的路由,但是如果它們去/ en /管理它會知道使用en語言環境。例如下面的#2就是這種情況。

因此,例如:

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

在你想要的在整個程序中使用的區域將被正確設置所有場景。

您可以查看完整的解決方案如下,其中包括如何使它與登錄和安全工作,否則短版可能會爲你工作:

完整版本

Symfony 3 Redirect All Routes To Current Locale Version

短版

爲了讓我的例子中的案例#2成爲可能需要這樣做使用httpKernal聽者

LocaleRewriteListener.php

<?php 
//src/AppBundle/EventListener/LocaleRewriteListener.php 
namespace AppBundle\EventListener; 

use Symfony\Component\HttpFoundation\RedirectResponse; 

use Symfony\Component\Routing\RouterInterface; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 
use Symfony\Component\HttpKernel\KernelEvents; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\HttpFoundation\Session\Session; 
use Symfony\Component\Routing\RouteCollection; 

class LocaleRewriteListener implements EventSubscriberInterface 
{ 
    /** 
    * @var Symfony\Component\Routing\RouterInterface 
    */ 
    private $router; 

    /** 
    * @var routeCollection \Symfony\Component\Routing\RouteCollection 
    */ 
    private $routeCollection; 

    /** 
    * @var string 
    */ 
    private $defaultLocale; 

    /** 
    * @var array 
    */ 
    private $supportedLocales; 

    /** 
    * @var string 
    */ 
    private $localeRouteParam; 

    public function __construct(RouterInterface $router, $defaultLocale = 'en', array $supportedLocales = array('en'), $localeRouteParam = '_locale') 
    { 
     $this->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)), 
     ); 
    } 
} 

要了解這是如何工作的擡頭上的symfony文檔事件的用戶界面。

要激活你需要把它架在你的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 } 

最後,這是指需要在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'] 

最後,您需要確保所有路由現在都以/ {locale}開頭。這方面的一個樣品低於我的默認Controller.php這樣

<?php 

namespace AppBundle\Controller; 

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 
use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Symfony\Component\HttpFoundation\Request; 

/** 
* @Route("/{_locale}", requirements={"_locale" = "%app.locales%"}) 
*/ 
class DefaultController extends Controller 
{ 

    /** 
    * @Route("/", name="home") 
    */ 
    public function indexAction(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 
     ]); 
    } 

    /** 
    * @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 
     ]); 
    } 
} 
?> 

注意要求requirements={"_locale" = "%app.locales%"},這是引用config.yml文件,這樣就只需要定義所有的路線在一個地方這些要求。

希望這可以幫助別人:)

2

LocalRewriteListener的約瑟夫Astrahan的解決方案的工作,除了用,因爲$routePath == "/{_locale}".$path)

防爆PARAMS路線:$routePath = "/{_locale}/my/route/{foo}"$path = "/{_locale}/my/route/bar"

不同,我不得不使用UrlMatcher(鏈接到Symfony 2.7 api文檔),以便將實際路由與url相匹配。

我更改isLocaleSupported使用瀏覽器本地代碼(例如:fr - > fr_FR)。我使用瀏覽器區域設置作爲鍵和路由區域設置作爲值。我有一個這樣array(['fr_FR'] => ['fr'], ['en_GB'] => 'en'...)數組(見下面的參數文件的詳細信息)

的變化:

  • 檢查放棄請求當地的支載。如果不是,請使用默認語言環境。
  • 嘗試將路徑與應用程序路徑集合進行匹配。如果不是什麼都不做的話(如果路由不存在,應用會拋出404)。如果是,則在路由參數中使用正確的語言環境重定向。

這是我的代碼。適用於任何具有或不具有參數的路線。只有在路由中設置了{_local}時,纔會添加區域設置。

路由文件(在我的情況下,一個在app /配置)

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

在app /配置/ parameters.yml文件

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

服務的參數。 yml

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

LocaleRewriteListener.php

<?php 
namespace AppBundle\EventListener; 

use Symfony\Component\HttpFoundation\RedirectResponse; 

use Symfony\Component\Routing\RouterInterface; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 
use Symfony\Component\HttpKernel\KernelEvents; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\HttpFoundation\Session\Session; 
use Symfony\Component\Routing\RouteCollection; 
use Symfony\Component\Routing\Matcher\UrlMatcher; 
use Symfony\Component\Routing\RequestContext; 

class LocaleRewriteListener implements EventSubscriberInterface 
{ 
    /** 
    * @var Symfony\Component\Routing\RouterInterface 
    */ 
    private $router; 

    /** 
    * @var routeCollection \Symfony\Component\Routing\RouteCollection 
    */ 
    private $routeCollection; 

    /** 
    * @var urlMatcher \Symfony\Component\Routing\Matcher\UrlMatcher; 
    */ 
    private $urlMatcher; 

    /** 
    * @var string 
    */ 
    private $defaultLocale; 

    /** 
    * @var array 
    */ 
    private $supportedLocales; 

    /** 
    * @var string 
    */ 
    private $localeRouteParam; 

    public function __construct(RouterInterface $router, $defaultLocale = 'fr', array $supportedLocales, $localeRouteParam = '_locale') 
    { 
     $this->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)), 
     ); 
    } 
} 
0

也許我在一個相當簡單的方式解決了這個:

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

好奇的批評的判斷... 最良好的祝願, 格雷格

2

Symfony3

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

這隻會允許'domain.com //測試'而不是'domain.com/test'。 –

相關問題