2015-09-15 7 views
21

Ich versuche, eine mehrsprachige MVC-Anwendung zu erstellen. Ich habe ein Formular in meiner Bewerbung und ich habe Feld um eine Kosten einzugeben. Ich kann mit der spanischen Kultur einen Rekord erstellen.Was ist der beste Weg zur Validierung mit anderen Kultur

Aber beim Versuch, den Datensatz zu aktualisieren, bekomme ich Jquery Validierung falsch. und ich bekomme eine Standard Fehlermeldung als:

In meinem Modell habe ich die folgenden Attribute festgelegt.

[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; } 

Ich habe in meinem Gobal.asax Datei-Set mit folgenden

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 
    } 
} 

und die obigen Methode funktioniert wie bei Server-Seite erwartet, dass die Kultur zu verändern. Aber die clientseitige Validierung bricht bei nicht-englischen Kulturen, da JavaScript nur Dezimal-Literale erkennt. Ich würde gerne wissen, wie man am besten die mvc-clientseitige Validierung mit kulturspezifischer Validierung erweitert.

EDIT

Mit Referenz-URL zu Mikes ich folgende Änderungen in Js Bündel vorgenommen haben. Js Bündel ist als

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")); 
} 

In der Layoutseite folgt ich umgesetzt haben, wie

folgt
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)) 
+0

Ich bin nicht persönlich gut in Culture Info, aber Sie können diese "fangen", erweitern Sie es, um die allgemeine Ausnahme enthalten, und schreiben Sie das auf die Konsole (für Debugging-Zwecke): 'catch (Exception err) {Console.WriteLine (Fehler); } Viel Glück! – jp2code

+0

Haben Sie die Lösung in dieser ähnlichen Frage untersucht: http://stackoverflow.com/questions/5199835/mvc-3-jquery-validation-globalizing-of-number-decimal-field –

+0

Warum in aller Welt würden Sie leer- Ausnahmen abfangen und dann bei SO nachfragen, um das zu beheben? –

Antwort

23

Es gibt 2 jQuery Plugins globalisieren.

Die alte Version ist v0.0.1 ein Skript globalize.js enthält, und es hat einen Unterordner cultures, wo Sie alle Skript Kulturen wie finden:

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

diese Skripte ermöglichen es Ihnen, so viele Kulturen hinzufügen, wie Sie so wollen, wäre es völlig in Ordnung, Ihr Bündel auf diese Weise gebaut haben:

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 wird eine Sammlung von Lokalisierungs Skripte, die Sie kann einfach eingestellt werden:

Globalize.culture('en-AU'); 

oder

Globalize.culture('es-AR'); 

Es kann eine Art von Nähe verwenden, um herauszufinden, welche Kultur am nächsten ist, die Sie verwenden möchten. Wenn Sie in Ihr Bündel geladen haben können Sie Globalize.culture('es'); setzen und Globalize wäre in der Lage, herauszufinden, dass Sie die 'es-AR' Kultur verwenden möchten; natürlich, wenn Sie globalize.culture.es.js hinzugefügt haben, würde der Lader diesen letzten wählen.

Die neue Version von jQuery Globalize (stabil) ist v1.0.0 und es funktioniert auf eine ganz andere Art und Weise.

Es hat immer noch die Hauptskriptdatei globalize.js, aber Sie müssen eine Menge mehr Skripte hinzufügen, damit es funktioniert.

Jemand hat eine tool erstellt, die Ihnen genau angibt, welches Skript Sie benötigen, je nachdem, welche Art von Modul (Nummer, Datum, Währung) Sie verwenden möchten.

Wenn Sie entscheiden sich v1.0.0 verwenden Sie werden sehen, dass das Tool Ihnen die Basis-Skripte (nur Zahlen) enthalten:

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

plus einige CLDR JSON-Skripte:

  • CLDR/Zusatz/likelySubtags.json
  • CLDR/main/{locale} /numbers.json
  • CLDR/Zusatz/numberingSystems.json

Sie finden diese Dateien im Paket core und im Paket numbers.
Wenn Sie Daten validieren möchten, ist dies die package. Weitere Informationen here.

Dies sind alle JSON-Dateien und Sie können sie nicht bündeln. Sie können sie in der Laufzeit geladen werden, indem Sie etwas wie folgt tun:

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); 
    }); 
}; 

Wie auch immer; Nehmen wir an, Sie möchten bei der alten v0.0.1 bleiben, die immer noch die beste ist.

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

jQuery validation bietet einige andere zusätzliche Erweiterung, die Sie in Erwägung ziehen könnte:
Ihr Bundle wird das globalize Skript und die Kultur diejenigen haben

  • Zusatz methods.js
  • Lokalisierung/messages_es_AR.js (Fehlermeldungen für die Kultur)

Ich habe gesehen, dass Sie Ihre einstellen Kultur in der Application_AcquireRequestState. Jemand vorschlagen, es ist besser es in Application_BeginRequest zu tun, wie es früher in dem Rohr verarbeitet wird:

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; 
    } 

Es scheint, dass Sie diesen jQuery plugin für die Validierung verwenden. Was ich normalerweise zu tun ist, sobald ich das Skript geladen werden, um die Kultur konfigurieren und die benutzerdefinierte Validierung gesetzt:

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]); 
     } 
    }); 

Eine Sache, die Sie fehlt, ist ein Modell Bindemittel für Dezimalzahlen:

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; 
    } 
} 

, die in ihrem Global.asax Application_Start können eingestellt werden:

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

Das ist so ziemlich alles, was man braucht.

Es gibt nur ein lästiges Problem mit diesem Ansatz.
Nehmen wir an, Sie verwenden die Kultur en-AU und Sie geben in Ihrem numerischen Feld einen Wert ein: 10,4. Diese Nummer ist in es-AR perfekt gültig, sollte aber für die Kultur en-AU nicht gültig sein.

jQuery Globalize wird es gültig betrachtet sowieso, wie es sie zu 104 hier Traslate würde:

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

Globalize.parseFloat('10,4') für die Kultur en-AU würde diese Zahl auf 104

Die gleiche Sache verwandeln würde passieren, wenn Sie tun das gleiche für Globalize.parseFloat('10.4') für die Kultur es-AR; es würde wieder 104 werden.

Sie können dieses Verhalten beim Ausführen dieser fiddle überprüfen.

Sowohl , als auch . sind gültige Symbole, da sie als Dezimaltrennzeichen und Tausendertrennzeichen verwendet würden.

Es gibt ein paar Probleme zu diesem Thema auf github und ich denke, es wäre schwer zu beheben, da sie jetzt an der neuen Version arbeiten, wo das gleiche Problem weiterhin besteht.

Sie werden das gleiche Problem auf der Server-Seite mit unseren decimal model binder Gesicht:

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

wo die Culture.CurrentCulture ist 'en-AU' würde wiederum das gleiche Ergebnis liefern: .

Es kann einen Haltepunkt dort platzieren und sehen, wie es den Wert konvertiert.

Ich denke, wahrscheinlich wäre dies einfacher zu beheben, vielleicht mit einigen regulären Ausdrücken.

Wenn Sie mit der Lösung mit jQuery Validator v.0.1.1 oder jQuery Validator v.1.0.0 spielen möchten, habe ich zwei Repositorys erstellt: here und here.

1

Sie Bündel in RegisterBundles hinzugefügt haben, sie aber nicht in der Layout-Seite verwenden. Sie haben auch redundante jqueryui Datei in RegisterBundles hinzugefügt. aktualisieren Ihre RegisterBundles Methode wie folgt:

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")); 
    } 

und dann Update Layout-Seite wie folgt aus:

@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> 
} 

Hope this helfen :)

+0

Eigentlich habe ich vergessen, die globalisationEN "und globalisationES" zu posten. Ich habe das in meine Bewerbung aufgenommen und meine Post überarbeitet. Nach dem Hinzufügen der globalisation.culture js erhalte ich einen Konsolenfehler "Uncaught TypeError: t.addCultureInfo ist keine Funktion" –

+0

werden Sie erwähnen, wie Sie t.addCultureInfo verwenden? –

+0

Der Fehler wird tatsächlich von jquery.globlisation.js ausgelöst. –