【问题标题】:Localization for input field with double value in Razor PagesRazor Pages 中具有双值的输入字段的本地化
【发布时间】:2019-10-12 20:34:18
【问题描述】:

在我的 ViewModel 中,我有一个这样的属性:

[DisplayFormat(DataFormatString = "{0:0.00}", ApplyFormatInEditMode = true)]        
public double SomeDoubleProperty { get; set; }

标记:

<div class="form-group row">
    <label asp-for="ViewModel.SomeDoubleProperty" class="col-sm-3 col-form-label">
        @Localizer[nameof(Model.ViewModel.SomeDoubleProperty)]
    </label>
    <div class="col-sm-9">
        <div class="input-group">
            <div class="input-group-prepend">
                <span class="input-group-text">%</span>
            </div>
            <input asp-for="ViewModel.SomeDoubleProperty"
                   class="form-control">
        </div>
        <span asp-validation-for="ViewModel.SomeDoubleProperty" class="text-danger"></span>
    </div>
</div>

加载页面后(默认值为0)在输入字段中显示如下:

(线程的当前文化和当前ui文化是“de”,所以小数分隔符“,”是预期的)。

但是当我现在离开输入字段时,会显示以下验证错误:

字段 SomeDoubleProperty 必须是数字。

当用“.”替换“,”时,验证器接受该值。 如果当前的 ui 文化是“de”,我怎样才能实现“,”也被接受?

【问题讨论】:

    标签: c# validation asp.net-core localization razor-pages


    【解决方案1】:

    您需要下载和配置客户端验证脚本:

    • cldrjs
    • cldr 数据
    • 全球化

    在项目的根目录中创建一个新的文件名为“libman.json”,并将以下库添加到其中:

    {
      "version": "1.0",
      "defaultProvider": "jsdelivr",
      "libraries": [
        {
          "library": "cldrjs@0.5.1",
          "destination": "wwwroot/lib/cldr"
        },
        {
          "library": "cldr-data@35.1.0",
          "destination": "wwwroot/lib/cldr-data"
        },
        {
          "library": "globalize@1.4.2",
          "destination": "wwwroot/lib/globalize"
        }
      ]
    }
    

    当您保存文件时,它会将所有脚本下载到 wwwroor/lib 文件夹。

    然后打开wwwroot/lib/cldr-data/package.json 并将以下行添加到页面末尾的关闭括号之前:

    "peerDependencies": {
        "cldr-data": ">=26"
      }
    

    当您保存文件时,它将下载所有文化的所有 json 数据(编号、日期、时间、货币等)。下载可能需要一段时间 (~35MB)。

    还有一个js库“jquery.validate.globalize.min.js”需要安装,但是jsdelivr 0.1.1的版本不兼容,我们需要v1.0,所以要么从@987654321手动下载@ 或者直接使用 GitHub 上的 jsdelivr 的导入功能如下:

    <script src="https://cdn.jsdelivr.net/gh/johnnyreilly/jquery-validation-globalize@1.0.0/jquery.validate.globalize.min.js"></script>
    

    然后创建一个新的局部视图,将其命名为“_LocalizationValidationScriptsPartial.cshtml”并将库添加到其中:

    <!-- cldr scripts (needed for globalize) -->
    <script src="/lib/cldr/dist/cldr.min.js"></script>
    <script src="/lib/cldr/dist/cldr/event.min.js"></script>
    <script src="/lib/cldr/dist/cldr/supplemental.min.js"></script>
    
    <!-- globalize scripts -->
    <script src="/lib/globalize/dist/globalize.min.js"></script>
    <script src="/lib/globalize/dist/globalize/number.min.js"></script>
    <script src="/lib/globalize/dist/globalize/date.min.js"></script>
    <script src="/lib/globalize/dist/globalize/currency.min.js"></script>
    
    <!-- this file can be downloaded from : -->
    <!-- https://github.com/johnnyreilly/jquery-validation-globalize -->
    <script src="https://cdn.jsdelivr.net/gh/johnnyreilly/jquery-validation-globalize@1.0.0/jquery.validate.globalize.min.js"></script>
    
    <!-- code to get check if current cultures scripts are exists -->
    <!-- if not, select parent cultures scripts -->
    @inject Microsoft.AspNetCore.Hosting.IHostingEnvironment HostingEnvironment
    @{
        string GetDefaultLocale()
        {
            const string localePattern = "lib\\cldr-data\\main\\{0}";
            var currentCulture = System.Globalization.CultureInfo.CurrentCulture;
            var cultureToUse = "en"; //Default regionalisation to use
    
            if (System.IO.Directory.Exists(System.IO.Path.Combine(HostingEnvironment.WebRootPath, string.Format(localePattern, currentCulture.Name))))
                cultureToUse = currentCulture.Name;
            else if (System.IO.Directory.Exists(System.IO.Path.Combine(HostingEnvironment.WebRootPath, string.Format(localePattern, currentCulture.TwoLetterISOLanguageName))))
                cultureToUse = currentCulture.TwoLetterISOLanguageName;
    
            return cultureToUse;
        }
    }
    
    <script type="text/javascript">
        var culture = "@GetDefaultLocale()";
        $.when(
            $.get("/lib/cldr-data/supplemental/likelySubtags.json"),
            $.get("/lib/cldr-data/main/" + culture + "numbers.json"),
            $.get("/lib/cldr-data/main/" + culture + "/currencies.json"),
            $.get("/lib/cldr-data/supplemental/numberingSystems.json"),
            $.get("/lib/cldr-data/main/" + culture + "/ca-gregorian.json"),
            $.get("/lib/cldr-data/main/" + culture + "/timeZoneNames.json"),
            $.get("/lib/cldr-data/supplemental/timeData.json"),
            $.get("/lib/cldr-data/supplemental/weekData.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);
        });
    </script>
    
    

    最后,只需在默认的 _ValidationScriptsPartial.cshtml 之后包含此部分视图,您需要在其中完成本地化验证。

    <partial name="_ValidationScriptsPartial.cshtml" />
    <partial name="_LocalizationValidationScriptsPartial.cshtml" />
    

    替代方法

    我创建了一个 TagHelperComponent 来避免所有繁重的工作,您甚至不需要将脚本下载到本地。

    • 安装 nuget 包:
    Install-Package LazZiya.TagHelpers -Version 2.1.0
    
    • 将 LazZiya.TagHelpers 添加到 _ViewImports :
    @using LazZiya.TagHelpers
    @addTagHelper *, LazZiya.TagHelpers
    
    • 在启动时注册本地化验证标签助手组件:
    services.AddTransient<ITagHelperComponent, LocalizationValidationScriptsTagHelperComponent>();
    
    • 将标记添加到页面的脚本部分以验证本地化输入字段(还必须加载默认的_ValidationScriptsPartial.cshtml):
    <partial name="_ValidationScriptsPartial.cshtml" />
    <localization-validation-scripts></localization-validation-scripts>
    

    此 TagHelper 将自动检测当前区域性名称并添加所有必要的脚本以验证本地化值。

    更多详情见LazZiya.TagHelpers

    【讨论】:

    • 您的 Nuget 包有效,非常感谢!现在唯一不起作用的是重新格式化输入值 -> Id 应更改为定义的格式(“{0:0.00}”)。知道如何在不丢失本地化逗号分隔符的情况下实现这一点吗?
    • 很高兴它对您有用 :) 关于格式问题,您可以根据文化定义本地化格式字符串。只需使用公共访问修饰符创建一个资源文件,然后为每种文化添加格式字符串,然后在属性中使用 [DisplayFormat(DataFormatString = MyResource.DecimalFormat, ApplyFormatInEditMode = true)]
    • 顺便说一句,我没有尝试格式化的本地化,但我认为它应该可以工作
    • 好像不行。我有另一个带有 dataformatstring {0:N0} 的双重属性,它应该适用于所有文化,但是当离开输入字段时,值不会再次格式化。
    • 格式有什么问题?我刚刚尝试过,对于两种文化,“{0:0.00}”和“{0:N0}”一切正常,我没有使用任何资源进行文化特定格式
    【解决方案2】:

    感谢@Laz Ziya,我找到了一个可以解决问题的组合:

    视图模型:

        [DisplayFormat(DataFormatString = "{0:0.00}", ApplyFormatInEditMode = true)]
        [Range(0, 100, ErrorMessage = "RangeAttribute_ValidationError")]
        public double SomeDoubleProperty { get; set; }
    

    标记:

        <div class="form-group row">
            <label asp-for="ViewModel.SomeDoubleProperty" class="col-sm-3 col-form-label">
                @Localizer[nameof(Model.ViewModel.SomeDoubleProperty)]
            </label>
            <div class="col-sm-9">
                <div class="input-group">
                    <div class="input-group-prepend">
                        <span class="input-group-text">%</span>
                    </div>
                    <input asp-for="ViewModel.SomeDoubleProperty"
                           class="form-control"
                           id="some-double-input" digit-count="2">
                </div>
                <span asp-validation-for="ViewModel.SomeDoubleProperty" class="text-danger"></span>
            </div>
        </div>
    <partial name="_NumberInputPartial" />
    

    数字输入部分:

     @using System.Threading;
    
    @*To use this partial add the following attribute to the input element: digit-count="{enter requested digit count here}"*@
    
    <script asp-location="Footer">
        function toLocalizedNumberString(numberAsString, digitCount) {
            var decimalSeparator = '@(Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator)';
            var groupSeparator = '@(Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberGroupSeparator)';
              var num = parseFloat(numberAsString.replace(decimalSeparator, '.'));
              return ( num
                .toFixed(digitCount)
                .replace('.', decimalSeparator)
                .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + groupSeparator)
                )
        }
        $("input[digit-count]").on("focusin", function () {
            $(this).val($(this).val().replace(@("/[" + Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberGroupSeparator + "]/g"), ""));
        });
        $("input[digit-count]").on("focusout", function () {
            $(this).val(toLocalizedNumberString($(this).val(), $(this).attr("digit-count")));
        });
    </script>
    
    <partial name="_ValidationScriptsPartial" />
    <localization-validation-scripts></localization-validation-scripts>
    

    【讨论】:

      猜你喜欢
      • 2022-01-12
      • 1970-01-01
      • 2018-04-16
      • 2023-01-19
      • 2022-12-05
      • 2018-06-19
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多