Večjezična podpora za privzeta sporočila, prikazana med preverjanjem vnosa

Datum ustvarjanja strani :

okolje

ASP.NET Core
  • 5.0 MVC

Sprva

Večjezična podpora privzetih sporočil za preverjanje veljavnosti vnosa s tem Nasveti morda ni dokončana. Prosim, opravite z manjkajočimi.

Tudi spreminjanje jezika, odvisno od stanja seje ali stanja predpomnilnika, se lahko še vedno prikaže v besedilu iz prejšnjega jezika.

Privzeto sporočilo o preverjanju veljavnosti vnosa lahko spremenite na več načinov, od katerih je vsako mogoče združiti. To ni eden od njih, tako da, če želite, da ga spremeniti zanesljivo, morate ujemati z vsemi vzorci.

Predpostavki

Ti nasveti so napisani kot razumevanje naslednjih nasvetov:

Če ustvarjate nov projekt, morate na podlagi zgornjih nasvetov dodati naslednje datoteke in kodo.

  • Ustvarite datoteko SharedResource.resx (+sl, es). (Ker je prevedeno le sporočilo teh nasvetov, je vsebina lahko prazna.)
  • Ustvarjanje datoteke v skupni rabi.cs datoteke
  • Dodajanje kode lokalizacije zagonu.ConfigureServices
  • Dodajte kodo za lokalizacijo v zagon.Konfiguriraj
  • Dodan UserViewModel (tokrat ne tipkamo izrecno privzetih sporočil v več jezikih)
  • Dodana dejanja in pogledi zaslona, ki jih je ustvaril uporabnik (Create.cshtml)

Začetna koda

Na podlagi zgornjih predpostavk je vsaka oznaka naslednja:

Zagon.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>
Ustvari.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,
  }
}
Skupni presledki.cs
namespace LocalizationDefaultValidation
{
  // クラス名は作成した .resx のファイル名と同じにする必要がある
  public class SharedResource { }
}

Zavezujoča sporočila modela

Če nastavite vrsto lastnosti modela ali jo privezate na pogled in jo poskusite registrirati nepotipkano, se prikaže sporočilo, kot je »Vrednost '' ni int DateTime veljavno.« Ta sporočila se prikažejo, ko praznega niza ni mogoče zavezati na primer int v modelu. Ker gre za časovni okvir, ki ga ni mogoče zavezati, se pojavi le pred drugim preverjanjem vrednosti in obdelavo na strani strežnika.

Ta sporočila so DefaultModelBindingMessageProvider opredeljena kot .

Startup.cs Dodajte argumentom metode, ki so bile opredeljene od začetka v services.AddControllersWithViews in nato dodajte Action . Večjezični ste lahko tako, da nastavite podajano v options ModelBindingMessageProvider argumentu.

Na voljo je 11 vrst sporočil, ki jih lahko nastavite, zato morate najprej določiti sporočilo na naslednji način: SharedResource.resx Ime ključa je neobvezno. Privzeto angleško sporočilo v stolpcu s komentarji je (komentarjev ni treba vključiti). Ni vam treba prevajati vsakega jezika, zato morate narediti svoj prevod (vzorčna koda vključuje tudi prevedeni SharedResource.resx).

Komentar
vrednosti imena
ModelBinding_AttemptedValueIsInvalid "{0}" je neveljavna vrednost v {1}. Vrednost "{0}" ni veljavna za {1}.
ModelBinding_MissingBindRequiredValue Vrednost za {0} ni določena. Vrednost parametra ali lastnosti "{0}" ni bila zagotovljena.
ModelBinding_MissingKeyOrValue Zahteva. Potrebna je vrednost.
ModelBinding_MissingRequestBodyRequiredValue Zahteva mora imeti truplo. Potreben je neprazen organ zahteve.
ModelBinding_NonPropertyAttemptedValueIsInvalid "{0}" ni veljavna. Vrednost "{0}" ni veljavna.
ModelBinding_NonPropertyUnknownValueIsInvalid Vrednost ni veljavna. Priložena vrednost ni veljavna.
ModelBinding_NonPropertyValueMustBeANumber Določiti je treba številko. Polje mora biti številka.
ModelBinding_UnknownValueIsInvalid Vrednost {0} ni veljavna. Priložena vrednost ni veljavna za {0}.
ModelBinding_ValueIsInvalid "{0}" ni veljavna. Vrednost "{0}" ni veljavna.
ModelBinding_ValueMustBeANumber {0} mora biti številka. Polje {0} mora biti številka.
ModelBinding_ValueMustNotBeNull Zahtevan vnos. Vrednost "{0}" ni veljavna.

Popravite zagon.cs na naslednji način:

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
      });

      // 省略 (初期コード)
    }
  }
}

Ključna točka je dodati services.AddControllersWithViews metodi, ki prejme option Action , Nastavljam lokalizirano besedilo za vsako metodo options.ModelBindingMessageProvider Nastavitev v programu .

Prevedeno besedilo je IStringLocalizer pridobljeno iz . Ni načina, da bi prejeli neposredno IStringLocalizer kodo, ki je nekoliko okrogla koda. Če ustvarjate kodo, boste iz tega neposredno dobili SharedResource.resx lokalizirane vrednosti.

IStringLocalizer Ključ, ki ga določite SharedResource.resx v, določa ključ, ki ste ga dodali . Nastavite ga tako, da se ujema z vsebino vsakega načina nabora.

Tudi zato, ker ima vsako sporočilo argument niza formata, na primer , uporabljam Preprosto s tako, da lahko zamenjate {0}{1} prejete string.Format Func vrednosti.

Lokalizacija privzetih sporočil za preverjanje veljavnosti

Privzeto sporočilo o napaki, ko so atributi lastnosti modela nastavljeni na ali tako, je določeno s okvirom in je v bistvu v Required StringLength angleščini.

Te lahko lokalizirate tako, da določite razred, ki izhaja IValidationAttributeAdapterProvider iz vmesnika.

Najprej registrirajte besedilo, ki je SharedResource.resx večjezično. Ime ključa je samovoljno, vendar za poenostavitev programa, ga registrirajte v obliki "Validator_< ime atributa za preverjanje>".

Komentar
vrednosti imena
Validator_CompareAttribute {0} in {1} se ne ujemata. "{0}" in "{1}" se ne ujemata.
Validator_CreditCardAttribute {0} ni veljavna številka kartice. Polje {0} ni veljavna številka kreditne kartice.
Validator_DataTypeAttribute_Date Vnesite veljaven datum. Vnesite veljaven datum.
Validator_EmailAddressAttribute {0} ni veljaven e-poštni naslov. Polje {0} ni veljaven e-poštni naslov.
Validator_FileExtensionsAttribute {0} sprejema samo datoteke z naslednjimi razširitvami: : {1} Polje {0} sprejema samo datoteke z naslednjimi razširitvami: {1}
Validator_MaxLengthAttribute {0} mora biti vrsta niza ali polja z največjo dolžino "{1}". Polje {0} mora biti vrsta niza ali polja z največjo dolžino "{1}".
Validator_MinLengthAttribute {0} mora biti vrsta niza ali polja z minimalno dolžino "{1}". Polje {0} mora biti vrsta niza ali polja z minimalno dolžino "{1}".
Validator_PhoneAttribute {0} ni veljavna telefonska številka. Polje {0} ni veljavna telefonska številka.
Validator_RangeAttribute {0} mora biti od {1} do {2}. Polje {0} mora biti med {1} in {2}.
Validator_RegularExpressionAttribute {0} se mora ujemati z običajnim izrazom "{1}". Polje {0} se mora ujemati z regularnim izrazom "{1}".
Validator_RequiredAttribute {0} je potrebno. Polje {0} je potrebno.
Validator_StringLengthAttribute {0} mora biti znotraj {1} številk. Polje {0} mora biti niz z največjo dolžino {1}.
Validator_UrlAttribute {0} ni veljaven URL. Polje {0} ni veljaven popolnoma kvalificirani URL http, https ali FTP.
Validator_StringLengthAttributeWithMin {0} mora biti vsaj {2} {1} števk. Polje {0} mora biti niz z največjo dolžino {1} in minimalno dolžino {2}.

Nato ustvarite ta razred adapterProvider:

Ime razreda je poljubno, tokrat pa bom napisal razred, ki se imenuje in napisal kodo na CustomValidationAttributeAdapterProvider naslednji način: Lokacija kodne datoteke je poljubna, vendar je vzorec v mapo, imenovano Adapter.

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);
    }
  }
}

Če nastavite lastnosti modela na ali , je metoda poklicana za Required vsako StringLength IValidationAttributeAdapterProvider.GetAttributeAdapter preverjanje veljavnosti.

ErrorMessageResourceName Če lastnost vsebuje vrednost, ima koda na strani modela že sporočilo ali ključ za lokalizacijo, zato se vrne, kot je.

Če je prazno, se ujemajo z imeni razredov predpone in atributa za preverjanje veljavnosti, da bo ključ za lokalizacijo, nato pa iz ključa pridobite lokalizirano besedilo in ga nastavite na ErrorMessage . To omogoča lokaliziranje večine privzetih sporočil.

Nato registrirajte ta razred v zagonskem .cs. V bistvu ga lahko dodate na naslednji način.

// 省略

using Microsoft.AspNetCore.Mvc.DataAnnotations;

namespace LocalizationDefaultValidation
{
  public class Startup
  {
    // 省略

    // このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
    public void ConfigureServices(IServiceCollection services)
    {
      // 省略

      // 作成した CustomValidationAttributeAdapterProvider をシングルトンとして登録します
      services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    }
    
    // 省略
  }
}

Zaženi ga, da se prepričaš, da deluje pravilno.

Spreminjanje obstoječega sporočila po parametrih

Sporočilo atributa je na primer lokalizirano, na primer »{0} mora biti znotraj StringLength {1} številk«. Če je lastnost nastavljena, boste morda želeli spremeniti {0} kot »Navedite {2} številke ali več {1} znotraj več MinimumLength števk«.

V tem CustomValidationAttributeAdapterProvider primeru razred razširite na naslednji način:

// 省略

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);
        }
      }

      // 省略
    }
  }
}

Ker je metoda poklicana za vsako preverjanje veljavnosti, če je bila uporabljena spremenljivka atribut, preverite GetAttributeAdapter attribute StringLengthAttribute MinimumLength lastnost, Če je nastavljeno, se prikaže sporočilo, ki upošteva tudi minimalno število številk in ErrorMessage zamenja .

Če ga zaženete, preverite in sporočilo se spremeni, je v redu.

Druga generična sporočila

Nekatera sporočila niso lokalizirana po tem, ko to storite do zdaj. Na primer sporočila, ki so določena samo v Javascriptu.

Cilj je sporočilo, jquery.validate.js ki je našteto v datoteki.

Ker te datoteke ne smete urejati neposredno, če želite ta sporočila nadomestiti z lokaliziranim besedilom, morate dodati atribut, kot je oznaki, in tam nastaviti input data-val-XXXX lokalizirano besedilo. XXXX del vsebuje ključ na zgornji jquery.validate.js sliki. (npr. data-val-number itd.)

data-val-XXXX Če želite lokalizirano besedilo nastaviti na atribute v

Lokalizirajmo sporočilo, ko so neštevilični znaki kot primer vključeni v vnosno polje »Starost«. ima UserViewModel.Age Range atribut, izhodni HTML pa data-val-range pripiše vhodni atribut.

<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>

Vendar sporočilo številčnega preverjanja ni lokalizirano, ker data-val-number atributa ni. Dodali boste še en atribut na strani modela, da natisnete tudi lokaliziran atribut dodanega data-val-number sporočila.

Prvi korak je ustvariti razred atributov, ki preveri, ali gre za IntAttribute številko: To je omejeno na tukaj, vendar lahko to spremenite glede int na situacijo. Kodna datoteka je lahko kjerkoli, tokrat pa je v mapi Adapter.

using System.ComponentModel.DataAnnotations;

namespace LocalizationDefaultValidation
{
  public class IntAttribute : ValidationAttribute
  {
    public override bool IsValid(object value)
    {
      // 渡された値が int であれば有効な値とする
      return value is int;
    }
  }
}

Če je nastavljena vrednost vrsta, je atribut, ki je le običajna razsodba, v praksi pa je 100% normalna, če je nastavljena na lastnost tipa int, zato obdelava samega tega razreda nima nobenega int smisla. Namen tega časa je prikazati lokalizirana sporočila o napakah v odjemalcu.

Nato ustvarite ta razred IntAttributeAdapter kartice: To je tudi v mapi Adapter.

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;
  }
}

Tukaj je točka AddValidation metoda, opisana v MergeAttribute metodi.

Spajanje atributov kot atributov vhodne oznake za vrnitev data-val-number v odjemalca. Vrednost, ki jo nastavite v atributu, nastavi lokalizirano sporočilo o napaki.

Vrnite ta adapter v razredu, ki ste ga prej CustomValidationAttributeAdapterProvider ustvarili.

// 省略

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);
      }

      // 省略 (前に追加したコード)
    }
  }
}

Če je vrednost za preverjanje veljavnosti , vrnite prej IntAttribute IntAttributeAdapter ustvarjeno vrednost. Lastnost z atributom Int se zdaj doda, ko je prikazana na strani data-val-number odjemalca.

Na koncu še UserViewModel.Age IntAttribute dodaj v .

Ko popravite kodo, jo poskusite preveriti, ali jo želite preveriti.

<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>

Obstajajo druga sporočila, ki niso lokalizirana, vendar jih lahko lokalizirate v zgoraj opisanih metodah. Dodaj kodo, ko jo potrebuješ.