Flerspråkigt stöd för standardmeddelanden som visas under inmatningsvalidering
miljö
- ASP.NET kärna
-
- 5.0 MVC
Först
Det flerspråkiga stödet för standardverifieringsmeddelandena för indata med de här tipsen kanske inte är slutfört. Ta hand om de saknade.
Om du ändrar språket beroende på sessionstillstånd eller cachetillstånd kan det fortfarande visas i text från föregående språk.
Det finns flera sätt att ändra standardverifieringsmeddelandet för indata, som var och en kan kombineras. Det är inte en av dem, så om du vill ändra det på ett tillförlitligt sätt måste du korrespondera med alla mönster.
premiss
Detta tips är skrivet som att förstå följande tips:
- ASP.NET De inbyggda funktionerna i Core MVC för flerspråkig växling
- Flerspråkigt stöd för DataAnnotationer som används för parameternamn, indataverifieringsmeddelanden osv.
Om du skapar ett nytt projekt måste du också ha lagt till följande filer och kod baserat på tips ovan.
- Skapa en SharedResource.resx-fil (+en, es). (Eftersom endast meddelandet i detta tips översätts kan innehållet vara tomt.)
- Skapa en SharedResource.cs-fil
- Lägga till lokaliseringskod i Startup.ConfigureServices
- Lägg till lokaliseringskod i Start.Configure
- Lade till UserViewModel (den här gången anger vi inte uttryckligen standardmeddelandena på flera språk)
- Lade till användarskapade skärmåtgärder och vyer (Create.cshtml)
Startkod
På grundval av ovanstående antaganden skall varje kod vara följande:
Start.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 { }
}
Modellbindningsmeddelanden
Om du anger modellgenskapstypen int
till eller binder den till DateTime
vyn och försöker registrera den oskriven visas ett meddelande som "Värdet '' är ogiltigt".
Dessa meddelanden visas när en tom sträng int
inte kan bindas till, till exempel i modellen.
Eftersom det är en tidsinställning som inte kan bindas sker den bara före annan värdevalidering och bearbetning på serversidan.
Dessa meddelanden DefaultModelBindingMessageProvider
definieras som .
Startup.cs
Lägg till argumenten för den metod som har definierats sedan början services.AddControllersWithViews
i och lägg sedan till Action
.
Du kan vara flerspråkig genom att ange det godkända i options
ModelBindingMessageProvider
argumentet.
Det finns 11 typer av meddelanden som du kan ange, så du måste först definiera meddelandet i följande: SharedResource.resx
Namnet på nyckeln är valfritt. Standardmeddelandet engelska i kommentarskolumnen är (kommentarer behöver inte inkluderas).
Du behöver inte översätta varje språk, så du bör göra din egen översättning (exempelkoden innehåller också den översatta SharedResource.resx).
Kommentar | om | namnvärde |
---|---|---|
ModelBinding_AttemptedValueIsInvalid | "{0}" är ett ogiltigt värde i {1}. | Värdet "{0}" gäller inte för {1}. |
ModelBinding_MissingBindRequiredValue | Värdet för {0} har inte angetts. | Något värde för parametern "{0}" angavs inte. |
ModelBinding_MissingKeyOrValue | Krävs. | Ett värde krävs. |
ModelBinding_MissingRequestBodyRequiredValue | Begäran måste ha en kropp. | Ett icke-tomt förfrågnings brödtext krävs. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | "{0}" är ogiltigt. | Värdet "{0}" är ogiltigt. |
ModelBinding_NonPropertyUnknownValueIsInvalid | Värdet är ogiltigt. | Det angivna värdet är ogiltigt. |
ModelBinding_NonPropertyValueMustBeANumber | Nummer måste anges. | Fältet måste vara ett tal. |
ModelBinding_UnknownValueIsInvalid | Värdet på {0} är ogiltigt. | Det angivna värdet är ogiltigt för {0}. |
ModelBinding_ValueIsInvalid | "{0}" är ogiltigt. | Värdet "{0}" är ogiltigt. |
ModelBinding_ValueMustBeANumber | {0} måste vara ett nummer. | Fältet {0} måste vara ett tal. |
ModelBinding_ValueMustNotBeNull | Obligatorisk inmatning. | Värdet "{0}" är ogiltigt. |
Åtgärda start.cs enligt följande:
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
});
// 省略 (初期コード)
}
}
}
Den viktigaste punkten är services.AddControllersWithViews
att lägga till en metod som tar emot option
Action
,
options.ModelBindingMessageProvider
Jag anger lokaliserad text för varje uppsättningsmetod i .
Den översatta texten IStringLocalizer
hämtas från .
Det finns inget sätt att ta emot IStringLocalizer
direktkod, vilket är lite av en rund kod.
SharedResource.resx
Om du genererar kod från får du lokaliserade värden direkt från den.
IStringLocalizer
Nyckeln som du anger i SharedResource.resx
anger nyckeln som du har lagt till i .
Ställ in den så att den matchar innehållet i varje uppsättningsmetod.
Eftersom varje meddelande har ett formatsträngargument, till exempel , använder jag {0}{1}
Enkel med så att du kan ersätta de mottagna string.Format
Func
värdena.
Lokalisera standardverifieringsmeddelanden
Standardfelmeddelandet när attributen Required
för en modells egenskaper är inställda på eller så bestäms av ramverket och är StringLength
i princip på engelska.
Dessa kan IValidationAttributeAdapterProvider
lokaliseras genom att definiera en klass som härleds från gränssnittet.
Registrera SharedResource.resx
först och främst den text som är flerspråkig.
Namnet på nyckeln är godtyckligt, men för att förenkla programmet registrerar du det i form av "Validator_< valideringsattributnamn>".
Kommentar | om | namnvärde |
---|---|---|
Validator_CompareAttribute | De {0} och {1} stämmer inte överens. | "{0}" och "{1}" stämmer inte överens. |
Validator_CreditCardAttribute | {0} är inte ett giltigt kortnummer. | Fältet {0} är inte ett giltigt kreditkortsnummer. |
Validator_DataTypeAttribute_Date | Ange ett giltigt datum. | Ange ett giltigt datum. |
Validator_EmailAddressAttribute | {0} är inte en giltig e-postadress. | Fältet {0} är inte en giltig e-postadress. |
Validator_FileExtensionsAttribute | {0} accepterar bara filer med följande tillägg: : {1} | Fältet {0} accepterar bara filer med följande tillägg: {1} |
Validator_MaxLengthAttribute | {0} måste vara en sträng- eller matristyp med en maximal längd på "{1}". | Fältet {0} måste vara en sträng- eller matristyp med en maximal längd på "{1}". |
Validator_MinLengthAttribute | {0} måste vara en sträng- eller matristyp med en minsta längd på "{1}". | Fältet {0} måste vara en sträng- eller matristyp med en minsta längd på "{1}". |
Validator_PhoneAttribute | {0} är inte ett giltigt telefonnummer. | Fältet {0} är inte ett giltigt telefonnummer. |
Validator_RangeAttribute | {0} måste sträcka sig från {1} till {2}. | Fältet {0} måste vara mellan {1} och {2}. |
Validator_RegularExpressionAttribute | {0} måste matcha det reguljära uttrycket "{1}". | Fältet {0} måste matcha det reguljära uttrycket "{1}". |
Validator_RequiredAttribute | {0} krävs. | Fältet {0} krävs. |
Validator_StringLengthAttribute | {0} måste ligga inom {1} siffror. | Fältet {0} måste vara en sträng med en maximal längd på {1}. |
Validator_UrlAttribute | {0} är inte en giltig URL. | Fältet {0} är inte en giltig fullständigt kvalificerad http-, https- eller ftp-URL. |
Validator_StringLengthAttributeWithMin | {0} måste vara minst {2} {1} siffror. | Fältet {0} måste vara en sträng med en maximal längd på {1} och en minsta längd på {2}. |
Skapa sedan följande AdapterProvider-klass:
Klassnamnet är godtyckligt, men den här gången CustomValidationAttributeAdapterProvider
ska jag skriva en klass som heter och skriva koden enligt följande:
Platsen för kodfilen är godtycklig, men exemplet placeras i en mapp som heter Adapter.
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);
}
}
}
Om du anger modellens egenskaper till Required
eller , anropas metoden för varje StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
validering.
ErrorMessageResourceName
Om egenskapen innehåller ett värde har koden på modellsidan redan ett meddelande eller en lokaliseringsnyckel, så den returneras som den är.
Om den är tom matchar du klassnamnen för prefixet och valideringsattributet för att göra den till lokaliseringsnyckel och hämtar sedan den lokaliserade texten från nyckeln och ställer in den ErrorMessage
på .
Detta gör att de flesta standardmeddelanden kan lokaliseras.
Registrera sedan den här klassen i start .cs. I grund och botten kan du lägga till det enligt följande.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Kör den för att se till att den fungerar som den ska.
Ändra ett befintligt meddelande efter parametrar
Attributmeddelandet är till exempel StringLength
lokaliserat, till exempel "{0} måste ligga inom {1} siffror".
MinimumLength
Om egenskapen är inställd kanske du vill ändra {0} som "Ange {2} siffror eller fler {1} inom ett antal siffror".
I CustomValidationAttributeAdapterProvider
så fall förlänger du klassen på följande sätt:
// 省略
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);
}
}
// 省略
}
}
}
Eftersom metoden anropas för varje GetAttributeAdapter
validering, om variabeln som attribute
skickades var StringLengthAttribute
ett MinimumLength
attribut, kontrollerar du egenskapen,
Om du anger det får du ett meddelande som också tar hänsyn till det minsta antalet siffror och ErrorMessage
ersätter .
Om du kör det, kontrollerar och meddelandet ändras, är det OK.
Andra allmänna meddelanden
Vissa meddelanden är inte lokaliserade efter att du har gjort det hittills. Till exempel meddelanden som bara bestäms i Javascript.
Målet är jquery.validate.js
meddelandet som visas i filen.
Eftersom den här filen inte ska redigeras direkt måste du input
lägga till ett attribut som taggen och ange lokaliserad text där om du vill ersätta dessa meddelanden med lokaliserad data-val-XXXX
text.
XXXX-delen innehåller nyckeln i figuren jquery.validate.js
ovan. (t.ex. data-val-number
etc.)
data-val-XXXX
Om du vill ange lokaliserad text till attribut i
Låt oss lokalisera meddelandet när icke-numeriska tecken ingår i åldersinmatningsfältet som ett exempel.
UserViewModel.Age
har Range
ett attribut och utdata-HTML data-val-range
lägger till indataattributet.
<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>
Det data-val-number
numeriska kontrollmeddelandet är dock inte lokaliserat eftersom det inte finns något attribut.
Du lägger till ett annat attribut på modellsidan för att också skriva ut det lokaliserade data-val-number
meddelandets tillagde attribut.
Det första steget är att skapa en attributklass som kontrollerar om det är IntAttribute
ett tal: Det är begränsat till här, men du är int
fri att ändra det beroende på situationen.
Kodfilen kan vara var som helst, men den här gången finns den i adaptermappen.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Om det inställda värdet är int
en typ är det ett attribut som bara är en normal dom, men i praktiken är det 100% normalt om det är inställt på en egenskap av typ int, så bearbetningen av den här klassen själv är inte meningsfull.
Syftet med den här tiden är att visa lokaliserade felmeddelanden i klienten.
Skapa sedan följande IntAttributeAdapter
adapterklass: Detta finns också i adaptermappen.
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;
}
}
Poängen här är AddValidation
den metod som beskrivs i MergeAttribute
metoden.
Sammanfoga attribut som attribut för indatataggen för att återgå data-val-number
till klienten.
Värdet som ska anges i attributet anger ett lokaliserat felmeddelande.
Returnera det här kortet i klassen som du skapade CustomValidationAttributeAdapterProvider
tidigare.
// 省略
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);
}
// 省略 (前に追加したコード)
}
}
}
Om värdet som ska IntAttribute
valideras returnerar du det som du skapade IntAttributeAdapter
tidigare.
Egenskapen med attributet Int läggs nu till när den visas på data-val-number
klientsidan.
Lägg UserViewModel.Age
IntAttribute
slutligen till i .
När du har fixat koden kan du prova den för att se om du vill kolla in den.
<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>
Det finns andra icke-lokaliserade meddelanden, men du kan lokalisera dem i metoderna som beskrivs ovan. Lägg till kod när du behöver den.