ان پٹ توثیق کے دوران دکھائے گئے طے شدہ پیغامات کے لیے کثیر لسانی معاونت

صفحہ تخلیق تاریخ :

ماحول

ASP.NET کور
  • 5.0 ایم وی سی

پہلے تو

اس تجاویز کے ساتھ طے شدہ ان پٹ توثیق پیغامات کی کثیر لسانی معاونت مکمل نہیں ہوسکتی ہے۔ براہ کرم لاپتہ افراد سے نمٹیں۔

اس کے علاوہ، سیشن ریاست یا کیشے ریاست پر منحصر زبان تبدیل کرنا اب بھی پچھلی زبان سے متن میں ظاہر ہوسکتا ہے۔

طے شدہ ان پٹ توثیق پیغام کو تبدیل کرنے کے کئی طریقے ہیں، جن میں سے ہر ایک کو یکجا کیا جاسکتا ہے۔ یہ ان میں سے ایک نہیں ہے، لہذا اگر آپ اسے قابل اعتماد طور پر تبدیل کرنا چاہتے ہیں، تو آپ کو تمام نمونوں کے ساتھ مطابقت رکھنے کی ضرورت ہے۔

بنیاد

یہ تجاویز مندرجہ ذیل تجاویز کو سمجھنے کے طور پر لکھی گئی ہیں:

اس کے علاوہ، اگر آپ کوئی نیا پروجیکٹ بنا رہے ہیں، تو آپ نے مندرجہ ذیل فائلوں اور کوڈ کو اوپر کی تجاویز کی بنیاد پر شامل کیا ہوگا۔

  • ایک مشترکہ وسیلہ.راسکس (+این، ایس) مسل بنائیں۔ (چونکہ صرف اس تجاویز کے پیغام کا ترجمہ کیا جاتا ہے، اس لیے مشمولات خالی ہو سکتے ہیں۔)
  • مشترکہ وسیلہ بنائیں.cs مسل
  • اسٹارٹ اپ میں مقامیت کوڈ شامل کریں۔تشکیل خدمات
  • شروع میں مقامیت کوڈ شامل کریں۔تشکیل کریں
  • اضافی صارف منظر نمونہ (اس بار، ہم واضح طور پر متعدد زبانوں میں طے شدہ پیغامات کی کلید نہیں کرتے)
  • صارف کی تخلیق کردہ سکرین عمل اور مناظر شامل کریں (تخلیق.سی ایس ایچ ٹی ایم)

کوڈ شروع کر رہا ہے

مندرجہ بالا مفروضوں کی بنیاد پر، ہر ضابطہ درج ذیل ہوگا:

اسٹارٹ اپ.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>
تخلیق کریں.سی ایس ایچ ٹی ایم ایل
@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 کلید کا نام اختیاری ہے۔ تبصروں کے کالم میں طے شدہ انگریزی پیغام یہ ہے (تبصروں کو شامل کرنے کی ضرورت نہیں ہے)۔ آپ کو ہر زبان کا ترجمہ نہیں کرنا پڑے گا، لہذا آپ کو اپنا ترجمہ کرنا چاہئے (نمونہ کوڈ میں ترجمہ شدہ مشترکہ وسائل.ریسکس بھی شامل ہے)۔

نام قدر تبصرہ
ModelBinding_AttemptedValueIsInvalid {1} میں '{0}' ایک ناجائز قدر ہے۔ {1} کے لیے '{0}' کی قدر جائز نہیں ہے۔
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} قطعہ ایک جائز مکمل طور پر اہل ایچٹی ٹی پی، ایچ ٹی ٹی پی یا ایف ٹی پی یو آر ایل نہیں ہے۔
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} ہندسوں کے اندر ہونا چاہیے"۔ اگر پراپرٹی سیٹ ہے، تو آپ {0} کو تبدیل کرنا چاہیں گے کہ "ہندسوں {2} یا اس MinimumLength سے زیادہ {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 ہوگا۔ ایکس ایکس ایکس حصہ اوپر دی گئی شکل میں کلید کا حامل jquery.validate.js ہے۔ data-val-number (جیسے)

data-val-XXXX مقامی متن کو <0/a) میں خصوصیات پر سیٹ کرنے کے لیے، پیش کار کی طرف ایچ ٹی ایم ایل واپس کرتے وقت اسے سیٹ کرنا ٹھیک ہے۔

آئیے پیغام کو مقامی بناتے ہیں جب غیر عددی حروف کو مثال کے طور پر ایج ان پٹ فیلڈ میں شامل کیا جاتا ہے۔ 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>

دیگر غیر مقامی پیغامات بھی ہیں، لیکن آپ انہیں اوپر بیان کردہ طریقوں میں مقامی بنا سکتے ہیں۔ جب آپ کو ضرورت ہو تو کوڈ شامل کریں۔