In an ASP.NET MVC application, changing the Thread.CurrentThread.CurrentCulture[UI] can change the way MVC picks messages from resources. In the example application I've created to present the problem, there are two resource file - Res.resx for the English messages and Res.es.resx for the Spanish messages.
However, error messages resulting from the model validation always display in English.
My question is, how can I control the language in which the model validation error messages are displayed?
Below are parts of an example application I've wrote (based on the default ASP.NET MVC application) to demonstrate this problem.
Screenshots of how it looks in the browser:
https://dl.dropboxusercontent.com/u/4453002/SO_LanguageOfValidation.png
ViewModel and 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);
}
}
}
View - 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" />
}
I also run into the same problem. When the model binder has invalid data it runs before the ActionFilter(s).
I didn't like the proposed solutions because messing with the routing was not my preferred solution. Listen for Application_AcquireRequestState is problematic because this event fire for each and every request, not just for requests that will be routed into MVC controllers.
I've end up writing a custom implementation of IControllerFactory
that use DefaultControllerFactory
internally and execute the localization code inside CreateController
method.
This is not ideal either, hope it helps.
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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With