2010-01-27 63 views
18

我需要現有控制器的多語言URL路由。讓我來解釋更多:如何使用MVC路由多語言URL

我有一個名爲「產品」和查看名稱爲「軟件」的控制器;因此,在默認情況下,如果用戶輸入「http://example.com/en/Product/Software」,得到正確的內容(即確實存在在http://example.com/Product/Software),

但是,如果另一個用戶 - 法國用戶 - 類型「http://example.com/fr/Produits/logiciels」,必須讓上述控制器和顯示與正確的內容(相同http://example.com/Product/Software,但與法文文本)。

注:我設爲 「{語言}/{控制器}/{行動}/{ID}」 的路由表

其他任何無效的URL必須顯示404頁。

可能嗎?

+0

其實這不是一個好主意,如果你關心搜索引擎的排名。您總是可以重定向到英文頁面,或者對同一實體的所有實例使用標準規範URL。 – 2011-02-02 21:20:28

回答

6

建立在丹的職位,我使用下方翻譯我的控制器和動作名稱。

我創建了一個表來存儲值,這可能,也可能應該保留在資源文件中,以保持一切;但是我使用了數據庫表,因爲它與我的公司流程更好地協作。然後

CREATE TABLE [dbo].[RoutingTranslations](
[RouteId] [int] IDENTITY(1,1) NOT NULL, 
[ControllerName] [nvarchar](50) NOT NULL, 
[ActionName] [nvarchar](50) NOT NULL, 
[ControllerDisplayName] [nvarchar](50) NOT NULL, 
[ActionDisplayName] [nvarchar](50) NOT NULL, 
[LanguageCode] [varchar](10) NOT NULL) 

的RouteConfig.cs文件改爲:

public class RouteConfig 
{ 
    public static void RegisterRoutes(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

     //Build up routing table based from the database. 
     //This will stop us from having to create shedloads of these statements each time a new language, controller or action is added 
     using (GeneralEntities db = new GeneralEntities()) 
     { 
      List<RoutingTranslation> rt = db.RoutingTranslations.ToList(); 
      foreach (var r in rt) 
      { 
       routes.MapRoute(
        name: r.LanguageCode + r.ControllerDisplayName + r.ActionDisplayName, 
        url: r.LanguageCode + "/" + r.ControllerDisplayName + "/" + r.ActionDisplayName + "/{id}", 
        defaults: new { culture = r.LanguageCode, controller = r.ControllerName, action = r.ActionName, id = UrlParameter.Optional }, 
        constraints: new { culture = r.LanguageCode } 
       ); 
      }     
     } 

     //Global catchall 
     routes.MapRoute(
      name: "Default", 
      url: "{culture}/{controller}/{action}/{id}", 
      defaults: new {culture = CultureHelper.GetDefaultCulture(), controller = "Default", action = "Index", id = UrlParameter.Optional } 
      //defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
     ); 

    } 
} 

默認情況下,這將始終使用英語控制器和動作的名稱,但允許您通過輸入值到提供一個覆蓋表。

(我的國際代碼主要是從這個偉大的博客文章爲主。 http://afana.me/post/aspnet-mvc-internationalization-part-2.aspx

+0

雖然這對新增加的路由不起作用,是否因爲註冊路由只執行一次啓動? – alex 2016-04-29 00:03:23

4

如前所述,這與網站網址(和路線)使用英語的慣例不同。

儘管如此,但爲了做到這一點,您可能必須考慮爲每種外語生成一條路徑。因此,對於有20種行爲和三種語言(英語,法語和德語)的網站,您需要41條路線(20個法語,20個德語和1個英語)。我承認,這不是最有效的系統,但它可以按照您的要求運行。

//You'll only need one of these, which is the default. 
routes.MapRoute(
    "English route", 
    "en/{controller}/{action}/{id}" 
    new { controller = "Home", action = "Index", language = "en" }, 
); 

routes.MapRoute(
    "FrenchHome", 
    "fr/Demarrer/Index/{id}", 
    new { controller = "Home", action = "Index", language = "fr" } 
); 

routes.MapRoute(
    "GermanHome", 
    "de/Heim/Index/{id}", //'Heim' is, I believe the correct usage of Home in German. 
    new { controller = "Home", action = "Index", language = "de" } 
); 

//Some more routes... 

routes.MapRoute(
    "FrenchSoftware", 
    "fr/Produit/Logiciels/{id}", 
    new { controller = "Product", action = "Software", language = "fr" } 
); 

routes.MapRoute(
    "GermanSoftware", 
    "de/Produkt/Software/{id}", //In this instance, Software should be the same in German and English. 
    new { controller = "Product", action = "Software", language = "de" } 
); 

//And finally, the 404 action. 
routes.MapRoute(
    "Catchall", 
    "{language}/{*catchall}", 
    new { controller = "Home", action = "PageNotFound", language = "en" }, 
    new { language = "^(en|fr|de)$" } 
); 

//This is for the folks who didn't put a language in their url. 
routes.MapRoute(
    "Catchall", 
    "{*catchall}", 
    new { controller = "Home", action = "PageNotFound", language = "en" } 
); 

在你的行動,例如產品/軟件...

public ActionResult Software(string language, int id) 
{ 
    //This would go off to the DAL and get the content in whatever language you want. 
    ProductModel model = ProductService.GetSoftware(language, id); 

    return View(model); 
} 

我會LOVE,如果有人走過來,說,有這樣做的更好的辦法,因爲我同意擁有外語網址並不好,並且考慮到互聯網本身正在朝着允許非羅馬字符的URL發展,我們越早尋求解決方案就越好。

不僅如此,但我知道驕傲的法國人不喜歡看到他們的網站URL包含英語。 :)

+1

回答(有人提出更好的方法......)不關心傳遞給action方法的是什麼?相反,像正常一樣進行路由。但是在你的基本控制器上有一個OnActionExecuting()重載,它根據路由相應地設置了CultureUI(例如,它會查看filterContext中的Request.Url)。或者更強大的版本將創建自己的繼承自Route的LangaugeRoute()類。在它上面添加一個新的屬性LanguageCode,並在你的答案中的MapRoute中設置它。然後,你可以在你的OnActionExecuting()中強制類型化它。 – eduncan911 2012-09-24 01:24:55

+0

我喜歡這一點,但檢查當前的文化有其風險,主要與您可能實際上沒有該網站版本的可能性有關。例如,土耳其語在文化方面有很多問題(谷歌土耳其語問題)。在任何情況下,您都必須在某處創建一堆if/else或外殼聲明來處理您確實具有的翻譯,以便在不正確的情況下默認給另一個翻譯。 – 2012-09-24 11:03:56

+1

另外,這是Maarten Balliauw撰寫的關於這個主題的優秀博客文章。 http://blog.maartenballiauw.be/post/2010/01/26/Translating-routes-(ASPNET-MVC-and-Webforms).aspx – 2012-09-24 11:05:18

0

我強烈建議採用以下方法來實現MVC模式5(和<)Web應用程序的多語言,因爲我發現它是我在最近幾年中嘗試過的最通用的一個。

你基本上需要實現三兩件事:

  • 多語言感知路由處理傳入的URL(如果你使用MVC5或以上,你也可以去基於屬性的路由相反,但我仍然喜歡使用全局規則來處理這個問題)。
  • A LocalizationAttribute來處理這些類型的多語言請求。
  • 幫助程序在您的應用程序(Html.ActionLink和/或Url.Action擴展方法)中生成這些URL的幫助方法。

查看this answer瞭解更多詳情和代碼示例。

有關此主題的其他信息和進一步示例,您還可以閱讀this post