我知道这是一个非常古老的问题,但刚刚解决了完整的相关问题,我想我会分享我的解决方案。
下面是一个完整的解决方案,包括一些额外的技巧,可以轻松更改语言。它允许特定的文化,而不仅仅是特定的语言(但在这个例子中只保留了语言部分)。
功能包括:
- 在确定语言时回退到浏览器区域设置
- 使用 cookie 在访问中保留语言
- 用 url 覆盖语言
- 支持通过链接更改语言(例如简单的菜单选项)
第一步:在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 = @"[a-z]{2}|[a-z]{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(@"/[a-z]{2}/|/[a-z]{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 步:添加语言菜单链接
菜单选项由一个链接组成,新语言指定为路由参数。
例如(剃刀示例)
<li>@Html.ActionLink("English", "ChangeLanguage", "Account", new { lang = "en", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)</li>
<li>@Html.ActionLink("Spanish", "ChangeLanguage", "Account", new { lang = "es", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)</li>
返回的 URl 是当前页面,经过编码可以成为 URL 的 id 参数。这意味着您需要启用某些转义序列,否则 Razor 会拒绝这些转义序列作为潜在的安全违规行为。
注意:对于非剃须刀设置,您基本上需要一个具有新语言和当前页面相对 URL 的锚点,路径如下:
http://website.com/{language}/account/changelanguage/{existingURL}
其中{language} 是新的文化代码,{existingURL} 是当前相对页面地址的 URL 编码版本(这样我们将返回同一页面,并选择新的语言)。
第 6 步:在 URL 中启用某些“不安全”字符
返回 URL 所需的编码意味着您需要在 web.config 中启用某些转义字符,否则现有 URL 参数将导致错误。
在您的 web.config 中,找到 <system.web> 中的 httpRuntime 标记(或添加它)并向其添加以下内容(基本上删除该属性的标准版本中的 %):
requestPathInvalidCharacters="<,>,&,:,\,?"
在您的 web.config 中,找到 <system.webserver> 部分并在其中添加以下内容:
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>