ASP.NET MVC 4 jQuery Validation Globalization

Going thru the ASP.NET MVC 4 intro on www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-model, I thought that I couldn’t believe what I saw.

In this intro, a MVC Web application is built, having a page to enter movie data, including a date and a price. The price is a decimal value.

Now on my machine, the culture is en-US, while the UI culture is de-DE. Saving a price of 9.78 (where the point is the decimal separator), the app writes 978 into the database. And trying to save a date in German format (dd.MM.yyyy) leads to an “invalid date format” error on the client. On the other hand, the date entered in en-US format (MM/dd/yyyy), was displayed in German format after reading.

The kind of problem is not new to me. Working with UI apps (and not just in that case), one always has to consider the culture settings. What causes my surprise was the fact that still there seems to be no built-in support to handle this issue. Even ASP.NET MVC 4 is not able to handle this itself, making sure the client side validator validates the values using the correct culture settings 🙁

Well, I looked around a little bit, and found a solution. It doesn’t make me happy, but it works.

First, I extended the system.web section of the web.config to enable ASP.NET to set the UI culture and culture for a Web page automatically, based on the values that are sent by a browser:

<globalization enableClientBasedCulture="true" 
  culture="auto:en-US" 
  uiCulture="auto:en"/>

And then I extended the view with this code:

<script src="~/Scripts/globalize.js" type="text/javascript">
</script>
<script src="~/Scripts/globalize.culture.de-DE.js" type="text/javascript">
</script>
<script src="~/Scripts/globalize.culture.en-US.js" type="text/javascript">
</script>

<script>
  $.validator.methods.number = function (value, element) {
    return this.optional(element) ||
        !isNaN(Globalize.parseFloat(value));
  }

  $.validator.methods.date = function (value, element) {
    return this.optional(element) ||
        Globalize.parseDate(value);
  }

  $(document).ready(function () {
    Globalize.culture('@System.Threading.Thread.CurrentThread.CurrentCulture');
  });
</script>

<script>
  jQuery.extend(jQuery.validator.methods, {
    range: function (value, element, param) {
      //Use the Globalization plugin to parse the value        
      var val = Globalize.parseFloat(value);
      return this.optional(element) || (
          val >= param[0] && val <= param[1]);
    }
  });
</script>

Update: Please have a look at the comments below. Dan shared his solution for the situation when the user is in a browser that has native datepicker/number support and an unknown culture (i.e. you don’t want to account for and load ALL globalize.js culture files. Thanks, Dan!

Since this code is needed by several views, I put it into a partial view and included it into the Scripts section using

@Html.Partial("_PartialViewName");

In this context I think it’s worth it to mention that the link to the jQuery Globalization plugin https://github.com/nje/jquery-glob, which is mentioned in the Web several times, works, but the new location, where it should reside now (https://github.com/jquery/jquery-global, is not valid. I found the required files on https://github.com/jquery/globalize and copied the required files from the lib directory.