Razor Pages 中双值输入字段的本地化
Localization for input field with double value in Razor Pages
在我的 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",所以小数分隔符“,”是预期的)。
但是当我现在离开输入字段时,显示以下验证错误:
The field SomeDoubleProperty must be a number.
用“.”替换“,”时,验证器接受该值。
如果当前 ui 文化是 "de",我怎样才能让“,”也被接受?
您需要下载并配置客户端验证脚本:
- cldrjs
- cldr-data
- globalizejs
在项目的根目录中创建一个新文件,将其命名为 "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,所以要么从GitHub手动下载或者只需使用来自 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
感谢@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" />
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, '' + 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>
在我的 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",所以小数分隔符“,”是预期的)。
但是当我现在离开输入字段时,显示以下验证错误:
The field SomeDoubleProperty must be a number.
用“.”替换“,”时,验证器接受该值。 如果当前 ui 文化是 "de",我怎样才能让“,”也被接受?
您需要下载并配置客户端验证脚本:
- cldrjs
- cldr-data
- globalizejs
在项目的根目录中创建一个新文件,将其命名为 "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,所以要么从GitHub手动下载或者只需使用来自 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
感谢@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" />
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, '' + 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>