پشتیبانی چند زبانه از پیام های پیش فرض نمایش داده شده در هنگام اعتبارسنجی ورودی
محیط
- ASP.NET هسته
-
- 5.0 MVC
در ابتدا
پشتیبانی چند زبانه از پیام های اعتبارسنجی ورودی پیش فرض با این نکات ممکن است کامل نیست. لطفا با گمشده ها کنار بيا
همچنین تغییر زبان بسته به وضعیت جلسه یا حالت کش ممکن است هنوز هم در متن از زبان قبلی ظاهر شود.
راه های متعددی برای تغییر پیام اعتبارسنجی ورودی پیش فرض وجود دارد که هر کدام می توانند با هم ترکیب شوند. این یکی از آنها نیست، بنابراین اگر شما می خواهید آن را به طور قابل اعتماد تغییر دهید، شما نیاز به مکاتبه با تمام الگوها.
فرض
این نکات به عنوان درک نکات زیر نوشته شده است:
- ASP.NET ویژگی های ساخته شده در هسته MVC برای سوئیچینگ چند زبانه
- پشتیبانی چند زبانه از DataAnnotations مورد استفاده برای نام پارامترها، پیام های اعتبارسنجی ورودی، و غیره.
همچنین اگر در حال ایجاد یک پروژه جدید هستید، باید فایل ها و کدهای زیر را بر اساس راهنمایی های بالا اضافه کرده باشد.
- ایجاد یک فایل SharedResource.resx (+en, es) . (از آنجا که فقط پیام این نکته ترجمه شده است، ممکن است محتویات خالی باشد.)
- ایجاد یک فایل مشترکResource.cs است
- افزودن کد محلی سازی به Startup.ConfigureServices
- افزودن کد محلی سازی به Startup.Configure
- اضافه شده UserViewModel (این بار، ما به صراحت کلید پیام های پیش فرض در زبان های متعدد)
- اعمال و نماهای صفحه نمایش ایجاد شده توسط کاربر اضافه شده (Create.cshtml)
شروع کد
بر اساس فرضیات فوق هر کد به صورت زیر خواهد بود:
راه اندازی.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 { }
}
پیام های اتصال مدل
اگر نوع ملک مدل را به آن تنظیم کنید یا آن را به نمایش متصل کنید، و سعی کنید آن را بدون تایپ ثبت کنید، پیامی مانند «ارزش '' نامعتبر است» را خواهید int
DateTime
دید.
این پیام ها زمانی ظاهر می شوند که یک رشته خالی نمی تواند به int
عنوان مثال در مدل محدود شود.
از آنجا که زمان بندی است که نمی تواند محدود شود، آن را تنها قبل از اعتبار سنجی ارزش دیگر و پردازش سمت سرور رخ می دهد.
این پیام ها به DefaultModelBindingMessageProvider
این عنوان تعریف شده اند.
Startup.cs
به آر استدلال های روشی که از ابتدا در تعریف شده اند اضافه کنید و سپس services.AddControllersWithViews
اضافه Action
کنید.
شما می توانید چند زبانه با تنظیم عبور در options
ModelBindingMessageProvider
استدلال.
۱۱ نوع پیام وجود دارد که می توانید تنظیم کنید، بنابراین ابتدا باید پیام را به صورت زیر تعریف کنید: SharedResource.resx
نام کلید اختیاری است. پیام پیش فرض انگلیسی در ستون نظرات است (نظرات لازم نیست گنجانده شود).
شما مجبور به ترجمه هر زبان نیست، بنابراین شما باید ترجمه خود را انجام دهید (کد نمونه نیز شامل SharedResource.resx ترجمه شده).
ارزش | نام | |
---|---|---|
ModelBinding_AttemptedValueIsInvalid | '{0}' یک مقدار نامعتبر در {1}. | ارزش '{0}' برای آن معتبر {1}. |
ModelBinding_MissingBindRequiredValue | مقدار برای {0} مشخص نشده است. | مقداری برای پارامتر یا {0} '' ارائه نشد. |
ModelBinding_MissingKeyOrValue | مورد نیاز. | یک مقدار مورد نیاز است. |
ModelBinding_MissingRequestBodyRequiredValue | درخواست بايد يک جسد داشته باشه . | یک بدن درخواست غیر خالی مورد نیاز است. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | '{0}' معتبر نیست. | مقدار '{0}' معتبر نیست. |
ModelBinding_NonPropertyUnknownValueIsInvalid | مقدار معتبر نیست. | مقدار عرضه شده نامعتبر است. |
ModelBinding_NonPropertyValueMustBeANumber | شماره باید مشخص شود. | فیلد باید یک عدد باشد. |
ModelBinding_UnknownValueIsInvalid | ارزش ارزش {0} معتبر نیست. | مقدار عرضه شده برای یک {0}. |
ModelBinding_ValueIsInvalid | '{0}' معتبر نیست. | مقدار '{0}' نامعتبر است. |
ModelBinding_ValueMustBeANumber | {0} باید یک عدد باشد. | فیلد {0} باید یک عدد باشد. |
ModelBinding_ValueMustNotBeNull | ورودی مورد نیاز. | مقدار '{0}' نامعتبر است. |
رفع راه اندازی.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 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
});
// 省略 (初期コード)
}
}
}
نکته کلیدی این است services.AddControllersWithViews
که اضافه کردن یک به روشی که دریافت می کند option
Action
،
من options.ModelBindingMessageProvider
تنظیم متن محلی برای هر روش تنظیم در .
متن ترجمه شده از IStringLocalizer
بازیابی شده است.
هیچ راهی برای دریافت کد مستقیم IStringLocalizer
که کمی کد گرد است وجود ندارد.
اگر SharedResource.resx
شما در حال تولید کد از, شما ارزش های محلی به طور مستقیم از آن دریافت کنید.
IStringLocalizer
کلیدی که شما در آن مشخص می SharedResource.resx
کنید کلید را که به آن اضافه کرده بودید مشخص می کند.
آن را تنظیم کنید تا با محتویات هر روش Set مطابقت داشته باشد.
همچنین چون هر پیام یک آر استدلال رشته فرمت دارد، مانند ، من از Simple با آن استفاده می کنم تا شما می توانید مقادیر {0}{1}
دریافتی را جایگزین string.Format
Func
کنید.
محلی سازی پیام های اعتبارسنجی پیش فرض
پیام خطای پیش فرض هنگامی که ویژگی های ویژگی های یک مدل به یا بیشتر تنظیم می شوند توسط چارچوب تعیین می شود و اساساً به Required
StringLength
زبان انگلیسی است.
این ها را می IValidationAttributeAdapterProvider
توان با تعریف یک کلاس مشتق شده از رابط محلی کرد.
اول از SharedResource.resx
همه، متنی که چند زبانه است را ثبت کنید.
نام کلید دلخواه است، اما برای ساده سازی برنامه، آن را در قالب «نام ویژگی اعتبارسنجی Validator_<» ثبت >.
ارزش | نام | |
---|---|---|
Validator_CompareAttribute | تیم {0} و {1} با هم مطابقت نمی کنند. | "{0}" و "{1}" با هم مطابقت نداره. |
Validator_CreditCardAttribute | {0} شماره کارت معتبر نیست. | رشته {0} شماره کارت اعتباری معتبر نیست. |
Validator_DataTypeAttribute_Date | تاریخ معتبری را وارد کنید. | لطفاً تاریخ معتبری را وارد کنید. |
Validator_EmailAddressAttribute | {0} یک آدرس ایمیل معتبر نیست. | فیلد {0} یک آدرس ایمیل معتبر نیست. |
Validator_FileExtensionsAttribute | {0} فایل ها را با پسوندهای زیر می پذیرد: : {1} | فیلد {0} فایل ها را با پسوندهای زیر می پذیرد: {1} |
Validator_MaxLengthAttribute | {0} باید یک رشته یا نوع آرایه با حداکثر طول '{1}' باشد. | فیلد {0} باید یک نوع رشته یا آرایه با حداکثر طول '{1}' باشد. |
Validator_MinLengthAttribute | {0} باید یک نوع رشته یا آرایه با حداقل طول '{1}' باشد. | فیلد {0} باید یک نوع رشته یا آرایه با حداقل طول '{1}' باشد. |
Validator_PhoneAttribute | {0} یک شماره تلفن معتبر نیست. | فیلد {0} شماره تلفن معتبر نیست. |
Validator_RangeAttribute | {0} باید از {1} تا {2}. | میدانی که {0} باید بین {1} و {2}. |
Validator_RegularExpressionAttribute | {0} باید با بیان منظم '{1}' مطابقت داشته باشد. | میدانی که {0} باید با عبارت منظم '{1}' مطابقت داشته باشد. |
Validator_RequiredAttribute | {0} مورد نیاز است. | رشته {0} مورد نیاز است. |
Validator_StringLengthAttribute | {0} باید درون {1} باشد. | فیلد {0} باید رشته ای با حداکثر طول {1}. |
Validator_UrlAttribute | {0} یک URL معتبر نیست. | زمینه {0} معتبر به طور کامل واجد شرایط http، https، و یا FTP URL نیست. |
Validator_StringLengthAttributeWithMin | {0} باید حداقل {2} {1} باشد. | فیلد {0} باید رشته ای با حداکثر طول {1} و حداقل طول {2}. |
بعد، ایجاد کلاس آداپتورپرویدر زیر:
نام کلاس دلخواه است، اما این بار کلاسی به نام می نویسم و کد CustomValidationAttributeAdapterProvider
را به این قرار می نویسم:
محل فایل کد دلخواه است، اما نمونه در پوشه ای به نام آداپتور قرار می گیرد.
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);
}
}
}
اگر شما خواص مدل را به یا ، روش برای Required
هر اعتبار سنجی نامیده می StringLength
IValidationAttributeAdapterProvider.GetAttributeAdapter
شود.
ErrorMessageResourceName
اگر ویژگی حاوی مقدار باشد، کد سمت مدل در حال حاضر یک پیام یا کلید محلی سازی دارد، بنابراین همان طور که هست برمی گردد.
اگر خالی باشد، با نام های کلاسی پیش درآمد و ویژگی اعتبارسنجی مطابقت داشته باشد تا آن را کلید محلی سازی کند، و سپس متن محلی شده را از کلید بازیابی کنید و آن را به ErrorMessage
.
این اجازه می دهد تا بسیاری از پیام های پیش فرض به محلی.
بعد، این کلاس را در استارتاپ .cs. اصولاً می توانید آن را به صورت زیر اضافه کنید.
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
اجرا کنید تا مطمئن شوید که درست کار می کند.
تغییر پیام موجود بر اساس پارامترها
به عنوان مثال، پیام ویژگی محلی شده است، مانند "{0} باید درون StringLength
{1} باشد."
اگر این ملک تنظیم شده باشد، ممکن است بخواهید {0} را به عنوان "{2} یا تعداد بیشتری از {1} در تعدادی از MinimumLength
ارقام" تغییر دهید.
در آن CustomValidationAttributeAdapterProvider
صورت، گسترش کلاس به صورت زیر است:
// 省略
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);
}
}
// 省略
}
}
}
چون روش برای هر اعتبارسنجی فراخوانی می شود، اگر متغیر عبور کرده یک ویژگی بود، ویژگی GetAttributeAdapter
attribute
را بررسی StringLengthAttribute
MinimumLength
کنید،
در صورت تنظیم، پیامی دریافت کنید که حداقل تعداد ارقام را نیز در نظر بگیرد و ErrorMessage
جایگزین آن شود.
اگر آن را اجرا کنید، بررسی کنید و پیام تغییر کند، اشکالی ندارد.
سایر پیام های عمومی
برخی از پیام ها پس از انجام این کار تا کنون محلی نمی شوند. برای مثال پیام هایی که فقط در جاوا اسکریپت تعیین می شوند.
هدف پیامی jquery.validate.js
است که در پرونده ذکر شده است.
از آنجا که این فایل نباید به طور مستقیم ویرایش شود، برای جایگزینی این پیام ها با متن محلی شده، باید یک ویژگی مانند برچسب اضافه کنید و متن محلی شده را در آنجا input
data-val-XXXX
تنظیم کنید.
قسمت XXXX شامل کلید در شکل بالا jquery.validate.js
است. (مانند و data-val-number
غیره)
data-val-XXXX
برای تنظیم متن محلی شده به ویژگی ها در
هنگامی که کاراکترهای غیر عددی به عنوان مثال در زمینه ورودی Age گنجانده می شوند، پیام را محلی سازی کنیم.
یک UserViewModel.Age
ویژگی Range
دارد، و HTML خروجی ویژگی ورودی را data-val-range
آپند می کند.
<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>
با این حال، پیام بررسی عددی محلی نمی data-val-number
شود زیرا هیچ ویژگی وجود ندارد.
شما یک ویژگی دیگر در سمت مدل برای چاپ ویژگی محلی پیام اضافه شده data-val-number
نیز اضافه کنید.
مرحله اول ایجاد یک کلاس ویژگی است که چک می کند اگر آن را IntAttribute
یک عدد است: این محدود به اینجا است، اما شما آزاد int
هستید که بسته به وضعیت آن را تغییر دهید.
فایل کد می تواند در هر جایی باشد، اما این بار در پوشه آداپتور است.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
اگر مقدار مجموعه یک نوع باشد، یک ویژگی است که فقط یک حکم عادی است، اما در عمل اگر به یک ویژگی از نوع int تنظیم شود، صد در صد طبیعی است، بنابراین پردازش خود این کلاس هیچ معنایی int
ندارد.
هدف از این زمان نمایش پیام های خطای محلی شده در سرویس گیرنده است.
بعد، کلاس آداپتور زیر را ایجاد IntAttributeAdapter
کنید: این هم در پوشه آداپتور.
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;
}
}
نکته در اینجا روش AddValidation
توصیف شده در روش MergeAttribute
است.
ادغام ویژگی ها به عنوان ویژگی های تگ ورودی برای بازگشت data-val-number
به مشتری است.
مقداری که در ویژگی تنظیم می شود، یک پیام خطای محلی شده را تعیین می کند.
این آداپتور را در کلاسی که قبلاً ایجاد کرده CustomValidationAttributeAdapterProvider
اید برگرداند.
// 省略
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);
}
// 省略 (前に追加したコード)
}
}
}
اگر مقدار اعتبار است IntAttribute
، بازگشت که شما زودتر ایجاد شده IntAttributeAdapter
است.
ویژگی با ویژگی Int در حال حاضر اضافه شده است زمانی که آن را در سمت مشتری نمایش داده می data-val-number
شود.
در نهایت ، UserViewModel.Age
IntAttribute
اضافه کردن به .
هنگامی که شما کد خود را ثابت, سعی کنید آن را ببینید که آیا شما می خواهید آن را بررسی کنید.
<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>
پیام های غیر محلی شده دیگری نیز وجود دارد، اما شما می توانید آنها را در روش های شرح داده شده در بالا بومی سازی کنید. اضافه کردن کد زمانی که شما به آن نیاز دارید.