如何翻译身份密码验证消息

时间:2018-11-30 23:51:44

标签: c# asp.net-core asp.net-core-2.1 asp.net-core-identity

到目前为止,我已经能够翻译ASP.Net Core 2.1 Web应用程序中的所有内容。

事实证明这是一个小挑战,因为脚手架的“帐户页面”需要一些设置。

但是我找不到一种翻译密码验证消息的方法。另外,翻译模型绑定消息是一个小挑战(感谢stackoverflow)。

有什么想法吗?

我将Startup.cs文件的相关部分包括在内:

public void ConfigureServices(IServiceCollection services)
{
     ...

     services.AddMvc(options =>
     {
         var type = typeof(SharedResources);
         var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
         var factory = services.BuildServiceProvider().GetService<IStringLocalizerFactory>();
         var L = factory.Create("SharedResources", assemblyName.Name);

         options.ModelBindingMessageProvider.SetValueIsInvalidAccessor(x => L["The value '{0}' is invalid.", x]);
         options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(x => L["The value '{0}' is invalid.", x]);
         options.ModelBindingMessageProvider.SetValueMustBeANumberAccessor(x => L["The field {0} must be a number.", x]);
         options.ModelBindingMessageProvider.SetMissingBindRequiredValueAccessor(x => L["A value for the '{0}' property was not provided.", x]);
         options.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor((x, y) => L["The value '{0}' is not valid for {1}.", x, y]);
         options.ModelBindingMessageProvider.SetMissingKeyOrValueAccessor(() => L["A value is required."]);
         options.ModelBindingMessageProvider.SetUnknownValueIsInvalidAccessor(x => L["The supplied value is invalid for {0}.", x]);
         options.ModelBindingMessageProvider.SetMissingRequestBodyRequiredValueAccessor(() => L["A non-empty request body is required."]);
         options.ModelBindingMessageProvider.SetNonPropertyAttemptedValueIsInvalidAccessor(x => L["The value '{0}' is not valid.", x]);
         options.ModelBindingMessageProvider.SetNonPropertyUnknownValueIsInvalidAccessor(() => L["The supplied value is invalid."]);
         options.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(() => L["NonPropertyValueMustBeNumber"]);
     })
     .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
     .AddDataAnnotationsLocalization(options =>
        {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
            {
                // This is for Account scaffolded pages data annotations
                return factory.Create(typeof(SharedResources));
            };
        });

     ...

}

我无法在InputModel的{​​{1}}中放入这样的内容,因为Register.cshtml.cs被忽略了(我也不会这样做,因为我不想对代码进行硬编码密码策略说明):

ErrorMessage

Screenshot of translated registration page

3 个答案:

答案 0 :(得分:3)

这可以通过本地化身份错误消息来完成,有22条消息必须本地化。

首先,创建一个共享资源文件“其密钥使用public access修饰符定义”,然后键入具有本地化版本的所有错误消息,如下图所示:

enter image description here

然后创建一个实现IdentityErrorDescriber的新类,并参考共享资源文件覆盖所有默认消息;在此示例中,共享资源文件名为LocalizedIdentityErrorMessages:

public class LocalizedIdentityErrorDescriber : IdentityErrorDescriber
    {
        public override IdentityError DuplicateEmail(string email)
        {
            return new IdentityError
            {
                Code = nameof(DuplicateEmail),
                Description = string.Format(LocalizedIdentityErrorMessages.DuplicateEmail, email)
            };
        }

        public override IdentityError DuplicateUserName(string userName)
        {
            return new IdentityError
            {
                Code = nameof(DuplicateUserName),
                Description = string.Format(LocalizedIdentityErrorMessages.DuplicateUserName, userName)
            };
        }

        public override IdentityError InvalidEmail(string email)
        {
            return new IdentityError
            {
                Code = nameof(InvalidEmail),
                Description = string.Format(LocalizedIdentityErrorMessages.InvalidEmail, email)
            };
        }

        public override IdentityError DuplicateRoleName(string role)
        {
            return new IdentityError
            {
                Code = nameof(DuplicateRoleName),
                Description = string.Format(LocalizedIdentityErrorMessages.DuplicateRoleName, role)
            };
        }

        public override IdentityError InvalidRoleName(string role)
        {
            return new IdentityError
            {
                Code = nameof(InvalidRoleName),
                Description = string.Format(LocalizedIdentityErrorMessages.InvalidRoleName, role)
            };
        }

        public override IdentityError InvalidToken()
        {
            return new IdentityError
            {
                Code = nameof(InvalidToken),
                Description = LocalizedIdentityErrorMessages.InvalidToken
            };
        }

        public override IdentityError InvalidUserName(string userName)
        {
            return new IdentityError
            {
                Code = nameof(InvalidUserName),
                Description = string.Format(LocalizedIdentityErrorMessages.InvalidUserName, userName)
            };
        }

        public override IdentityError LoginAlreadyAssociated()
        {
            return new IdentityError
            {
                Code = nameof(LoginAlreadyAssociated),
                Description = LocalizedIdentityErrorMessages.LoginAlreadyAssociated
            };
        }

        public override IdentityError PasswordMismatch()
        {
            return new IdentityError
            {
                Code = nameof(PasswordMismatch),
                Description = LocalizedIdentityErrorMessages.PasswordMismatch
            };
        }

        public override IdentityError PasswordRequiresDigit()
        {
            return new IdentityError
            {
                Code = nameof(PasswordRequiresDigit),
                Description = LocalizedIdentityErrorMessages.PasswordRequiresDigit
            };
        }

        public override IdentityError PasswordRequiresLower()
        {
            return new IdentityError
            {
                Code = nameof(PasswordRequiresLower),
                Description = LocalizedIdentityErrorMessages.PasswordRequiresLower
            };
        }

        public override IdentityError PasswordRequiresNonAlphanumeric()
        {
            return new IdentityError
            {
                Code = nameof(PasswordRequiresNonAlphanumeric),
                Description = LocalizedIdentityErrorMessages.PasswordRequiresNonAlphanumeric
            };
        }

        public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
        {
            return new IdentityError
            {
                Code = nameof(PasswordRequiresUniqueChars),
                Description = string.Format(LocalizedIdentityErrorMessages.PasswordRequiresUniqueChars, uniqueChars)
            };
        }

        public override IdentityError PasswordRequiresUpper()
        {
            return new IdentityError
            {
                Code = nameof(PasswordRequiresUpper),
                Description = LocalizedIdentityErrorMessages.PasswordRequiresUpper
            };
        }

        public override IdentityError PasswordTooShort(int length)
        {
            return new IdentityError
            {
                Code = nameof(PasswordTooShort),
                Description = string.Format(LocalizedIdentityErrorMessages.PasswordTooShort, length)
            };
        }

        public override IdentityError UserAlreadyHasPassword()
        {
            return new IdentityError
            {
                Code = nameof(UserAlreadyHasPassword),
                Description = LocalizedIdentityErrorMessages.UserAlreadyHasPassword
            };
        }

        public override IdentityError UserAlreadyInRole(string role)
        {
            return new IdentityError
            {
                Code = nameof(UserAlreadyInRole),
                Description = string.Format(LocalizedIdentityErrorMessages.UserAlreadyInRole, role)
            };
        }

        public override IdentityError UserNotInRole(string role)
        {
            return new IdentityError
            {
                Code = nameof(UserNotInRole),
                Description = string.Format(LocalizedIdentityErrorMessages.UserNotInRole, role)
            };
        }

        public override IdentityError UserLockoutNotEnabled()
        {
            return new IdentityError
            {
                Code = nameof(UserLockoutNotEnabled),
                Description = LocalizedIdentityErrorMessages.UserLockoutNotEnabled
            };
        }

        public override IdentityError RecoveryCodeRedemptionFailed()
        {
            return new IdentityError
            {
                Code = nameof(RecoveryCodeRedemptionFailed),
                Description = LocalizedIdentityErrorMessages.RecoveryCodeRedemptionFailed
            };
        }

        public override IdentityError ConcurrencyFailure()
        {
            return new IdentityError
            {
                Code = nameof(ConcurrencyFailure),
                Description = LocalizedIdentityErrorMessages.ConcurrencyFailure
            };
        }

        public override IdentityError DefaultError()
        {
            return new IdentityError
            {
                Code = nameof(DefaultError),
                Description = LocalizedIdentityErrorMessages.DefaultIdentityError
            };
        }
    }

最后,将本地化的错误描述器添加到启动类中的ConfigureServices方法下的身份设置中:

services.AddIdentity<AppUser, AppRole>()
        // localize identity error messages
        .AddErrorDescriber<LocalizedIdentityErrorDescriber>()
        .AddEntityFrameworkStores()
        .AddDefaultTokenProviders();

资源:http://www.ziyad.info/en/articles/20-Localizing_Identity_Error_Messages

此外,您可能需要阅读分步本地化文章: http://www.ziyad.info/en/articles/10-Developing_Multicultural_Web_Application

答案 1 :(得分:1)

这些错误消息是使用IdentityErrorDescriber生成的。这是类本身的示例:

public class IdentityErrorDescriber
{
    ...

    public virtual IdentityError PasswordTooShort(int length)
    {
        return new IdentityError
        {
            Code = nameof(PasswordTooShort),
            Description = Resources.FormatPasswordTooShort(length)
        };
    }


    ...
}

如果您要自定义特定消息,则可以创建自己的IdentityErrorDescriber实现。这是一个示例:

public class MyIdentityErrorDescriber : IdentityErrorDescriber
{    
    public override IdentityError PasswordTooShort(int length)
    {
        return new IdentityError
        {
            Code = nameof(PasswordTooShort),
            Description = "Your description goes here."
        };
    }
}

要使用此新实现,需要将其添加到Startup.ConfigureServices中的DI容器中:

services.AddScoped<IdentityErrorDescriber, MyIdentityErrorDescriber>();

答案 2 :(得分:0)

你可以使用 ViewModel 而不是你可以只使用 DataAnnotations 这里是 ControllerViewModelView 在这种情况下的样子(翻译是克罗地亚语).

控制器

    [HttpGet]
    public IActionResult Login()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            var result = await signInManager.PasswordSignInAsync(
                model.Email, model.Password, model.RememberMe, false);

            if (result.Succeeded)
            {
                return RedirectToAction("index", "home");
            }

            ModelState.AddModelError(string.Empty, "Neuspješni pokušaj");
        }

        return View(model);
    }

视图模型

ErrorMessage 下放置您的错误信息

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace MyApplication.ViewModels
{
    public class LoginViewModel
    {
        [Required(ErrorMessage = "Email je obavezan")]
        [EmailAddress]
        public string Email { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Lozinka")]
        [Required(ErrorMessage = "Lozinka je obavezna")]
        public string Password { get; set; }

        [Display(Name = "Zapamti me")]
        public bool RememberMe { get; set; }
    }
}

登录查看

@model LoginViewModel

@{
    ViewBag.Title = "Prijava";
}

<h2>Prijava</h2>

<div class="row">
    <div class="col-md-12">
        <form method="post">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Email"></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="Password"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <div class="checkbox">
                    <label asp-for="RememberMe">
                        <input asp-for="RememberMe" />
                        @Html.DisplayNameFor(m => m.RememberMe)
                    </label>
                </div>
            </div>
            <button type="submit" class="btn btn-primary">Prijava</button>
        </form>
    </div>
</div>