Meertalige ondersteuning voor standaardberichten die worden weergegeven tijdens invoervalidatie
milieu
- ASP.NET kern
-
- 5,0 MVC
Eerst
De meertalige ondersteuning van de standaardinvoervalidatieberichten met deze tips is mogelijk niet volledig. Ga alsjeblieft om met de ontbrekende.
Ook kan het wijzigen van de taal afhankelijk van de sessiestatus of cachestatus nog steeds worden weergegeven in tekst uit de vorige taal.
Er zijn verschillende manieren om het standaardinvoervalidatiebericht te wijzigen, die elk kunnen worden gecombineerd. Het is er niet een van, dus als je het betrouwbaar wilt veranderen, moet je met alle patronen corresponderen.
premisse
Deze tips zijn geschreven als begrip van de volgende tips:
- ASP.NET De ingebouwde functies van Core MVC voor meertalig schakelen
- Meertalige ondersteuning voor dataannotaties die worden gebruikt voor parameternamen, invoervalidatieberichten, enz.
Als u een nieuw project maakt, moet u ook de volgende bestanden en code hebben toegevoegd op basis van bovenstaande tips.
- Maak een SharedResource.resx-bestand (+en, es). (Aangezien alleen het bericht van deze tips wordt vertaald, kan de inhoud leeg zijn.)
- Een SharedResource.cs bestand maken
- Lokalisatiecode toevoegen aan Startup.ConfigureServices
- Lokalisatiecode toevoegen aan Startup.Configure
- UserViewModel toegevoegd (deze keer toetsen we de standaardberichten niet expliciet in meerdere talen)
- Door de gebruiker gemaakte schermacties en weergaven toegevoegd (Create.cshtml)
Startcode
Op basis van de bovenstaande aannames ziet elke code er als volgt uit:
Opstarten.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 { }
}
Modelbindingsberichten
Als u het type modeleigenschap instelt int
op of en het aan de weergave bindt en probeert het niet DateTime
getypt te registreren, ziet u een bericht als '' De waarde '' is ongeldig'.
Deze berichten worden weergegeven wanneer een lege tekenreeks int
niet kan worden gekoppeld aan bijvoorbeeld het model.
Omdat het een timing is die niet kan worden gebonden, vindt deze alleen plaats vóór andere waardevalidatie en server-side verwerking.
Deze berichten worden DefaultModelBindingMessageProvider
gedefinieerd als .
Startup.cs
Voeg toe aan de argumenten van de methode die sinds het begin zijn gedefinieerd services.AddControllersWithViews
in , en voeg vervolgens toe Action
.
U kunt meertalig zijn door het geslaagde in het argument in te options
ModelBindingMessageProvider
stellen.
Er zijn 11 soorten berichten die u kunt instellen, dus u moet het bericht eerst als volgt definiëren: SharedResource.resx
De naam van de sleutel is optioneel. Het standaard Engelse bericht in de kolom Opmerkingen is (opmerkingen hoeven niet te worden opgenomen).
U hoeft niet elke taal te vertalen, dus u moet uw eigen vertaling maken (de voorbeeldcode bevat ook de vertaalde SharedResource.resx).
Opmerking over | naamwaarde | |
---|---|---|
ModelBinding_AttemptedValueIsInvalid | '{0}' is een ongeldige waarde in de {1}. | De waarde '{0}' is niet geldig voor {1}. |
ModelBinding_MissingBindRequiredValue | De waarde voor de {0} is niet opgegeven. | Er is geen waarde voor de parameter of eigenschap '{0}' opgegeven. |
ModelBinding_MissingKeyOrValue | Vereist. | Er is een waarde vereist. |
ModelBinding_MissingRequestBodyRequiredValue | Het verzoek moet een lichaam hebben. | Een niet-lege aanvraaginstantie is vereist. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | '{0}' is niet geldig. | De waarde '{0}' is niet geldig. |
ModelBinding_NonPropertyUnknownValueIsInvalid | De waarde is niet geldig. | De opgegeven waarde is ongeldig. |
ModelBinding_NonPropertyValueMustBeANumber | Het nummer moet worden opgegeven. | Het veld moet een getal zijn. |
ModelBinding_UnknownValueIsInvalid | De waarde van de {0} is niet geldig. | De opgegeven waarde is ongeldig voor {0}. |
ModelBinding_ValueIsInvalid | '{0}' is niet geldig. | De waarde '{0}' is ongeldig. |
ModelBinding_ValueMustBeANumber | {0} moet een nummer zijn. | Het veld {0} moet een getal zijn. |
ModelBinding_ValueMustNotBeNull | Vereiste invoer. | De waarde '{0}' is ongeldig. |
Los het opstarten.cs als volgt op:
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
});
// 省略 (初期コード)
}
}
}
Het belangrijkste punt is services.AddControllersWithViews
om een toe te voegen aan de methode die de option
Action
,
options.ModelBindingMessageProvider
Ik stel gelokaliseerde tekst in voor elke methode Set in .
De vertaalde tekst is IStringLocalizer
opgehaald uit .
Er is geen manier om directe code te IStringLocalizer
ontvangen, wat een beetje een ronde code is.
SharedResource.resx
Als u code genereert, krijgt u er rechtstreeks gelokaliseerde waarden van.
IStringLocalizer
De sleutel die u opgeeft, SharedResource.resx
geeft de sleutel op die u hebt toegevoegd aan .
Stel deze in op de inhoud van elke setmethode.
Ook omdat elk bericht een tekenreeksargument heeft, zoals , gebruik ik {0}{1}
Eenvoudig met zodat u de ontvangen waarden kunt string.Format
Func
vervangen.
Standaardvalidatieberichten lokaliseren
Het standaardfoutbericht wanneer de kenmerken van de eigenschappen van Required
een model zijn ingesteld op of zo, wordt bepaald door het framework en is in principe in het StringLength
Engels.
Deze kunnen worden IValidationAttributeAdapterProvider
gelokaliseerd door een klasse te definiëren die is afgeleid van de interface.
Registreer SharedResource.resx
allereerst de tekst die meertalig is.
De naam van de sleutel is willekeurig, maar om het programma te vereenvoudigen, registreert u het in de vorm van "Validator_< validatie attribuutnaam>".
Opmerking over | naamwaarde | |
---|---|---|
Validator_CompareAttribute | De {0} en {1} komen niet overeen. | '{0}' en '{1}' komen niet overeen. |
Validator_CreditCardAttribute | {0} is geen geldig kaartnummer. | Het veld {0} is geen geldig creditcardnummer. |
Validator_DataTypeAttribute_Date | Voer een geldige datum in. | Voer een geldige datum in. |
Validator_EmailAddressAttribute | {0} is geen geldig e-mailadres. | Het veld {0} is geen geldig e-mailadres. |
Validator_FileExtensionsAttribute | {0} accepteert alleen bestanden met de volgende extensies: : {1} | Het veld {0} accepteert alleen bestanden met de volgende extensies: {1} |
Validator_MaxLengthAttribute | {0} moet een tekenreeks of arraytype zijn met een maximale lengte van '{1}'. | Het veld {0} moet een tekenreeks of arraytype zijn met een maximale lengte van '{1}'. |
Validator_MinLengthAttribute | {0} moet een tekenreeks of arraytype zijn met een minimale lengte van '{1}'. | Het veld {0} moet een tekenreeks of arraytype zijn met een minimale lengte van '{1}'. |
Validator_PhoneAttribute | {0} is geen geldig telefoonnummer. | Het veld {0} is geen geldig telefoonnummer. |
Validator_RangeAttribute | {0} moet variëren van {1} tot {2}. | Het veld {0} moet tussen {1} en {2} liggen. |
Validator_RegularExpressionAttribute | {0} moet overeenkomen met de reguliere expressie '{1}'. | Het veld {0} moet overeenkomen met de reguliere expressie '{1}'. |
Validator_RequiredAttribute | {0} is vereist. | Het {0} veld is verplicht. |
Validator_StringLengthAttribute | {0} moet binnen {1} cijfers zijn. | Het veld {0} moet een tekenreeks zijn met een maximale lengte van {1}. |
Validator_UrlAttribute | {0} is geen geldige URL. | Het veld {0} is geen geldige volledig gekwalificeerde http-, https- of ftp-URL. |
Validator_StringLengthAttributeWithMin | {0} moeten ten minste {2} {1} cijfers zijn. | Het veld {0} moet een tekenreeks zijn met een maximale lengte van {1} en een minimale lengte van {2}. |
Maak vervolgens de volgende klasse AdapterProvider:
De naam van de klasse is willekeurig, maar deze keer CustomValidationAttributeAdapterProvider
schrijf ik een klasse met de naam en schrijf ik de code als volgt:
De locatie van het codebestand is willekeurig, maar het voorbeeld wordt in een map met de naam Adapter geplaatst.
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);
}
}
}
Als u de eigenschappen van het model instelt Required
op of , wordt de methode voor elke validatie aangeroepen. StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
ErrorMessageResourceName
Als de eigenschap een waarde bevat, heeft de code aan de modelzijde al een bericht- of lokalisatiesleutel, dus deze wordt geretourneerd zoals deze is.
Als deze leeg is, komt u overeen met de klassenamen van het voorvoegsel en het validatiekenmerk om er de lokalisatiesleutel van te maken en haalt u vervolgens de gelokaliseerde tekst op uit de sleutel en stelt u deze in ErrorMessage
op .
Hierdoor kunnen de meeste standaardberichten worden gelokaliseerd.
Registreer deze klasse vervolgens in opstart- .cs. Kortom, u kunt het als volgt toevoegen.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Voer het uit om er zeker van te zijn dat het goed werkt.
Een bestaand bericht wijzigen op parameters
Het kenmerkbericht is bijvoorbeeld StringLength
gelokaliseerd, zoals '{0} moet zich binnen {1} cijfers bevindt'.
MinimumLength
Als de eigenschap is ingesteld, kunt u de {0} wijzigen in 'Geef {2} cijfers of meer {1} op binnen een aantal cijfers'.
Breid in dat CustomValidationAttributeAdapterProvider
geval de klasse als volgt uit:
// 省略
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);
}
}
// 省略
}
}
}
Omdat de methode voor elke validatie wordt GetAttributeAdapter
aangeroepen, controleert u de eigenschap als de doorgegeven variabele attribute
een kenmerk StringLengthAttribute
MinimumLength
was,
Indien ingesteld, krijgt u een bericht dat ook rekening houdt met het minimum aantal cijfers en ErrorMessage
vervangt .
Als u het uitvoert, controleert en het bericht verandert, is het OK.
Andere algemene berichten
Sommige berichten worden niet gelokaliseerd nadat u dat tot nu toe hebt gedaan. Bijvoorbeeld berichten die alleen in Javascript worden bepaald.
Het doel is jquery.validate.js
het bericht dat in het bestand wordt vermeld.
Omdat dit bestand niet rechtstreeks mag worden bewerkt, moet u een input
kenmerk toevoegen zoals aan de tag en gelokaliseerde tekst instellen om deze berichten te vervangen door gelokaliseerde data-val-XXXX
tekst.
Het XXXX-gedeelte bevat de sleutel in de jquery.validate.js
bovenstaande afbeelding. (bijv. data-val-number
enz.)
data-val-XXXX
Als u gelokaliseerde tekst wilt instellen op kenmerken in
Laten we het bericht lokaliseren wanneer niet-numerieke tekens als voorbeeld zijn opgenomen in het invoerveld Leeftijd.
UserViewModel.Age
heeft Range
een attribuut en de uitvoer-HTML data-val-range
voegt het invoerkenmerk toe.
<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>
Het data-val-number
numerieke controlebericht is echter niet gelokaliseerd omdat er geen kenmerk is.
U voegt nog een attribuut toe aan de modelzijde om ook het gelokaliseerde, aan bericht toegevoegde kenmerk af te data-val-number
drukken.
De eerste stap is het maken van een kenmerkklasse die controleert of het IntAttribute
een getal is: Het is beperkt tot hier, maar je bent int
vrij om het te veranderen afhankelijk van de situatie.
Het codebestand kan zich overal bevinden, maar dit keer bevindt het zich in de map Adapter.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Als de ingestelde waarde int
een type is, is het een attribuut dat slechts een normaal oordeel is, maar in de praktijk is het 100% normaal als het wordt ingesteld op een eigenschap van type int, dus de verwerking van deze klasse zelf heeft geen zin.
Het doel van deze tijd is om gelokaliseerde foutmeldingen in de client weer te geven.
Maak vervolgens de volgende IntAttributeAdapter
klasse Adapter: Dit bevindt zich ook in de map Adapter.
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;
}
}
Het punt hier is AddValidation
de methode die in de methode wordt MergeAttribute
beschreven.
Kenmerken samenvoegen als kenmerken van de invoertag om terug te keren data-val-number
naar de client.
De waarde die in het kenmerk moet worden ingesteld, stelt een gelokaliseerd foutbericht in.
Retourneer deze adapter in de klasse die u eerder hebt CustomValidationAttributeAdapterProvider
gemaakt.
// 省略
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);
}
// 省略 (前に追加したコード)
}
}
}
Als de te valideren waarde IntAttribute
is, retourneer je de waarde die je eerder hebt IntAttributeAdapter
gemaakt.
De eigenschap met het kenmerk Int wordt nu toegevoegd wanneer deze aan de clientzijde wordt data-val-number
weergegeven.
Voeg ten slotte UserViewModel.Age
IntAttribute
toe aan .
Zodra je je code hebt opgelost, probeer je het uit om te zien of je het wilt bekijken.
<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>
Er zijn andere niet-gelokaliseerde berichten, maar u kunt deze lokaliseren op de hierboven beschreven methoden. Voeg code toe wanneer u deze nodig hebt.