处理不同文化验证的最佳方法是什么?

时间:2022-08-12 20:10:07

I am trying to build a multilingual MVC application. I have a form in my application and I have field to enter a cost. I am able to create a record using the spanish culture.

我正在尝试构建一个多语言MVC应用程序。我的应用程序中有一个表单,我有字段输入成本。我能够使用西班牙文化创建一个记录。

But on trying to update the record I am getting jquery validation false. and I am getting a default error message as:

但是在尝试更新记录时,我得到了jquery验证错误。我收到一条默认错误消息:

The field must be numeric.

该字段必须是数字。

In my view model I have set the following attributes.

在我的视图模型中,我设置了以下属性。

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

I have set in my Gobal.asax file with following

我已经在我的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
    }
}

and the above method works as expected at server side in changing the culture . But the client side validation breaks on non-english cultures as javascript recognizes only decimal literals. I'd like to know the best way to extend the mvc client side validation with culture specific validation.

并且上述方法在服务器端按预期工作以改变文化。但是客户端验证打破了非英语文化,因为javascript只识别十进制文字。我想知道使用特定于文化的验证来扩展mvc客户端验证的最佳方法。

EDIT

编辑

With reference to Mike's url I have made following changes in Js bundle. Js bundle is as follows

参考Mike的网址,我在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"));
}

In the layout page I have implemented as follows

在布局页面中,我实现如下

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

2 个解决方案

#1


23  

There are 2 jQuery Globalize plugins.

有2个jQuery Globalize插件。

The old version is v0.0.1 contains one script globalize.js and it has a subfolder cultures where you can find all the script cultures such as:

旧版本v0.0.1包含一个脚本globalize.js,它有一个子文件夹文化,您可以在其中找到所有脚本文化,例如:

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

those scripts allow you to add as many cultures as you want so it would be perfectly fine to have your bundle built this way:

这些脚本允许您添加任意数量的文化,因此以这种方式构建捆绑包是完全可以的:

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 will have a collection of localization scripts which you can set simply using:

Globalize将有一组本地化脚本,您可以使用以下方法设置:

Globalize.culture('en-AU');

or

要么

Globalize.culture('es-AR');

It can use some sort of proximity to figure out which is the closest culture you want to use. If you have loaded in your bundle globalize.culture.es-AR.js you can set Globalize.culture('es'); and Globalize would be able to figure out that you want to use the 'es-AR' culture; of course if you have added globalize.culture.es.js the loader would chose this last one.

它可以使用某种接近来找出你想要使用的最接近的文化。如果你已经加载了你的bundle globalize.culture.es-AR.js,你可以设置Globalize.culture('es');而Globalize可以弄清楚你想要使用'es-AR'文化;当然,如果你添加了globalize.culture.es.js,加载器会选择最后一个。

The new version of jQuery Globalize (stable) is v1.0.0 and it works in a completely different way.

新版本的jQuery Globalize(稳定版)是v1.0.0,它的工作方式完全不同。

It still have the main script file called globalize.js but you have to add a lot more scripts to make it work.

它仍然有一个名为globalize.js的主脚本文件,但您必须添加更多脚本才能使其正常工作。

Someone has built a tool which tells you exactly what script you need, depending on what type of module (number, dates, currencies) you want to use.

有人已经构建了一个工具,可以准确地告诉您需要什么脚本,具体取决于您要使用的模块类型(数量,日期,货币)。

If you're opting to use v1.0.0 you will see that the tool will suggest to include the base scripts (numbers only):

如果您选择使用v1.0.0,您将看到该工具将建议包含基本脚本(仅限数字):

  • cldr.js
  • cldr.js
  • cldr/event.js
  • CLDR / event.js
  • cldr/supplemental.js
  • CLDR / supplemental.js
  • globalize.js
  • globalize.js
  • globalize/number.js
  • 全球化/ number.js

plus some CLDR JSON scripts:

加上一些CLDR JSON脚本:

  • cldr/supplemental/likelySubtags.json
  • CLDR /补充/ likelySubtags.json
  • cldr/main/{locale}/numbers.json
  • CLDR /主/ {区域设置} /numbers.json
  • cldr/supplemental/numberingSystems.json
  • CLDR /补充/ numberingSystems.json

You can find these files in the core package and the numbers package.
If you want to validate dates this is the package. More info here.

您可以在核心包和数字包中找到这些文件。如果您想验证日期,这是包。更多信息在这里。

These are all json file and you cannot bundle them. You can loaded them in run-time doing something like this:

这些都是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);
    });
};

Anyway; let's say you want to stick to the old v0.0.1 which is still the best.
Your bundle will have the globalize script and the culture ones:

无论如何;让我们说你想坚持旧的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 validation offers some other additional extension which you might want to consider:

jQuery验证提供了一些您可能需要考虑的其他扩展:

  • additional-methods.js
  • 另外,methods.js
  • localization/messages_es_AR.js (error messages for the culture)
  • 本地化/ messages_es_AR.js(文化的错误消息)

I have seen that you're setting your culture in the Application_AcquireRequestState. Someone suggest it's better to do it in Application_BeginRequest as it is processed earlier in the pipe:

我已经看到你在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;
    }

It seems that you're using this jQuery plugin for the validation. What I normally would do is, as soon as I load the script, configure the culture and set the custom validation:

看来你正在使用这个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]);
        }
    });

One thing that you're missing is a model binder for decimals:

你缺少的一件事是小数的模型绑定器:

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

which can be set in your Global.asax Application_Start:

可以在Global.asax Application_Start中设置:

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

This is pretty much everything you need.

这几乎是你需要的一切。

There's only an annoying problem with this approach.
Let's say you're using the culture en-AU and you input in your numeric field a value: 10,4. This number is perfectly valid in es-AR but it should be non-valid for the en-AU culture.

这种方法只有一个恼人的问题。假设你正在使用文化en-AU,你在数字字段中输入一个值:10,4。这个数字在es-AR中完全有效,但它对于en-AU文化应该是无效的。

jQuery Globalize will consider it valid anyway as it would traslate it to 104 here:

jQuery Globalize无论如何都会认为它有效,因为它会将它转换为104:

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

Globalize.parseFloat('10,4') for the culture en-AU would transform that number to 104.

文化en-AU的Globalize.parseFloat('10,4')会将该数字转换为104。

Same thing would happen if you do the same for Globalize.parseFloat('10.4') for the culture es-AR; it would become, again, 104.

如果您对文化es-AR的Globalize.parseFloat('10 .4')执行相同操作,也会发生同样的事情;它将再次成为104。

You can check this behaviour running this fiddle.

您可以检查运行此小提琴的此行为。

Both , and . are valid symbols as they would be used as decimal separator and thousands separator.

两者,和。是有效的符号,因为它们将用作小数分隔符和千位分隔符。

There are a few issues open on this topic on github and I guess it would be hard to fix since they are now working on the new version, where the same problem persists, by the way.

在github上有一些关于这个主题的问题,我想这很难解决,因为他们现在正在开发新版本,顺便说一下同样的问题仍然存在。

You're going to face the same problem on the server-side with our decimal model binder:

使用我们的十进制模型绑定器,您将在服务器端面临同样的问题:

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

where the CultureInfo.CurrentCulture is 'en-AU' would, again, produce the same result: 104.

CultureInfo.CurrentCulture是'en-AU'的地方再次产生相同的结果:104。

It can place a breakpoint there and see how it converts the value.

它可以在那里放置一个断点,看看它是如何转换价值的。

I guess probably this would be easier to fix, maybe using some regular expressions.

我想这可能更容易修复,也许使用一些正则表达式。

If you want to play with the solution with jQuery Validator v.0.1.1 or jQuery Validator v.1.0.0 I've created two repositories here and here.

如果你想使用jQuery Validator v.0.1.1或jQuery Validator v.1.0.0来解决这个问题,我在这里和这里创建了两个存储库。

#2


1  

You have added bundles in RegisterBundles but didn't use them in layout page. You also added redundant jqueryui file in RegisterBundles. Update your RegisterBundles method like this:

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

and then update layout page like this :

然后像这样更新布局页面:

@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 will help :)

希望这会有所帮助:)

#1


23  

There are 2 jQuery Globalize plugins.

有2个jQuery Globalize插件。

The old version is v0.0.1 contains one script globalize.js and it has a subfolder cultures where you can find all the script cultures such as:

旧版本v0.0.1包含一个脚本globalize.js,它有一个子文件夹文化,您可以在其中找到所有脚本文化,例如:

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

those scripts allow you to add as many cultures as you want so it would be perfectly fine to have your bundle built this way:

这些脚本允许您添加任意数量的文化,因此以这种方式构建捆绑包是完全可以的:

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 will have a collection of localization scripts which you can set simply using:

Globalize将有一组本地化脚本,您可以使用以下方法设置:

Globalize.culture('en-AU');

or

要么

Globalize.culture('es-AR');

It can use some sort of proximity to figure out which is the closest culture you want to use. If you have loaded in your bundle globalize.culture.es-AR.js you can set Globalize.culture('es'); and Globalize would be able to figure out that you want to use the 'es-AR' culture; of course if you have added globalize.culture.es.js the loader would chose this last one.

它可以使用某种接近来找出你想要使用的最接近的文化。如果你已经加载了你的bundle globalize.culture.es-AR.js,你可以设置Globalize.culture('es');而Globalize可以弄清楚你想要使用'es-AR'文化;当然,如果你添加了globalize.culture.es.js,加载器会选择最后一个。

The new version of jQuery Globalize (stable) is v1.0.0 and it works in a completely different way.

新版本的jQuery Globalize(稳定版)是v1.0.0,它的工作方式完全不同。

It still have the main script file called globalize.js but you have to add a lot more scripts to make it work.

它仍然有一个名为globalize.js的主脚本文件,但您必须添加更多脚本才能使其正常工作。

Someone has built a tool which tells you exactly what script you need, depending on what type of module (number, dates, currencies) you want to use.

有人已经构建了一个工具,可以准确地告诉您需要什么脚本,具体取决于您要使用的模块类型(数量,日期,货币)。

If you're opting to use v1.0.0 you will see that the tool will suggest to include the base scripts (numbers only):

如果您选择使用v1.0.0,您将看到该工具将建议包含基本脚本(仅限数字):

  • cldr.js
  • cldr.js
  • cldr/event.js
  • CLDR / event.js
  • cldr/supplemental.js
  • CLDR / supplemental.js
  • globalize.js
  • globalize.js
  • globalize/number.js
  • 全球化/ number.js

plus some CLDR JSON scripts:

加上一些CLDR JSON脚本:

  • cldr/supplemental/likelySubtags.json
  • CLDR /补充/ likelySubtags.json
  • cldr/main/{locale}/numbers.json
  • CLDR /主/ {区域设置} /numbers.json
  • cldr/supplemental/numberingSystems.json
  • CLDR /补充/ numberingSystems.json

You can find these files in the core package and the numbers package.
If you want to validate dates this is the package. More info here.

您可以在核心包和数字包中找到这些文件。如果您想验证日期,这是包。更多信息在这里。

These are all json file and you cannot bundle them. You can loaded them in run-time doing something like this:

这些都是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);
    });
};

Anyway; let's say you want to stick to the old v0.0.1 which is still the best.
Your bundle will have the globalize script and the culture ones:

无论如何;让我们说你想坚持旧的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 validation offers some other additional extension which you might want to consider:

jQuery验证提供了一些您可能需要考虑的其他扩展:

  • additional-methods.js
  • 另外,methods.js
  • localization/messages_es_AR.js (error messages for the culture)
  • 本地化/ messages_es_AR.js(文化的错误消息)

I have seen that you're setting your culture in the Application_AcquireRequestState. Someone suggest it's better to do it in Application_BeginRequest as it is processed earlier in the pipe:

我已经看到你在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;
    }

It seems that you're using this jQuery plugin for the validation. What I normally would do is, as soon as I load the script, configure the culture and set the custom validation:

看来你正在使用这个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]);
        }
    });

One thing that you're missing is a model binder for decimals:

你缺少的一件事是小数的模型绑定器:

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

which can be set in your Global.asax Application_Start:

可以在Global.asax Application_Start中设置:

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

This is pretty much everything you need.

这几乎是你需要的一切。

There's only an annoying problem with this approach.
Let's say you're using the culture en-AU and you input in your numeric field a value: 10,4. This number is perfectly valid in es-AR but it should be non-valid for the en-AU culture.

这种方法只有一个恼人的问题。假设你正在使用文化en-AU,你在数字字段中输入一个值:10,4。这个数字在es-AR中完全有效,但它对于en-AU文化应该是无效的。

jQuery Globalize will consider it valid anyway as it would traslate it to 104 here:

jQuery Globalize无论如何都会认为它有效,因为它会将它转换为104:

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

Globalize.parseFloat('10,4') for the culture en-AU would transform that number to 104.

文化en-AU的Globalize.parseFloat('10,4')会将该数字转换为104。

Same thing would happen if you do the same for Globalize.parseFloat('10.4') for the culture es-AR; it would become, again, 104.

如果您对文化es-AR的Globalize.parseFloat('10 .4')执行相同操作,也会发生同样的事情;它将再次成为104。

You can check this behaviour running this fiddle.

您可以检查运行此小提琴的此行为。

Both , and . are valid symbols as they would be used as decimal separator and thousands separator.

两者,和。是有效的符号,因为它们将用作小数分隔符和千位分隔符。

There are a few issues open on this topic on github and I guess it would be hard to fix since they are now working on the new version, where the same problem persists, by the way.

在github上有一些关于这个主题的问题,我想这很难解决,因为他们现在正在开发新版本,顺便说一下同样的问题仍然存在。

You're going to face the same problem on the server-side with our decimal model binder:

使用我们的十进制模型绑定器,您将在服务器端面临同样的问题:

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

where the CultureInfo.CurrentCulture is 'en-AU' would, again, produce the same result: 104.

CultureInfo.CurrentCulture是'en-AU'的地方再次产生相同的结果:104。

It can place a breakpoint there and see how it converts the value.

它可以在那里放置一个断点,看看它是如何转换价值的。

I guess probably this would be easier to fix, maybe using some regular expressions.

我想这可能更容易修复,也许使用一些正则表达式。

If you want to play with the solution with jQuery Validator v.0.1.1 or jQuery Validator v.1.0.0 I've created two repositories here and here.

如果你想使用jQuery Validator v.0.1.1或jQuery Validator v.1.0.0来解决这个问题,我在这里和这里创建了两个存储库。

#2


1  

You have added bundles in RegisterBundles but didn't use them in layout page. You also added redundant jqueryui file in RegisterBundles. Update your RegisterBundles method like this:

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

and then update layout page like this :

然后像这样更新布局页面:

@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 will help :)

希望这会有所帮助:)