javascriptc#jqueryasp.net-mvcjquery-globalize

Using Jquery Globalize with MVC 5


I am trying to use the MVC unobstrusive validation with jquery globalize plugin in MVC5 (in conjunction with the package jquery-validate-globalize). For learning purposes I started a demo project as per here, but it fails to run with globalize (it works on default Microsoft unobstrusive validation). The model is very simple:

public class GlobalizeModel
{
    [Range(10.5D, 20.3D)]
    public decimal Double { get; set; }

    [Required]
    public DateTime? DateTime { get; set; }
}

I try to initiate Globalize as follows at the bottom of the _Layout page (the view is minimal with 2 input only): (I get list of necessary files from https://johnnyreilly.github.io/globalize-so-what-cha-want/)

<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

<!--cldr scripts-->
<script src="~/Scripts/cldr.js"></script>
<script src="~/Scripts/cldr/event.js"></script>
<script src="~/Scripts/cldr/supplemental.js"></script>
<!--globalize scripts-->
<script src="~/Scripts/globalize.js"></script>
<script src="~/Scripts/globalize/number.js"></script>
<script src="~/Scripts/globalize/date.js"></script>
<!--jquery globalize-->
<script src="~/Scripts/jquery.validate.globalize.js"></script>


<script>

    $.when(
        $.getJSON("/Scripts/cldr/supplemental/likelySubtags.json"),
        $.getJSON("/Scripts/cldr/main/en/numbers.json"),
        $.getJSON("/Scripts/cldr/supplemental/numberingSystems.json"),
        $.getJSON("/Scripts/cldr/main/en/ca-gregorian.json"),
        $.getJSON("/Scripts/cldr/main/en/timeZoneNames.json"),
        $.getJSON("/Scripts/cldr/supplemental/timeData.json"),
        $.getJSON("/Scripts/cldr/supplemental/weekData.json"),
        $.getJSON("/Scripts/cldr/main/tr/numbers.json"),
        $.getJSON("/Scripts/cldr/main/tr/ca-gregorian.json"),
        $.getJSON("/Scripts/cldr/main/tr/timeZoneNames.json"),
        console.log("JSONs loaded")
        ).then(function () {
            console.log("start slicing");
            return [].slice.apply(arguments, [0]).map(function (result) {
                console.log("slicing done");
                return result[0];
            });
        }).then(Globalize.load).then(function () {
            Globalize.locale("en");
            console.log("Locale set to en");
        }).then(console.log("LOADED EVERYTHING"));


</script>

But when I run the page, I only see the console logs JSOns loaded and LOADED EVERYTHING. Moreover, when I try a client side validation by typing anything in the number textbox (and of course when the focus is lost), I get the following error in the console:

Uncaught Error: E_DEFAULT_LOCALE_NOT_DEFINED: Default locale has not been defined.

This post here is similar, and I tried to check the things listed there. I think my JSON objects are not fetched, but I am not good aj JS so I am not sure on that. I added the following items to web.config to see if this is something related with file serving, with no avail:

<system.webServer>
 <staticContent>
  <remove fileExtension=".json"/>
  <mimeMap fileExtension=".json" mimeType="application/json" />
 </staticContent>
</system.webServer> 

The culture is set to auto in web.config as follows:

<system.web>
  <globalization culture="auto" uiCulture="auto" />
  <compilation debug="true" targetFramework="4.5.2"/>
  <httpRuntime targetFramework="4.5.2"/>
</system.web>

You can see Scripts folder structure in here:

You can see <code>Scripts</code> folder structure in here

So, what is the problem here? How can I make this thing work?


Solution

  • I recently ran into the same problem, trying to add I18n to an MVC5 web app. After several days of research and partly using your code as base, I found some things that helped me implement it.

    My Solution: In a separate project, I added decimal and DateTime properties to the ApplicationUser class:

    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    
        public DateTime birthdate { get; set; }
        public decimal balance { get; set; }
    }
    

    I also modified the RegisterViewModel to accept those properties, as follows:

    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }
    
        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }
    
        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    
        [Required]
        [DataType(DataType.DateTime)]
        public DateTime birthdate { get; set; }
    
        [Required]
        [DataType(DataType.Currency)]
        public decimal balance { get; set; }
    }
    

    Then, I set the culture in a base controller, from which other controllers inherit:

    public class BaseController : Controller
    {
        protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
        {
            string[] cultures = { "es-CL", "es-GT", "en-US" };
            Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultures[1]);
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
    
            return base.BeginExecuteCore(callback, state);
        }
    }
    

    That's just for testing purposes, not the way I fetch culture in the real app.

    My file structure is the same as yours and I didn't modify the web.config file.

    I also used this link for dependencies. But then I modified a few things in the scripts section of Register.cshtml:

    <!-- CLDR -->
    <script src="~/Scripts/cldr.js"></script>
    <script src="~/Scripts/cldr/event.js"></script>
    <script src="~/Scripts/cldr/supplemental.js"></script>
    <!-- Globalize -->
    <script src="~/Scripts/globalize.js"></script>
    <script src="~/Scripts/globalize/number.js"></script>
    <script src="~/Scripts/globalize/date.js"></script>
    <!-- $ validate -->
    <script src="~/Scripts/jquery.validate.js"></script>
    <script src="~/Scripts/jquery.validate.globalize.js"></script>
    <!-- fetch files -->
    <script>
        $.when(
            $.getJSON("/Scripts/cldr/supplemental/likelySubtags.json"),
            $.getJSON("/Scripts/cldr/main/en/numbers.json"),
            $.getJSON("/Scripts/cldr/supplemental/numberingSystems.json"),
            $.getJSON("/Scripts/cldr/main/en/ca-gregorian.json"),
            $.getJSON("/Scripts/cldr/main/en/timeZoneNames.json"),
            $.getJSON("/Scripts/cldr/supplemental/timeData.json"),
            $.getJSON("/Scripts/cldr/supplemental/weekData.json"),
            $.getJSON("/Scripts/cldr/main/tr/numbers.json"),
            $.getJSON("/Scripts/cldr/main/tr/ca-gregorian.json"),
            $.getJSON("/Scripts/cldr/main/tr/timeZoneNames.json"),
            ).then(function () {
                console.log("start slicing");
                return [].slice.apply(arguments, [0]).map(function (result) {
                    console.log("slicing done");
                    return result[0];
                });
            }).then(Globalize.load).then(function () {
                Globalize.locale("en");
                console.log("Locale set to en");
            }).then(console.log("LOADED EVERYTHING"));
    </script>
    

    The _Layout view scripts weren't modified at all, and I had no problem with the console logs.

    That's all, it worked out for me, and as it's a very similar case, I hope it works for you too.