دعم متعدد اللغات للرسائل الافتراضية المعروضة أثناء التحقق من صحة الإدخال
وسط
- ASP.NET كور
-
- 5.0 MVC
في البداية
قد لا يكون الدعم متعدد اللغات لرسائل التحقق من صحة الإدخال الافتراضية مع هذه التلميحات كاملا. رجاء تعامل مع المفقودين
أيضا، تغيير اللغة استنادا إلى حالة جلسة العمل أو حالة ذاكرة التخزين المؤقت قد لا تزال تظهر في نص من اللغة السابقة.
هناك عدة طرق لتغيير رسالة التحقق من صحة الإدخال الافتراضية، يمكن دمج كل منها. انها ليست واحدة منهم، لذلك إذا كنت ترغب في تغييره بشكل موثوق، تحتاج إلى تتوافق مع جميع الأنماط.
فرضيه
تتم كتابة هذه النصائح كفهم للنصائح التالية:
- ASP.NET الميزات المدمجة ل Core MVC للتبديل متعدد اللغات
- دعم متعدد اللغات ل DataAnnotations المستخدمة لأسماء المعلمات ورسائل التحقق من صحة الإدخال، إلخ.
أيضا، إذا كنت تقوم بإنشاء مشروع جديد، يجب أن يكون لديك إضافة الملفات والتعليمات البرمجية التالية استنادا إلى تلميحات أعلاه.
- إنشاء ملف SharedResource.resx (+en, es). (بما أن رسالة هذه التلميحات فقط مترجمة، فقد تكون المحتويات فارغة.)
- إنشاء ملف مشتركالمصدر.cs
- إضافة رمز التعريب إلى Startup.ConfigureServices
- إضافة رمز التعريب إلى بدء التشغيل.تكوين
- تمت إضافة 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();
// 省略
}
}
}
هومكونترولر.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()));
}
}
مؤشر.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>
إنشاء.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");}
}
المستخدمفيوموديل.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,
}
}
الموارد المشتركة.cs
namespace LocalizationDefaultValidation
{
// クラス名は作成した .resx のファイル名と同じにする必要がある
public class SharedResource { }
}
رسائل ربط الطراز
إذا قمت بتعيين نوع الخاصية طراز int
إلى أو ربطه إلى DateTime
طريقة العرض، وحاول تسجيله غير مكتوب، سترى رسالة مثل "القيمة '' غير صالحة.".
تظهر هذه الرسائل عندما لا يمكن ربط سلسلة فارغة int
إلى، على سبيل المثال، في الطراز.
لأنه توقيت لا يمكن ربطه، فإنه يحدث فقط قبل التحقق من صحة القيمة الأخرى والمعالجة من جانب الخادم.
يتم تعريف هذه الرسائل DefaultModelBindingMessageProvider
ك .
Startup.cs
أضف إلى وسائط الأسلوب التي تم تعريفها منذ البداية services.AddControllersWithViews
في ، ثم أضف Action
.
يمكنك أن تكون متعدد اللغات عن طريق تعيين تمرير في options
ModelBindingMessageProvider
الوسيطة.
هناك 11 نوع من الرسائل التي يمكنك تعيينها، لذا يجب أولا تعريف الرسالة على النحو التالي: SharedResource.resx
اسم المفتاح اختياري. الرسالة الافتراضية باللغة الإنجليزية في عمود التعليقات هي (لا يلزم تضمين التعليقات).
لن تضطر إلى ترجمة كل لغة، لذا يجب عليك القيام بالترجمة الخاصة بك (تتضمن نموذج التعليمات البرمجية أيضا المشتركة.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
أنا أقوم بتعيين نص مترجم لكل أسلوب Set في .
يتم استرداد النص المترجم IStringLocalizer
من .
لا توجد طريقة لتلقي IStringLocalizer
التعليمات البرمجية المباشرة، وهو جزء من التعليمات البرمجية المستديرة.
SharedResource.resx
إذا كنت تقوم بإنشاء التعليمات البرمجية من، فستحصل على قيم مترجمة منها مباشرة.
IStringLocalizer
يحدد المفتاح الذي تحدده في SharedResource.resx
المفتاح الذي قمت بإضافتها إلى .
قم بتعيينه لمطابقة محتويات كل أسلوب Set.
أيضا، لأن كل رسالة لها وسيطة سلسلة تنسيق، مثل ، {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} غير محدد موقع معلومات صحيح. | حقل {0} غير صالح مؤهل بالكامل http أو https أو FTP URL. |
Validator_StringLengthAttributeWithMin | يجب أن تكون {0} أرقام {2} {1} على الأقل. | يجب أن يكون الحقل {0} سلسلة بطول أقصى {1} والحد الأدنى من طول {2}. |
بعد ذلك، إنشاء الفئة AdapterProvider التالية:
اسم الفئة هو إجبارية، ولكن هذه المرة 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>();
}
// 省略
}
}
تشغيله للتأكد من أنه يعمل بشكل صحيح.
تغيير رسالة موجودة حسب المعلمات
على سبيل المثال، StringLength
يتم ترجمة رسالة السمة مثل "يجب أن تكون {0} ضمن أرقام {1}."
MinimumLength
إذا تم تعيين الخاصية، قد تحتاج إلى تغيير {0} ك "تحديد أرقام {2} أو أكثر {1} ضمن عدد من الأرقام".
في هذه 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
لتعيين نص مترجم إلى سمات في
دعونا ترجمة الرسالة عندما يتم تضمين أحرف غير رقمية في حقل إدخال السن كمثال.
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
نوع، وهي سمة التي هي فقط حكم عادي، ولكن في الممارسة العملية هو 100٪ طبيعي إذا تم تعيينها إلى خاصية من نوع 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>
هناك رسائل أخرى غير مترجمة، ولكن يمكنك ترجمة لهم في الأساليب المذكورة أعلاه. أضف التعليمات البرمجية عندما تحتاج إليها.