Sisestus valideerimise ajal kuvatavate vaikesõnumite mitmekeelne tugi

Lehe loomise kuupäev :

keskkond

ASP.NET Core
  • 5,0 MVC

Alguses

Nende näpunäidetega sisendi valideerimise vaikesõnumite mitmekeelne tugi ei pruugi olla täielik. Palun tegelege kadunud inimestega.

Samuti võib keele muutmine sõltuvalt seansi olekust või vahemälu olekust siiski ilmuda eelmise keele tekstis.

Sisendi valideerimise vaikesõnumi muutmiseks on mitu võimalust, millest igaüks saab kombineerida. See ei ole üks neist, nii et kui soovite seda usaldusväärselt muuta, peate vastama kõigile mustritele.

Eeldus

Need näpunäited on kirjutatud järgmiste näpunäidete mõistmiseks:

Samuti, kui loote uut projekti, peate ülaltoodud näpunäidete põhjal lisama järgmised failid ja koodi.

  • Looge fail SharedResource.resx (+en, es). (Kuna tõlgitakse ainult selle näpunäite sõnum, võib sisu olla tühi.)
  • Ühiskasutamise.cs faili loomine
  • Lokaliseerimiskoodi lisamine rakendusse Startup.ConfigureServices
  • Lokaliseerimiskoodi lisamine rakendusse Startup.Configure
  • Lisatud UserViewModel (seekord ei võtme me vaikesõnumeid selgesõnaliselt mitmes keeles)
  • Lisatud kasutaja loodud ekraanitoimingud ja vaated (Create.cshtml)

Käivituskood

Ülaltoodud eelduste põhjal peab iga kood olema järgmine:

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

Mudeli siduvad sõnumid

Kui määrate mudeli int atribuudi tüübiks või seote selle DateTime vaatega ja proovite selle registreerida sisestamata, kuvatakse teade "Väärtus". Need sõnumid kuvatakse siis, kui tühja stringi int ei saa siduda näiteks mudeliga. Kuna see on ajastus, mida ei saa siduda, toimub see ainult enne muud väärtuse valideerimist ja serveripoolset töötlemist.

Need sõnumid on DefaultModelBindingMessageProvider määratletud kui .

Startup.cs Lisage meetodi argumendid, mis on rakenduses algusest peale services.AddControllersWithViews määratletud, ja seejärel lisage Action . Võite olla mitmekeelne, määrates options ModelBindingMessageProvider argumendis läbimise.

Saate määrata 11 tüüpi sõnumeid, nii et peate sõnumi esmalt määratlema järgmiselt. SharedResource.resx Võtme nimi on valikuline. Kommentaaride veeru ingliskeelne vaikesõnum on (kommentaare ei pea lisama). Te ei pea iga keelt tõlkima, seega peaksite tegema oma tõlke (näidiskood sisaldab ka tõlgitud SharedResource.resx).

Nime väärtuse kommentaar
ModelBinding_AttemptedValueIsInvalid "{0}" on {1} kehtetu väärtus. Väärtus "{0}" ei kehti {1} puhul.
ModelBinding_MissingBindRequiredValue {0} väärtust pole määratud. Parameetri "{0}" või atribuudi väärtust ei esitatud.
ModelBinding_MissingKeyOrValue Nõutav. Väärtus on vajalik.
ModelBinding_MissingRequestBodyRequiredValue Taotlusel peab olema organ. Vaja on mittetühja taotluse esitanud asutust.
ModelBinding_NonPropertyAttemptedValueIsInvalid "{0}" ei kehti. Väärtus "{0}" ei sobi.
ModelBinding_NonPropertyUnknownValueIsInvalid Väärtus ei sobi. Tarnitud väärtus on kehtetu.
ModelBinding_NonPropertyValueMustBeANumber Number peab olema määratud. Väli peab olema number.
ModelBinding_UnknownValueIsInvalid {0} väärtus ei sobi. Tarnitud väärtus on {0} jaoks kehtetu.
ModelBinding_ValueIsInvalid "{0}" ei kehti. Väärtus "{0}" on kehtetu.
ModelBinding_ValueMustBeANumber {0} peab olema number. Väli {0} peab olema number.
ModelBinding_ValueMustNotBeNull Nõutav sisend. Väärtus "{0}" on kehtetu.

Parandage käivitus.cs järgmiselt:

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

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

Võtmepunktiks on services.AddControllersWithViews lisada a meetodile, mis saab option Action , options.ModelBindingMessageProvider Määran lokaliseeritud teksti iga määramismeetodi jaoks.

Tõlgitud tekst IStringLocalizer on toodud . Otsest koodi ei ole võimalik IStringLocalizer saada, mis on natuke ümmargune kood. SharedResource.resx Kui genereerite koodi, saate lokaliseeritud väärtused otse sellest.

IStringLocalizer Võtmes, mille SharedResource.resx määrate, määrab võtme, mille lisasite . Seadke see nii, et see vastaks iga määratud meetodi sisule.

Samuti, kuna igal sõnumil on vormingustringi argument, näiteks , {0}{1} kasutan vastuvõetud väärtuste asendamiseks string.Format Func lihtsat.

Vaike valideerimisteadete lokaliseerimine

Vaikevea teade, kui Required mudeli atribuutide atribuudid on seatud väärtusele või nii, määrab raamistik ja see on StringLength põhimõtteliselt inglise keeles.

Neid saab IValidationAttributeAdapterProvider lokaliseerida, määratledes liidesest tuletatud klassi.

SharedResource.resxKõigepealt registreerige mitmekeelne tekst. Võtme nimi on meelevaldne, kuid programmi lihtsustamiseks registreerige see "Validator_< valideerimise atribuudi nime>" kujul.

Nime väärtuse kommentaar
Validator_CompareAttribute {0} ja {1} ei klapi. "{0}" ja "{1}" ei sobi kokku.
Validator_CreditCardAttribute {0} ei ole kehtiv kaardinumber. Väli {0} pole kehtiv krediitkaardi number.
Validator_DataTypeAttribute_Date Sisestage kehtiv kuupäev. Sisestage kehtiv kuupäev.
Validator_EmailAddressAttribute {0} ei ole kehtiv e-posti aadress. Väli {0} pole kehtiv meiliaadress.
Validator_FileExtensionsAttribute {0} aktsepteerib ainult järgmiste laiendustega faile. : {1} Väli {0} aktsepteerib ainult järgmiste laiendustega faile: {1}
Validator_MaxLengthAttribute {0} peab olema stringi- või massiivitüüp, mille maksimaalne pikkus on "{1}". Välja {0} peab olema stringi- või massiivitüüp, mille maksimaalne pikkus on "{1}".
Validator_MinLengthAttribute {0} peab olema string või massiivitüüp, mille minimaalne pikkus on "{1}". Välja {0} peab olema stringi- või massiivitüüp, mille minimaalne pikkus on "{1}".
Validator_PhoneAttribute {0} ei ole kehtiv telefoninumber. Väli {0} pole sobiv telefoninumber.
Validator_RangeAttribute {0} peab ulatuma {1} kuni {2}. Väli {0} peab olema {1} ja {2} vahel.
Validator_RegularExpressionAttribute {0} peab vastama tavalisele väljendile "{1}". väljal {0} peab vastama tavalisele avaldisele "{1}".
Validator_RequiredAttribute {0} on vajalik. Väli {0} on nõutav.
Validator_StringLengthAttribute {0} peab olema {1} numbri piires. Väli {0} peab olema string, mille maksimaalne pikkus on {1}.
Validator_UrlAttribute {0} ei ole kehtiv URL. Väli {0} pole kehtiv täielikult kvalifitseeritud HTTP-, https- või FTP URL.
Validator_StringLengthAttributeWithMin {0} peab olema vähemalt {2} {1} numbrit. Välja {0} peab olema string, mille maksimaalne pikkus on {1} ja minimaalne pikkus {2}.

Seejärel looge järgmine AdapterProvider klass.

Klassi nimi on meelevaldne, kuid seekord CustomValidationAttributeAdapterProvider kirjutan klassi, mida kutsutakse ja kirjutan koodi järgmiselt: Koodifaili asukoht on meelevaldne, kuid proov paigutatakse kausta nimega 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);
    }
  }
}

Kui määrate mudeli atribuudid või Required , on vaja meetodit iga StringLength IValidationAttributeAdapterProvider.GetAttributeAdapter valideerimise jaoks.

ErrorMessageResourceName Kui atribuut sisaldab väärtust, on mudeli poolel oleval koodil juba sõnumi- või lokaliseerimisvõti, nii et see naaseb nii, nagu see on.

Kui see on tühi, sobitage eesliidete ja valideerimisatribuudi klassinimed, et muuta see lokaliseerimisvõtmeks, ning seejärel tooge lokaliseeritud tekst võtmest ja seadke selle ErrorMessage väärtuseks . See võimaldab enamikku vaikesõnumeid lokaliseerida.

Seejärel registreerige see klass käivitamisel .cs. Põhimõtteliselt saate selle lisada järgmiselt.

// 省略

using Microsoft.AspNetCore.Mvc.DataAnnotations;

namespace LocalizationDefaultValidation
{
  public class Startup
  {
    // 省略

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

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

Käivitage see veendumaks, et see töötab korralikult.

Olemasoleva sõnumi muutmine parameetrite järgi

Näiteks StringLength atribuudisõnum on lokaliseeritud, näiteks "{0} peab olema {1} numbri piires". MinimumLength Kui atribuut on seatud, võite muuta {0} "Määrake {2} numbrit või rohkem {1} arvu numbrite piires".

Sellisel CustomValidationAttributeAdapterProvider juhul laiendage klassi järgmiselt:

// 省略

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

      // 省略
    }
  }
}

Kuna meetod on iga valideerimise jaoks, GetAttributeAdapter kui läbitud muutuja attribute oli StringLengthAttribute MinimumLength atribuut, kontrollige atribuuti, Kui see on seatud, saate sõnumi, mis võtab arvesse ka minimaalset arvu numbreid ja ErrorMessage asendab .

Kui käivitate selle, kontrollige ja sõnum muutub, on kõik korras.

Muud üldised sõnumid

Mõned sõnumid ei ole lokaliseeritud pärast seda, kui olete seda seni teinud. Näiteks sõnumid, mis määratakse ainult Javascriptis.

Sihtmärk on jquery.validate.js failis loetletud sõnum.

Kuna seda faili ei tohiks otse redigeerida, peate nende sõnumite asendamiseks lokaliseeritud tekstiga input lisama sildile sarnase atribuudi ja seadma data-val-XXXX seal lokaliseeritud teksti. XXXX osa sisaldab ülaltoodud joonise jquery.validate.js võtit. (nt data-val-number jne)

data-val-XXXX Lokaliseeritud teksti seadmiseks atribuutidele

Lokaliseerime sõnumi, kui näitena kaasatakse mittenumbrilised märgid sisestusväljale Vanus. UserViewModel.Age on Range atribuut ja väljund HTML data-val-range lisab sisendatribuudi.

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

Numbrilise kontrolli sõnumit ei lokaliseerita siiski, data-val-number kuna atribuuti pole. Lokaliseeritud sõnumiga lisatud atribuudi printimiseks lisate mudelipoolele veel ühe data-val-number atribuudi.

Esimene samm on luua atribuutklass, mis kontrollib, kas see IntAttribute on number: See piirdub siin, kuid teil on int vabadus seda sõltuvalt olukorrast muuta. Koodifail võib olla kõikjal, kuid seekord on see kaustas Adapter.

using System.ComponentModel.DataAnnotations;

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

Kui määratud väärtus on int tüüp, on see atribuut, mis on ainult tavaline otsus, kuid praktikas on see 100% normaalne, kui see on seatud int-tüüpi varale, nii et selle klassi töötlemine ei ole mõtet. Selle aja eesmärk on kuvada kliendis lokaliseeritud tõrketeated.

Seejärel looge järgmine IntAttributeAdapter adapteriklass. See on ka kaustas 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;
  }
}

Siinkohal on AddValidation meetodis kirjeldatud MergeAttribute meetod.

Atribuutide ühendamine sisendsildi atribuutidena data-val-number kliendile tagastamiseks. Atribuudis määratav väärtus määrab lokaliseeritud tõrketeate.

Tagastage see adapter varem loodud CustomValidationAttributeAdapterProvider klassis.

// 省略

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

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

Kui valideerimise väärtus IntAttribute on , tagastage varem loodud IntAttributeAdapter väärtus. Atribuut int lisatakse nüüd, kui see kuvatakse kliendi data-val-number poolel.

Lõpuks UserViewModel.Age IntAttribute lisage .

Kui olete oma koodi parandanud, proovige seda, et näha, kas soovite seda kontrollida.

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

On ka teisi lokaliseerimata sõnumeid, kuid neid saate lokaliseerida ülalkirjeldatud meetodites. Lisage kood, kui seda vajate.