Viacjazyčná podpora predvolených správ zobrazených počas overovania vstupu
životné prostredie
- ASP.NET jadro
-
- 5,0 MVC
Najskôr
Viacjazyčná podpora predvolených správ na overenie vstupu s týmtoi tipmi nemusí byť úplná. Prosím, vysporiadajte sa s chýbajúcimi.
Zmena jazyka v závislosti od stavu relácie alebo stavu vyrovnávacej pamäte sa môže stále zobrazovať v texte z predchádzajúceho jazyka.
Existuje niekoľko spôsobov, ako zmeniť predvolenú správu o overení vstupu, z ktorých každý je možné kombinovať. Nie je to jeden z nich, takže ak ho chcete spoľahlivo zmeniť, musíte zodpovedať všetkým vzorom.
predpoklad
Tieto tipy sú napísané ako pochopenie nasledujúcich tipov:
- ASP.NET Vstavané funkcie Core MVC pre viacjazyčné prepínanie
- Viacjazyčná podpora pre dataAnnotácie používané pre názvy parametrov, vstupné overovacie správy atď.
Ak tiež vytvárate nový projekt, musíte pridať nasledujúce súbory a kód na základe vyššie uvedených tipov.
- Vytvorte súbor SharedResource.resx (+en, es). (Keďže sa prekladá iba správa týchto tipov, obsah môže byť prázdny.)
- Vytvorenie súboru SharedResource.cs
- Pridanie lokalizačného kódu do služby Startup.ConfigureServices
- Pridanie lokalizačného kódu do programu Startup.Configure
- Pridaný UserViewModel (tentoraz explicitne neodsunievame predvolené správy vo viacerých jazykoch)
- Pridané akcie a zobrazenia obrazovky vytvorené používateľom (Create.cshtml)
Počiatočný kód
Na základe uvedených predpokladov je každý kód takýto:
Štart.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Globalization;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddMvc()
// ローカライズに必要。Resx ファイルのフォルダパスを指定
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = "Resources"; })
// DataAnnotations のローカライズに必要
.AddDataAnnotationsLocalization(options =>
{
// DataAnnotation を使ったときのメッセージは SharedResource に集約する
options.DataAnnotationLocalizerProvider = (type, factory) => factory.Create(typeof(SharedResource));
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
// 標準の機能で切り替えたい言語を定義します。
var supportedCultures = new[]
{
new CultureInfo("ja"),
new CultureInfo("en"),
new CultureInfo("es"),
};
// 標準の言語切り替え機能を有効にします。対応しているのは「クエリ文字列」「Cookie」「Accept-Language HTTP ヘッダー」です。
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("ja"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseHttpsRedirection();
app.UseStaticFiles();
// 省略
}
}
}
HomeController.cs
using LocalizationDefaultValidation.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace LocalizationDefaultValidation.Controllers
{
public class HomeController : Controller
{
// 省略
public IActionResult Create()
{
SetDayOfWeeksViewData();
return View();
}
[HttpPost]
public IActionResult Create(UserViewModel model)
{
SetDayOfWeeksViewData();
// エラーなら差し戻し
if (ModelState.IsValid == false) return View(model);
// 正常に登録できた場合は Index に戻る
return RedirectToAction(nameof(Index));
}
<summary>曜日の一覧を ViewData に設定します。</summary>
private void SetDayOfWeeksViewData()
=> ViewData["DayOfWeeks"] = ((DayOfWeek[])Enum.GetValues(typeof(DayOfWeek))).Select(x => new SelectListItem(x.ToString(), ((int)x).ToString()));
}
}
Index.cshtml
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
<p>ユーザー作成画面に遷移します。リンクごとに選択した言語で表示できます。</p>
<ul>
<li><a asp-action="Create">Create</a></li>
<li><a asp-action="Create" asp-route-culture="ja">Create (ja)</a></li>
<li><a asp-action="Create" asp-route-culture="en">Create (en)</a></li>
<li><a asp-action="Create" asp-route-culture="es">Create (es)</a></li>
</ul>
Create.cshtml
@model LocalizationDefaultValidation.Models.UserViewModel
@using System.Globalization;
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>UserViewModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data" >
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ID" class="control-label"></label>
<input asp-for="ID" class="form-control" />
<span asp-validation-for="ID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password" class="control-label"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword" class="control-label"></label>
<input asp-for="ConfirmPassword" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Age" class="control-label"></label>
<input asp-for="Age" class="form-control" />
<span asp-validation-for="Age" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Gender"></label>
<div>
<label><input type="radio" asp-for="Gender" value="@(GenderType.None)" />@(GenderType.None)</label>
<label><input type="radio" asp-for="Gender" value="@(GenderType.Man)" />@(GenderType.Man)</label>
<label><input type="radio" asp-for="Gender" value="@(GenderType.Woman)" />@(GenderType.Woman)</label>
</div>
<span asp-validation-for="Gender" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Birthday" class="control-label"></label>
<input asp-for="Birthday" class="form-control" />
<span asp-validation-for="Birthday" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Phone" class="control-label"></label>
<input asp-for="Phone" class="form-control" />
<span asp-validation-for="Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PostalCode" class="control-label"></label>
<input asp-for="PostalCode" class="form-control" />
<span asp-validation-for="PostalCode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreditCard" class="control-label"></label>
<input asp-for="CreditCard" class="form-control" />
<span asp-validation-for="CreditCard" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Money" class="control-label"></label>
<input asp-for="Money" class="form-control" />
<span asp-validation-for="Money" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="StartDateTime" class="control-label"></label>
<input asp-for="StartDateTime" class="form-control" />
<span asp-validation-for="StartDateTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="WakeUpTime" class="control-label"></label>
<input asp-for="WakeUpTime" class="form-control" />
<span asp-validation-for="WakeUpTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Homepage" class="control-label"></label>
<input asp-for="Homepage" class="form-control" />
<span asp-validation-for="Homepage" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MyImage" class="control-label"></label>
<input asp-for="MyImage" class="form-control" />
<span asp-validation-for="MyImage" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MyColor" class="control-label"></label>
<input asp-for="MyColor" class="form-control" type="color" />
<span asp-validation-for="MyColor" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="WorkingDays" class="control-label"></label>
<select asp-for="WorkingDays" class="form-control" asp-items="@((IEnumerable<SelectListItem>)ViewData["DayOfWeeks"])" multiple></select>
<span asp-validation-for="WorkingDays" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="VacationDay" class="control-label"></label>
<select asp-for="VacationDay" class="form-control" asp-items="@((IEnumerable<SelectListItem>)ViewData["DayOfWeeks"])" multiple></select>
<span asp-validation-for="VacationDay" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Comment" class="control-label"></label>
<textarea asp-for="Comment" class="form-control"></textarea>
<span asp-validation-for="Comment" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FileName" class="control-label"></label>
<input asp-for="FileName" class="form-control" />
<span asp-validation-for="FileName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UploadFile" class="control-label"></label>
<input asp-for="UploadFile" type="file" multiple />
<span asp-validation-for="UploadFile" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Month" class="control-label"></label>
<input asp-for="Month" class="form-control" type="month" />
<span asp-validation-for="Month" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Search" class="control-label"></label>
<input asp-for="Search" class="form-control" type="search" />
<span asp-validation-for="Search" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Range" class="control-label"></label>
<input asp-for="Range" class="form-control" type="range" min="10" max="100" />
<span asp-validation-for="Range" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Week" class="control-label"></label>
<input asp-for="Week" class="form-control" type="week" />
<span asp-validation-for="Week" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsAccepted" /> @Html.DisplayNameFor(model => model.IsAccepted)
</label>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" asp-route-culture="@CultureInfo.CurrentCulture.Name" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
UserViewModel.cs
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation.Models
{
public class UserViewModel
{
[Required]
[Display(Name = "ID (半角英数字)")]
[StringLength(20)]
[RegularExpression(@"^[0-9a-zA-Z]*$")]
public string ID { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(50, MinimumLength = 8)]
[DataType(DataType.Password)]
[RegularExpression(@"^[0-9a-zA-Z]*$")]
public string Password { get; set; }
[StringLength(50, MinimumLength = 8)]
[DataType(DataType.Password)]
[Compare(nameof(Password))]
public string ConfirmPassword { get; set; }
[EmailAddress]
[DataType(DataType.EmailAddress)] // スキャフォールディングするときはコメントアウトする
public string Email { get; set; }
//[Int]
[Range(0, 150)]
public int Age { get; set; }
[Required]
[EnumDataType(typeof(GenderType))]
public GenderType Gender { get; set; }
[DataType(DataType.Date)]
public DateTime Birthday { get; set; }
[Phone()]
[DataType(DataType.PhoneNumber)] // スキャフォールディングするときはコメントアウトする
public string Phone { get; set; }
[DataType(DataType.PostalCode)]
public string PostalCode { get; set; }
[CreditCard()]
[DataType(DataType.CreditCard)] // スキャフォールディングするときはコメントアウトする
public string CreditCard { get; set; }
[DataType(DataType.Currency)]
public decimal Money { get; set; }
[DataType(DataType.DateTime)]
public DateTime StartDateTime { get; set; }
[DataType(DataType.Time)]
public TimeSpan WakeUpTime { get; set; }
[Url]
[DataType(DataType.Url)] // スキャフォールディングするときはコメントアウトする
public string Homepage { get; set; }
[Url]
[DataType(DataType.ImageUrl)] // スキャフォールディングするときはコメントアウトする
public string MyImage { get; set; }
public string MyColor { get; set; }
[MaxLength(5)]
public DayOfWeek[] WorkingDays { get; set; }
[MinLength(3)]
public DayOfWeek[] VacationDay { get; set; }
[StringLength(200)]
[DataType(DataType.MultilineText)]
public string Comment { get; set; }
[Display(Name = "ファイル名 (.png)")]
[FileExtensions(Extensions = "png")]
public string FileName { get; set; }
[DataType(DataType.Upload)]
public List<IFormFile> UploadFile { get; set; }
public DateTime Month { get; set; }
public string Search { get; set; }
[Range(10, 100)]
public int Range { get; set; }
public string Week { get; set; }
[Required]
public bool IsAccepted { get; set; }
}
public enum GenderType
{
None,
Man,
Woman,
Other,
}
}
SharedResource.cs
namespace LocalizationDefaultValidation
{
// クラス名は作成した .resx のファイル名と同じにする必要がある
public class SharedResource { }
}
Vzorové väzbové správy
Ak nastavíte typ vlastnosti modelu int
alebo ho naviažete na DateTime
zobrazenie a pokúsite sa ho zaregistrovať netypovo, zobrazí sa hlásenie s nápisom "Hodnota "" je neplatná.
Tieto správy sa zobrazia, keď prázdny reťazec int
nie je viazaný napríklad v modeli.
Keďže ide o načasovanie, ktoré nie je možné viazať, vyskytuje sa len pred iným overovaním hodnoty a spracovaním na strane servera.
Tieto správy sú DefaultModelBindingMessageProvider
definované ako .
Startup.cs
Pridajte k argumentom metódy , ktorá bola definovaná od začiatku services.AddControllersWithViews
v , a potom pridajte Action
.
Nastavením odovzdaného argumentu môžete byť options
ModelBindingMessageProvider
viacjazyční.
Existuje 11 typov správ, ktoré môžete nastaviť, takže musíte najprv definovať správu takto: SharedResource.resx
Názov kľúča je voliteľný. Predvolená anglická správa v stĺpci komentárov je (komentáre nemusia byť zahrnuté).
Nebudete musieť prekladať každý jazyk, takže by ste mali urobiť svoj vlastný preklad (vzorový kód obsahuje aj preklad SharedResource.resx).
Komentár | k hodnote | názvu |
---|---|---|
ModelBinding_AttemptedValueIsInvalid | "{0}" je neplatná hodnota v {1}. | Hodnota "{0}" nie je platná pre {1}. |
ModelBinding_MissingBindRequiredValue | Hodnota pre {0} nie je zadaná. | Hodnota parametra alebo vlastnosti "{0}" nebola poskytnutá. |
ModelBinding_MissingKeyOrValue | Požadovaný. | Vyžaduje sa hodnota. |
ModelBinding_MissingRequestBodyRequiredValue | Žiadosť musí mať telo. | Vyžaduje sa ne vyprázdnenie tela žiadosti. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | "{0}" nie je platné. | Hodnota "{0}" nie je platná. |
ModelBinding_NonPropertyUnknownValueIsInvalid | Hodnota nie je platná. | Zadaná hodnota je neplatná. |
ModelBinding_NonPropertyValueMustBeANumber | Číslo musí byť špecifikované. | Pole musí byť číslo. |
ModelBinding_UnknownValueIsInvalid | Hodnota {0} nie je platná. | Zadaná hodnota je pre {0} neplatná. |
ModelBinding_ValueIsInvalid | "{0}" nie je platné. | Hodnota "{0}" je neplatná. |
ModelBinding_ValueMustBeANumber | {0} musí byť číslo. | Pole {0} musí byť číslo. |
ModelBinding_ValueMustNotBeNull | Požadovaný vstup. | Hodnota "{0}" je neplatná. |
Opravte spustenie.cs takto:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using System;
using System.Globalization;
using System.Reflection;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略 (初期コード)
<summary>
検証メッセージローカライズで使用。
</summary>
private IServiceProvider ServiceProvider { get; set; }
private IStringLocalizer _localizer = null;
<summary>
検証メッセージローカライズで使用。
</summary>
private IStringLocalizer Localizer
=> _localizer ?? (_localizer = ServiceProvider.GetService<IStringLocalizerFactory>()
.Create(nameof(SharedResource), new AssemblyName(typeof(SharedResource).Assembly.FullName).Name));
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
// 検証メッセージのローカライズで使用
// モデルバインディング失敗時のエラーメッセージをカスタマイズ
// サーバ側でモデルに値を格納する際に発生する可能性がある
// メッセージの {0} や {1} を置換するための関数を定義
static string f1(string f, string a1) => string.Format(f, a1);
static string f2(string f, string a1, string a2) => string.Format(f, a1, a2);
// 各メソッドを読んでメッセージを置き換えます
var mp = options.ModelBindingMessageProvider;
mp.SetAttemptedValueIsInvalidAccessor((x, y) => f2(Localizer["ModelBinding_AttemptedValueIsInvalid"], x, y));
mp.SetMissingBindRequiredValueAccessor((x) => f1(Localizer["ModelBinding_MissingBindRequiredValue"], x));
mp.SetMissingKeyOrValueAccessor(() => Localizer["ModelBinding_MissingKeyOrValue"]);
mp.SetMissingRequestBodyRequiredValueAccessor(() => Localizer["ModelBinding_MissingRequestBodyRequiredValue"]);
mp.SetNonPropertyAttemptedValueIsInvalidAccessor((x) => f1(Localizer["ModelBinding_NonPropertyAttemptedValueIsInvalid"], x));
mp.SetNonPropertyUnknownValueIsInvalidAccessor(() => Localizer["ModelBinding_NonPropertyUnknownValueIsInvalid"]);
mp.SetNonPropertyValueMustBeANumberAccessor(() => Localizer["ModelBinding_NonPropertyValueMustBeANumber"]);
mp.SetUnknownValueIsInvalidAccessor((x) => f1(Localizer["ModelBinding_UnknownValueIsInvalid"], x));
mp.SetValueIsInvalidAccessor((x) => f1(Localizer["ModelBinding_ValueIsInvalid"], x));
mp.SetValueMustBeANumberAccessor((x) => f1(Localizer["ModelBinding_ValueMustBeANumber"], x));
mp.SetValueMustNotBeNullAccessor((x) => f1(Localizer["ModelBinding_ValueMustNotBeNull"], x));
});
services.AddMvc()
// ローカライズに必要。Resx ファイルのフォルダパスを指定
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = "Resources"; })
// DataAnnotations のローカライズに必要
.AddDataAnnotationsLocalization(options =>
{
// DataAnnotation を使ったときのメッセージは SharedResource に集約する
options.DataAnnotationLocalizerProvider = (type, factory) => factory.Create(typeof(SharedResource));
});
}
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、HTTP要求パイプラインを構成します。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ローカライズで使用するため IServiceProvider をプロパティに保持しておきます。
ServiceProvider = app.ApplicationServices;
// 標準の機能で切り替えたい言語を定義します。
var supportedCultures = new[]
{
new CultureInfo("ja"),
new CultureInfo("en"),
new CultureInfo("es"),
};
// 標準の言語切り替え機能を有効にします。対応しているのは「クエリ文字列」「Cookie」「Accept-Language HTTP ヘッダー」です。
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("ja"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
// 省略 (初期コード)
}
}
}
Kľúčovým bodom je services.AddControllersWithViews
pridať a do metódy, ktorá prijíma option
Action
,
options.ModelBindingMessageProvider
Nastavujem lokalizovaný text pre každú metódu množiny v .
Preložený text IStringLocalizer
sa načíta z .
Neexistuje žiadny spôsob, ako získať priamy IStringLocalizer
kód, čo je trochu okrúhly kód.
SharedResource.resx
Ak generujete kód z neho, získate lokalizované hodnoty priamo z neho.
IStringLocalizer
Kľúč, ktorý zadáte, SharedResource.resx
určuje kľúč, ku ktorému ste pridali .
Nastavte ho tak, aby zodpovedal obsahu každej metódy množiny.
Tiež preto, že každá správa má argument reťazca formátu, napríklad , {0}{1}
používam jednoduché s, aby ste mohli nahradiť prijaté string.Format
Func
hodnoty.
Lokalizácia predvolených overovacích správ
Predvolené chybové hlásenie, keď sú atribúty Required
vlastností modelu nastavené alebo sú nastavené tak, je určené rámcom a je v podstate v StringLength
angličtine.
Tieto môžu byť IValidationAttributeAdapterProvider
lokalizované definovaním triedy odvodenej z rozhrania.
V prvom rade SharedResource.resx
zaregistrujte text, ktorý je viacjazyčný.
Názov kľúča je ľubovoľný, ale na zjednodušenie programu ho zaregistrujte vo forme "Validator_< názov atribútu overenia>".
Komentár | k hodnote | názvu |
---|---|---|
Validator_CompareAttribute | {0} a {1} sa nezhodujú. | "{0}" a "{1}" sa nezhodujú. |
Validator_CreditCardAttribute | {0} nie je platné číslo karty. | Pole {0} nie je platné číslo kreditnej karty. |
Validator_DataTypeAttribute_Date | Zadajte platný dátum. | Zadajte platný dátum. |
Validator_EmailAddressAttribute | {0} nie je platná e-mailová adresa. | Pole {0} nie je platnou e-mailovou adresou. |
Validator_FileExtensionsAttribute | {0} prijíma iba súbory s nasledujúcimi príponami: : {1} | Pole {0} prijíma iba súbory s nasledujúcimi príponami: {1} |
Validator_MaxLengthAttribute | {0} musí byť typ reťazca alebo poľa s maximálnou dĺžkou "{1}". | Pole {0} musí byť reťazec alebo typ poľa s maximálnou dĺžkou "{1}". |
Validator_MinLengthAttribute | {0} musí byť typ reťazca alebo poľa s minimálnou dĺžkou "{1}". | Pole {0} musí byť reťazec alebo typ poľa s minimálnou dĺžkou "{1}". |
Validator_PhoneAttribute | {0} nie je platné telefónne číslo. | Pole {0} nie je platné telefónne číslo. |
Validator_RangeAttribute | {0} sa musia pohybovať od {1} do {2}. | Pole {0} musí byť medzi {1} a {2}. |
Validator_RegularExpressionAttribute | {0} sa musí zhodovať s regulárnym výrazom "{1}". | Pole {0} musí zodpovedať regulárnemu výrazu "{1}". |
Validator_RequiredAttribute | {0} je potrebná. | Vyžaduje sa pole {0}. |
Validator_StringLengthAttribute | {0} musí byť v {1} čísliciach. | Pole {0} musí byť reťazec s maximálnou dĺžkou {1}. |
Validator_UrlAttribute | {0} nie je platná adresa URL. | Pole {0} nie je platnou plne kvalifikovanou adresou HTTP, https alebo FTP. |
Validator_StringLengthAttributeWithMin | {0} musí byť aspoň {2} {1} číslic. | Pole {0} musí byť reťazec s maximálnou dĺžkou {1} a minimálnou dĺžkou {2}. |
Ďalej vytvorte nasledujúcu triedu AdapterProvider:
Názov triedy je ľubovoľný, ale tentoraz CustomValidationAttributeAdapterProvider
napíšem triedu s názvom a napíšem kód takto:
Umiestnenie súboru kódu je ľubovoľné, ale vzorka sa umiestni do priečinka s názvom Adaptér.
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.Extensions.Localization;
using System;
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
{
<summary>コード簡略化のためのリソースキー命名規則プリフィックス</summary>
private const string RESOURCE_KEY_PREFIX = "Validator_";
private readonly IValidationAttributeAdapterProvider _fallback = new ValidationAttributeAdapterProvider();
<summary>
指定された ValidationAttribute の IAttributeAdapter を返します。
</summary>
<param name="attribute">IAttributeAdapter を作成するための ValidationAttribute。</param>
<param name="stringLocalizer">メッセージの作成に使用される IStringLocalizer。</param>
<returns>指定された属性の IAttributeAdapter。</returns>
IAttributeAdapter IValidationAttributeAdapterProvider.GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
{
// すでにエラーメッセージが設定されている場合はそれを使用するのでここでは何も設定しない
if (attribute.ErrorMessageResourceName != null) return _fallback.GetAttributeAdapter(attribute, stringLocalizer);
// attribute には「Required」や「StringLength」などが設定されています
Type attrType = attribute.GetType();
// プリフィックスと属性のクラス名からローカライズ用のキーを生成します
var key = RESOURCE_KEY_PREFIX + attrType.Name;
// IStringLocalizer から指定したキーでローカライズされたテキストを取得します
// ない場合は getString にそのまま key の値が入ります
var getString = stringLocalizer[key];
// 正しくローカライズされたテキストが取得できた場合は ErrorMessage に値をセットします。
if (key != getString && attribute.ErrorMessage != getString)
{
attribute.ErrorMessage = getString;
}
// 設定した attribute を渡します
return _fallback.GetAttributeAdapter(attribute, stringLocalizer);
}
}
}
Ak nastavíte vlastnosti modelu na Required
alebo , metóda sa požaduje pre každé StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
overenie.
ErrorMessageResourceName
Ak vlastnosť obsahuje hodnotu, kód na strane modelu už obsahuje správu alebo lokalizačný kľúč, takže sa vráti tak, ako je.
Ak je prázdny, priraďte názvy tried atribútu predpony a overenia, aby sa z neho urobil lokalizačný kľúč, a potom načítať lokalizovaný text z kľúča a nastaviť ho ErrorMessage
na .
To umožňuje lokalizáciu väčšiny predvolených správ.
Ďalej zaregistrujte túto triedu v startupovej .cs. V podstate ho môžete pridať nasledovne.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Spustite ho, aby ste sa uistili, že funguje správne.
Zmena existujúcej správy podľa parametrov
Správa atribútu je napríklad StringLength
lokalizovaná, napríklad "{0} musí byť v {1} číslicach".
MinimumLength
Ak je vlastnosť nastavená, možno budete chcieť zmeniť {0} ako "Zadajte {2} číslic alebo viac {1} v rámci viacerých číslic".
V takom CustomValidationAttributeAdapterProvider
prípade rozšírte triedu takto:
// 省略
namespace LocalizationDefaultValidation
{
public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
{
// 省略
IAttributeAdapter IValidationAttributeAdapterProvider.GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
{
if (attribute is StringLengthAttribute slAttribute)
{
// attribute が StringLengthAttribute で MinimumLength が設定されている場合はメッセージを変える
if (slAttribute.MinimumLength >= 1)
{
attribute.ErrorMessage = stringLocalizer["Validator_StringLengthAttributeWithMin"];
return _fallback.GetAttributeAdapter(slAttribute, stringLocalizer);
}
}
// 省略
}
}
}
Keďže metóda je privolaná pre každé GetAttributeAdapter
overenie, ak odovzdaná premenná attribute
bola StringLengthAttribute
MinimumLength
atribútom, skontrolujte vlastnosť,
Ak je nastavené, zobrazí sa hlásenie, ktoré zohľadňuje aj minimálny počet číslic a ErrorMessage
nahrádza .
Ak ho spustíte, skontrolujte a správa sa zmení, je to v poriadku.
Ďalšie všeobecné správy
Niektoré správy nie sú lokalizované po tom, čo tak urobíte. Napríklad správy, ktoré sú určené iba v jazyku JavaScript.
Cieľom je jquery.validate.js
správa uvedená v súbore.
Keďže tento súbor by sa nemal upravovať priamo, nahradiť tieto správy lokalizovaným input
textom, musíte pridať atribút, ako je značka a nastaviť data-val-XXXX
lokalizovaný text tam.
Časť XXXX obsahuje kľúč na obrázku jquery.validate.js
vyššie. (napr. data-val-number
atď.)
data-val-XXXX
Ak chcete nastaviť lokalizovaný text na atribúty v
Lokalizovajme správu, keď sú napríklad do vstupného poľa Vek zahrnuté nečíselné znaky.
UserViewModel.Age
má Range
atribút a výstupný HTML data-val-range
prikladá vstupný atribút.
<div class="form-group">
<label class="control-label" for="Age">Age</label>
<input class="form-control" type="number" data-val="true" data-val-range="Ageは0から150の範囲で指定してください。" data-val-range-max="150" data-val-range-min="0" data-val-required="Ageは必須です。" id="Age" name="Age" value="" />
<span class="text-danger field-validation-valid" data-valmsg-for="Age" data-valmsg-replace="true"></span>
</div>
data-val-number
Numerická kontrolná správa však nie je lokalizovaná, pretože neexistuje žiadny atribút.
Na strane modelu pridáte ďalší atribút a vytlačíte aj lokalizovaný atribút pridaný data-val-number
správou.
Prvým krokom je vytvorenie triedy atribútov, ktorá skontroluje, či ide IntAttribute
o číslo: Je to obmedzené na tu, ale môžete int
ho zmeniť v závislosti od situácie.
Súbor kódu môže byť kdekoľvek, ale tentoraz je v priečinku Adaptér.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Ak je nastavená hodnota int
typom, je to atribút, ktorý je len normálnym verdiktom, ale v praxi je 100% normálny, ak je nastavený na vlastnosť typu int, takže samotné spracovanie tejto triedy nedáva zmysel.
Účelom tejto doby je zobraziť lokalizované chybové hlásenia v klientovi.
Ďalej vytvorte nasledujúcu IntAttributeAdapter
triedu adaptéra: Nachádza sa aj v priečinku Adaptér.
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Localization;
namespace LocalizationDefaultValidation
{
<summary>Int 属性のアダプター。</summary>
public class IntAttributeAdapter : AttributeAdapterBase<IntAttribute>
{
<summary>受け取った IStringLocalizer を保持しておく</summary>
IStringLocalizer _stringLocalizer;
public IntAttributeAdapter(IntAttribute attribute, IStringLocalizer stringLocalizer)
: base(attribute, stringLocalizer)
{
_stringLocalizer = stringLocalizer;
}
<summary>バリデーションの追加処理として呼ばれる。</summary>
public override void AddValidation(ClientModelValidationContext context)
{
// 新たに data-val-number 属性をマージして追加します。値はローカライズしたテキストをセットします。
MergeAttribute(context.Attributes, "data-val-number", _stringLocalizer["ModelBinding_NonPropertyValueMustBeANumber"]);
}
<summary>サーバーのエラーメッセージはそのまま返します。</summary>
public override string GetErrorMessage(ModelValidationContextBase validationContext) => Attribute.ErrorMessage;
}
}
Tu je AddValidation
metóda opísaná v MergeAttribute
metóde.
Zlúčenie atribútov ako atribútov vstupnej značky na návrat data-val-number
k klientovi.
Hodnota, ktorú sa má nastaviť v atribúte, nastavuje lokalizované chybové hlásenie.
Vráťte tento adaptér do triedy, ktorú ste vytvorili CustomValidationAttributeAdapterProvider
predtým.
// 省略
namespace LocalizationDefaultValidation
{
public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
{
// 省略
IAttributeAdapter IValidationAttributeAdapterProvider.GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
{
// IntAttribute の場合は IntAttributeAdapter 経由で返す
if (attribute is IntAttribute intAttribute)
{
return new IntAttributeAdapter(intAttribute, stringLocalizer);
}
// 省略 (前に追加したコード)
}
}
}
Ak je hodnota, ktorú chcete IntAttribute
overiť, vrátená hodnota, ktorú ste vytvorili IntAttributeAdapter
predtým.
Vlastnosť s atribútom Int sa teraz pridá, keď sa zobrazí na data-val-number
strane klienta.
Nakoniec UserViewModel.Age
IntAttribute
pridajte k .
Akonáhle ste opravili kód, vyskúšajte ho, aby ste zistili, či ho chcete skontrolovať.
<div class="form-group">
<label class="control-label" for="Age">Age</label>
<input class="form-control" type="number" data-val="true" data-val-number="数字を指定してください。" data-val-range="Ageは0から150の範囲で指定してください。" data-val-range-max="150" data-val-range-min="0" data-val-required="Ageは必須です。" id="Age" name="Age" value="" />
<span class="text-danger field-validation-valid" data-valmsg-for="Age" data-valmsg-replace="true"></span>
</div>
Existujú aj iné neau lokalizované správy, ale môžete ich lokalizovať v metódach popísaných vyššie. Pridajte kód, keď ho potrebujete.