c# - net - routedatarequestcultureprovider




Quel est le meilleur moyen de gérer la validation avec une culture différente (2)

J'essaie de créer une application MVC multilingue. J'ai un formulaire dans ma candidature et j'ai un champ pour saisir un coût. Je suis capable de créer un disque en utilisant la culture espagnole.

Mais en essayant de mettre à jour l'enregistrement, la validation de jquery est fausse. et je reçois un message d'erreur par défaut comme:

Le champ doit être numérique.

Dans mon modèle de vue, j'ai défini les attributs suivants.

[LocalizedDisplayName("Label_Cost")]
[RegularExpression("^[^<>,<|>]+$", ErrorMessage = null, ErrorMessageResourceName = "Error_Message_Html_Tags_Prevented", ErrorMessageResourceType = typeof(Resources))]
[Range(0, 9999.99, ErrorMessage = null, ErrorMessageResourceName = "Error_Message_Cost_Not_Valid", ErrorMessageResourceType = typeof(Resources))]
public decimal? Cost { get; set; }

J'ai mis dans mon fichier Gobal.asax avec

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    try
    {
        HttpCookie cookie = HttpContext.Current.Request.Cookies.Get("CurrentCulture");
        string culutureCode = cookie != null && !string.IsNullOrEmpty(cookie.Value) ? cookie.Value : "en";
        CultureInfo ci = new CultureInfo(culutureCode);
        System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
        System.Threading.Thread.CurrentThread.CurrentCulture =
        CultureInfo.CreateSpecificCulture(ci.Name);
    }
    catch(Exception ex)
    {
        // Code
    }
}

et la méthode ci-dessus fonctionne comme prévu au niveau du serveur pour changer la culture. Mais la validation côté client se limite à des cultures non anglaises car javascript ne reconnaît que les littéraux décimaux. Je voudrais connaître la meilleure façon d'étendre la validation côté client mvc avec la validation spécifique à la culture.

MODIFIER

En référence à l'url de Mike, j'ai effectué les modifications suivantes dans le bundle Js. Js bundle est comme suit

public static void RegisterBundles(BundleCollection bundles)
{
   BundleTable.EnableOptimizations = true;

  bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

bundles.Add(new ScriptBundle("~/bundles/globalisation").Include(
               "~/Scripts/globalize.js",
               "~/Scripts/globalize/currency.js",
                "~/Scripts/globalize/date.js",
                "~/Scripts/globalize/message.js",
                "~/Scripts/globalize/number.js",
                "~/Scripts/globalize/plural.js",
                "~/Scripts/globalize/relative-time.js"));

  bundles.Add(new ScriptBundle("~/bundles/globalisationEN").Include(
               "~/Scripts/GlobalisationCulture/globalize.culture.en-AU.js"));

            bundles.Add(new ScriptBundle("~/bundles/globalisationES").Include(
               "~/Scripts/GlobalisationCulture/globalize.culture.es-AR.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryuiEN").Include(
                        "~/Scripts/jquery-ui-1.10.3.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryuiES").Include(
                        "~/Scripts/jquery-ui-1.10.3.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                "~/Scripts/jquery.validate.js",
                "~/Scripts/jquery.validate.unobtrusive.js",
                "~/Scripts/jquery.unobtrusive-ajax.js",
                "~/Scripts/jquery.validate.globalize.js"));
}

Dans la page de mise en page, j'ai implémenté comme suit

HttpCookie cookie = HttpContext.Current.Request.Cookies.Get("CurrentCulture");
        string culutureCode = cookie != null && !string.IsNullOrEmpty(cookie.Value) ? cookie.Value : "en";
        if (culutureCode.Equals("en-AU", StringComparison.OrdinalIgnoreCase))
        {
            culutureCode = "EN";
        }
        else if (culutureCode.Equals("es-AR", StringComparison.OrdinalIgnoreCase))
        {
            culutureCode = "ES";
        }
        else
        {
            culutureCode = "EN";
        }
@Scripts.Render("~/bundles/jquery",
                    "~/bundles/globalisation",
                    string.Format("~/bundles/globalisation{0}", culutureCode),
                    "~/bundles/jqueryval",
                    string.Format("~/bundles/jqueryui{0}", culutureCode))

Il y a 2 plugins jQuery Globalize.

L'ancienne version v0.0.1 contient un script globalize.js et possède un sous-répertoire de cultures où vous pouvez trouver toutes les cultures de script telles que:

  • globalize.culture.en-AU.js
  • globalize.culture.es-AR.js

Ces scripts vous permettent d’ajouter autant de cultures que vous le souhaitez, il serait donc parfaitement judicieux de créer votre bundle de la manière suivante:

bundles.Add(new ScriptBundle("~/bundles/globalisation").Include(
    "~/Scripts/globalize.js",
    "~/Scripts/cultures/globalize.culture.en-AU.js",
    "~/Scripts/cultures/globalize.culture.es-AR.js"
));

Globalize aura une collection de scripts de localisation que vous pouvez définir simplement en utilisant:

Globalize.culture('en-AU');

ou

Globalize.culture('es-AR');

Il peut utiliser une sorte de proximité pour déterminer quelle est la culture la plus proche que vous souhaitez utiliser. Si vous avez chargé dans votre bundle globalize.culture.es-AR.js vous pouvez définir Globalize.culture('es'); et Globalize serait en mesure de comprendre que vous voulez utiliser la culture «es-AR»; Bien sûr, si vous avez ajouté globalize.culture.es.js le chargeur choisira ce dernier.

La nouvelle version de jQuery Globalize (stable) est la version v1.0.0 et fonctionne de manière complètement différente.

Il a toujours le fichier de script principal appelé globalize.js mais vous devez ajouter beaucoup plus de scripts pour le faire fonctionner.

Quelqu'un a créé un tool qui vous indique exactement quel script vous avez besoin, en fonction du type de module (nombre, dates, devises) que vous souhaitez utiliser.

Si vous choisissez d'utiliser v1.0.0, vous verrez que l'outil suggérera d'inclure les scripts de base (chiffres uniquement):

  • cldr.js
  • cldr / event.js
  • cldr / supplemental.js
  • globalize.js
  • globalize / number.js

plus quelques scripts JDR CLDR:

  • cldr / supplementaire / probableSubtags.json
  • cldr / main / {locale} /numbers.json
  • Cldr / Supplémentaire / NumérotationSystems.json

Vous pouvez trouver ces fichiers dans le package de core et le package de numbers .
Si vous voulez valider les dates, c'est le package . Plus d'infos here .

Ce sont tous des fichiers json et vous ne pouvez pas les regrouper. Vous pouvez les charger lors de l'exécution en faisant quelque chose comme ceci:

Application.loadCulture = function (culture) {

    $.when(
      $.get(Application.CldrFetch + '/' + culture + '/' + encodeURIComponent("likelySubtags.json")),
      $.get(Application.CldrFetch + '/' + culture + '/' + "numberingSystems.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "plurals.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "ordinals.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "currencyData.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "timeData.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "weekData.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "ca-gregorian.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "timeZoneNames.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "numbers.json"),
      $.get(Application.CldrFetch + '/' + culture + '/' + "currencies.json")
    )
    .then(function () {
        // Normalize $.get results, we only need the JSON, not the request statuses.
        return [].slice.apply(arguments, [0]).map(function (result) {
            return result[0];
        });

    }).then(Globalize.load).then(function () {
        Globalize.locale(culture);
    });
};

En tous cas; Disons que vous voulez vous en tenir à l'ancienne version v0.0.1 qui est toujours la meilleure.
Votre bundle aura le script globalize et les cultures:

bundles.Add(new ScriptBundle("~/bundles/globalisation").Include(
    "~/Scripts/globalize.js",
    "~/Scripts/cultures/globalize.culture.en-AU.js",
    "~/Scripts/cultures/globalize.culture.es-AR.js"
));

La validation jQuery offre une autre extension supplémentaire que vous pouvez envisager:

  • additional-methods.js
  • localization / messages_es_AR.js (messages d'erreur pour la culture)

J'ai vu que vous définissez votre culture dans Application_AcquireRequestState . Quelqu'un suggère qu'il est préférable de le faire dans Application_BeginRequest car il est traité plus tôt dans le tube:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpCookie cookie = HttpContext.Current.Request.Cookies.Get("CurrentCulture");
        string cultureCode = cookie != null && !string.IsNullOrEmpty(cookie.Value) ? cookie.Value : "en";
        CultureInfo ci = new CultureInfo(cultureCode);
        System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureCode);
        System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture;
    }

Il semble que vous utilisiez ce plugin jQuery pour la validation. Ce que je ferais normalement, c'est que dès que je charge le script, configurez la culture et définissez la validation personnalisée:

    Globalize.culture(this.culture);

    $.validator.methods.number = function (value, element) {
        return this.optional(element) || jQuery.isNumeric(Globalize.parseFloat(value));
    };

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

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

Une chose qui vous manque est un modèle de classeur pour les décimales:

using System;
using System.Web.Mvc;
using System.Globalization;

public class DecimalModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        ModelState modelState = new ModelState { Value = valueResult };
        object actualValue = null;
        try
        {
            //Check if this is a nullable decimal and a null or empty string has been passed
            var isNullableAndNull = (bindingContext.ModelMetadata.IsNullableValueType && string.IsNullOrEmpty(valueResult.AttemptedValue));

            //If not nullable and null then we should try and parse the decimal
            if (!isNullableAndNull)
            {
                actualValue = decimal.Parse(valueResult.AttemptedValue, NumberStyles.Any, CultureInfo.CurrentCulture);
            }
        }
        catch (FormatException e)
        {
            modelState.Errors.Add(e);
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return actualValue;
    }
}

qui peut être définie dans votre Global.asax Application_Start :

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());

C'est à peu près tout ce dont vous avez besoin.

Il y a seulement un problème agaçant avec cette approche.
Disons que vous utilisez la culture en-AU et que vous entrez une valeur dans votre champ numérique: 10,4. Ce nombre est parfaitement valable dans es-AR mais il ne devrait pas être valable pour la culture en-AU .

jQuery Globalize le considérera comme valide car il le transposerait ici à 104:

$.validator.methods.number = function (value, element) {
    return this.optional(element) || jQuery.isNumeric(Globalize.parseFloat(value));
};

Globalize.parseFloat('10,4') pour la culture en-AU transformerait ce nombre en 104.

La même chose se produirait si vous faites la même chose pour Globalize.parseFloat('10.4') pour la culture es-AR; ce serait à nouveau 104.

Vous pouvez vérifier ce comportement en exécutant ce fiddle .

Les deux et . sont des symboles valables car ils seraient utilisés comme séparateur décimal et séparateur de milliers.

Il y a quelques problèmes ouverts sur ce sujet sur github et je suppose que ce serait difficile à corriger car ils travaillent maintenant sur la nouvelle version, où le même problème persiste, soit dit en passant.

Vous allez rencontrer le même problème côté serveur avec notre classeur décimal :

decimal.Parse('10,4', NumberStyles.Any, CultureInfo.CurrentCulture);

où CultureInfo.CurrentCulture est 'en-AU' produirait à nouveau le même résultat: 104 .

Il peut y placer un point d'arrêt et voir comment il convertit la valeur.

Je suppose que cela serait probablement plus facile à corriger, peut-être en utilisant des expressions régulières.

Si vous voulez jouer avec la solution avec jQuery Validator v.0.1.1 ou jQuery Validator v.1.0.0, j'ai créé deux référentiels here et here .


Vous avez ajouté des bundles dans RegisterBundles mais ne les avez pas utilisés dans la page de disposition. Vous avez également ajouté un fichier jqueryui redondant dans RegisterBundles. Mettez à jour votre méthode RegisterBundles comme ceci:

public static void RegisterBundles(BundleCollection bundles)
 {
   BundleTable.EnableOptimizations = true;
   bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js"));
   bundles.Add(new ScriptBundle("~/bundles/globalisation").Include(
            "~/Scripts/globalize.js",                
            "~/Scripts/globalize/currency.js",
            "~/Scripts/globalize/date.js",
            "~/Scripts/globalize/message.js",
            "~/Scripts/globalize/number.js",
            "~/Scripts/globalize/plural.js",
            "~/Scripts/globalize/relative-time.js"));
   bundles.Add(new ScriptBundle("~/bundles/globalisationEN").Include(
           "~/Scripts/GlobalisationCulture/globalize.culture.en-AU.js"));
   bundles.Add(new ScriptBundle("~/bundles/globalisationES").Include(
           "~/Scripts/GlobalisationCulture/globalize.culture.es-AR.js"));
   bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                    "~/Scripts/jquery-ui-1.10.3.js"));      

   bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
            "~/Scripts/jquery.validate.js",
            "~/Scripts/jquery.validate.unobtrusive.js",
            "~/Scripts/jquery.unobtrusive-ajax.js",
            "~/Scripts/jquery.validate.globalize.js"));
  }

puis mettez à jour la page de disposition comme ceci:

@section Scripts 
{
    @Scripts.Render("~/bundles/jquery",
                "~/bundles/globalisation",
                "~/bundles/globalisationEN",
                "~/bundles/globalisationES",
                "~/bundles/jqueryval",
                "~/bundles/jqueryui"))

   <script type="text/javascript">
    $.validator.methods.number = function (value, element) {
        return this.optional(element) ||
            !isNaN(Globalize.parseFloat(value));
    }
    $(document).ready(function () {
        Globalize.culture('es-AR'); //set spanish culture
    });

   </script>
}

J'espère que cela aidera :)





globalization