asp.net mvc本地化

我正在尝试使用路由实现本地化

我有以下内容:

routes.MapRoute( "DefaultLocalized", "{lang}/{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "", lang = "en" } ); routes.MapRoute( "Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" } ); 

当我调用我的页面domain/en/home/index ,它工作正常,但是当我调用domain/home/index我得到错误404:找不到资源。

此外,当我在domain/en/home/index并且我点击一个安全页面时,我被重定向到domain/Account/login ,我如何被重定向到domain/en/Account/login

另外,当我收到应用程序错误时,如何将其重定向到domain/en/home/error

真正的问题是如何使用语言作为路由参数实现本地化?

你还可以引入一个比Marc Gravell和Freddy Rios更严格的约束。

像“en | de | fr | es”这样的东西。 这意味着对语言进行硬编码,但通常这些语言很少且已知。

默认情况下,路由将从左到右匹配,因此“domain / home / index”将首先匹配lang = domain,controller = index,action(默认为index),id(默认为0 / null)。

要解决这个问题,我相信你可以在MapRoute上指定一个正则表达式(例如,匹配,正好是2个字符的语言) – 它在某些时候发生了变化,但是……(对不起,目前没有IDE,所以我可以不完全检查。

从记忆中,它可能是:

 routes.MapRoute( "DefaultLocalized", "{lang}/{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "",}, new { lang = "[az]{2}" } ); 

请注意,您可能不希望每个操作都采用“字符串lang”,因此您应该在基本控制器或动作filter中处理路径的“lang”部分(在任何一种情况下,大概都是将信息添加到ViewData)。

我知道这是一个非常古老的问题,但只需要解决一整套相关问题,我想我会分享我的解决方案。

以下是一个完整的解决方案,包括一些额外的技巧,可以轻松更改语言。 它允许特定的文化,而不仅仅是特定的语言(但在这个例子中只保留语言部分)。

function包括:

  • 在确定语言时回退到浏览器区域设置
  • 使用cookie来保持跨访问语言
  • 用url覆盖语言
  • 支持通过链接更改语言(例如简单的菜单选项)

第1步:修改RouteConfig中的RegisterRoutes

这个新路由包括一个约束(正如其他人也建议的那样),以确保语言路由不会获取某些标准路径。 不需要默认语言值,因为它全部由LocalisationAttribute处理(参见步骤2)。

  public static void RegisterRoutes(RouteCollection routes) { ... // Special localisation route mapping - expects specific language/culture code as first param routes.MapRoute( name: "Localisation", url: "{lang}/{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { lang = @"[az]{2}|[az]{2}-[a-zA-Z]{2}" } ); // Default routing routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } 

第2步:创建本地化属性

这将在处理控制器请求之前查看它们,并根据URL,cookie或默认浏览器文化更改当前区域性。

 // Based on: http://geekswithblogs.net/shaunxu/archive/2010/05/06/localization-in-asp.net-mvc-ndash-3-days-investigation-1-day.aspx public class LocalisationAttribute : ActionFilterAttribute { public const string LangParam = "lang"; public const string CookieName = "mydomain.CurrentUICulture"; // List of allowed languages in this app (to speed up check) private const string Cultures = "en-GB en-US de-DE fr-FR es-ES ro-RO "; public override void OnActionExecuting(ActionExecutingContext filterContext) { // Try getting culture from URL first var culture = (string)filterContext.RouteData.Values[LangParam]; // If not provided, or the culture does not match the list of known cultures, try cookie or browser setting if (string.IsNullOrEmpty(culture) || !Cultures.Contains(culture)) { // load the culture info from the cookie var cookie = filterContext.HttpContext.Request.Cookies[CookieName]; var langHeader = string.Empty; if (cookie != null) { // set the culture by the cookie content culture = cookie.Value; } else { // set the culture by the location if not specified - default to English for bots culture = filterContext.HttpContext.Request.UserLanguages == null ? "en-EN" : filterContext.HttpContext.Request.UserLanguages[0]; } // set the lang value into route data filterContext.RouteData.Values[LangParam] = langHeader; } // Keep the part up to the "-" as the primary language var language = culture.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries)[0]; filterContext.RouteData.Values[LangParam] = language; // Set the language - ignore specific culture for now Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language); // save the locale into cookie (full locale) HttpCookie _cookie = new HttpCookie(CookieName, culture); _cookie.Expires = DateTime.Now.AddYears(1); filterContext.HttpContext.Response.SetCookie(_cookie); // Pass on to normal controller processing base.OnActionExecuting(filterContext); } } 

第3步:将本地化应用于所有控制器

例如

 [Localisation] <<< ADD THIS TO ALL CONTROLLERS (OR A BASE CONTROLLER) public class AccountController : Controller { 

第4步:更改语言(例如从菜单中)

这是一个有点棘手的地方,需要一些解决方法。

将ChangeLanguage方法添加到您的帐户控制器。 这将从“上一个路径”中删除任何现有语言代码,以允许新语言生效。

  // Regex to find only the language code part of the URL - language (aa) or locale (aa-AA) syntax static readonly Regex removeLanguage = new Regex(@"/[az]{2}/|/[az]{2}-[a-zA-Z]{2}/", RegexOptions.Compiled); [AllowAnonymous] public ActionResult ChangeLanguage(string id) { if (!string.IsNullOrEmpty(id)) { // Decode the return URL and remove any language selector from it id = Server.UrlDecode(id); id = removeLanguage.Replace(id, @"/"); return Redirect(id); } return Redirect(@"/"); } 

第5步:添加语言菜单链接

菜单选项包含指定为路径参数的新语言的链接。

例如(Razor例子)

 
  • @Html.ActionLink("English", "ChangeLanguage", "Account", new { lang = "en", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)
  • @Html.ActionLink("Spanish", "ChangeLanguage", "Account", new { lang = "es", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)
  • 返回URl是当前页面,经过编码,以便它可以成为URL的id参数。 这意味着您需要启用某些转义序列,否则Razor会拒绝这些转义序列作为潜在的安全违规。

    注意:对于非剃刀设置,您基本上需要一个具有新语言的锚点和当前页面相对URL,如下所示: http://website.com/{language}/account/changelanguage/{existingURL}http://website.com/{language}/account/changelanguage/{existingURL} language http://website.com/{language}/account/changelanguage/{existingURL} account/ http://website.com/{language}/account/changelanguage/{existingURL}

    其中{language}是新的文化代码, {existingURL}是当前相对页面地址的URLencoded版本(这样我们将返回同一页面,选择新的语言)。

    第6步:在url中启用某些“不安全”字符

    返回URL所需的编码意味着您需要在web.config启用某些转义字符,否则现有的URL参数将导致错误。

    在您的web.config中,在找到httpRuntime标记(或添加它)并向其中添加以下内容(基本上删除此属性的标准版本中的%):

      requestPathInvalidCharacters="<,>,&,:,\,?" 

    在web.config中,找到部分并在其中添加以下内容:

        

    添加约束作为新{lang =“[az] {2}”}。

    另外,删除默认的lang =“en”。 如果不这样做,路由将在没有它的情况下浏览语言规则。 因此,如果您正在查看并选择关于,它将使用domain / en / Home / About而不是更简单的域/ Home / About