Asp.Net Identity Localization PublicKeyToken
我试图通过使用以下post的建议来获取瑞典语对Asp.Net Identity的本地化错误消息: 如何本地化ASP.NET Identity UserName和Password错误消息?
使用NuGet我下载了德语语言包,然后在dotPeek中打开\ packages \ Microsoft.AspNet.Identity.Core.2.0.0 \ lib \ net45 \ de \ Microsoft.AspNet.Identity.Core.resources.dll,然后将其导出到一个新的VS项目:
https://github.com/nielsbosma/AspNet.Identity.Resources.Swedish/
我已将生成的\ Microsoft.AspNet.Identity.Core.resources.dll复制到\ packages \ Microsoft.AspNet.Identity.Core.2.0.0 \ lib \ net45 \ se下的新文件夹。
当我在本地运行我的网站时,我看到Microsoft.AspNet.Identity.Core.resources.dll已被复制到MySite \ bin \ sv \
但我不能让它工作:(
如果我在我的Web.config中设置:
...
我仍然得到英文默认错误消息。 但如果我改为德语,我已经从NuGet中包含了我收到德语错误消息。
使用dotPeek我将我的dll与德语进行了比较,除了我的PublicKeyToken = null和德语为“31bf3856ad364e35”之外,它们是相同的。 这可能是我无法加载我的DLL的原因吗? 无论如何为dll设置PublicKeyToken? 任何解决方法?
谢谢你的任何指示。
除非您拥有Microsoft用于签署dll的私钥。
更新:作为一种解决方法,直到我们添加对插入您自己的资源的支持,您现在可能只使用显式切换包装所有默认标识结果错误消息,应该只有大约10-20个面向用户的错误。
就像是:
public static string Localize(string error) { switch (error) { case "": return "
在Peter的答案的启发下,我想出了蹩脚但快速的解决方案。
我需要在默认的AccountController模板中本地化错误,所以我编写了自己的AddLocalizedErrors
方法。 我正在使用Resources来本地化错误。
//Original method private void AddErrors(IdentityResult result) { foreach (var error in result.Errors) { ModelState.AddModelError("", error); } } //My method private void AddLocalizedErrors(IdentityResult result, ApplicationUser user) { foreach (var error in result.Errors) { var localizedError = error; string userName = ""; string email = ""; if (user != null) { userName = user.UserName; email = user.Email; } //password errors localizedError = localizedError.Replace("Passwords must have at least one uppercase ('A'-'Z').", AspNetValidationMessages.password_uppercase); localizedError = localizedError.Replace("Passwords must have at least one digit ('0'-'9').", AspNetValidationMessages.password_digit); localizedError = localizedError.Replace("Passwords must have at least one lowercase ('a'-'z').", AspNetValidationMessages.password_lowercase); localizedError = localizedError.Replace("Passwords must have at least one non letter or digit character.", AspNetValidationMessages.password_nonletter_nondigit); localizedError = localizedError.Replace("Passwords must have at least one non letter or digit character.", AspNetValidationMessages.password_nonletter_nondigit); localizedError = localizedError.Replace("Passwords must have at least one non letter or digit character.", AspNetValidationMessages.password_nonletter_nondigit); //register errors localizedError = localizedError.Replace("Name "+userName+" is already taken.", AspNetValidationMessages.name_taken.Replace("{0}", userName)); localizedError = localizedError.Replace("Email '" + email + "' is already taken.", AspNetValidationMessages.email_taken.Replace("{0}", email)); ModelState.AddModelError("", localizedError); } }
我正在使用string.Replace()
因为例如密码错误只是单个密码要求的字符串。
谈到角色的收集,我应该更有创意。 可能使用string.Contains()
。
目前这是一个非常糟糕的解决方案,但一个解决方案解决方案。 为我们这些需要本地化并且不在Microsoft工作的人节省时间…这就是我作为荷兰语语言的解决方法所做的。
public class Demo { private string LocalizeIdentityError(string error, IdentityUser user) { if (error == "User already in role.") return "De gebruiker zit reeds in deze rol."; else if (error == "User is not in role.") return "De gebruiker zit niet in deze rol."; //else if (error == "Role {0} does not exist.") return "De rol bestaat nog niet"; //else if (error == "Store does not implement IUserClaimStore<TUser>.") return ""; //else if (error == "No IUserTwoFactorProvider for '{0}' is registered.") return ""; //else if (error == "Store does not implement IUserEmailStore<TUser>.") return ""; else if (error == "Incorrect password.") return "Ongeldig wachtwoord"; //else if (error == "Store does not implement IUserLockoutStore<TUser>.") return ""; //else if (error == "No IUserTokenProvider is registered.") return ""; //else if (error == "Store does not implement IUserRoleStore<TUser>.") return ""; //else if (error == "Store does not implement IUserLoginStore<TUser>.") return ""; else if (error == "User name {0} is invalid, can only contain letters or digits.") return "De gebruikersnaam '"+user.UserName+"' kan alleen letters of cijfers bevatten."; //else if (error == "Store does not implement IUserPhoneNumberStore<TUser>.") return ""; //else if (error == "Store does not implement IUserConfirmationStore<TUser>.") return ""; else if (error.StartsWith("Passwords must be at least ")) return "Een wachtwoord moet minstens {0} karakters bevatten."; //else if (error == "{0} cannot be null or empty.") return ""; else if (user != null && error == "Name "+user.UserName+" is already taken.") return "De gebruikersnaam '" + user.UserName + "' is reeds in gebruik."; else if (error == "User already has a password set.") return "Deze gebruiker heeft reeds een wachtwoord ingesteld."; //else if (error == "Store does not implement IUserPasswordStore<TUser>.") return ""; else if (error == "Passwords must have at least one non letter or digit character.") return "Wachtwoorden moeten minstens een ander karakter dan een letter of cijfer bevatten."; else if (error == "UserId not found.") return "De gebruiker kon niet gevonden worden."; else if (error == "Invalid token.") return "Ongeldig token."; else if (user != null && error == "Email '" + user.Email + "' is invalid.") return "Het emailadres '" + user.Email + "' is ongeldig."; else if (user != null && error == "User " + user.UserName + " does not exist.") return "De gebruiker '" + user.UserName + "' bestaat niet."; else if (error == "Store does not implement IQueryableRoleStore<TRole>.") return ""; else if (error == "Lockout is not enabled for this user.") return "Lockout is niet geactiveerd voor deze gebruiker."; //else if (error == "Store does not implement IUserTwoFactorStore<TUser>.") return ""; else if (error == "Passwords must have at least one uppercase ('A'-'Z').") return "Wachtwoorden moeten minstens één hoofdletter bevatten. (AZ)"; else if (error == "Passwords must have at least one digit ('0'-'9').") return "Wachtwoorden moeten minstens één getal bevatten. (0-9)"; else if (error == "Passwords must have at least one lowercase ('a'-'z').") return "Wachtwoorden moeten minstens één kleine letter bevatten. (az)"; //else if (error == "Store does not implement IQueryableUserStore<TUser>.") return ""; else if (user != null && error == "Email '" + user.Email + "' is already taken.") return "Het emailadres '" + user.Email + "' is reeds in gebruik. Probeer aan te melden."; //else if (error == "Store does not implement IUserSecurityStampStore<TUser>.") return ""; else if (error == "A user with that external login already exists.") return "Een gebruiker met deze externe login bestaat reeds."; else if (error == "An unknown failure has occured.") return "Een onbekende fout is opgetreden. Probeer het later opnieuw."; return error; } }
另一种选择是从Microsoft.AspNet.Identity.PasswordValidatorinheritance然后覆盖ValidateAsync。
然后,您可以使用自己的资源文件进行本地化。 可以使用DotPeek或类似工具找到英语的原始资源文件,然后您可以将其用作英语作为您自己的其他语言翻译的模板。
我的resx文件:
MyLocalization / IdentityResource.resx(与Microsoft.AspNet.Identity.Core.Resources中的相同)
MyLocalization / IdentityResource.nb-no.resx(我的挪威语翻译)
var manager = new ApplicationUserManager(new UserStore (context.Get())); // Configure validation logic for passwords manager.PasswordValidator = new MyCustomPasswordValidator(System.Threading.Thread.CurrentThread.CurrentUICulture)
在MyCustomPasswordValidator.cs中:(还请注意我在ValidateAsync中也必须做的错误修正)
using Resources = MyLocalization.IdentityResource; public class MyCustomPasswordValidator : Microsoft.AspNet.Identity.PasswordValidator { private readonly CultureInfo _currentUIculture; public MyCustomPasswordValidator(CultureInfo currentUIculture) { _currentUIculture = currentUIculture; } /// /// Ensures that the string is of the required length and meets the configured requirements /// /// /// /// public override Task ValidateAsync(string item) { //BUG: CurrentUICulture is not set correctly https://aspnetidentity.codeplex.com/workitem/2060 System.Threading.Thread.CurrentThread.CurrentUICulture = _currentUIculture; if (item == null) throw new ArgumentNullException("item"); List list = new List (); if (string.IsNullOrWhiteSpace(item) || item.Length < this.RequiredLength) list.Add(string.Format((IFormatProvider)CultureInfo.CurrentCulture, Resources.PasswordTooShort, new object[1] { (object) this.RequiredLength })); if (this.RequireNonLetterOrDigit && Enumerable.All((IEnumerable )item, new Func(this.IsLetterOrDigit))) list.Add(Resources.PasswordRequireNonLetterOrDigit); if (this.RequireDigit && Enumerable.All ((IEnumerable )item, (Func)(c => !this.IsDigit(c)))) list.Add(Resources.PasswordRequireDigit); if (this.RequireLowercase && Enumerable.All ((IEnumerable )item, (Func)(c => !this.IsLower(c)))) list.Add(Resources.PasswordRequireLower); if (this.RequireUppercase && Enumerable.All ((IEnumerable )item, (Func)(c => !this.IsUpper(c)))) list.Add(Resources.PasswordRequireUpper); if (list.Count == 0) return Task.FromResult(IdentityResult.Success); return Task.FromResult (IdentityResult.Failed(new string[1] { string.Join(" ", (IEnumerable) list) })); } }
`
Password
字段的另一个解决方法可能是使用CustomValidationAttribute
实现RegisterViewModel.Password
:
public class RegisterViewModel { [CustomValidation(typeof(CustomValidations), "ValidatePassword")] public string Password { get; set; } }
并拥有CustomValidations.ValidatePassword
方法,该方法将模拟您为PasswordValidator
设置的密码validation规则。 即:
public static class CustomValidations { public static ValidationResult ValidatePassword(string password) { // Implement validation logic here, eg require numbers, // uppercase etc. and create localized ValidationResult. return new ValidationResult(Resources.PasswordValidation.NoNumbers); } }
在这里,您可以使用标准resx资源文件,根据个人喜好显然可以本地化您的错误消息。 因此,总而言之,您只需禁止任何无效密码到达PasswordValidator
。
对于Email
字段,这会有点难看,因为它需要往返DB来validation唯一性等,但它应该是可行的。
使用此解决方案的额外好处是产生的错误将是“每个字段”,即您不必使用@Html.ValidationSummary
显示所有validation错误,但可以执行以下操作:
@Html.ValidationMessageFor(m => m.Password, null, new { @class = "text-danger" })
这是en-US Resources.resx文件键和值列表。 这些是需要本地化的值。 源代码见http://aspnetidentity.codeplex.com
Asp.Net Identity {name} Validator.cs ErrorMessage Resources.resx本地化请参阅: http : //aspnetidentity.codeplex.com/discussions/638351
*DefaultError= An unknown failure has occured. DuplicateEmail= Email '{0}' is already taken. DuplicateName= Name {0} is already taken. ExternalLoginExists= A user with that external login already exists. InvalidEmail= Email '{0}' is invalid. InvalidToken= Invalid token. InvalidUserName= User name {0} is invalid, can only contain letters or digits. LockoutNotEnabled= Lockout is not enabled for this user. NoTokenProvider= No IUserTokenProvider is registered. NoTwoFactorProvider= No IUserTwoFactorProvider for '{0}' is registered. PasswordMismatch= Incorrect password. PasswordRequireDigit= Passwords must have at least one digit ('0'-'9'). PasswordRequireLower= Passwords must have at least one lowercase ('a'-'z'). PasswordRequireNonLetterOrDigit= Passwords must have at least one non letter or digit character. PasswordRequireUpper= Passwords must have at least one uppercase ('A'-'Z'). PasswordTooShort= Passwords must be at least {0} characters. PropertyTooShort= {0} cannot be null or empty. RoleNotFound= Role {0} does not exist. StoreNotIQueryableRoleStore= Store does not implement IQueryableRoleStore. StoreNotIQueryableUserStore= Store does not implement IQueryableUserStore. StoreNotIUserClaimStore= Store does not implement IUserClaimStore . StoreNotIUserConfirmationStore= Store does not implement IUserConfirmationStore . StoreNotIUserEmailStore= Store does not implement IUserEmailStore . StoreNotIUserLockoutStore= Store does not implement IUserLockoutStore . StoreNotIUserLoginStore= Store does not implement IUserLoginStore . StoreNotIUserPasswordStore= Store does not implement IUserPasswordStore . StoreNotIUserPhoneNumberStore= Store does not implement IUserPhoneNumberStore . StoreNotIUserRoleStore= Store does not implement IUserRoleStore . StoreNotIUserSecurityStampStore= Store does not implement IUserSecurityStampStore . StoreNotIUserTwoFactorStore= Store does not implement IUserTwoFactorStore . UserAlreadyHasPassword= User already has a password set. UserAlreadyInRole= User already in role. UserIdNotFound= UserId not found. UserNameNotFound= User {0} does not exist. UserNotInRole= User is not in role.*