在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和Controller - 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" />
}
答案 0 :(得分:2)
我也遇到了同样的问题。当模型绑定器具有无效数据时,它将在ActionFilter之前运行。
我不喜欢提出的解决方案,因为弄乱路由不是我首选的解决方案。侦听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);
}
}
}
答案 1 :(得分:0)
.NET使用完整的文化代码来获取资源文件作为首选。将Res.es.resx
重命名为Res.es-ES.resx
,看看是否有效。
答案 2 :(得分: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);
}
答案 3 :(得分:0)
我发现了一个不同的解决方案,我认为它是更好的解决方案,它需要更少的工作。在Global.asax文件中:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
// Run your culture localization here
}