5

在 ASP.NET MVC 应用程序中,更改 Thread.CurrentThread.CurrentCulture[UI] 可以改变 MVC 从资源中挑选消息的方式。在我为呈现问题而创建的示例应用程序中,有两个资源文件 - 用于英语消息的 Res.resx 和用于西班牙语消息的 Res.es.resx。

但是,模型验证产生的错误消息始终以英文显示。

我的问题是,如何控制模型验证错误消息的显示语言?

下面是我编写的示例应用程序的一部分(基于默认的 ASP.NET MVC 应用程序)来演示这个问题。

它在浏览器中的外观截图:

https://dl.dropboxusercontent.com/u/4453002/SO_LanguageOfValidation.png

ViewModel 和控制器 - HomeController.cs :

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

namespace SO_ValidationMessageInEnglish.Controllers {

  /// <summary>
  /// A very basic view model.
  /// </summary>
  public class ViewModel {

    [Display(Name = "Message", ResourceType = typeof(Res))]
    [DisplayName("Message")]
    [Required(AllowEmptyStrings = false, ErrorMessageResourceName = "MessageRequired", ErrorMessageResourceType = typeof(Res))]
    public string Message { get; set; }

    public string Language { get; set; }
  }

  public class HomeController : Controller {

    public ActionResult Index(string language = "en") {
      Thread.CurrentThread.CurrentCulture = new CultureInfo(language);
      Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
      return View();
    }

    [HttpPost]
    [ActionName("Index")]
    public ActionResult IndexPost(ViewModel foo) {
      Thread.CurrentThread.CurrentCulture = new CultureInfo(foo.Language ?? "en");
      Thread.CurrentThread.CurrentUICulture = new CultureInfo(foo.Language ?? "en");
      return View(foo);
    }

  }
}

查看 - Index.cshtml:

@model SO_ValidationMessageInEnglish.Controllers.ViewModel
@using SO_ValidationMessageInEnglish
@{ ViewBag.Title = Res.Title; }
@Res.CurrentMessage:<br />
<h2>@((Model != null) ? Model.Message : Res.Default)</h2>
<p />    
@using (Html.BeginForm("Index", "Home", FormMethod.Post, null)) {        
    @Html.LabelFor(m => m.Message)    
    @Html.TextBoxFor(m => m.Message)
    @Html.HiddenFor(m => m.Language)
    @Html.ValidationMessageFor(m => m.Message)
    <input type="submit" value="@Res.Submit" />
}
4

4 回答 4

2

我也遇到了同样的问题。当模型绑定器具有无效数据时,它会在 ActionFilter(s) 之前运行。

我不喜欢建议的解决方案,因为弄乱路由不是我的首选解决方案。监听 Application_AcquireRequestState 是有问题的,因为这个事件会针对每个请求触发,而不仅仅是路由到 MVC 控制器的请求。

我最终在内部编写了IControllerFactory该使用的自定义实现DefaultControllerFactory并在方法内部执行本地化代码CreateController
这也不理想,希望对您有所帮助。

  public class PluggableControllerFactory : IControllerFactory {

    private readonly IControllerFactory innerControllerFactory;

    public PluggableControllerFactory() {
      innerControllerFactory = new DefaultControllerFactory();
    }

    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
      // Run your culture localization here

      return innerControllerFactory.CreateController(requestContext, controllerName);
    }

    public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName) {
      return innerControllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
    }

    public void ReleaseController(IController controller) {
      innerControllerFactory.ReleaseController(controller);
    }

  }
}
于 2013-07-16T09:31:01.760 回答
0

.NET 使用完整的文化代码来选择资源文件作为首选。重命名Res.es.resxRes.es-ES.resx,看看是否有效。

于 2013-07-14T21:34:02.227 回答
0

我想,一种方法是使用您自己的模型绑定器(尽管在某些情况下这可能会导致其他问题)。仅当操作上有模型时才会执行,因此您可能必须在两个地方设置文化(一个用于所有操作,这个用于模型验证):

public class MyModelBinder : DefaultModelBinder
{

    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        var un = HttpContext.Current.User.Identity.Name;
        if (!string.IsNullOrWhiteSpace(un))
        {
            var userLanguageCode = .......
            var culture = CultureInfo.GetCultureInfo(userLanguageCode ?? "en-US");
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;
        }

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
于 2017-03-30T15:03:58.013 回答
0

我发现了一个不同的、我认为更好的解决方案,它需要的工作更少。在 Global.asax 文件中:

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    // Run your culture localization here

}
于 2019-10-10T14:56:05.267 回答