Suport multilingv pentru dataannotări utilizate pentru nume de parametri, mesaje de validare a intrărilor etc.
mediu
- ASP.NET Core
-
- 5.0 MVC
premisă
Acest sfat este scris ca înțelegerea următoarele sfaturi:
De asemenea, dacă creați un proiect nou, trebuie să fi adăugat următoarele fișiere și cod pe baza sfaturilor de mai sus.
- Creați un fișier SharedResource.resx (+en, es). (Conținutul poate fi gol.)
- Crearea unui fișier SharedResource.cs
- Adăugați codul de localizare la Startup.ConfigureServices
- Adăugați codul de localizare la Startup.Configure
Remedieri .cs de pornire
Deoarece sunt necesare setări multilingve suplimentare legate de DataAnnotations, Startup.ConfigureServices
modificați metoda după cum urmează:
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));
});
}
Modelare pentru intrare
Creați un model care să se lege la ecranul de intrare. În acest eșantion, am creat o serie de proprietăți pentru a găzdui diverse controale de intrare. Dacă întâmpinați probleme la crearea, puteți crea doar două.
Creați un .cs UserViewModel în folderul Modele.
Codul ar trebui să arate astfel: Spațiul de nume ar trebui să fie adecvat. Atributele pe care le setați nu sunt foarte relevante pentru mai multe limbi, deoarece acestea sunt atribuite numai acestora. Sprijinul multilingv se va face mai târziu.
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace LocalizationDataAnnotation.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]*$", ErrorMessage = "Password")]
public string Password { get; set; }
// 省略
}
// 省略
}
Crearea unei acțiuni
Creați acțiuni pentru a afișa ecranul de înregistrare al utilizatorului și pentru a efectua acțiuni de HomeController
înregistrare.
Crearea de ecrane și acțiuni nu este subiectul principal al acestor sfaturi, deci este potrivit. În plus, procesul de înregistrare efectivă nu este efectuat.
// 初期コードは省略
namespace LocalizationDataAnnotation.Controllers
{
public class HomeController : Controller
{
// 初期コードは省略
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(UserViewModel model)
{
// エラーなら差し戻し
if (ModelState.IsValid == false) return View(model);
// 正常に登録できた場合は Index に戻る
return RedirectToAction(nameof(Index));
}
}
}
Link către ecranul de înregistrare a utilizatorului
Creați un link către ecranul de înregistrare a utilizatorului în Views\Home\Index.cshtml. Puteți scrie orice, atâta timp cât puteți avea o tranziție a ecranului.
asp-route-culture
Atributul deschide pagina în limba specificată.
<!-- 初期コード省略 -->
<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>
Crearea unui ecran de înregistrare a utilizatorului
Create
Faceți clic dreapta pe acțiune și selectați Adăugare vizualizare.
Selectează Vizualizare aparat de ras.
Faceți șablonul "Creare" și clasa de model "UserViewModel".
Dacă utilizați UserViewModel
codul eșantion, am inclus, de asemenea, comentarii în cod.
Dacă puneți anumite atribute într-o proprietate, veți primi o eroare la generarea de cod în schele.
Vă rugăm să comentați temporar înainte de a crea o vizualizare.
Dacă într-adevăr primiți o eroare atunci când o creați, creați o vizualizare Razor goală și includeți următorul cod:
@model LocalizationDataAnnotation.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">
<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">
<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");}
}
Pentru moment, ca o etapă pregătitoare, puteți construi codul până acum cu succes și încercați să vedeți și să rulați corect ecranul.
Înregistrarea textului multilingv pentru Adnotări de date
Toate proprietățile sunt lungi pentru a explica, așa că vom ID
vorbi cu și pentru . Name
Alte proprietăți sunt multilingve într-un mod similar, așa că încercați-le.
Următoarele texte sunt disponibile în mai multe limbi aici.
Taste text multilingve | |
---|---|
Numele afișat al parametrului ID | ID_DisplayName |
Mesaj de eroare atunci când ID-ul nu a fost introdus | Validate_Required |
Mesaj de eroare atunci când id-ul de intrare caracter depășește 20 de caractere | Validate_StringLength |
Mesaj de eroare atunci când ID-ul este tastat cu caractere nenumerice | Validate_Alphanumeric |
Nume afișat parametru nume | Name_DisplayName |
Mesaj de eroare atunci când numele are mai mult de 50 de caractere introduse | Validate_StringLength |
Validate_XXXXX
să fie universal. Nu există o convenție de denumire a cheilor, astfel încât să o puteți atașa liber.
Folosind aceste chei ca bază, SharedResource.resx
vom completa textul tradus în , , SharedResource.en.resx
SharedResource.es.resx
.
SharedResource.resx
numeValoare | |
---|---|
Validate_Required | Este necesară "{0}". |
Validate_StringLength | Puteți introduce până la "{1}" în "{0}". |
Validate_Alphanumeric | {0} poate fi doar alfanumerică. |
ID_DisplayName | ID (alfanumeric) |
Name_DisplayName | identitate |
SharedResource.ro.resx
numeValoare | |
---|---|
Validate_Required | "{0}" este o intrare necesară. |
Validate_StringLength | Numărul maxim de caractere care pot fi introduse în "{0}" este "{1}". |
Validate_Alphanumeric | Numai caracterele alfanumerice pot fi introduse pentru "{0}". |
ID_DisplayName | ID (caractere alfanumerice) |
Name_DisplayName | Numele complet |
SharedResource.es.resx
numeValoare | |
---|---|
Validate_Required | "{0}" es una entrada obligatoria. |
Validate_StringLength | El número máximo de caracteres que se pueden ingresar en "{0}" es "{1}". |
Validate_Alphanumeric | Solo se pueden ingresar caracteres alfanuméricos para "{0}". |
ID_DisplayName | ID (caracteres alfanuméricos) |
Name_DisplayName | Nombre completo |
Mesajele de eroare de validare a intrărilor înlocuiesc numele parametrilor și numerele cu {0} și {1}. Să-l folosim pozitiv.
Aplicație multilingvă la DataAnnotations
Toate setările multilingve sunt aplicate atributelor modelului (DataAnnotations).
Pentru a-l aplica la numele afișat al parametrului, Display
atașați și specificați o Name
cheie sharedResource.resx în proprietate.
Pentru a aplica la mesajele de eroare în timpul validării de intrare, specificați o ErrorMessage
cheie sharedResource.resx în proprietatea fiecărui atribut de validare.
public class UserViewModel
{
[Required(ErrorMessage = "Validate_Required")]
[Display(Name = "ID_DisplayName")]
[StringLength(20, ErrorMessage = "Validate_StringLength")]
[RegularExpression(@"^[0-9a-zA-Z]*$", ErrorMessage = "Validate_Alphanumeric")]
public string ID { get; set; }
[Display(Name = "Name_DisplayName")]
[StringLength(50, ErrorMessage = "Validate_StringLength")]
public string Name { get; set; }
// 省略
}
Acest lucru finalizează configurarea. După aceea, rulați-l pentru a vedea cum funcționează.
Apropo, numărul de caractere de intrare este limitat de atributul etichetei de maxlength
intrare.
Dacă doriți să vedeți mesajul, trebuie să eliminați restricțiile, cum ar fi în instrumentele pentru dezvoltatori ale browserului web.
Apropo, există unele mesaje afișate atunci când vă înregistrați vârsta, data etc. goale. Acesta este un mesaj care este configurat pe partea de cadru, dar un alt Sfat vă va arăta cum să-l sprijine în mai multe limbi.
Pentru toate codurile
Aceste sfaturi conțin doar unele proprietăți, dar codul eșantion acoperă toate câmpurile de intrare activate html5. Dacă doriți să verificați, vă rugăm să consultați link-ul de mai sus a paginii.
Enumerate în parte de mai jos
UserViewModel.cs
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace LocalizationDataAnnotation.Models
{
public class UserViewModel
{
[Required(ErrorMessage = "Validate_Required")]
[Display(Name = "ID_DisplayName")]
[StringLength(20, ErrorMessage = "Validate_StringLength")]
[RegularExpression(@"^[0-9a-zA-Z]*$", ErrorMessage = "Validate_Alphanumeric")]
public string ID { get; set; }
[Display(Name = "Name_DisplayName")]
[StringLength(50, ErrorMessage = "Validate_StringLength")]
public string Name { get; set; }
[Display(Name = "Password_DisplayName")]
[StringLength(50, MinimumLength = 8, ErrorMessage = "Validate_StringLengthRange")]
[DataType(DataType.Password)]
[RegularExpression(@"^[0-9a-zA-Z]*$", ErrorMessage = "Validate_Alphanumeric")]
public string Password { get; set; }
[Display(Name = "ConfirmPassword_DisplayName")]
[StringLength(50, MinimumLength = 8, ErrorMessage = "Validate_StringLengthRange")]
[DataType(DataType.Password)]
[Compare(nameof(Password), ErrorMessage = "Validate_Compare")]
public string ConfirmPassword { get; set; }
[Display(Name = "Email_DisplayName")]
[EmailAddress(ErrorMessage = "Validate_EmailAddress")]
[DataType(DataType.EmailAddress)] // スキャフォールディングするときはコメントアウトする
public string Email { get; set; }
[Display(Name = "Age_DisplayName")]
[Required(ErrorMessage = "Validate_Required")]
[Range(0, 150, ErrorMessage = "Validate_Range")]
public int Age { get; set; }
[Display(Name = "Gender_DisplayName")]
[Required(ErrorMessage = "Validate_Required")]
[EnumDataType(typeof(GenderType))]
public GenderType Gender { get; set; }
[Display(Name = "Birthday_DisplayName")]
[DataType(DataType.Date)]
public DateTime Birthday { get; set; }
[Display(Name = "Phone_DisplayName")]
[Phone(ErrorMessage = "Validate_Phone")]
[DataType(DataType.PhoneNumber)] // スキャフォールディングするときはコメントアウトする
public string Phone { get; set; }
[Display(Name = "PostalCode_DisplayName")]
[DataType(DataType.PostalCode)]
public string PostalCode { get; set; }
[Display(Name = "CreditCard_DisplayName")]
[CreditCard(ErrorMessage = "Validate_CreditCard")]
[DataType(DataType.CreditCard)] // スキャフォールディングするときはコメントアウトする
public string CreditCard { get; set; }
[Display(Name = "Money_DisplayName")]
[DataType(DataType.Currency)]
public decimal Money { get; set; }
[Display(Name = "StartDateTime_DisplayName")]
[DataType(DataType.DateTime)]
public DateTime StartDateTime { get; set; }
[Display(Name = "WakeUpTime_DisplayName")]
[DataType(DataType.Time)]
public TimeSpan WakeUpTime { get; set; }
[Display(Name = "Homepage_DisplayName")]
[Url(ErrorMessage = "Validate_Url")]
[DataType(DataType.Url)] // スキャフォールディングするときはコメントアウトする
public string Homepage { get; set; }
[Display(Name = "MyImage_DisplayName")]
[Url(ErrorMessage = "Validate_Url")]
[DataType(DataType.ImageUrl)] // スキャフォールディングするときはコメントアウトする
public string MyImage { get; set; }
[Display(Name = "MyColor_DisplayName")]
public string MyColor { get; set; }
[Display(Name = "WorkingDays_DisplayName")]
[MaxLength(5, ErrorMessage = "Validate_MaxLength")]
[EnumDataType(typeof(DayOfWeek))]
public DayOfWeek[] WorkingDays { get; set; }
[Display(Name = "VacationDay_DisplayName")]
[MinLength(3, ErrorMessage = "Validate_MinLength")]
[EnumDataType(typeof(DayOfWeek))]
public DayOfWeek[] VacationDay { get; set; }
[Display(Name = "Comment_DisplayName")]
[StringLength(200, ErrorMessage = "Validate_StringLength")]
[DataType(DataType.MultilineText)]
public string Comment { get; set; }
[Display(Name = "FileName_DisplayName")]
[FileExtensions(Extensions = "png", ErrorMessage = "Validate_FileExtensions")]
public string FileName { get; set; }
[Display(Name = "UploadFile_DisplayName")]
[DataType(DataType.Upload)]
public List<IFormFile> UploadFile { get; set; }
[Display(Name = "Month_DisplayName")]
public DateTime Month { get; set; }
[Display(Name = "Search_DisplayName")]
public string Search { get; set; }
[Display(Name = "Range_DisplayName")]
[Range(10, 100, ErrorMessage = "Validate_Range")]
public int Range { get; set; }
[Display(Name = "Week_DisplayName")]
public string Week { get; set; }
[Display(Name = "IsAccepted_DisplayName")]
[Required(ErrorMessage = "Validate_Required")]
public bool IsAccepted { get; set; }
}
public enum GenderType
{
None,
Man,
Woman,
Other,
}
}
HomeController.cs
using LocalizationDataAnnotation.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 LocalizationDataAnnotation.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
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()));
}
}
Create.cshtml
@model LocalizationDataAnnotation.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");}
}