web-dev-qa-db-ja.com

異なる文化で検証を処理するための最良の方法は何ですか

多言語MVCアプリケーションを構築しようとしています。アプリケーションにフォームがあり、コストを入力するフィールドがあります。スペイン文化を使ってレコードを作ることができます。

しかし、レコードを更新しようとすると、jquery検証がfalseになります。次のようなデフォルトのエラーメッセージが表示されます。

フィールドは数値でなければなりません。

私のビューモデルでは、次の属性を設定しました。

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

Gobal.asaxファイルに次のように設定しました

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

上記の方法は、文化を変更する際にサーバー側で期待どおりに機能します。ただし、JavaScriptは10進リテラルのみを認識するため、クライアント側の検証は英語以外のカルチャでは機能しません。カルチャ固有の検証を使用してMVCクライアント側の検証を拡張するための最良の方法を知りたいです。

[〜#〜]編集[〜#〜]

MikeのURLを参照して、Jsバンドルに次の変更を加えました。 Jsバンドルは以下の通りです

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

レイアウトページでは、次のように実装しました

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))
21
Jayaraj.K

2つのjQueryGlobalizeプラグインがあります。

古いバージョンは v0.0.1 1つのスクリプト_globalize.js_が含まれ、サブフォルダーculturesがあり、次のようなすべてのスクリプトカルチャを見つけることができます。

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

これらのスクリプトを使用すると、必要な数のカルチャを追加できるため、バンドルを次のように構築することはまったく問題ありません。

_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には、以下を使用して簡単に設定できるローカリゼーションスクリプトのコレクションがあります。

_Globalize.culture('en-AU');
_

または

_Globalize.culture('es-AR');
_

ある種の近接性を使用して、使用したい最も近いカルチャを特定できます。バンドルに_globalize.culture.es-AR.js_をロードした場合は、Globalize.culture('es');を設定できます。Globalizeは、「es-AR」カルチャを使用することを認識できます。もちろん、_globalize.culture.es.js_を追加した場合、ローダーはこの最後のものを選択します。

JQuery Globalize(安定版)の新しいバージョンは v1.0. であり、まったく異なる方法で機能します。

_globalize.js_というメインスクリプトファイルがまだありますが、それを機能させるには、さらに多くのスクリプトを追加する必要があります。

誰かが tool を作成しました。これは、使用するモジュールのタイプ(数値、日付、通貨)に応じて、必要なスクリプトを正確に示します。

V1.0.0の使用を選択した場合、ツールが基本スクリプト(数値のみ)を含めることを提案することがわかります。

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

プラスいくつかのCLDRJSONスクリプト:

  • cldr/Supplemental/LikelySubtags.json
  • cldr/main/{locale} /numbers.json
  • cldr/Supplemental/numberingSystems.json

これらのファイルは、 core パッケージおよび numbers パッケージにあります。
日付を検証する場合、これは パッケージ です。詳細 ここ

これらはすべてjsonファイルであり、バンドルすることはできません。次のようなことを実行して、実行時にそれらをロードできます。

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

とにかく;まだ最高の古いv0.0.1に固執したいとしましょう。
バンドルには、グローバル化スクリプトとカルチャスクリプトが含まれます。

_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検証 は、考慮したい他の追加の拡張機能を提供します。

  • 追加-methods.js
  • ローカリゼーション/messages_es_AR.js(カルチャのエラーメッセージ)

あなたが_Application_AcquireRequestState_であなたの文化を設定しているのを見ました。パイプの早い段階で処理されるため、_Application_BeginRequest_で実行する方がよいと誰かが提案しています。

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

検証にこれを使用しているようです jQueryプラグイン 。私が通常行うことは、スクリプトをロードしたらすぐに、カルチャを構成し、カスタム検証を設定することです。

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

不足しているものの1つは、小数のモデルバインダーです。

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

これはGlobal.asaxで設定できます_Application_Start_:

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

これはあなたが必要とするほとんどすべてです。

このアプローチには厄介な問題しかありません。
カルチャ_en-AU_を使用していて、数値フィールドに値:10,4を入力したとします。この番号は_es-AR_で完全に有効ですが、_en-AU_カルチャでは無効である必要があります。

jQuery Globalizeは、ここで104に変換するため、とにかく有効であると見なします。

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

カルチャen-AUのGlobalize.parseFloat('10,4')は、その数を104に変換します。

カルチャes-ARのGlobalize.parseFloat('10.4')に対して同じことを行うと、同じことが起こります。再び104になります。

これを実行してこの動作を確認できます fiddle

_,_と_._はどちらも、小数点と千単位の区切り文字として使用されるため、有効な記号です。

github でこのトピックに関して未解決の問題がいくつかありますが、同じ問題が続く新しいバージョンで作業しているため、修正するのは難しいと思います。

サーバー側でも同じ問題が発生します 10進モデルバインダー

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

ここでも、CultureInfo.CurrentCultureが 'en-AU'の場合、同じ結果が生成されます:104

そこにブレークポイントを配置して、値がどのように変換されるかを確認できます。

おそらくこれは、正規表現を使用して修正する方が簡単だと思います。

JQuery Validatorv.0.1.1またはjQueryValidator v.1.0.0を使用してソリューションを試してみたい場合は、2つのリポジトリ ここここ を作成しました。

24
LeftyX

RegisterBundlesにバンドルを追加しましたが、レイアウトページでは使用していません。また、RegisterBundlesに冗長なjqueryuiファイルを追加しました。 更新次のようなRegisterBundlesメソッド:

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

そしてpdateこのようなレイアウトページ:

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

これがお役に立てば幸いです:)

1
Mahbubur Rahman