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

本文关键字:最佳 方法 是什么 验证 文化 处理 | 更新日期: 2023-09-27 18:12:45

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

但是在尝试更新记录时,我得到的jquery验证是错误的。 并且我收到默认错误消息为:

该字段必须是数字。

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

[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 只能识别十进制文字。我想知道使用特定于区域性的验证扩展 mvc 客户端验证的最佳方法。

编辑

参考迈克的网址,我在 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))

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

有 2 个 jQuery Globalize 插件。

旧版本是 v0.0.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.0,它以完全不同的方式工作。

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

有人构建了一个工具,它可以准确地告诉你你需要什么脚本,这取决于你想使用的模块类型(数字、日期、货币(。

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

  • CLDR.js
  • CLDR/事件.js
  • CLDR/补充.js
  • 全球化.js
  • 全球化/编号.js

加上一些 CLDR JSON 脚本:

  • cldr/supplemental/possibleSubtags.json
  • cldr/main/{locale}/numbers.json
  • cldr/supplemental/numberingSystems.json

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

这些都是 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验证提供了一些其他扩展,您可能需要考虑:

  • 其他方法.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]);
        }
    });

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

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。

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

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

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

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

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

其中CultureInfo.CurrentCulture是"en-AU"将再次产生相同的结果:104

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

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

如果你想使用jQuery Validator v.0.1.1或

jQuery Validator v.1.0.0的解决方案,我在这里和这里创建了两个存储库。

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

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

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

希望这对:)有所帮助