Suport multilingüe per als missatges predeterminats que es mostren durant la validació d'entrada
entorn
- Nucli ASP.NET
-
- 5,0 MVC
Al principi
Pot ser que el suport multilingüe dels missatges de validació d'entrada per defecte amb aquest Consell no s'hagi completat. Si us plau, tracteu amb els desapareguts.
A més, pot ser que el canvi d'idioma en funció de l'estat de sessió o de l'estat de la memòria cau encara aparegui al text de l'idioma anterior.
Hi ha diverses maneres de canviar el missatge de validació d'entrada per defecte, cadascuna de les quals es pot combinar. No és un d'ells, de manera que si voleu canviar-lo de manera fiable, heu de correspondre amb tots els patrons.
premissa
Aquests consells s'escriuen com a comprensió dels següents consells:
- ASP.NET Les característiques integrades del Core MVC per al canvi multilingüe
- Suport multilingüe per a DataAnnotations utilitzat per a noms de paràmetres, missatges de validació d'entrada, etc.
A més, si esteu creant un projecte nou, heu d'haver afegit els fitxers i el codi següents basats en els consells anteriors.
- Crea un fitxer SharedResource.resx (+ca, es). (Com que només es tradueix el missatge d'aquests consells, el contingut pot estar buit.)
- Crea un fitxer sharedResource.cs
- Afegeix un codi de localització a Startup.ConfigureServices
- Afegeix un codi de localització a Startup.Configura
- S'ha afegit UserViewModel (aquesta vegada, no teclegem explícitament els missatges per defecte en diversos idiomes)
- S'han afegit accions i visualitzacions de pantalla creades per l'usuari (Create.cshtml)
S'està iniciant el codi
Sobre la base dels supòsits anteriors, cada codi serà el següent:
Inici.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();
// 省略
}
}
}
HomeControlador.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 { }
}
Missatges d'enquadernació del model
Si definiu el tipus de propietat del model int
a o l'vinculeu a la DateTime
visualització i intenteu registrar-lo sense escriure, veureu un missatge com ara "El valor '' no és vàlid".
Aquests missatges apareixen quan una cadena buida int
no es pot vincular, per exemple, al model.
Com que és un temps que no es pot vincular, només es produeix abans d'una altra validació de valor i processament del servidor.
Aquests missatges DefaultModelBindingMessageProvider
es defineixen com a .
Startup.cs
Afegiu als arguments del mètode que s'han definit des del principi services.AddControllersWithViews
a i, a continuació, afegiu Action
.
Podeu ser multilingüe establint el passat a options
ModelBindingMessageProvider
l'argument.
Hi ha 11 tipus de missatges que podeu establir, de manera que primer heu de definir el missatge de la manera següent: SharedResource.resx
El nom de la clau és opcional. El missatge en anglès per defecte de la columna de comentaris és (els comentaris no s'han d'incloure).
No haureu de traduir cada idioma, de manera que hauríeu de fer la vostra pròpia traducció (el codi d'exemple també inclou el sharedresource.resx traduït).
Comentari del valor del nom | ||
---|---|---|
ModelBinding_AttemptedValueIsInvalid | "{0}" és un valor no vàlid a la {1}. | El valor "{0}" no és vàlid per a {1}. |
ModelBinding_MissingBindRequiredValue | No s'especifica el valor del {0}. | No s'ha proporcionat cap valor per al paràmetre o la propietat "{0}". |
ModelBinding_MissingKeyOrValue | Obligatori. | Es requereix un valor. |
ModelBinding_MissingRequestBodyRequiredValue | La sol·licitud ha de tenir un cadàver. | Es requereix un cos de sol·licitud no buit. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | "{0}" no és vàlida. | El valor "{0}" no és vàlid. |
ModelBinding_NonPropertyUnknownValueIsInvalid | El valor no és vàlid. | El valor proporcionat no és vàlid. |
ModelBinding_NonPropertyValueMustBeANumber | S'ha d'especificar el número. | El camp ha de ser un número. |
ModelBinding_UnknownValueIsInvalid | El valor de la {0} no és vàlid. | El valor proporcionat no és vàlid per a {0}. |
ModelBinding_ValueIsInvalid | "{0}" no és vàlida. | El valor "{0}" no és vàlid. |
ModelBinding_ValueMustBeANumber | {0} ha de ser un número. | El camp {0} ha de ser un número. |
ModelBinding_ValueMustNotBeNull | Entrada necessària. | El valor "{0}" no és vàlid. |
Esmena l'inici.cs de la manera següent:
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
});
// 省略 (初期コード)
}
}
}
El punt clau és services.AddControllersWithViews
afegir a al mètode que rep el option
Action
,
options.ModelBindingMessageProvider
Estic establint text localitzat per a cada mètode Descció a .
El text traduït IStringLocalizer
es recupera de .
No hi ha manera de rebre IStringLocalizer
codi directe, que és una mica d'un codi rodó.
SharedResource.resx
Si esteu generant codi des de, obtindreu valors localitzats directament.
IStringLocalizer
La clau que especifiqueu SharedResource.resx
especifica especifica la clau a la que heu afegit a .
Establiu-lo perquè coincideixi amb el contingut de cada mètode de conjunt.
A més, perquè cada missatge té un argument de cadena de format, com ara , {0}{1}
utilitzo Simple amb perquè pugueu reemplaçar els string.Format
Func
valors rebuts.
Localitzar els missatges de validació per defecte
El missatge d'error per defecte quan els atributs de les Required
propietats d'un model estan definits en o així està determinat pel framework i és StringLength
bàsicament en anglès.
Aquests es poden IValidationAttributeAdapterProvider
localitzar definint una classe derivada de la interfície.
En primer SharedResource.resx
lloc, registreu el text multilingüe.
El nom de la clau és arbitrari, però per simplificar el programa, registreu-lo en forma de "nom de l'atribut de validació Validator_<>".
Comentari del valor del nom | ||
---|---|---|
Validator_CompareAttribute | Els {0} i {1} no coincideixen. | "{0}" i "{1}" no coincideixen. |
Validator_CreditCardAttribute | {0} no és un número de targeta vàlid. | El camp {0} no és un número de targeta de crèdit vàlid. |
Validator_DataTypeAttribute_Date | Introduïu una data vàlida. | Introduïu una data vàlida. |
Validator_EmailAddressAttribute | {0} no és una adreça de correu electrònic vàlida. | El camp {0} no és una adreça electrònica vàlida. |
Validator_FileExtensionsAttribute | {0} només accepta fitxers amb les extensions següents: : {1} | El camp {0} només accepta fitxers amb les extensions següents: {1} |
Validator_MaxLengthAttribute | {0} ha de ser un tipus de cadena o matriu amb una longitud màxima de "{1}". | El camp {0} ha de ser un tipus de cadena o matriu amb una longitud màxima de "{1}". |
Validator_MinLengthAttribute | {0} ha de ser un tipus de cadena o matriu amb una longitud mínima de "{1}". | El camp {0} ha de ser un tipus de cadena o matriu amb una longitud mínima de "{1}". |
Validator_PhoneAttribute | {0} no és un número de telèfon vàlid. | El camp {0} no és un número de telèfon vàlid. |
Validator_RangeAttribute | {0} ha d'anar des de {1} fins a {2}. | El camp {0} ha d'estar entre {1} i {2}. |
Validator_RegularExpressionAttribute | {0} ha de coincidir amb l'expressió regular "{1}". | El camp {0} ha de coincidir amb l'expressió regular "{1}". |
Validator_RequiredAttribute | {0} és necessària. | Es requereix el camp {0}. |
Validator_StringLengthAttribute | {0} ha d'estar dins {1} dígits. | El camp {0} ha de ser una cadena amb una longitud màxima de {1}. |
Validator_UrlAttribute | {0} no és una adreça URL vàlida. | El camp {0} no és un URL http, https o ftp totalment qualificat vàlid. |
Validator_StringLengthAttributeWithMin | {0} ha de tenir com a mínim {2} {1} dígits. | El camp {0} ha de ser una cadena amb una longitud màxima de {1} i una longitud mínima de {2}. |
A continuació, creeu la següent classe AdapterProvider:
El nom de la classe és arbitrari, però aquesta vegada CustomValidationAttributeAdapterProvider
escriuré una classe anomenada i escriuré el codi de la següent manera:
La ubicació del fitxer de codi és arbitrària, però la mostra es col·loca en una carpeta anomenada Adaptador.
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);
}
}
}
Si definiu les propietats del model a Required
o , el mètode s'anomena per a cada StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
validació.
ErrorMessageResourceName
Si la propietat conté un valor, el codi del costat del model ja té un missatge o una clau de localització, de manera que torna tal com és.
Si està buit, feu coincidir els noms de classe del prefix i l'atribut de validació per convertir-lo en la clau de localització i, a continuació, recupereu el text localitzat de la clau i establiu-lo ErrorMessage
a .
Això permet localitzar la majoria dels missatges per defecte.
A continuació, registreu aquesta classe a .cs d'inici. Bàsicament, podeu afegir-lo de la manera següent.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Executeu-lo per assegurar-vos que funciona correctament.
Canvia un missatge existent per paràmetres
Per exemple, StringLength
el missatge d'atribut està localitzat, com ara "{0} ha d'estar dins {1} dígits".
MinimumLength
Si la propietat està establerta, és possible que vulgueu canviar la {0} com a "Especifiqueu {2} dígits o més {1} dins d'un nombre de dígits".
En aquest CustomValidationAttributeAdapterProvider
cas, amplieu la classe de la manera següent:
// 省略
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);
}
}
// 省略
}
}
}
Com que el mètode s'anomena per a cada GetAttributeAdapter
validació, si la variable passada attribute
era un StringLengthAttribute
MinimumLength
atribut, comproveu la propietat,
Si s'estableix, reberu un missatge que també tingui en compte el nombre mínim de dígits i ErrorMessage
substitueixi .
Si l'executeu, comproveu i el missatge canvia, no passa res.
Altres missatges genèrics
Alguns missatges no es localitzen després de fer-ho fins ara. Per exemple, missatges que només es determinen en Javascript.
L'objectiu és jquery.validate.js
el missatge que apareix al fitxer.
Com que aquest fitxer no s'ha d'editar directament, per substituir aquests missatges per text localitzat, input
heu d'afegir un atribut com ara a l'etiqueta i data-val-XXXX
establir-hi text localitzat.
La part XXXX conté la clau de la figura jquery.validate.js
anterior. (per exemple, data-val-number
etc.)
data-val-XXXX
Per establir el text localitzat als atributs de
Localitzem el missatge quan s'incloguin caràcters no numèrics al camp d'entrada Edat com a exemple.
UserViewModel.Age
té Range
un atribut, i l'HTML de sortida data-val-range
afegeix l'atribut d'entrada.
<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>
Tanmateix, data-val-number
el missatge de comprovació numèric no està localitzat perquè no hi ha cap atribut.
També afegireu un altre atribut al costat del model per imprimir l'atribut localitzat afegit al data-val-number
missatge.
El primer pas és crear una classe d'atribut que comprovi si és IntAttribute
un número: Es limita a aquí, però vostè és int
lliure de canviar-lo en funció de la situació.
El fitxer de codi pot ser en qualsevol lloc, però aquesta vegada és a la carpeta Adaptador.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Si el valor establert és int
un tipus, és un atribut que només és un veredicte normal, però a la pràctica és 100% normal si s'estableix a una propietat de tipus int, de manera que el processament d'aquesta classe en si no té cap sentit.
L'objectiu d'aquest temps és mostrar missatges d'error localitzats al client.
A continuació, creeu la classe d'adaptador IntAttributeAdapter
següent: Això també es troba a la carpeta Adaptador.
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;
}
}
El punt aquí és AddValidation
el mètode descrit en el MergeAttribute
mètode.
S'estan fusionant els atributs com a atributs de l'etiqueta d'entrada per tornar data-val-number
al client.
El valor que s'ha d'establir a l'atribut estableix un missatge d'error localitzat.
Retorna aquest adaptador a la classe que has creat CustomValidationAttributeAdapterProvider
abans.
// 省略
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);
}
// 省略 (前に追加したコード)
}
}
}
Si el valor a validar IntAttribute
és , torneu el que heu creat IntAttributeAdapter
anteriorment.
La propietat amb l'atribut Int s'afegeix ara quan es mostra al costat del data-val-number
client.
Finalment, UserViewModel.Age
IntAttribute
afegiu-hi .
Un cop hàgiu corregit el codi, proveu-lo per veure si voleu comprovar-lo.
<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>
Hi ha altres missatges no localitzats, però podeu localitzar-los en els mètodes descrits anteriorment. Afegiu codi quan ho necessiteu.