ASP.NET MVC - 本地化路由

23
我想为我的网站创建本地化的URL。它们应该指向相同的控制器操作,但我希望第一个路由值始终是位置/语言规范。这可能吗?

http://www.website.com/en/us/controller/action

http://www.website.com/en/gb/controller/action

我理解可以通过在每个路由中定义{language}{location}来实现,但我正在寻找一种简洁、非hacky的解决方案。
4个回答

15
你可以创建一个带有内置文化的路由,像这样...
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                              // Route name
        "{culture}/{controller}/{action}/{id}",                           // URL with parameters
        new { culture="en-US", controller = "Home", action = "Index", id = "" }  // Parameter defaults
    );

}

您可以通过向所有操作添加一个 culture 参数来获取文化信息,例如:

public ActionResult Index(string culture)
{
    ViewData["Message"] = "Welcome to ASP.NET MVC! (" + culture + ")";

    return View();
}

您也可以在Global.asax的Application_BeginRequest方法中解析URL并设置线程文化(下面的代码示例显示如何设置文化,而解析则由您完成)。
如果这样做,您可能无法使用RedirectToAction和HTML.ActionLink类型的方法,因为它们不知道文化。当然,您可以自己编写。
使用URL存储文化的缺点是,如果您在网站上错过了某个链接或用户离开网站然后再次回来,您可能会丢失用户文化,他们将不得不再次设置它(虽然不是世界末日,但很烦人)。使用URL存储文化的好处可能在于Google将索引所有不同的语言。
如果您更关心用户体验或开发的便利性而不是Google索引不同的文化(这取决于您正在构建什么样的网站),我建议将文化存储在cookie或会话状态中。
请参阅如何本地化ASP .Net MVC应用程序?。 接受的答案指向一个博客文章,展示了如何本地化ASP.Net应用程序。
如果您将用户选择的文化存储在cookie、会话状态或查询参数中,然后在Global.asax文件的BeginRequest方法中设置线程文化,则可以使用标准的Microsoft本地化程序集进行本地化。
以下代码允许您通过将culture=??添加到查询字符串(MyPage?culture=es-MX)来随时更改文化。然后它将被添加到cookie中,这样您就不需要在系统中的每个链接末尾添加它。
protected void Application_BeginRequest()
{
    var culture = Request["culture"] ?? Request.Cookies["culture"]?.Name;
    if (culture == null) culture = "en-US";
    var ci = CultureInfo.GetCultureInfo(culture);

    Thread.CurrentThread.CurrentCulture = ci;
    Thread.CurrentThread.CurrentUICulture = ci;

    var cookie = new HttpCookie("culture", ci.Name);
    Response.Cookies.Add(cookie);
}

他正在寻求一种方法,在所有路由中添加文化和语言。 - Eduardo Molteni
我明白了。我的建议是一种不需要将其添加到路由中就可以实现的方法。把它添加到路由中会使应用程序变得更加复杂无益。 - Brian
如果有答案回答我的问题,您能具体说明会使情况复杂化吗? - Ropstah
我更新了我的回答,并提供了有关如何修改路由以允许在 URL 中包含文化信息的信息。 - Brian
我希望能够实现一种路由继承的解决方案。感谢您清晰的回答,根据我的要求,将文化存储在URL中的最显着好处(Google索引)可能并不是最需要的。创建每种语言的单独路由文件(或者显然在每个路由前缀中添加一个文化路由值)是否是使用“文化URL”并保持ActionLink.RouteUrl功能的唯一解决方案? - Ropstah
你可能很容易地设置“路由继承”。只需在默认的MVC路由之前添加我之前提到的路由,然后删除默认值或使用正则表达式来确定是否应该使用文化路由。如果不这样做,就永远无法访问默认控制器。也许有一种方法可以自动将MVC ActionLink方法放入url中。Html.ActionLink确实允许您指定路由值。我以前没有尝试过这个,所以我不确定这是否适用于您。 - Brian

8

输出缓存依赖于URL变体。在设计本地化策略时请考虑此点。如果您计划使用输出缓存,请将本地化令牌嵌入到URL的某个位置。


7

绝对是最佳解决方案。 - Alfredo Cavalcanti
提供的URL已经失效。 - percebus
1
新网址:https://blog.maartenballiauw.be/post/2010/01/26/translating-routes-%28aspnet-mvc-and-webforms%29.html - Rob Johnston

5
这是一篇关于使用路由机制在URL中存储本地化信息的非常简单而又非常强大的博客。核心是在所有指定类型的路由上添加新参数。具体内容请参考以下链接:http://adamyan.blogspot.com/2010/07/addition-to-aspnet-mvc-localization.html
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
         "Default", // Route name
         "{controller}/{action}/{id}", // URL with parameters
         new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

    foreach (Route r in routes)
    {
        if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
        {
            r.RouteHandler = new MultiCultureMvcRouteHandler();
            r.Url = "{culture}/" + r.Url;
           //Adding default culture 
           if (r.Defaults == null)
           {
               r.Defaults = new RouteValueDictionary();
           }
           r.Defaults.Add("culture", Culture.ru.ToString());

           //Adding constraint for culture param
           if (r.Constraints == null)
           {
               r.Constraints = new RouteValueDictionary();
           }
           r.Constraints.Add("culture", new CultureConstraint(Culture.en.ToString(), 
Culture.ru.ToString()));
        }
   }

}

以及转换控制器的操作

public ActionResult ChangeCulture(Culture lang, string returnUrl)
{
     if (returnUrl.Length >= 3)
     {
         returnUrl = returnUrl.Substring(3);
     }
     return Redirect("/" + lang.ToString() + returnUrl);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接