Hỗ trợ đa ngôn ngữ cho thư mặc định được hiển thị khi nhập xác minh
Môi trường
- ASP.NET Core
-
- 5.0 MVC
Bắt đầu
Hỗ trợ đa ngôn ngữ cho thư xác minh đầu vào mặc định cho lời nhắc này có thể không đầy đủ. Vui lòng giải quyết mọi vấn đề bị mất.
Ngoài ra, khi bạn thay đổi ngôn ngữ dựa trên phiên hoặc trạng thái bộ nhớ cache, nó cũng có thể được hiển thị bằng văn bản của ngôn ngữ trước đó.
Có một số cách để thay đổi thông báo xác thực đầu vào mặc định, mỗi phương pháp có thể được đáp ứng bằng cách kết hợp. Bất kỳ một, vì vậy nếu bạn muốn thay đổi nó chắc chắn, bạn phải đối phó với tất cả các mô hình.
Tiền đề
Lời nhắc này có nghĩa là bạn hiểu các mẹo sau:
- ASP.NET các tính năng tích hợp của MVC lõi cung cấp màn hình chuyển đổi đa ngôn ngữ
- Hỗ trợ đa ngôn ngữ cho điều hướng dữ liệu cho tên tham số và thư xác minh đầu vào
Ngoài ra, nếu bạn muốn tạo một dự án mới, hãy thêm các tệp và mã sau theo lời nhắc ở trên:
- tạo SharedResource.resx (+ en, es) 文件。 (Vì chỉ có thông báo được dịch cho lời nhắc này, nội dung trống.)
- Tạo tệp .cs tài nguyên được chia sẻ
- Thêm mã bản địa hóa vào dịch vụ khởi động. Cấu hình
- Thêm mã bản địa hóa vào Bắt đầu. Cấu hình
- Thêm mô hình chế độ xem người dùng (lần này, vì thông báo mặc định là đa ngôn ngữ, không có điều khiển phím rõ ràng)
- Thêm hành động và chế độ xem tạo màn hình do người dùng tạo (Create.cshtml)
Bắt đầu mã
Dựa trên các giả định trên, mỗi mã nên trông giống như sau:
Startup.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 { }
}
Mô hình ràng buộc thư
Đặt loại thuộc tính mô hình int
thành hoặc bị ràng DateTime
buộc với chế độ xem và thử đăng ký khi không điền, bạn sẽ thấy thông báo tương tự như Giá trị.
Các thông báo này được hiển thị khi chuỗi trống không thể int
bị ràng buộc với mô hình, v.v.
Bởi vì nó không thể bị ràng buộc, nó chỉ xảy ra trước khi xác minh giá trị khác và trong xử lý phía máy chủ.
Những thông báo này DefaultModelBindingMessageProvider
được định nghĩa là .
Startup.cs
thêm các tham số cho phương pháp được xác định từ đầu services.AddControllersWithViews
và sau đó nhấp Action
vào
Cài đặt có thể được truyền bằng cách thiết lập các tham số cho options
ModelBindingMessageProvider
đa ngôn ngữ.
Có 11 loại thư có thể được thiết lập, vì vậy trước tiên hãy SharedResource.resx
định nghĩa thư là:
Tên của khóa là tùy chọn. Thông báo tiếng Anh mặc định trong cột nhận xét (không cần phải là nhận xét).
Chúng tôi không liệt kê bản dịch cho từng ngôn ngữ, vì vậy hãy tự dịch (mã mẫu bao gồm SharedResource.resx đã dịch).
Giá | trị | Ghi chú |
---|---|---|
ModelBinding_AttemptedValueIsInvalid | Trong {1}, "{0}" không hợp lệ. | The value '{0}' is not valid for {1}. |
ModelBinding_MissingBindRequiredValue | Giá trị không được chỉ định cho {0}. | A value for the '{0}' parameter or property was not provided. |
ModelBinding_MissingKeyOrValue | Bắt buộc. | A value is required. |
ModelBinding_MissingRequestBodyRequiredValue | Yêu cầu phải có nội dung. | A non-empty request body is required. |
ModelBinding_NonPropertyAttemptedValueIsInvalid | "{0}" không hợp lệ. | The value '{0}' is not valid. |
ModelBinding_NonPropertyUnknownValueIsInvalid | Giá trị này không hợp lệ. | The supplied value is invalid. |
ModelBinding_NonPropertyValueMustBeANumber | Vui lòng chỉ định một số. | The field must be a number. |
ModelBinding_UnknownValueIsInvalid | Giá trị {0} không hợp lệ. | The supplied value is invalid for {0}. |
ModelBinding_ValueIsInvalid | "{0}" không hợp lệ. | The value '{0}' is invalid. |
ModelBinding_ValueMustBeANumber | {0} phải chỉ định một số. | The field {0} must be a number. |
ModelBinding_ValueMustNotBeNull | Đây là trường bắt buộc. | The value '{0}' is invalid. |
Sửa đổi .cs khởi động thành:
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
});
// 省略 (初期コード)
}
}
}
Điểm mấu chốt là thêm nhận vào services.AddControllersWithViews
phương option
Action
pháp, và sau đó
options.ModelBindingMessageProvider
Bạn vừa thiết lập văn bản được bản địa hóa cho mỗi phương pháp Set.
Văn bản sau khi dịch IStringLocalizer
đến từ
IStringLocalizer
Vì nó không thể được nhận trực tiếp, mã là một chút vòng tròn.
SharedResource.resx
Nếu bạn tạo mã, bạn nhận được giá trị bản địa hóa trực tiếp từ nó.
IStringLocalizer
Các phím được chỉ định trong là các phím được thêm SharedResource.resx
vào.
Đặt nó để sử dụng với nội dung của mỗi phương pháp Set.
Ngoài ra, vì mỗi tin nhắn có {0}{1}
tham số chuỗi định dạng, chúng tôi sử dụng đơn giản để thay thế các giá trị nhận string.Format
Func
được.
Bản địa hóa thông báo xác minh mặc định
Khi các thuộc tính của thuộc tính mô hình được đặt thành Required
bằng StringLength
không, thông báo lỗi mặc định được xác định bởi khung, về cơ bản bằng tiếng Anh.
IValidationAttributeAdapterProvider
Bạn có thể bản địa hóa chúng bằng cách xác định các lớp học của giao diện phái sinh.
Trước SharedResource.resx
tiên, bạn đã đăng ký văn bản tương thích với đa ngôn ngữ.
Tên của khóa là tùy chọn, nhưng để đơn giản hóa chương trình, > đăng ký dưới dạng "Validator_< xác minh tên thuộc tính".
Giá | trị | Ghi chú |
---|---|---|
Validator_CompareAttribute | {0} không khớp với {1}. | '{0}' and '{1}' do not match. |
Validator_CreditCardAttribute | {0} không phải là số thẻ hợp lệ. | The {0} field is not a valid credit card number. |
Validator_DataTypeAttribute_Date | Vui lòng nhập ngày hợp lệ. | Please enter a valid date. |
Validator_EmailAddressAttribute | {0} không phải là một địa chỉ email hợp lệ. | The {0} field is not a valid e-mail address. |
Validator_FileExtensionsAttribute | {0} chỉ chấp nhận các tệp có phần mở rộng sau: : {1} | The {0} field only accepts files with the following extensions: {1} |
Validator_MaxLengthAttribute | {0} phải là loại chuỗi hoặc mảng có độ dài tối đa là "{1}". | The field {0} must be a string or array type with a maximum length of '{1}'. |
Validator_MinLengthAttribute | {0} phải là loại chuỗi hoặc mảng có độ dài tối thiểu là "{1}". | The field {0} must be a string or array type with a minimum length of '{1}'. |
Validator_PhoneAttribute | {0} không phải là số điện thoại hợp lệ. | The {0} field is not a valid phone number. |
Validator_RangeAttribute | {0} nên nằm giữa {1} và {2}. | The field {0} must be between {1} and {2}. |
Validator_RegularExpressionAttribute | Chỉ định rằng {0} khớp với biểu thức chính quy "{1}". | The field {0} must match the regular expression '{1}'. |
Validator_RequiredAttribute | {0} là bắt buộc. | The {0} field is required. |
Validator_StringLengthAttribute | {0} phải {1} bit. | The field {0} must be a string with a maximum length of {1}. |
Validator_UrlAttribute | {0} không phải là URL hợp lệ. | The {0} field is not a valid fully-qualified http, https, or ftp URL. |
Validator_StringLengthAttributeWithMin | {0} phải có ít nhất {2} bit {1} bit. | The field {0} must be a string with a maximum length of {1} and a minimum length of {2}. |
Tiếp theo, bạn sẽ tạo các lớp nhà cung cấp bộ điều hợp sau:
Tên lớp là tùy chọn, nhưng lần này chúng ta sẽ tạo CustomValidationAttributeAdapterProvider
một lớp được gọi là và viết mã như sau.
Vị trí của tệp mã là tùy chọn, nhưng ví dụ đặt nó trong một thư mục được gọi là bộ điều hợp.
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);
}
}
}
Nếu thuộc tính mô hình Required
được đặt thành StringLength
hoặc, phương pháp được gọi mỗi khi bạn xác IValidationAttributeAdapterProvider.GetAttributeAdapter
minh.
ErrorMessageResourceName
Nếu thuộc tính chứa giá trị, nó được trả về vì mã mô hình đã thiết lập một tin nhắn hoặc phím bản địa hóa.
Nếu tiền tố và thuộc tính xác thực có tên lớp trống, hãy đặt nó thành phím bản địa hóa và lấy văn bản được bản địa hóa từ khóa ErrorMessage
và đặt nó thành.
Điều này cho phép hầu hết các thư mặc định được bản địa hóa.
Sau đó, đăng ký lớp này trong .cs Bắt đầu. Về cơ bản, bạn có thể thêm những điều sau đây:
// 省略
using Microsoft.AspNetCore.Mvc.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class Startup
{
// 省略
// このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
public void ConfigureServices(IServiceCollection services)
{
// 省略
// 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
}
// 省略
}
}
Chạy nó để đảm bảo rằng nó hoạt động đúng.
Thay đổi thông báo hiện có theo tham số
Ví dụ: StringLength
thông báo thuộc tính đã được bản địa hóa thành "{0} phải {1} bit."
MinimumLength
Nếu thuộc tính được thiết lập, bạn có thể cần phải thay đổi bit {0}{1}{2} hoặc nhiều hơn."
Trong trường hợp này, CustomValidationAttributeAdapterProvider
mở rộng lớp để:
// 省略
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);
}
}
// 省略
}
}
}
Bởi vì mỗi xác nhận GetAttributeAdapter
gọi một phương pháp, nếu biến được truyền attribute
là một thuộc StringLengthAttribute
MinimumLength
tính, kiểm tra các thuộc tính,
Nếu bạn đã thiết lập, nhận được một thông báo cũng xem xét số bit tối thiểu và thay thế nó ErrorMessage
bằng.
Nếu bạn chạy và xác nhận rằng thư thay đổi, nó sẽ là ok.
Thông điệp chung khác
Cho đến nay, một số thư chưa được bản địa hóa. Ví dụ: thư chỉ được xác định bởi tập lệnh Java.
Điều này áp dụng cho các jquery.validate.js
thư được liệt kê trong tệp.
Vì tệp này không nên được chỉnh sửa trực tiếp, bạn phải input
thêm thuộc tính vào thẻ và đặt văn bản bản địa hóa thành thay thế các thư data-val-XXXX
này.
Phần XXXX có các phím trong hình jquery.validate.js
trên. (ví data-val-number
dụ:
data-val-XXXX
Để thiết lập văn bản được bản địa hóa trong thuộc tính, bạn có thể đặt văn bản đó khi HTML được trả về ở phía máy chủ.
Ví dụ: bản địa hóa thư khi các ký tự không phải số được bao gồm trong trường đầu vào Age.
UserViewModel.Age
HTML có Range
thuộc tính và đầu ra data-val-range
đính kèm thuộc tính vào đầu vào.
<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>
Tuy data-val-number
nhiên, vì không có thuộc tính, thư kiểm tra kỹ thuật số không được bản địa hóa.
Vì vậy, thêm một thuộc tính khác vào mô hình và đầu ra các thuộc tính có chứa thư được bản địa data-val-number
hóa.
Trước tiên, tạo một lớp thuộc tính kiểm tra xem nó có phải là số hay IntAttribute
không, như sau: Ở đây int
bạn có thể tự do thay đổi nó tùy thuộc vào hoàn cảnh.
Vị trí của tệp mã không quan trọng, nhưng lần này tôi đặt nó trong thư mục bộ điều hợp.
using System.ComponentModel.DataAnnotations;
namespace LocalizationDefaultValidation
{
public class IntAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// 渡された値が int であれば有効な値とする
return value is int;
}
}
}
Nếu giá trị được đặt int
là loại, thuộc tính này chỉ là một quyết định bình thường, nhưng bản thân lớp này không có ý nghĩa đặc biệt vì thuộc tính thực sự được đặt thành loại int là 100% bình thường.
Mục đích là để hiển thị thông báo lỗi bản địa hóa trên máy khách.
Tiếp theo, IntAttributeAdapter
bạn sẽ tạo các lớp bộ điều hợp sau: Tôi cũng đặt nó trong thư mục bộ điều hợp.
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;
}
}
Điểm chính ở đây là AddValidation
phương pháp tôi đã viết trong phương pháp của MergeAttribute
tôi.
Hợp nhất thuộc tính thành thuộc tính mà bạn muốn trả về thẻ đầu vào cho khách data-val-number
hàng.
Đặt thông báo lỗi được bản địa hóa cho các giá trị được đặt cho thuộc tính.
Trả về bộ điều hợp này trong lớp được tạo trước 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);
}
// 省略 (前に追加したコード)
}
}
}
Nếu giá trị bạn muốn xác minh IntAttribute
là, trả về những gì bạn vừa IntAttributeAdapter
tạo.
Bây giờ các thuộc tính có thuộc tính Int được thêm vào khi máy khách được hiển data-val-number
thị.
Cuối cùng, UserViewModel.Age
IntAttribute
thêm vào .
Sau khi bạn sửa chữa mã, chạy nó để xem nó.
<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>
Có những tin nhắn khác không được bản địa hóa, nhưng có thể được bản địa hóa bằng cách sử dụng các phương pháp trên. Nếu cần, hãy thêm mã.