इनपुट सत्यापन के दौरान प्रदर्शित डिफ़ॉल्ट संदेशों के लिए बहुभाषी समर्थन

पेज निर्माण की तारीख :

पर्यावरण

ASP.NET कोर
  • 5.0 एमवीसी

पहले

इस टिप्स के साथ डिफ़ॉल्ट इनपुट सत्यापन संदेशों का बहुभाषी समर्थन पूरा नहीं हो सकता है। कृपया लापता लोगों से निपटें।

इसके अलावा, सत्र राज्य या कैश राज्य के आधार पर भाषा को बदलना अभी भी पिछली भाषा से पाठ में दिखाई दे सकता है।

डिफ़ॉल्ट इनपुट सत्यापन संदेश को बदलने के कई तरीके हैं, जिनमें से प्रत्येक को जोड़ा जा सकता है। यह उनमें से एक नहीं है, इसलिए यदि आप इसे मज़बूती से बदलना चाहते हैं, तो आपको सभी पैटर्न के अनुरूप होना चाहिए।

प्राक्कल्पना

इस टिप्स को निम्नलिखित सुझावों को समझने के रूप में लिखा गया है:

इसके अलावा, यदि आप एक नया प्रोजेक्ट बना रहे हैं, तो आपने ऊपर दिए गए सुझावों के आधार पर निम्नलिखित फ़ाइलों और कोड को जोड़ना होगा।

  • एक हैंडेरेसोर्स.resx (+en, es) फ़ाइल बनाएं। (चूंकि केवल इस टिप्स के संदेश का अनुवाद किया जाता है, इसलिए सामग्री खाली हो सकती है।
  • एक शेयर्डरिसोर्स.cs फ़ाइल बनाएं
  • Startup.ConfigureServices में स्थानीयकरण कोड जोड़ें
  • Startup.कॉन्फ़िगर में स्थानीयकरण कोड जोड़ें
  • जोड़ा गया UserViewModel (इस बार, हम स्पष्ट रूप से कई भाषाओं में डिफ़ॉल्ट संदेशों को महत्वपूर्ण नहीं करते हैं)
  • जोड़ा गया उपयोगकर्ता-निर्मित स्क्रीन क्रियाएं और दृश्य (Create.cshtml)

कोड शुरू करना

उपरोक्त मान्यताओं के आधार पर, प्रत्येक कोड इस प्रकार होगा:

स्टार्टअप.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();

      // 省略
    }
  }
}
होमकंट्रोलर.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()));
  }
}
इंडेक्स.सीसैटएमएल
@{
  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>
बनाएं.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");}
}
उपयोगकर्ताव्यूमॉडल.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,
  }
}
शेयर्डरिसोर्स.cs
namespace LocalizationDefaultValidation
{
  // クラス名は作成した .resx のファイル名と同じにする必要がある
  public class SharedResource { }
}

मॉडल बाध्यकारी संदेश

यदि आप मॉडल संपत्ति प्रकार को सेट करते हैं int या उसे देखने के लिए बाध्य DateTime करते हैं, और इसे बिना टाइप करने की कोशिश करते हैं, तो आपको "मूल्य' अमान्य है" जैसे संदेश दिखाई देंगे। ये संदेश तब दिखाई देते हैं जब मॉडल में एक खाली स्ट्रिंग int को बाध्य नहीं किया जा सकता है। क्योंकि यह एक समय है कि बाध्य नहीं किया जा सकता है, यह केवल अन्य मूल्य सत्यापन और सर्वर साइड प्रसंस्करण से पहले होता है।

इन संदेशों को DefaultModelBindingMessageProvider परिभाषित किया गया है ।

Startup.cs शुरू से ही परिभाषित की गई विधि के तर्कों को जोड़ें services.AddControllersWithViews और फिर जोड़ें Action । आप तर्क में पारित की स्थापना के द्वारा बहुभाषी हो सकता options ModelBindingMessageProvider है ।

11 प्रकार के संदेश हैं जिन्हें आप सेट कर सकते हैं, इसलिए आपको सबसे पहले संदेश को निम्नानुसार परिभाषित करना होगा: SharedResource.resx कुंजी का नाम वैकल्पिक है। टिप्पणियों कॉलम में डिफ़ॉल्ट अंग्रेजी संदेश है (टिप्पणियां शामिल करने की ललक नहीं है) । आपको प्रत्येक भाषा का अनुवाद नहीं करना होगा, इसलिए आपको अपना अनुवाद करना चाहिए (नमूना कोड में अनुवादित हैंकंप्रायरोर्स.resx)।

नाम मूल्य टिप्पणी
ModelBinding_AttemptedValueIsInvalid {1} में '{0}' एक अमान्य मूल्य है। मूल्य '{0}' {1} के लिए मान्य नहीं है।
ModelBinding_MissingBindRequiredValue {0} के लिए मूल्य निर्दिष्ट नहीं है। '{0}' पैरामीटर या संपत्ति के लिए एक मूल्य प्रदान नहीं किया गया था।
ModelBinding_MissingKeyOrValue आवश्यक। एक मूल्य की आवश्यकता है।
ModelBinding_MissingRequestBodyRequiredValue अनुरोध में एक शरीर होना चाहिए। एक गैर-खाली अनुरोध निकाय की आवश्यकता होती है।
ModelBinding_NonPropertyAttemptedValueIsInvalid '{0}' मान्य नहीं है। मूल्य '{0}' मान्य नहीं है।
ModelBinding_NonPropertyUnknownValueIsInvalid मूल्य मान्य नहीं है। आपूर्ति मूल्य अमान्य है।
ModelBinding_NonPropertyValueMustBeANumber संख्या निर्दिष्ट की जानी चाहिए। मैदान एक नंबर होना चाहिए।
ModelBinding_UnknownValueIsInvalid {0} का मूल्य मान्य नहीं है। आपूर्ति मूल्य {0} के लिए अमान्य है।
ModelBinding_ValueIsInvalid '{0}' मान्य नहीं है। मूल्य '{0}' अमान्य है।
ModelBinding_ValueMustBeANumber {0} एक नंबर होना चाहिए । फील्ड {0} एक नंबर होना चाहिए।
ModelBinding_ValueMustNotBeNull आवश्यक इनपुट। मूल्य '{0}' अमान्य है।

स्टार्टअप को ठीक करें.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 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
      });

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

मुख्य बिंदु उस विधि में जोड़ना है services.AddControllersWithViews जो प्राप्त करता option Action है, options.ModelBindingMessageProvider मैं प्रत्येक सेट विधि के लिए स्थानीयकृत पाठ सेट कर रहा हूं।

अनुवादित पाठ IStringLocalizer से प्राप्त किया जाता है । प्रत्यक्ष कोड प्राप्त करने का कोई तरीका नहीं IStringLocalizer है, जो एक गोल कोड का एक सा है। SharedResource.resx अगर आप कोड जेनरेट कर रहे हैं, तो आपको उससे सीधे स्थानीयकृत मान मिलेंगे.

IStringLocalizer आपके द्वारा निर्दिष्ट की गई कुंजी उस SharedResource.resx कुंजी को निर्दिष्ट करती है जिसे आपने जोड़ा था । इसे प्रत्येक सेट विधि की सामग्री से मेल खाने के लिए सेट करें।

इसके अलावा, क्योंकि प्रत्येक संदेश में एक प्रारूप स्ट्रिंग तर्क होता है, जैसे, मैं सरल का उपयोग करता हूं {0}{1} ताकि आप प्राप्त मूल्यों को बदल string.Format Func सकें।

डिफ़ॉल्ट सत्यापन संदेशों को स्थानीयकृत करें

डिफ़ॉल्ट त्रुटि संदेश जब किसी मॉडल के गुणों के गुण निर्धारित किए Required जाते हैं तो यह ढांचे द्वारा निर्धारित किया जाता है और StringLength मूल रूप से अंग्रेजी में होता है।

IValidationAttributeAdapterProviderइंटरफ़ेस से प्राप्त वर्ग को परिभाषित करके इन्हें स्थानीयकृत किया जा सकता है।

सबसे SharedResource.resx पहले, बहुभाषी पाठ को पंजीकृत करें। कुंजी का नाम मनमाना है, लेकिन कार्यक्रम को सरल बनाने के लिए, इसे "Validator_< सत्यापन विशेषता नाम>" के रूप में पंजीकृत करें।

नाम मूल्य टिप्पणी
Validator_CompareAttribute {0} और {1} मैच नहीं करते। '{0}' और '{1}' मैच नहीं करते।
Validator_CreditCardAttribute {0} वैध कार्ड नंबर नहीं है। {0} फ़ील्ड वैध क्रेडिट कार्ड नंबर नहीं है।
Validator_DataTypeAttribute_Date एक वैध तिथि दर्ज करें। कृपया एक वैध तिथि दर्ज करें।
Validator_EmailAddressAttribute {0} एक वैध ईमेल पता नहीं है। {0} क्षेत्र एक वैध ई-मेल पता नहीं है।
Validator_FileExtensionsAttribute {0} केवल निम्नलिखित एक्सटेंशन वाली फ़ाइलों को स्वीकार करता है: : {1} {0} फ़ील्ड केवल निम्नलिखित एक्सटेंशन वाली फ़ाइलों को स्वीकार करता है: {1}
Validator_MaxLengthAttribute {0} एक स्ट्रिंग या सरणी प्रकार होना चाहिए जिसमें अधिकतम लंबाई '{1}' हो। {0} क्षेत्र एक स्ट्रिंग या सरणी प्रकार होना चाहिए जिसमें अधिकतम लंबाई '{1}' हो।
Validator_MinLengthAttribute {0} एक स्ट्रिंग या सरणी प्रकार होना चाहिए जिसमें न्यूनतम लंबाई '{1}' हो। {0} क्षेत्र '{1}' की न्यूनतम लंबाई के साथ एक स्ट्रिंग या सरणी प्रकार होना चाहिए।
Validator_PhoneAttribute {0} एक वैध फोन नंबर नहीं है। {0} फ़ील्ड वैध फ़ोन नंबर नहीं है।
Validator_RangeAttribute {0} {1} से लेकर {2} तक होना चाहिए । फील्ड {0} {1} और {2} के बीच होना चाहिए ।
Validator_RegularExpressionAttribute {0} नियमित अभिव्यक्ति '{1}' मैच होना चाहिए। {0} क्षेत्र को नियमित अभिव्यक्ति '{1}' से मेल खाने चाहिए।
Validator_RequiredAttribute {0} की आवश्यकता है। {0} फील्ड की जरूरत है।
Validator_StringLengthAttribute {0} {1} अंकों के भीतर होना चाहिए। क्षेत्र {0} {1} की अधिकतम लंबाई के साथ एक स्ट्रिंग होना चाहिए।
Validator_UrlAttribute {0} एक वैध यूआरएल नहीं है। {0} फ़ील्ड पूरी तरह से योग्य http, https, या FTP URL नहीं है।
Validator_StringLengthAttributeWithMin {0} कम से कम {2} {1} अंक होने चाहिए। क्षेत्र {0} {1} की अधिकतम लंबाई और {2} की एक न्यूनतम लंबाई के साथ एक स्ट्रिंग होना चाहिए ।

इसके बाद, निम्नलिखित एडाप्टर प्रोविडर क्लास बनाएं:

वर्ग का नाम मनमाना है, लेकिन इस बार CustomValidationAttributeAdapterProvider मैं एक वर्ग लिखूंगा और कोड को इस प्रकार लिखूंगा: कोड फाइल का स्थान मनमाना है, लेकिन नमूना एडाप्टर नामक फ़ोल्डर में रखा गया है।

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

यदि आप मॉडल के गुणों को या सेट करते Required हैं, तो विधि को हर सत्यापन के लिए कहा StringLength IValidationAttributeAdapterProvider.GetAttributeAdapter जाता है।

ErrorMessageResourceName यदि संपत्ति में एक मूल्य होता है, तो मॉडल पक्ष के कोड में पहले से ही एक संदेश या स्थानीयकरण कुंजी है, इसलिए यह उतना ही रिटर्न देता है।

यदि खाली है, तो इसे स्थानीयकरण कुंजी बनाने के लिए उपसर्ग और सत्यापन विशेषता के वर्ग के नामों से मेल खाते हैं, और फिर स्थानीयकृत पाठ को कुंजी से पुनः प्राप्त करें और इसे सेट ErrorMessage करें। इससे अधिकांश डिफ़ॉल्ट संदेशों को स्थानीयकृत किया जा सकता है।

इसके बाद, स्टार्टअप .cs में इस वर्ग को पंजीकृत करें। असल में, आप इसे इस प्रकार जोड़ सकते हैं।

// 省略

using Microsoft.AspNetCore.Mvc.DataAnnotations;

namespace LocalizationDefaultValidation
{
  public class Startup
  {
    // 省略

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

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

यह सुनिश्चित करने के लिए इसे चलाने के लिए यह ठीक से काम कर रहा है ।

मापदंडों के अनुसार एक मौजूदा संदेश बदलें

उदाहरण के लिए, StringLength विशेषता संदेश को स्थानीयकृत किया जाता है, जैसे कि "{0} {1} अंकों के भीतर होना चाहिए। MinimumLength यदि संपत्ति सेट की गई है, तो आप {0} को "कई अंकों के भीतर {2} अंक या अधिक {1} निर्दिष्ट" के रूप में बदलना चाह सकते हैं।

उस CustomValidationAttributeAdapterProvider मामले में, इस प्रकार वर्ग का विस्तार करें:

// 省略

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

      // 省略
    }
  }
}

क्योंकि विधि प्रत्येक सत्यापन के लिए कहा GetAttributeAdapter जाता है, अगर वेरिएबल पारित attribute एक विशेषता StringLengthAttribute MinimumLength थी, संपत्ति की जांच करें, यदि सेट किया जाता है, तो एक संदेश प्राप्त करें जो अंकों की न्यूनतम संख्या को भी ध्यान में रखता है और ErrorMessage बदलता है।

यदि आप इसे चलाते हैं, जांच करें और संदेश बदलता है, तो यह ठीक है।

अन्य जेनेरिक संदेश

अब तक आपके द्वारा किए जाने के बाद कुछ संदेशों को स्थानीयकृत नहीं किया जाता है। उदाहरण के लिए, ऐसे संदेश जो केवल जावास्क्रिप्ट में निर्धारित होते हैं।

लक्ष्य jquery.validate.js फ़ाइल में सूचीबद्ध संदेश है।

चूंकि इस फ़ाइल को सीधे संपादित नहीं किया जाना चाहिए, इसलिए इन संदेशों को स्थानीयकृत पाठ से बदलने के लिए, आपको input टैग की तरह एक विशेषता जोड़नी होगी और वहां स्थानीयकृत पाठ सेट करना data-val-XXXX होगा। XXXX भाग में ऊपर के आंकड़े में कुंजी शामिल jquery.validate.js है। (जैसे data-val-number आदि)

data-val-XXXX <ए0/एंड ए में विशेषताओं के लिए स्थानीयकृत पाठ सेट करने के लिए, सर्वर की ओर एचटीएमएल लौटते समय इसे सेट करना ठीक है।

जब गैर-संख्यात्मक पात्रों को एक उदाहरण के रूप में आयु इनपुट फ़ील्ड में शामिल किया जाता है तो संदेश को स्थानीयकृत करें। UserViewModel.Age Range एक विशेषता है, और आउटपुट एचटीएमएल data-val-range इनपुट विशेषता को संलग्न करता है।

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

हालांकि, data-val-number संख्यात्मक जांच संदेश स्थानीयकृत नहीं है क्योंकि कोई विशेषता नहीं है। आप स्थानीय संदेश-वर्धित विशेषता को भी मुद्रित करने के लिए मॉडल पक्ष पर एक और विशेषता जोड़ data-val-number देंगे।

पहला कदम एक विशेषता वर्ग बनाना है जो यह जांचता है कि क्या यह IntAttribute एक नंबर है: यह यहां तक सीमित है, लेकिन आप int स्थिति के आधार पर इसे बदलने के लिए स्वतंत्र हैं। कोड फ़ाइल कहीं भी हो सकती है, लेकिन इस बार यह एडाप्टर फ़ोल्डर में है।

using System.ComponentModel.DataAnnotations;

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

यदि सेट मूल्य int एक प्रकार है, तो यह एक विशेषता है जो केवल एक सामान्य निर्णय है, लेकिन व्यवहार में यह टाइप इंस्टीट की संपत्ति पर सेट होने पर 100% सामान्य है, इसलिए इस वर्ग की प्रसंस्करण का कोई मतलब नहीं है। इस समय का उद्देश्य ग्राहक में स्थानीयकृत त्रुटि संदेश प्रदर्शित करना है।

इसके बाद, निम्नलिखित एडाप्टर IntAttributeAdapter क्लास बनाएं: यह एडाप्टर फोल्डर में भी है।

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

यहां बिंदु AddValidation विधि में वर्णित विधि MergeAttribute है।

क्लाइंट को लौटने के लिए इनपुट टैग के गुणों के रूप data-val-number में गुणों को मिलाना। विशेषता में सेट करने का मूल्य स्थानीयकृत त्रुटि संदेश सेट करता है।

इस एडाप्टर को आपके द्वारा पहले बनाई गई कक्षा में वापस CustomValidationAttributeAdapterProvider करें।

// 省略

namespace LocalizationDefaultValidation
{
  public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
  {
    // 省略
    
    IAttributeAdapter IValidationAttributeAdapterProvider.GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
    {
      // IntAttribute の場合は IntAttributeAdapter 経由で返す
      if (attribute is IntAttribute intAttribute)
      {
        return new IntAttributeAdapter(intAttribute, stringLocalizer);
      }

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

यदि मान्य करने के लिए मूल्य IntAttribute है, तो आप पहले बनाया है कि वापस IntAttributeAdapter । आईएनटी विशेषता के साथ संपत्ति अब जोड़ा जाता है जब यह ग्राहक पक्ष पर प्रदर्शित होता data-val-number है।

अंत में, UserViewModel.Age IntAttribute जोड़ें।

एक बार जब आप अपना कोड तय कर लेते हैं, तो यह देखने के लिए प्रयास करें कि क्या आप इसे देखना चाहते हैं।

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

अन्य गैर-स्थानीयकृत संदेश हैं, लेकिन आप उन्हें ऊपर वर्णित तरीकों में स्थानीयकरण कर सकते हैं। जरूरत पड़ने पर कोड डालें।