هرچند ASP.NET Core Identity تمام پیامهای خطایی را که ارائه میدهد از یک فایل resx دریافت میکند، اما این فایل در نگارش 1.1 آن حداقل قابلیت چندزبانی شدن را ندارد و اگر فایل resx فارسی آنرا تهیه کنیم، توسط این فریم ورک استفاده نخواهد شد. در ادامه ابتدا نگاهی خواهیم داشت به زیرساخت استفاده شدهی در این فریم ورک برای بومی سازی پیامهای داخلی آن و سپس نحوهی فارسی کردن آنرا بررسی میکنیم.
ASP.NET Core Identity 1.1 چگونه پیامهای خطای خود را تامین میکند؟
نگارش 1.1 این فریم ورک به همراه یک فایل Resources.resx است که تمام پیامهای خطاهای ارائه شدهی توسط متدهای مختلف آنرا به همراه دارد. این فایل توسط کلاس IdentityErrorDescriber به نحو ذیل استفاده میشود:
برای مثال برای نمایش یک پیام خطای عمومی، به کلاس Resources معادل فایل resx یاد شده مراجعه کرده و خاصیت DefaultError آنرا ارائه میدهد و به همین نحو برای سایر خطاها و اخطارها.
سپس کلاس IdentityErrorDescriber به سیستم تزریق وابستگیهای آن اضافه شده و هرجائیکه نیاز به نمایش پیامی را داشته، از آن استفاده میکند.
بنابراین همانطور که ملاحظه میکنید کلاس Resources آن ثابت است و قابل تغییر نیست. به همین جهت اگر معادل فارسی این فایل را تهیه کنیم، توسط این فریم ورک به صورت خودکار استفاده نخواهد شد.
فارسی سازی IdentityErrorDescriber
بهترین راه فارسی سازی کلاس IdentityErrorDescriber، ارث بری از آن و بازنویسی متدهای virtual آن است که اینکار در کلاس CustomIdentityErrorDescriber انجام شدهاست:
پس از بازنویسی کامل این کلاس، اکنون نوبت به جایگزینی آن با IdentityErrorDescriber پیشفرض است:
معرفی CustomIdentityErrorDescriber، در دو قسمت معرفی عمومی آن به سیستم تزریق وابستگیها و همچنین متد AddErrorDescriber زنجیرهی AddIdentity کلاس IdentityServicesRegistry انجام شدهاست.
به این ترتیب این فریم ورک هرزمانیکه نیاز به وهلهای از نوع IdentityErrorDescriber را داشته باشد، از وهلهی فارسی سازی شدهی ما استفاده میکند.
مشکل! هنوز پس از جایگزینی سرویس IdentityServicesRegistry اصلی، تعدادی از خطاها فارسی نیستند!
اگر به کلاس PasswordValidator آن مراجعه کنید، در سازندهی کلاس یک چنین تعریفی را میتوان مشاهده کرد:
یعنی اگر ما این کلاس PasswordValidator را سفارشی سازی کردیم و فراموش کردیم که سازندهی آنرا هم بازنویسی کنیم، پارامتر errors آن نال خواهد بود (چون از مقدار پیشفرض پارامترها استفاده کردهاند). یعنی از new IdentityErrorDescriber اصلی (بدون مراجعهی به سیستم تزریق وابستگیها و استفادهی از نسخهی سفارشی سازی شدهی ما) استفاده میکند. بنابراین در هر دو کلاس سفارشی سازی شدهی اعتبارسنجی کاربران و کلمات عبور آنها، ذکر سازندهی پیشفرض این کلاسها و ذکر پارامتر IdentityErrorDescriber آن، اجباری است:
به این ترتیب، زمانیکه این کلاسها توسط سیستم تزریق وابستگیها وهله سازی میشوند، IdentityErrorDescriber آن دقیقا همان کلاس فارسی سازی شدهی ما خواهد بود و دیگر شرط ()errors ?? new IdentityErrorDescriber در کلاس پایه محقق نمیشود تا بازهم به همان تامین کنندهی پیش فرض خطاها مراجعه کند؛ چون base(errors) آن با کلاس جدید ما مقدار دهی شدهاست.
یک نکته: اگر کلاسهای زیر را سفارشی سازی کردید، تمامشان از حالت ()errors ?? new IdentityErrorDescriber در سازندهی کلاس خود استفاده میکنند. بنابراین ذکر مجدد و بازنویسی سازندهی آنها را فراموش نکنید (در حد ذکر مجدد سازندهی کلاس پایه کفایت میکند و مابقی آن توسط سیستم تزریق وابستگیها مدیریت خواهد شد):
- PasswordValidator
- RoleManager
- RoleStore
- UserStore
- UserValidator
- RoleValidator
کدهای کامل این سری را در مخزن کد DNT Identity میتوانید ملاحظه کنید.
ASP.NET Core Identity 1.1 چگونه پیامهای خطای خود را تامین میکند؟
نگارش 1.1 این فریم ورک به همراه یک فایل Resources.resx است که تمام پیامهای خطاهای ارائه شدهی توسط متدهای مختلف آنرا به همراه دارد. این فایل توسط کلاس IdentityErrorDescriber به نحو ذیل استفاده میشود:
public class IdentityErrorDescriber { public virtual IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = Resources.DefaultError }; }
سپس کلاس IdentityErrorDescriber به سیستم تزریق وابستگیهای آن اضافه شده و هرجائیکه نیاز به نمایش پیامی را داشته، از آن استفاده میکند.
بنابراین همانطور که ملاحظه میکنید کلاس Resources آن ثابت است و قابل تغییر نیست. به همین جهت اگر معادل فارسی این فایل را تهیه کنیم، توسط این فریم ورک به صورت خودکار استفاده نخواهد شد.
فارسی سازی IdentityErrorDescriber
بهترین راه فارسی سازی کلاس IdentityErrorDescriber، ارث بری از آن و بازنویسی متدهای virtual آن است که اینکار در کلاس CustomIdentityErrorDescriber انجام شدهاست:
public class CustomIdentityErrorDescriber : IdentityErrorDescriber { public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = "خطایی رخ دادهاست." }; }
services.AddScoped<IdentityErrorDescriber, CustomIdentityErrorDescriber>(); services.AddIdentity<User, Role>(identityOptions => { }).AddUserStore<ApplicationUserStore>() // the rest of the setting … .AddErrorDescriber<CustomIdentityErrorDescriber>() // the rest of the setting …
به این ترتیب این فریم ورک هرزمانیکه نیاز به وهلهای از نوع IdentityErrorDescriber را داشته باشد، از وهلهی فارسی سازی شدهی ما استفاده میکند.
مشکل! هنوز پس از جایگزینی سرویس IdentityServicesRegistry اصلی، تعدادی از خطاها فارسی نیستند!
اگر به کلاس PasswordValidator آن مراجعه کنید، در سازندهی کلاس یک چنین تعریفی را میتوان مشاهده کرد:
public class PasswordValidator<TUser> : IPasswordValidator<TUser> where TUser : class { public PasswordValidator(IdentityErrorDescriber errors = null) { Describer = errors ?? new IdentityErrorDescriber(); }
public class CustomPasswordValidator : PasswordValidator<User> { private readonly IUsedPasswordsService _usedPasswordsService; private readonly ISet<string> _passwordsBanList; public CustomPasswordValidator( IdentityErrorDescriber errors,// How to use CustomIdentityErrorDescriber IOptionsSnapshot<SiteSettings> configurationRoot, IUsedPasswordsService usedPasswordsService) : base(errors) public class CustomUserValidator : UserValidator<User> { private readonly ISet<string> _emailsBanList; public CustomUserValidator( IdentityErrorDescriber errors,// How to use CustomIdentityErrorDescriber IOptionsSnapshot<SiteSettings> configurationRoot ) : base(errors)
یک نکته: اگر کلاسهای زیر را سفارشی سازی کردید، تمامشان از حالت ()errors ?? new IdentityErrorDescriber در سازندهی کلاس خود استفاده میکنند. بنابراین ذکر مجدد و بازنویسی سازندهی آنها را فراموش نکنید (در حد ذکر مجدد سازندهی کلاس پایه کفایت میکند و مابقی آن توسط سیستم تزریق وابستگیها مدیریت خواهد شد):
- PasswordValidator
- RoleManager
- RoleStore
- UserStore
- UserValidator
- RoleValidator
کدهای کامل این سری را در مخزن کد DNT Identity میتوانید ملاحظه کنید.