Sokongan berbilang bahasa untuk mesej lalai dipaparkan semasa pengesahihan input
Persekitaran
- Teras ASP.NET
-
- 5.0 MVC
Pada mulanya
Sokongan berbilang bahasa bagi mesej pengesahihan input lalai dengan Petua ini mungkin tidak lengkap. Tolong berurusan dengan yang hilang.
Juga, menukar bahasa bergantung pada keadaan sesi atau keadaan cache mungkin masih muncul dalam teks dari bahasa sebelumnya.
Terdapat beberapa cara untuk menukar mesej pengesahan input lalai, masing-masing boleh digabungkan. Ia bukan salah seorang daripada mereka, jadi jika anda ingin mengubahnya dengan pasti, anda perlu sesuai dengan semua corak.
Premis
Petua ini ditulis sebagai memahami petua berikut:
- ASP.NET Ciri terbina dalam Core MVC untuk penukaran berbilang bahasa
- Sokongan berbilang bahasa untuk DataAnnotations yang digunakan untuk nama parameter, mesej pengesahan input, dll.
Juga, jika anda membuat projek baru, anda mesti telah menambah fail dan kod berikut berdasarkan petua di atas.
- Cipta fail SharedResource.resx (+en, es). (Oleh kerana hanya mesej Petua ini diterjemahkan, kandungannya mungkin kosong.)
- Cipta fail SharedResource.cs
- Tambah kod penyetempatan ke Startup.ConfigureServices
- Tambah kod penyetempatan ke Startup.Configure
- Tambah UserViewModel (kali ini, kami tidak secara jelas memasukkan mesej lalai dalam pelbagai bahasa)
- Tambah tindakan dan pandangan skrin yang dicipta pengguna (Create.cshtml)
Memulakan kod
Berdasarkan andaian di atas, setiap kod adalah seperti berikut:
Permulaan.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();
// 省略
}
}
}
UtamaMuaf.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 { }
}
Mesej pengikatan model
Jika anda mengesetkan jenis sifat model int
kepada atau dan mengikatnya ke DateTime
paparan, dan cuba mendaftarkannya tidak ditaip, anda akan melihat mesej seperti "Nilai'' tidak sah.".
Mesej ini muncul apabila rentetan kosong int
tidak boleh diikat, contohnya, dalam model.
Kerana ia adalah masa yang tidak boleh terikat, ia berlaku hanya sebelum pengesahan nilai lain dan pemprosesan bahagian pelayan.
Mesej ini DefaultModelBindingMessageProvider
ditakrifkan sebagai .
Startup.cs
Tambah kepada hujah kaedah yang telah ditakrifkan sejak permulaan services.AddControllersWithViews
dalam , dan kemudian tambah Action
.
Anda boleh berbilang bahasa dengan menetapkan yang diluluskan dalam options
ModelBindingMessageProvider
argumen.
Terdapat 11 jenis mesej yang boleh anda tetapkan, jadi anda mesti terlebih dahulu menentukan mesej seperti berikut: SharedResource.resx
Nama kekunci adalah pilihan. Mesej Bahasa Inggeris lalai dalam lajur komen adalah (komen tidak perlu disertakan).
Anda tidak perlu menterjemahkan setiap bahasa, jadi anda harus melakukan terjemahan anda sendiri (kod sampel juga termasuk SharedResource.resx yang diterjemahkan).
Komen | Nilai | Nama |
---|---|---|
ModelBinding_AttemptedValueIsInvalid | '{0}' ialah nilai tidak sah dalam {1}. | Nilai '{0}' tidak sah untuk {1}. |
ModelBinding_MissingBindRequiredValue | Nilai untuk {0} tidak dinyatakan. | Nilai untuk parameter atau sifat '{0}' tidak disediakan. |
ModelBinding_MissingKeyOrValue | Diperlukan. | Nilai diperlukan. |
ModelBinding_MissingRequestBodyRequiredValue | Permintaan mesti mempunyai badan. | Badan permintaan bukan kosong diperlukan. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | '{0}' tidak sah. | Nilai '{0}' tidak sah. |
ModelBinding_NonPropertyUnknownValueIsInvalid | Nilai tidak sah. | Nilai yang dibekalkan tidak sah. |
ModelBinding_NonPropertyValueMustBeANumber | Nombor mesti dinyatakan. | Medan mestilah nombor. |
ModelBinding_UnknownValueIsInvalid | Nilai {0} tidak sah. | Nilai yang dibekalkan tidak sah untuk {0}. |
ModelBinding_ValueIsInvalid | '{0}' tidak sah. | Nilai '{0}' tidak sah. |
ModelBinding_ValueMustBeANumber | {0} mesti menjadi nombor. | Medan {0} mestilah nombor. |
ModelBinding_ValueMustNotBeNull | Input yang diperlukan. | Nilai '{0}' tidak sah. |
Betulkan permulaan.cs seperti berikut:
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
});
// 省略 (初期コード)
}
}
}
Perkara utama adalah services.AddControllersWithViews
untuk menambah a kepada kaedah yang menerima option
Action
,
options.ModelBindingMessageProvider
Saya menetapkan teks setempat untuk setiap kaedah Set dalam .
Teks yang diterjemahkan IStringLocalizer
diambil dari .
Tidak ada cara untuk menerima IStringLocalizer
kod langsung, yang merupakan sedikit kod bulat.
SharedResource.resx
Jika anda menjana kod daripada, anda akan mendapat nilai setempat terus daripadanya.
IStringLocalizer
Kekunci yang anda tentukan menentukan SharedResource.resx
kekunci yang anda tambah .
Tetapkannya agar sepadan dengan kandungan setiap kaedah Set.
Juga, kerana setiap mesej mempunyai hujah rentetan format, seperti , saya {0}{1}
menggunakan Mudah dengan supaya anda boleh menggantikan nilai yang string.Format
Func
diterima.
Menyetempatkan mesej pengesahihan lalai
Mesej ralat lalai apabila atribut Required
sifat model disetkan kepada atau lebih ditentukan oleh rangka kerja dan StringLength
pada dasarnya dalam bahasa Inggeris.
Ini boleh IValidationAttributeAdapterProvider
disetempatkan dengan menentukan kelas yang berasal dari antara muka.
Pertama SharedResource.resx
sekali, daftarkan teks yang berbilang bahasa.
Nama kekunci adalah sewenang-wenangnya, tetapi untuk memudahkan program, mendaftarkannya dalam bentuk "Validator_< nama atribut pengesahan>".
Komen | Nilai | Nama |
---|---|---|
Validator_CompareAttribute | {0} dan {1} tidak sepadan. | '{0}' dan '{1}' tidak sepadan. |
Validator_CreditCardAttribute | {0} bukan nombor kad yang sah. | Medan {0} bukan nombor kad kredit yang sah. |
Validator_DataTypeAttribute_Date | Masukkan tarikh yang sah. | Sila masukkan tarikh yang sah. |
Validator_EmailAddressAttribute | {0} bukan alamat e-mel yang sah. | Medan {0} bukan alamat e-mel yang sah. |
Validator_FileExtensionsAttribute | {0} hanya menerima fail dengan sambungan berikut: : {1} | Medan {0} hanya menerima fail dengan sambungan berikut: {1} |
Validator_MaxLengthAttribute | {0} mestilah rentetan atau jenis tatasusunan dengan panjang maksimum '{1}'. | Medan {0} mestilah rentetan atau jenis tatasusunan dengan panjang maksimum '{1}'. |
Validator_MinLengthAttribute | {0} mestilah rentetan atau jenis tatasusunan dengan panjang minimum '{1}'. | Medan {0} mestilah rentetan atau jenis tatasusunan dengan panjang minimum '{1}'. |
Validator_PhoneAttribute | {0} bukan nombor telefon yang sah. | Medan {0} bukan nombor telefon yang sah. |
Validator_RangeAttribute | {0} mesti berkisar dari {1} hingga {2}. | Medan {0} mestilah antara {1} dan {2}. |
Validator_RegularExpressionAttribute | {0} mesti sepadan dengan ungkapan biasa '{1}'. | Medan {0} mesti sepadan dengan ungkapan biasa '{1}'. |
Validator_RequiredAttribute | {0} diperlukan. | Medan {0} diperlukan. |
Validator_StringLengthAttribute | {0} mesti berada dalam digit {1}. | Medan {0} mestilah rentetan dengan panjang maksimum {1}. |
Validator_UrlAttribute | {0} bukan URL yang sah. | Medan {0} bukan URL http, https atau ftp yang layak sepenuhnya yang sah. |
Validator_StringLengthAttributeWithMin | {0} mestilah sekurang-kurangnya {2} {1} digit. | Medan {0} mestilah rentetan dengan panjang maksimum {1} dan panjang minimum {2}. |
Seterusnya, cipta kelas AdapterProvider berikut:
Nama kelas adalah sewenang-wenangnya, tetapi kali ini CustomValidationAttributeAdapterProvider
saya akan menulis kelas yang dipanggil dan menulis kod seperti berikut:
Lokasi fail kod adalah sewenang-wenangnya, tetapi sampel diletakkan dalam folder yang dipanggil Penyesuai.
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);
}
}
}
Jika anda menetapkan sifat model kepada Required
atau , kaedah dipanggil untuk setiap StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
pengesahan.
ErrorMessageResourceName
Jika sifat mengandungi nilai, kod pada sisi model sudah mempunyai mesej atau kekunci penyetempatan, jadi ia kembali seperti sedia ada.
Jika kosong, padankan nama kelas awalan dan atribut pengesahihan untuk menjadikannya kekunci penyetempatan, kemudian ambil teks setempat dari kekunci dan tetapkannya ErrorMessage
kepada .
Ini membolehkan kebanyakan mesej lalai disetempatkan.
Seterusnya, daftar kelas ini dalam .cs permulaan. Pada asasnya, anda boleh menambahnya seperti berikut.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Jalankan untuk memastikan itu bekerja dengan benar.
Tukar mesej sedia ada mengikut parameter
Sebagai contoh, StringLength
mesej atribut disetempatkan, seperti "{0} mesti berada dalam {1} digit."
MinimumLength
Jika sifat ditetapkan, anda mungkin mahu menukar {0} sebagai "Tentukan digit {2} atau lebih {1} dalam beberapa digit".
Dalam CustomValidationAttributeAdapterProvider
kes itu, lanjutkan kelas seperti berikut:
// 省略
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);
}
}
// 省略
}
}
}
Oleh kerana kaedah dipanggil untuk setiap GetAttributeAdapter
pengesahan, jika pemboleh ubah yang diluluskan attribute
adalah StringLengthAttribute
MinimumLength
atribut, semak sifat,
Jika ditetapkan, dapatkan mesej yang juga mengambil kira bilangan minimum digit dan ErrorMessage
ganti .
Jika anda menjalankannya, semak dan mesej berubah, tidak mengapa.
Mesej generik lain
Sesetengah mesej tidak disetempatkan selepas anda berbuat demikian setakat ini. Sebagai contoh, mesej yang ditentukan hanya dalam Javascript.
Sasaran ialah jquery.validate.js
mesej yang disenaraikan dalam fail.
Oleh kerana fail ini tidak boleh diedit secara langsung, untuk menggantikan mesej ini dengan teks disetempatkan, anda input
mesti menambah atribut seperti tag dan menetapkan teks data-val-XXXX
disetempatkan di sana.
Bahagian XXXX mengandungi kunci dalam angka di jquery.validate.js
atas. (cth. data-val-number
dll.)
data-val-XXXX
Untuk menetapkan teks disetempatkan kepada atribut dalam
Mari kita menyetempatkan mesej apabila aksara bukan angka disertakan dalam medan input Umur sebagai contoh.
UserViewModel.Age
mempunyai Range
atribut, dan HTML output data-val-range
menambah atribut 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>
Walau bagaimanapun, data-val-number
mesej semakan angka tidak disetempatkan kerana tiada atribut.
Anda akan menambah atribut lain pada bahagian model untuk mencetak atribut tambah mesej data-val-number
setempat juga.
Langkah pertama ialah mencipta kelas atribut yang menyemak sama ada ia adalah IntAttribute
nombor: Ia terhad kepada di sini, tetapi anda int
bebas untuk mengubahnya bergantung kepada keadaan.
Fail kod boleh berada di mana-mana sahaja, tetapi kali ini ia berada dalam folder Penyesuai.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Jika nilai set adalah int
jenis, ia adalah atribut yang hanya keputusan biasa, tetapi dalam praktiknya ia adalah 100% normal jika ditetapkan kepada sifat jenis int, jadi pemprosesan kelas ini sendiri tidak masuk akal.
Tujuan masa ini adalah untuk memaparkan mesej ralat setempat dalam pelanggan.
Seterusnya, cipta kelas Penyesuai IntAttributeAdapter
berikut: Ini juga dalam folder Penyesuai.
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;
}
}
Titik di sini adalah AddValidation
kaedah yang diterangkan dalam kaedah MergeAttribute
ini.
Menggabungkan atribut sebagai atribut tag input untuk kembali data-val-number
kepada klien.
Nilai untuk disetkan dalam atribut mengesetkan mesej ralat disetempatkan.
Kembalikan penyesuai ini dalam kelas yang anda cipta CustomValidationAttributeAdapterProvider
sebelum ini.
// 省略
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);
}
// 省略 (前に追加したコード)
}
}
}
Jika nilai untuk disahkan IntAttribute
adalah , kembalikan yang anda cipta IntAttributeAdapter
sebelum ini.
Sifat dengan atribut Int kini ditambah apabila ia dipaparkan pada data-val-number
sisi klien.
Akhirnya, UserViewModel.Age
IntAttribute
tambah ke .
Sebaik sahaja anda telah membetulkan kod anda, cubalah untuk melihat sama ada anda mahu menyemaknya.
<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>
Terdapat mesej lain yang tidak disetempatkan, tetapi anda boleh menyetempatkannya dalam kaedah yang diterangkan di atas. Tambah kod apabila anda memerlukannya.