在ASP.Net MVC应用程序中设置文化

Chr*_*sCa 82 asp.net-mvc culture localization

在ASP.net MVC应用程序中设置Culture/UI Culture的最佳位置是什么

目前我有一个CultureController类,如下所示:

public class CultureController : Controller
{
    public ActionResult SetSpanishCulture()
    {
        HttpContext.Session["culture"] = "es-ES";
        return RedirectToAction("Index", "Home");
    }

    public ActionResult SetFrenchCulture()
    {
        HttpContext.Session["culture"] = "fr-FR";
        return RedirectToAction("Index", "Home");
    }
}
Run Code Online (Sandbox Code Playgroud)

以及主页上每种语言的超链接,其链接如下:

<li><%= Html.ActionLink("French", "SetFrenchCulture", "Culture")%></li>
<li><%= Html.ActionLink("Spanish", "SetSpanishCulture", "Culture")%></li>
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,但我认为有一个更合适的方法来做到这一点.

我正在使用以下ActionFilter http://www.iansuttle.com/blog/post/ASPNET-MVC-Action-Filter-for-Localized-Sites.aspx阅读文化 .我有点像MVC菜鸟,所以我不相信我会把它设置在正确的位置.我不想在web.config级别这样做,它必须基于用户的选择.我也不想检查他们的http-header以从他们的浏览器设置中获取文化.

编辑:

只是要明确 - 我不是要决定是否使用会话.我对此感到高兴.我想要解决的是,如果最好在文化控制器中执行此操作,该控制器具有要设置的每个文化的操作方法,或者在MVC管道中是否有更好的位置来执行此操作?

jao*_*jao 109

我正在使用这种本地化方法并添加了一个路由参数,可以在用户访问example.com/xx-xx/时设置文化和语言

例:

routes.MapRoute("DefaultLocalized",
            "{language}-{culture}/{controller}/{action}/{id}",
            new
            {
                controller = "Home",
                action = "Index",
                id = "",
                language = "nl",
                culture = "NL"
            });
Run Code Online (Sandbox Code Playgroud)

我有一个过滤器,可以进行实际的文化/语言设置:

using System.Globalization;
using System.Threading;
using System.Web.Mvc;

public class InternationalizationAttribute : ActionFilterAttribute {

    public override void OnActionExecuting(ActionExecutingContext filterContext) {

        string language = (string)filterContext.RouteData.Values["language"] ?? "nl";
        string culture = (string)filterContext.RouteData.Values["culture"] ?? "NL";

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture));
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture));

    }
}
Run Code Online (Sandbox Code Playgroud)

要激活国际化属性,只需将其添加到您的类:

[Internationalization]
public class HomeController : Controller {
...
Run Code Online (Sandbox Code Playgroud)

现在,只要访问者访问http://example.com/de-DE/Home/Index,就会显示德语网站.

我希望这个答案能指出你正确的方向.

我还制作了一个小型MVC 5示例项目,您可以在这里找到它

只需转到http:// {yourhost}:{port}/en-us/home/index查看当前日期(英文),或将其更改为http:// {yourhost}:{port}/de -de/home/index for German etcetera.

  • 将语言添加到URL不会违反REST.事实上,它通过使Web资源不依赖于隐藏的会话状态来遵守它. (50认同)
  • 我还喜欢将lang放在URL中,因为它可以被不同语言的搜索引擎抓取,并允许用户保存或发送具有特定语言的URL. (15认同)
  • Web资源不依赖于隐藏状态,即呈现的方式.如果要将该资源作为Web服务访问,则需要选择一种语言来执行此操作. (4认同)
  • 我遇到过这种解决方案的一些问题.验证错误消息未被翻译.为了解决这个问题,我在global.asax.cs文件的Application_AcquireRequestState函数中设置了culture. (4认同)
  • 把它放在过滤器中并不是一个好主意.模型绑定使用CurrentCulture,但ActionFilter在模型绑定后发生.最好在Global.asax,Application_PreRequestHandlerExecute中执行此操作. (4认同)

mar*_*pet 37

我知道这是一个老问题,但是如果你真的想要使用你的ModelBinder(关于DefaultModelBinder.ResourceClassKey = "MyResource";viewmodel类的数据注释中指示的资源),控制器甚至是一个ActionFilter为时已晚树立了文化.

文化可以设置Application_AcquireRequestState,例如:

protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        // For example a cookie, but better extract it from the url
        string culture = HttpContext.Current.Request.Cookies["culture"].Value;

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
    }
Run Code Online (Sandbox Code Playgroud)

编辑

实际上有一种更好的方式使用自定义路由处理程序,根据网址设置文化,Alex Adamyan在他的博客上完美描述.

所有要做的就是覆盖GetHttpHandler方法并在那里设置文化.

public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        // get culture from route data
        var culture = requestContext.RouteData.Values["culture"].ToString();
        var ci = new CultureInfo(culture);
        Thread.CurrentThread.CurrentUICulture = ci;
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);
        return base.GetHttpHandler(requestContext);
    }
}
Run Code Online (Sandbox Code Playgroud)


Jac*_*hea 24

我会在控制器的Initialize事件中这样做......

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);

        const string culture = "en-US";
        CultureInfo ci = CultureInfo.GetCultureInfo(culture);

        Thread.CurrentThread.CurrentCulture = ci;
        Thread.CurrentThread.CurrentUICulture = ci;
    }
Run Code Online (Sandbox Code Playgroud)

  • 我理解这一点,但问题是在哪里设置文化最好而不是如何设置文化。 (2认同)

Ner*_*ury 7

由于它是按用户存储的设置,因此会话是存储信息的适当位置.

我会更改您的控制器以将文化字符串作为参数,而不是为每个潜在的文化采用不同的操作方法.添加页面链接很简单,只要需要新的文化,就不需要重复编写相同的代码.

public class CultureController : Controller    
{
        public ActionResult SetCulture(string culture)
        {
            HttpContext.Session["culture"] = culture
            return RedirectToAction("Index", "Home");
        }        
}

<li><%= Html.ActionLink("French", "SetCulture", new {controller = "Culture", culture = "fr-FR"})%></li>
<li><%= Html.ActionLink("Spanish", "SetCulture", new {controller = "Culture", culture = "es-ES"})%></li>
Run Code Online (Sandbox Code Playgroud)


Pat*_*ins 5

什么是最好的地方是你的问题.最好的地方是Controller.Initialize方法.MSDN写道它是在构造函数之后和操作方法之前调用的.与覆盖OnActionExecuting相反,将代码放在Initialize方法中可以让您在类和属性上对所有自定义数据注释和属性进行本地化.

例如,我的本地化逻辑来自一个注入我的自定义控制器的类.我可以访问此对象,因为在构造函数之后调用Initialize.我可以执行Thread的文化分配,而不是正确显示每条错误消息.

 public BaseController(IRunningContext runningContext){/*...*/}

 protected override void Initialize(RequestContext requestContext)
 {
     base.Initialize(requestContext);
     var culture = runningContext.GetCulture();
     Thread.CurrentThread.CurrentUICulture = culture;
     Thread.CurrentThread.CurrentCulture = culture;
 }
Run Code Online (Sandbox Code Playgroud)

即使你的逻辑不在像我提供的例子那样的类中,你也可以访问RequestContext,它允许你拥有URL和HttpContext以及你可以做任何解析的RouteData.