Supporto multilingue per i messaggi predefiniti visualizzati durante la convalida dell'input
ambiente
- ASP.NET Nucleo
-
- 5,0 MVC
Dapprima
Il supporto multilingue dei messaggi di convalida dell'input predefiniti con questo suggerimento potrebbe non essere completo. Si prega di affrontare quelli mancanti.
Inoltre, la modifica della lingua a seconda dello stato della sessione o dello stato della cache potrebbe ancora essere visualizzata nel testo della lingua precedente.
Esistono diversi modi per modificare il messaggio di convalida dell'input predefinito, ognuno dei quali può essere combinato. Non è uno di questi, quindi se vuoi cambiarlo in modo affidabile, devi corrispondere a tutti i modelli.
premessa
Questo suggerimento è scritto come la comprensione dei seguenti suggerimenti:
- ASP.NET Le funzionalità integrate di Core MVC per la commutazione multilingue
- Supporto multilingue per DataAnnotations utilizzato per nomi di parametri, messaggi di convalida dell'input, ecc.
Inoltre, se si sta creando un nuovo progetto, è necessario aver aggiunto i seguenti file e codice in base ai suggerimenti precedenti.
- Creare un file SharedResource.resx (+en, es). (Poiché viene tradotto solo il messaggio di questo suggerimento, il contenuto potrebbe essere vuoto.)
- Creare un file SharedResource.cs
- Aggiungere codice di localizzazione a Startup.ConfigureServices
- Aggiungere codice di localizzazione a Startup.Configure
- Aggiunto UserViewModel (questa volta, non anccheggiamo esplicitamente i messaggi predefiniti in più lingue)
- Aggiunte azioni e viste dello schermo create dall'utente (Create.cshtml)
Codice di partenza
Sulla base delle ipotesi di cui sopra, ciascun codice è il seguente:
Avvio.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 { }
}
Modelli di messaggi di associazione
Se si imposta il tipo di proprietà del modello int
su o e lo si associa alla vista e si tenta di DateTime
registrarlo senza tipi, verrà visualizzato un messaggio come "Il valore '' non è valido.".
Questi messaggi vengono visualizzati quando una stringa vuota int
non può essere associata, ad esempio, nel modello.
Poiché si tratta di una tempistica che non può essere associata, si verifica solo prima di altre convalida dei valori e dell'elaborazione lato server.
Questi messaggi sono DefaultModelBindingMessageProvider
definiti come .
Startup.cs
Aggiungere agli argomenti del metodo definiti sin dall'inizio services.AddControllersWithViews
in , quindi aggiungere Action
.
Puoi essere multilingue impostando il passato options
ModelBindingMessageProvider
nell'argomento.
Esistono 11 tipi di messaggi che è possibile impostare, quindi è necessario prima definire il messaggio nel modo seguente: SharedResource.resx
Il nome della chiave è facoltativo. Il messaggio inglese predefinito nella colonna dei commenti è (non è necessario includere i commenti).
Non dovrai tradurre ogni lingua, quindi dovresti fare la tua traduzione (il codice di esempio include anche il sharedresource.resx tradotto).
Commento valore nome | ||
---|---|---|
ModelBinding_AttemptedValueIsInvalid | '{0}' è un valore non valido nel {1}. | Il valore '{0}' non è valido per {1}. |
ModelBinding_MissingBindRequiredValue | Il valore per il {0} non è specificato. | Non è stato fornito un valore per il parametro o la proprietà '{0}'. |
ModelBinding_MissingKeyOrValue | Obbligatorio. | È richiesto un valore. |
ModelBinding_MissingRequestBodyRequiredValue | La richiesta deve avere un corpo. | È richiesto un corpo di richiesta non vuoto. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | '{0}' non è valido. | Il valore '{0}' non è valido. |
ModelBinding_NonPropertyUnknownValueIsInvalid | Il valore non è valido. | Il valore fornito non è valido. |
ModelBinding_NonPropertyValueMustBeANumber | Il numero deve essere specificato. | Il campo deve essere un numero. |
ModelBinding_UnknownValueIsInvalid | Il valore del {0} non è valido. | Il valore fornito non è valido per {0}. |
ModelBinding_ValueIsInvalid | '{0}' non è valido. | Il valore '{0}' non è valido. |
ModelBinding_ValueMustBeANumber | {0} deve essere un numero. | Il campo {0} deve essere un numero. |
ModelBinding_ValueMustNotBeNull | Input richiesto. | Il valore '{0}' non è valido. |
Correggi l'avvio.cs come segue:
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
});
// 省略 (初期コード)
}
}
}
Il punto chiave è services.AddControllersWithViews
aggiungere a al metodo che riceve il file option
Action
,
options.ModelBindingMessageProvider
Sto impostando il testo localizzato per ogni metodo Set in .
Il testo tradotto viene IStringLocalizer
recuperato da .
Non c'è modo di ricevere IStringLocalizer
codice diretto, che è un po 'un codice rotondo.
SharedResource.resx
Se si genera codice da, si otterranno valori localizzati direttamente da esso.
IStringLocalizer
La chiave specificata in SharedResource.resx
specifica la chiave aggiunta a .
Impostarlo in modo che corrisponda al contenuto di ciascun metodo Set.
Inoltre, poiché ogni messaggio ha un argomento stringa di formato, ad esempio , {0}{1}
uso Simple con in modo da poter sostituire i valori string.Format
Func
ricevuti.
Localizzare i messaggi di convalida predefiniti
Il messaggio di errore predefinito quando gli attributi delle proprietà di Required
un modello sono impostati su o giù di lì è determinato dal framework ed è StringLength
fondamentalmente in inglese.
Questi possono essere IValidationAttributeAdapterProvider
localizzati definendo una classe derivata dall'interfaccia.
Prima di SharedResource.resx
tutto, registra il testo multilingue.
Il nome della chiave è arbitrario, ma per semplificare il programma, registrarlo sotto forma di "nome dell'attributo di convalida Validator_<>".
Commento valore nome | ||
---|---|---|
Validator_CompareAttribute | Il {0} e {1} non corrispondono. | '{0}' e '{1}' non corrispondono. |
Validator_CreditCardAttribute | {0} non è un numero di carta valido. | Il campo {0} non è un numero di carta di credito valido. |
Validator_DataTypeAttribute_Date | Inserisci una data valida. | Inserisci una data valida. |
Validator_EmailAddressAttribute | {0} non è un indirizzo email valido. | Il campo {0} non è un indirizzo di posta elettronica valido. |
Validator_FileExtensionsAttribute | {0} accetta solo file con le seguenti estensioni: : {1} | Il campo {0} accetta solo file con le seguenti estensioni: {1} |
Validator_MaxLengthAttribute | {0} deve essere un tipo di stringa o matrice con una lunghezza massima di '{1}'. | Il campo {0} deve essere un tipo di stringa o matrice con una lunghezza massima di '{1}'. |
Validator_MinLengthAttribute | {0} deve essere un tipo di stringa o matrice con una lunghezza minima di '{1}'. | Il campo {0} deve essere un tipo di stringa o matrice con una lunghezza minima di '{1}'. |
Validator_PhoneAttribute | {0} non è un numero di telefono valido. | Il campo {0} non è un numero di telefono valido. |
Validator_RangeAttribute | {0} deve variare da {1} a {2}. | Il campo {0} deve essere compreso tra {1} e {2}. |
Validator_RegularExpressionAttribute | {0} deve corrispondere all'espressione regolare "{1}". | Il campo {0} deve corrispondere all'espressione regolare «{1}». |
Validator_RequiredAttribute | {0} è richiesto. | Il campo {0} è obbligatorio. |
Validator_StringLengthAttribute | {0} deve essere all'interno di {1} cifre. | Il campo {0} deve essere una stringa con una lunghezza massima di {1}. |
Validator_UrlAttribute | {0} non è un URL valido. | Il campo {0} non è un URL http, https o ftp completo valido. |
Validator_StringLengthAttributeWithMin | {0} devono essere almeno {2} {1} cifre. | Il campo {0} deve essere una stringa con una lunghezza massima di {1} e una lunghezza minima di {2}. |
Creare quindi la seguente classe AdapterProvider:
Il nome della classe è arbitrario, ma questa volta CustomValidationAttributeAdapterProvider
scriverò una classe chiamata e scriverò il codice come segue:
Il percorso del file di codice è arbitrario, ma l'esempio viene inserito in una cartella denominata 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);
}
}
}
Se si impostano le proprietà del modello su Required
o , il metodo viene chiamato per ogni StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
convalida.
ErrorMessageResourceName
Se la proprietà contiene un valore, il codice sul lato del modello dispone già di un messaggio o di una chiave di localizzazione, quindi restituisce così com'è.
Se vuoto, corrispondere ai nomi delle classi del prefisso e dell'attributo di convalida per renderlo la chiave di localizzazione, quindi recuperare il testo localizzato dalla chiave e impostarlo su ErrorMessage
.
Ciò consente di localizzare la maggior parte dei messaggi predefiniti.
Quindi, registrare questa classe in .cs di avvio. Fondamentalmente, puoi aggiungerlo come segue.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Eseguilo per assicurarti che funzioni correttamente.
Modificare un messaggio esistente in modo da parametri
Ad esempio, StringLength
il messaggio dell'attributo è localizzato, ad esempio "{0} deve trovarsi all'interno di {1} cifre".
MinimumLength
Se la proprietà è impostata, è possibile modificare la {0} come "Specificare {2} cifre o più {1} all'interno di un numero di cifre".
In tal CustomValidationAttributeAdapterProvider
caso, estendere la classe come segue:
// 省略
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);
}
}
// 省略
}
}
}
Poiché il metodo viene chiamato per ogni GetAttributeAdapter
convalida, se la variabile passata attribute
era un StringLengthAttribute
MinimumLength
attributo, controllare la proprietà,
Se impostato, ricevi un messaggio che tenga conto anche del numero minimo di cifre e ErrorMessage
sostituisca .
Se lo esegui, controlla e il messaggio cambia, va bene.
Altri messaggi generici
Alcuni messaggi non vengono localizzati dopo l'averlo fatto finora. Ad esempio, messaggi determinati solo in Javascript.
La destinazione è jquery.validate.js
il messaggio elencato nel file.
Poiché questo file non deve essere modificato direttamente, per sostituire questi messaggi con testo input
localizzato, è necessario aggiungere un attributo simile al tag e impostare il testo data-val-XXXX
localizzato lì.
La parte XXXX contiene la chiave nella figura jquery.validate.js
sopra. (ad es. data-val-number
ecc.)
data-val-XXXX
Per impostare il testo localizzato sugli attributi in
Localizziamo il messaggio quando i caratteri non numerici sono inclusi nel campo di input Età come esempio.
UserViewModel.Age
ha Range
un attributo e il codice HTML di output data-val-range
aggiunge l'attributo di input.
<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>
Tuttavia, data-val-number
il messaggio di controllo numerico non è localizzato perché non è presente alcun attributo.
Aggiungerai un altro attributo sul lato del modello per stampare anche l'attributo localizzato aggiunto data-val-number
dal messaggio.
Il primo passaggio consiste nel creare una classe di attributi che controlli se si tratta IntAttribute
di un numero: È limitato a qui, ma sei int
libero di cambiarlo a seconda della situazione.
Il file di codice può trovarsi ovunque, ma questa volta si trova nella cartella Adapter.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Se il valore impostato è int
un tipo, è un attributo che è solo un verdetto normale, ma in pratica è normale al 100% se impostato su una proprietà di tipo int, quindi l'elaborazione di questa classe stessa non ha alcun senso.
Lo scopo di questa volta è quello di visualizzare messaggi di errore localizzati nel client.
Quindi, creare la seguente IntAttributeAdapter
classe Adapter: Questo è anche nella cartella 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;
}
}
Il punto qui è AddValidation
il metodo descritto nel MergeAttribute
metodo.
Unione di attributi come attributi del tag di input per tornare data-val-number
al client.
Il valore da impostare nell'attributo imposta un messaggio di errore localizzato.
Restituire questo adattatore nella classe creata in CustomValidationAttributeAdapterProvider
precedenza.
// 省略
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);
}
// 省略 (前に追加したコード)
}
}
}
Se il valore da convalidare IntAttribute
è , restituire quello creato in IntAttributeAdapter
precedenza.
La proprietà con l'attributo Int viene ora aggiunta quando viene visualizzata sul data-val-number
lato client.
Infine, UserViewModel.Age
IntAttribute
aggiungi a .
Dopo aver corretto il codice, provalo per vedere se vuoi erne il check-out.
<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>
Esistono altri messaggi non localizzati, ma è possibile localizzarli nei metodi descritti sopra. Aggiungi codice quando ne hai bisogno.