Daudzvalodu atbalsts noklusējuma ziņojumiem, kas tiek parādīti ievades validācijas laikā

Lapas izveides datums :

vide

ASP.NET kodols
  • 5.0 MVC

Sākumā

Noklusējuma ievades validācijas ziņojumu daudzvalodu atbalsts ar šiem padomiem var nebūt pabeigts. Lūdzu, nodarbojieties ar trūkstošajiem.

Arī valodas maiņa atkarībā no sesijas stāvokļa vai kešatmiņas stāvokļa joprojām var tikt parādīta iepriekšējās valodas tekstā.

Ir vairāki veidi, kā mainīt noklusējuma ievades validācijas ziņojumu, no kuriem katru var kombinēt. Tas nav viens no tiem, tāpēc, ja vēlaties to droši mainīt, jums jāatbilst visiem modeļiem.

Premisu

Šie padomi ir rakstīti kā izpratne par šādiem padomiem:

Turklāt, ja veidojat jaunu projektu, ir jāpievieno šādi faili un kods, pamatojoties uz iepriekš minētajiem padomiem.

  • Izveidojiet SharedResource.resx (+en, es) failu. (Tā kā tiek tulkots tikai šī padomu ziņojums, saturs var būt tukšs.)
  • SharedResource.cs faila izveide
  • Lokalizācijas koda pievienošana startēšanai.ConfigureServices
  • Pievienot lokalizācijas kodu startēšanai.Konfigurēt
  • Pievienots UserViewModel (šoreiz mēs skaidri nenoraisām noklusējuma ziņojumus vairākās valodās)
  • Pievienotās lietotāja izveidotās ekrāna darbības un skati (Create.cshtml)

Sākuma kods

Pamatojoties uz iepriekš minētajiem pieņēmumiem, katrs kods ir šāds:

Startēšana.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();

      // 省略
    }
  }
}
SākumsKontrollers.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 { }
}

Saistošo ziņojumu paraugs

Ja iestatāt modeļa rekvizīta tipu int uz skatu vai saistāt to ar to DateTime un mēģināt to reģistrēt bezraksta, tiks parādīts ziņojums, piemēram, "Vērtība '' nav derīga". Šie ziņojumi tiek parādīti, ja tukšu virkni int nevar saistīt, piemēram, modelī. Tā kā tas ir laiks, ko nevar saistīt, tas notiek tikai pirms citas vērtības validācijas un servera puses apstrādes.

Šie ziņojumi tiek DefaultModelBindingMessageProvider definēti kā .

Startup.cs Pievienojiet metodes argumentiem, kas definēti kopš sākuma services.AddControllersWithViews programmā , un pēc tam pievienojiet Action . Jūs varat būt daudzvalodīgs, iestatot options ModelBindingMessageProvider argumentu nodoto.

Ir 11 ziņojumu tipi, kurus var iestatīt, tāpēc vispirms ziņojums ir jādefinē šādi: SharedResource.resx Atslēgas nosaukums nav obligāts. Noklusējuma ziņojums angļu valodā komentāru slejā ir (komentāri nav jāiekļauj). Jums nebūs jātulko katra valoda, tāpēc jums vajadzētu veikt savu tulkojumu (koda paraugā ir iekļauts arī tulkotais SharedResource.resx).

Nosaukuma vērtības komentārs
ModelBinding_AttemptedValueIsInvalid "{0}" ir nederīga {1} vērtība. Vērtība "{0}" nav derīga {1}.
ModelBinding_MissingBindRequiredValue Nav norādīta {0} vērtība. Parametra vai rekvizīta "{0}" vērtība netika norādīta.
ModelBinding_MissingKeyOrValue Nepieciešams. Nepieciešama vērtība.
ModelBinding_MissingRequestBodyRequiredValue Pieprasījumam jābūt iestādei. Ir nepieciešama pieprasījuma struktūra, kas nav tukša.
ModelBinding_NonPropertyAttemptedValueIsInvalid "{0}" nav derīgs. Vērtība "{0}" nav derīga.
ModelBinding_NonPropertyUnknownValueIsInvalid Vērtība nav derīga. Norādītā vērtība nav derīga.
ModelBinding_NonPropertyValueMustBeANumber Jānorāda numurs. Laukam ir jābūt skaitlim.
ModelBinding_UnknownValueIsInvalid {0} vērtība nav derīga. Norādītā vērtība nav derīga {0}.
ModelBinding_ValueIsInvalid "{0}" nav derīgs. Vērtība "{0}" nav derīga.
ModelBinding_ValueMustBeANumber {0} jābūt skaitlim. Lauka {0} jābūt skaitlim.
ModelBinding_ValueMustNotBeNull Nepieciešamā ievade. Vērtība "{0}" nav derīga.

Novērsiet startēšanu.cs šādi:

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

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

Galvenais ir services.AddControllersWithViews pievienot metodi, kas saņem option Action , options.ModelBindingMessageProvider Katrai kopas metodei programmā tiek iestatīts lokalizēts teksts.

Tulkotais teksts tiek IStringLocalizer izgūts no . Nav iespējams saņemt tiešo IStringLocalizer kodu, kas ir mazliet apaļš kods. SharedResource.resx Ja ģenerējat kodu, jūs iegūsit lokalizētas vērtības tieši no tā.

IStringLocalizer Programmā norādītā atslēga SharedResource.resx norāda atslēgu, kuru pievienojāt programmā . Iestatiet to atbilstoši katras kopas metodes saturam.

Turklāt, tā kā katram ziņojumam ir formāta virknes arguments, piemēram, , es {0}{1} izmantoju Vienkārši ar, lai varētu aizstāt saņemtās string.Format Func vērtības.

Noklusējuma validācijas ziņojumu lokalizācija

Noklusējuma kļūdas ziņojumu, kad Required modeļa rekvizītu atribūti ir iestatīti uz vai tā, nosaka sistēma, un būtībā tas ir StringLength angļu valodā.

Tos var IValidationAttributeAdapterProvider lokalizēt, definējot klasi, kas atvasināta no interfeisa.

SharedResource.resxPirmkārt, reģistrējiet daudzvalodu tekstu. Atslēgas nosaukums ir patvaļīgs, bet, lai vienkāršotu programmu, reģistrējiet to kā "Validator_< validācijas atribūta nosaukumu>".

Nosaukuma vērtības komentārs
Validator_CompareAttribute {0} un {1} nesakrīt. "{0}" un "{1}" nesakrīt.
Validator_CreditCardAttribute {0} nav derīgs kartes numurs. Lauks {0} nav derīgs kredītkartes numurs.
Validator_DataTypeAttribute_Date Ievadiet derīgu datumu. Lūdzu, ievadiet derīgu datumu.
Validator_EmailAddressAttribute {0} nav derīga e-pasta adrese. Lauks {0} nav derīga e-pasta adrese.
Validator_FileExtensionsAttribute {0} pieņem tikai failus ar šādiem paplašinājumiem: : {1} Lauks {0} pieņem tikai failus ar šādiem paplašinājumiem: {1}
Validator_MaxLengthAttribute {0} jābūt virknei vai masīva tipam ar maksimālo garumu "{1}". Lauka {0} jābūt virknei vai masīva tipam ar maksimālo garumu "{1}".
Validator_MinLengthAttribute {0} jābūt virknei vai masīva tipam ar minimālo garumu "{1}". Lauka {0} jābūt virknei vai masīva tipam ar minimālo garumu "{1}".
Validator_PhoneAttribute {0} nav derīgs tālruņa numurs. Lauks {0} nav derīgs tālruņa numurs.
Validator_RangeAttribute {0} jābūt no {1} līdz {2}. Lauka {0} jābūt no {1} līdz {2}.
Validator_RegularExpressionAttribute {0} jāatbilst regulārajai izteiksmei "{1}". Lauku {0} jāatbilst regulārajai izteiksmei "{1}".
Validator_RequiredAttribute {0} ir nepieciešams. Ir nepieciešams lauks {0}.
Validator_StringLengthAttribute {0} jābūt {1} ciparu robežās. Lauka {0} jābūt virknei ar maksimālo garumu {1}.
Validator_UrlAttribute {0} nav derīgs URL. Lauks {0} nav derīgs pilnībā kvalificēts http, https vai ftp URL.
Validator_StringLengthAttributeWithMin {0} jābūt vismaz {2} {1} cipariem. Lauka {0} jābūt virknei ar maksimālo garumu {1} un minimālo {2} garumu.

Pēc tam izveidojiet šādu AdapterProvider klasi:

Klases nosaukums ir patvaļīgs, bet šoreiz CustomValidationAttributeAdapterProvider es uzrakstīšu klasi ar nosaukumu un uzrakstīšu kodu šādi: Koda faila atrašanās vieta ir patvaļīga, bet paraugs tiek ievietots mapē ar nosaukumu Adapteris.

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

Ja iestatāt modeļa rekvizītus uz Required vai , metode tiek izsaukta katrai StringLength IValidationAttributeAdapterProvider.GetAttributeAdapter validācijai.

ErrorMessageResourceName Ja rekvizītā ir vērtība, modeļa puses kodam jau ir ziņojuma vai lokalizācijas atslēga, tāpēc tas atgriežas tāds, kāds tas ir.

Ja tas ir tukšs, saskaņojiet prefiksa un validācijas atribūta klašu nosaukumus, lai padarītu to par lokalizācijas atslēgu, un pēc tam izgūstiet lokalizēto tekstu no atslēgas un iestatiet to ErrorMessage uz . Tas ļauj lokalizēt lielāko daļu noklusējuma ziņojumu.

Pēc tam reģistrējiet šo klasi startēšanas .cs. Būtībā to var pievienot šādi.

// 省略

using Microsoft.AspNetCore.Mvc.DataAnnotations;

namespace LocalizationDefaultValidation
{
  public class Startup
  {
    // 省略

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

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

Palaidiet to, lai pārliecinātos, ka tas darbojas pareizi.

Esoša ziņojuma mainīšana pēc parametriem

Piemēram, StringLength atribūta ziņojums ir lokalizēts, piemēram, "{0} jābūt {1} ciparu robežās." MinimumLength Ja rekvizīts ir iestatīts, iespējams, vēlēsities mainīt {0} kā "Norādīt {2} ciparus vai vairāk {1} ciparu skaitā".

Tādā CustomValidationAttributeAdapterProvider gadījumā paplašināt kategoriju šādi:

// 省略

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

      // 省略
    }
  }
}

Tā kā metode tiek izsaukta katrai GetAttributeAdapter validācijai, ja nodotais mainīgais attribute bija StringLengthAttribute MinimumLength atribūts, pārbaudiet rekvizītu, Ja ir iestatīts, iegūstiet ziņojumu, kurā ņemts vērā arī minimālais ciparu skaits un ErrorMessage tiek aizstāts .

Ja to palaižat, pārbaudiet un ziņojums mainās, viss ir kārtībā.

Citi vispārīgi ziņojumi

Daži ziņojumi netiek lokalizēti pēc tam, kad esat to jisijis līdz šim. Piemēram, ziņojumi, kas tiek noteikti tikai Javascriptā.

Mērķis ir jquery.validate.js failā norādītais ziņojums.

Tā kā šo failu nedrīkst rediģēt tieši, lai aizstātu šos ziņojumus ar lokalizētu tekstu, input tagam jāpievieno atribūts, piemēram, un data-val-XXXX jāiestata lokalizēts teksts. XXXX daļā ir jquery.validate.js atslēga iepriekš redzamajā attēlā. (piemēram, data-val-number u. c.)

data-val-XXXX Lai iestatītu lokalizētu tekstu atribūtiem

Lokalizēt ziņojumu, ja kā piemērs vecuma ievades laukā ir iekļautas rakstzīmes, kas nav skaitliskas. UserViewModel.Age ir Range atribūts, un data-val-range izvades HTML pievieno ievades atribūtu.

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

Tomēr data-val-number skaitliskās pārbaudes ziņojums nav lokalizēts, jo atribūta nav. Modeļa pusē tiks pievienots vēl viens atribūts, lai drukātu arī lokalizēto ziņojumu pievienoto data-val-number atribūtu.

Pirmais solis ir izveidot atribūtu klasi, kas pārbauda, vai tas ir IntAttribute skaitlis: Tas aprobežojas ar šeit, bet jūs int varat to mainīt atkarībā no situācijas. Koda fails var būt jebkurā vietā, bet šoreiz tas atrodas mapē Adapteris.

using System.ComponentModel.DataAnnotations;

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

Ja iestatītā vērtība ir int veids, tas ir atribūts, kas ir tikai parasts spriedums, bet praksē tas ir 100% normāls, ja tas ir iestatīts uz int tipa īpašību, tāpēc šīs klases apstrādei nav nekādas jēgas. Šī laika mērķis ir parādīt lokalizētus kļūdu ziņojumus klientā.

Pēc tam izveidojiet šādu adaptera IntAttributeAdapter klasi: Tas ir arī adaptera mapē.

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

Šeit ir AddValidation metode, kas aprakstīta MergeAttribute metodē.

Atribūtu sapludināšana kā ievades taga atribūti, data-val-number lai atgrieztos klientā. Atribūtā iestatāmā vērtība iestata lokalizētu kļūdas ziņojumu.

Atgrieziet šo adapteri iepriekš izveidotajā CustomValidationAttributeAdapterProvider klasē.

// 省略

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

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

Ja validamā vērtība IntAttribute ir , atgrieziet IntAttributeAdapter iepriekš izveidoto. Rekvizīts ar int atribūtu tagad tiek pievienots, kad tas tiek parādīts klienta data-val-number pusē.

Visbeidzot, UserViewModel.Age IntAttribute papildiniet .

Kad esat nofiksējis kodu, izmēģiniet to, lai redzētu, vai vēlaties to paņemt.

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

Ir arī citi nelokalizēti ziņojumi, bet tos var lokalizēt iepriekš aprakstītajās metodēs. Pievienojiet kodu, kad tas ir nepieciešams.