Impostare la culture per la client side validation di ASP.NET MVC 5

di Marco De Sanctis, in ASP.NET MVC, Razor,

Alcuni anni fa ci siamo occupati di come impostare la culture per la validazione client side con jQuery.Validate e, in particolare, Globalize.js. Questo framework nel tempo è stato completamente rivoluzionato, e oggi è interamente basato su CLDR (acronimo di Common Locale Data Repository), un progetto di Unicode Consortium che contiene un enorme numero di regole di localizzazione, non solo per numeri e date, ma anche nomi degli stati, delle lingue, della pluralizzazione, ecc.

Il sito ufficiale di questo progetto è raggiungibile a questo URL: http://cldr.unicode.org/

Come possiamo sfruttare questa enorme mole di dati nella nostra applicazione ASP.NET? Il primo passo è quello di includere i necessari script e il modo più semplice per farlo è aggiungere due package NuGet:

install-package cldrjs
install-package jquery-globalize

Questi sono i componenti infrastrutturali, che richiedono però una serie di informazioni addizionali specifiche per le culture che vogliamo supportare. I metadati di CLDR sono implementati sotto forma di file JSON, che vengono combinati tra di loro fino a generare il modello a oggetti vero e proprio. Essi sono disponibili in una serie di repository su GitHub, che possiamo raggiungere a partire da questo indirizzo: https://github.com/unicode-cldr/cldr-json

Come possiamo intuire, si tratta di un gran numero di file, e il rischio di perdersi nei meandri di GitHub è davvero molto alto. Un tool che ci viene in aiuto per capire quali siano quelli che effettivamente dobbiamo includere è questa pagina web, nella quale possiamo selezionare le funzioni che effettivamente vogliamo supportare: http://johnnyreilly.github.io/globalize-so-what-cha-want/

Immaginiamo, per esempio, di voler supportare solo la globalization delle date, il risultato sarà simile a quello dello screenshot in basso e includerà, oltre all'infrastruttura già aggiunta tramite NuGet, alcuni elementi globali nella cartella "supplemental" più altri che variano a seconda della culture.


Questi sono i file che dovremo scaricare da GitHub e aggiungere nella nostra cartella scripts, fino ad avere una struttura simile a quella della figura in basso, nella quale abbiamo aggiunto il supporto alla sola cultura italiana.


Ora che abbiamo aggiunto tutti i file necessari, possiamo creare un nuovo bundle in BundleConfig che comprenda i file JavaScript di cui abbiamo bisogno:

bundles.Add(new ScriptBundle("~/bundles/globalize").Include(
    "~/Scripts/cldr.js",
    "~/Scripts/cldr/event.js",
    "~/Scripts/cldr/supplemental.js",
    "~/Scripts/globalize.js",
    "~/Scripts/globalize/number.js",
    "~/Scripts/globalize/date.js"));

Ora rechiamoci sulla nostra layout view, e carichiamo anche questo nuovo bundle:

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Scripts.Render("~/bundles/globalize")
@RenderSection("scripts", required: false)

@if (!this.IsSectionDefined("scripts"))
{
    @Scripts.Render("~/bundles/jqueryval")
}

I componenti così caricati non sono ancora idonei ad assolvere il loro compito, perchè non abbiamo associato le definizioni JSON relative alla culture. Pertanto, al caricamento della pagina, dobbiamo ricordarci di effettuare il download dal server delle definizioni necessarie con alcune chiamate AJAX:

<script>
  @{ 
    var culture = "it";
  }

  $(function () {
    $.when(
      $.get('@Url.Content("~/Scripts/cldr/supplemental/likelySubtags.json")')
        .success(function (data) { Globalize.load(data); }),
      $.get('@Url.Content($"~/Scripts/cldr/main/{culture}/numbers.json")')
        .success(function (data) { Globalize.load(data); }),
      $.get('@Url.Content("~/Scripts/cldr/supplemental/numberingSystems.json")')
        .success(function (data) { Globalize.load(data); }),
      $.get('@Url.Content($"~/Scripts/cldr/main/{culture}/ca-gregorian.json")')
        .success(function (data) { Globalize.load(data); }),
      $.get('@Url.Content($"~/Scripts/cldr/main/{culture}/timeZoneNames.json")')
        .success(function (data) { Globalize.load(data); }),
      $.get('@Url.Content("~/Scripts/cldr/supplemental/timeData.json")')
        .success(function (data) { Globalize.load(data); }),
      $.get('@Url.Content("~/Scripts/cldr/supplemental/weekData.json")')
        .success(function (data) { Globalize.load(data); })
      ).then(function () {
        Globalize.locale('@culture');
      });
  })
</script>

Nel codice in alto abbiamo prima creato una variabile server side, culture, in questo esempio forzatamente impostata su "it", e poi l'abbiamo sfruttata per generare il path corretto per gli script da caricare. In un sito multilingua, invece, potremo determinare questo dato da Thread.CurrentThread.CurrentUICulture.

Ora che il tutto è configurato, manca un ultimo passaggio, ossia impostare l'uso di Globalize.js nelle funzioni di validazione di jQuery.Validate. Lo script necessario è concettualmente banale (non dobbiamo far altro che impostare i validator per i diversi tipi di dato), ma richiede una certa conoscenza di come jQuery.Validate funzioni internamente. L'alternativa più semplice è replicare lo snippet presente in questo blog post: http://blog.johnnyreilly.com/2015/10/jquery-validation-globalize-hits-10.html

(function ($, Globalize) {
    if (!$.validator) {
        return;
    }

    // Clone original methods we want to call into
    var originalMethods = {
        min: $.validator.methods.min,
        max: $.validator.methods.max,
        range: $.validator.methods.range
    };

    // Globalize options - initially just the date format used for parsing
    // Users can customise this to suit them
    $.validator.methods.dateGlobalizeOptions = { 
      dateParseFormat: { skeleton: "yMd" }
    };

    // Tell the validator that we want numbers parsed using Globalize
    $.validator.methods.number = function (value, element) {
        var val = Globalize.parseNumber(value);
        return this.optional(element) || ($.isNumeric(val));
    };

    // Tell the validator that we want dates parsed using Globalize
    $.validator.methods.date = function (value, element) {
        var val = Globalize.parseDate(value, 
          $.validator.methods.dateGlobalizeOptions.dateParseFormat);
        return this.optional(element) || (val instanceof Date);
    };

    // Tell the validator that we want numbers parsed using Globalize,
    // then call into original implementation with parsed value

    $.validator.methods.min = function (value, element, param) {
        var val = Globalize.parseNumber(value);
        return originalMethods.min.call(this, val, element, param);
    };

    $.validator.methods.max = function (value, element, param) {
        var val = Globalize.parseNumber(value);
        return originalMethods.max.call(this, val, element, param);
    };

    $.validator.methods.range = function (value, element, param) {
        var val = Globalize.parseNumber(value);
        return originalMethods.range.call(this, val, element, param);
    };
}(jQuery, Globalize));

Finalmente i passaggi sono terminati! Se abbiamo svolto tutto correttamente, dovremmo essere in grado di validare client side, una data inserita in formato italiano senza alcun ulteriore intervento. Per provarlo ci basta creare una semplice pagina di esempio:

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi