How to localize ASP.NET Identity UserName and Password error messages?
Asked Answered
R

24

90

Is it possible to provide localized strings for the "system" ASP.NET Identity v1 error messages, like "Name XYZ is already taken" or "User name XYZ is invalid, can only contain letters or digits"?

Robalo answered 13/11, 2013 at 18:32 Comment(1)
Not yet, we have a bug tracking this work item to allow specifying where the resources come from: github.com/aspnet/Identity/issues/86. For 3.0, we have some rough ideas and prototypes, but it's not quite ready yet for check-in.Stipendiary
K
144

For ASP.NET Core: (Microsoft.AspNetCore.Identity 1.0.0)

Create a class that inherits IdentityErrorDescriber and override the desired error messages.

public class CustomIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"An unknown failure has occurred." }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Optimistic concurrency failure, object has been modified." }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Incorrect password." }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Invalid token." }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "A user with this login already exists." }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"User name '{userName}' is invalid, can only contain letters or digits." }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"Email '{email}' is invalid."  }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"User Name '{userName}' is already taken."  }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"Email '{email}' is already taken."  }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Role name '{role}' is invalid."  }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Role name '{role}' is already taken."  }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "User already has a password set." }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Lockout is not enabled for this user." }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"User already in role '{role}'."  }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"User is not in role '{role}'."  }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Passwords must be at least {length} characters."  }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Passwords must have at least one non alphanumeric character." }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Passwords must have at least one digit ('0'-'9')." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Passwords must have at least one lowercase ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Passwords must have at least one uppercase ('A'-'Z')." }; }
}

On your Startup class, register the custom ErrorDescriber inside ConfigureServices:

services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddErrorDescriber<CustomIdentityErrorDescriber>(); // Add this line

UPDATE: Below you can find already translated versions for spanish and portuguese. Double check them!

public class SpanishIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"Ha ocurrido un error." }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Ha ocurrido un error, el objeto ya ha sido modificado (Optimistic concurrency failure)." }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Password Incorrecta." }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Ha ingresado un código Inválido." }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Un usuario con ese nombre ya existe." }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"El nombre de usuario '{userName}' es inválido. Solo puede contener letras y números." }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"La dirección de email '{email}' es incorrecta."  }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"El usuario '{userName}' ya existe, por favor ingrese un nombre diferente."  }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"La direccion de email '{email}' ya se encuentra registrada. Puede recupar su contraseña para ingresar nuevamente al sistema."  }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"El nombre de rol '{role}' es inválido."  }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"El nombre de rol '{role}' ya existe."  }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "El usuario ya tiene contraseña." }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "El bloqueo no esta habilitado para este usuario." }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"El usuario ya es parte del rol '{role}'."  }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"El usuario no es parte del rol '{role}'."  }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"La contraseña deben tener un largo mínimo de {length} caracteres."  }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "La contraseña debe contener al menos un caracter alfanumérico." }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "La contraseña debe incluir al menos un dígito ('0'-'9')." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "La contraseña debe incluir al menos una letra minúscula ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "La contraseña debe incluir al menos una letra MAYÚSCULA ('A'-'Z')." }; }
}

Portuguese: (many thanks to furlanrapha)

public class PortugueseIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"Um erro desconhecido ocorreu." }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Falha de concorrência otimista, o objeto foi modificado." }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Senha incorreta." }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Token inválido." }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Já existe um usuário com este login." }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Login '{userName}' é inválido, pode conter apenas letras ou dígitos." }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"Email '{email}' é inválido." }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Login '{userName}' já está sendo utilizado." }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"Email '{email}' já está sendo utilizado." }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"A permissão '{role}' é inválida." }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"A permissão '{role}' já está sendo utilizada." }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Usuário já possui uma senha definida." }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Lockout não está habilitado para este usuário." }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Usuário já possui a permissão '{role}'." }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Usuário não tem a permissão '{role}'." }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Senhas devem conter ao menos {length} caracteres." }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Senhas devem conter ao menos um caracter não alfanumérico." }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Senhas devem conter ao menos um digito ('0'-'9')." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Senhas devem conter ao menos um caracter em caixa baixa ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Senhas devem conter ao menos um caracter em caixa alta ('A'-'Z')." }; }
}
Korte answered 5/7, 2016 at 9:32 Comment(5)
This is a nice approach when using MVC Core.Atheist
What if I need to support multiple languages? is there a built in way to differentiate between different ErrorDescribers or do I need to do some weird patching myself?Stantonstanway
@Stantonstanway Excelent question. I haven't had that requirement, so Im not sure. I guess checking the CurrentCulture in the IdentityErrorDescriber and return localized error messages acordingly, but that is a recipe for messy code. Resource files should be the proper way. Looks like the original implementation is not extendable (please correct me if I'm wrong) but uses res files. Clonning the original original ErrorDescr + its resource file, and add new resources for your languages, maybe?Korte
@Stantonstanway No official solutions yet, check this issue for updates from MS: github.com/aspnet/Identity/issues/991#issuecomment-256516328Korte
@Stantonstanway You can inject the constructor of this IdentityErrorDescriber with an IStringLocalizer. For localalization see: learn.microsoft.com/en-us/aspnet/core/fundamentals/localizationKoblas
I
60

As of version 2 of identity which released on 20 march 2014 you can now have localized error messages.

First install the identity localized package.

Install-Package Microsoft.AspNet.Identity.Core.fr

Then the proper culture must be set in order to get localized messages for example one way to set culture is in web.config

<system.web>
      <globalization culture="fr-FR" uiCulture="fr"/>
</system.web>
Incandescence answered 22/3, 2014 at 5:20 Comment(9)
Unfortunately there don't seem to be a version for swedish? Any know if it's possible to get the source and make a translation for swedish by myself?Remittee
it's possible to make a dll decompile and recompile to gain access to resource files using tools like .netReflectorIncandescence
@1AmirJaliali I've tried this but failed :( #22836481 Any pointers?Remittee
Not working for me. Installed Czech and German resources, setting Thread culture to cs-CZ in BeginExecuteCore. My own resources are loaded just fine, but the ones from Identity.Core are not showing, I still see English strings. Anything else needed?Henning
Balíček obsahuje česká satelitní sestavení pro ASP.NET Identity Core Libraries. To install Microsoft ASP.NET Identity Core - české prostředky, run the following command in the Package Manager Console PM> Install-Package Microsoft.AspNet.Identity.Core.cs nuget.org/packages/Microsoft.AspNet.Identity.Core.csPaste
Thank you! Install-Package Microsoft.AspNet.Identity.Core.<locale> did the jobLuong
Any update on multilanguage support for Identity 2.0? It's simply ridiculous that there's no multi-lang support on such library!!! The workaround to download the library in the language you want to use doesn't fit at all the needs of developers because maybe I'd like also to change the message based on the user target by my application. Come on MS!Yah
This answer should be somewhere in the top because all other answers are same, i.e. custom implementation but this is built in implementation for some languagesCnossus
hm? in my core project I don't have a web.config?Steelhead
B
31

ASP NET Core workaround (25.11.2016)

You can inject IStringLocalizer into custom IdentityErrorDescriber

1) Create custom IdentityErrorDescriber (see Gerardo Grignoli answer)

public class MultilanguageIdentityErrorDescriber : IdentityErrorDescriber
{
    private readonly IStringLocalizer<SharedResource> _localizer;

    public MultilanguageIdentityErrorDescriber(IStringLocalizer<SharedResource> localizer)
    {
        _localizer = localizer;
    }

    public override IdentityError DuplicateEmail(string email)
    {
        return new IdentityError()
        {
            Code = nameof(DuplicateEmail),
            Description = string.Format(_localizer["Email {0} is already taken."], email)
        };
    }

    // DuplicateUserName, InvalidEmail, DuplicateUserName etc
}

2) Register MultilanguageIdentityErrorDescriber in Startup.cs

services.AddIdentity<IdentityUser, IdentityRole>()
            .AddErrorDescriber<MultilanguageIdentityErrorDescriber>()
            .AddDefaultTokenProviders();

3) Add error messages to SharedResource.language.resx.

Brawley answered 25/11, 2016 at 9:10 Comment(3)
Excelent Andril! Is always best to put the resources in resource files. Maybe we can colaborate to put this code and a few resources for common languages on github or even on NuGet.Korte
@GerardoGrignoli I'm happy with this approach and I use it in production. Unfortunately, I have no free time to work on this, but I submitted this idea on github. github.com/aspnet/Identity/issues/991, maybe it will help someone or .NET Core dev team will pick up this idea.Brawley
Excellent answer. Maybe I would add that localizer does not need string.Format, you can add the parameters within []Whipsaw
V
22

this is for dear Farsi(Persian) speakers

using Microsoft.AspNetCore.Identity;

namespace WebApplication.Admin.Helpers
{
    public class CustomIdentityErrorDescriber : IdentityErrorDescriber
    {
        public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"یک خطای ناشناخته رخ داده است." }; }
        public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "رکورد جاری پیشتر ویرایش شده‌است و تغییرات شما آن‌را بازنویسی خواهد کرد." }; }
        public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "کلمه عبور نادرست است." }; }
        public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "کلمه عبور نامعتبر است." }; }
        public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "این کاربر قبلأ اضافه شده‌است." }; }
        public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"نام کاربری '{userName}' نامعتبر است، فقط می تواند حاوی حروف ویا اعداد باشد." }; }
        public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"ایمیل '{email}' نامعتبر است." }; }
        public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"این نام کاربری '{userName}' به کاربر دیگری اختصاص یافته است." }; }
        public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"ایمیل '{email}' به کاربر دیگری اختصاص یافته است." }; }
        public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"نام نقش '{role}' نامعتبر است." }; }
        public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"این نام نقش '{role}' به کاربر دیگری اختصاص یافته است." }; }
        public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "کلمه‌ی عبور کاربر قبلأ تنظیم شده‌است." }; }
        public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "این کاربر فعال است." }; }
        public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"این نقش '{role}' قبلأ به این کاربر اختصاص یافته است." }; }
        public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"این نقش '{role}' قبلأ به این کاربر اختصاص نیافته است." }; }
        public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"کلمه عبور باید حداقل {length} کاراکتر باشد." }; }
        public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "کلمه عبور باید حداقل یک کاراکتر غیر از حروف الفبا داشته باشد." }; }
        public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "کلمه عبور باید حداقل یک عدد داشته باشد." }; }
        public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "کلمه عبور باید حداقل یک حرف کوچک داشته باشد." }; }
        public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "کلمه عبور باید حداقل یک حرف بزرگ داشته باشد." }; }
        public override IdentityError RecoveryCodeRedemptionFailed() { return new IdentityError { Code = nameof(RecoveryCodeRedemptionFailed), Description = "بازیابی ناموفق بود." }; }
        public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) { return new IdentityError { Code = nameof(PasswordRequiresUniqueChars), Description = $"کلمه عبور باید حداقل داراى {uniqueChars} حرف متفاوت باشد." }; }
    }
}
Voucher answered 26/1, 2019 at 6:14 Comment(4)
How we can use this?Semiaquatic
کلمه عبور باید حداقل یک حرف بزرگ انگلیسی داشته باشد ، کلمه عبور باید حداقل یک عدد انگلیسی داشته باشدCadence
جای ویرایش خیلی زیاد داره، مثلا "این" رو از قبل از نقش باید برداشته بشه و...Cadence
As a mere suggestion: UserLockoutNotEnabled=> غیر فعال کردن کاربر امکان‌پذیر نیست. Or غیر فعال کردن این کاربر امکان‌پذیر نیست.Blagoveshchensk
M
14

I ran into the same problem and found a quick-and-dirty workaround. I looked inside the Microsoft.AspNet.Identity.Core assembly using DotPeek (I assume any C# decompiler will do) and found two classes that are responsible for such messages:

  • Microsoft.AspNet.Identity.UserValidator<TUser> (UserName-related)
  • Microsoft.AspNet.Identity.MinimumLengthValidator (Password related)

These classes do not contain any external references (other than the string resources that you want to replace anyway), so re-implementing them in your own code should be fairly straightforward.

After doing so, don't forget to properly use them in your UserManager:

UserManager.UserValidator = new MyCustomUserValidator<MyUserType>(UserManager);
UserManager.PasswordValidator = new MyCustomMinimumLengthValidator(6);
Maracanda answered 7/3, 2014 at 20:15 Comment(1)
@NielsBosma It's a bit hacky, but it works fine. Have a look at my implementations of the UserValidator and the MinumumLengthValidator, which provide Romanian localization.Maracanda
P
7

German Version for Solution by @GerardoGrignoli

public class CustomIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"Ein unbekannter Fehler ist aufgetreten." }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Fehler bzgl. der Optimistischen Nebenläufigkeit, das Objekt wurde verändert." }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Ungültiges Passwort." }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Ungültiger Token." }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Es ist bereits ein Nutzer mit diesem Login vorhanden." }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Nutzername '{userName}' ist ungültig. Erlaubt sind nur Buchstaben und Zahlen." }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"E-Mail '{email}' ist ungültig." }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Nutzername '{userName}' ist bereits vergeben." }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"E-Mail '{email}' ist bereits vergeben." }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Rollen-Name '{role}' ist ungültig." }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Rollen-Name '{role}' ist bereits vergeben." }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Nutzer hat bereits ein Passwort gesetzt." }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Aussperrung ist für diesen Nutzer nicht aktiviert." }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Nutzer ist bereits in Rolle '{role}'." }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Nutzer ist nicht in Rolle '{role}'." }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Passwörter müssen mindestens {length} Zeichen lang sein." }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Passwörter müssen mindestens ein Sonderzeichen enthalten." }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Passwörter müssen mindestens eine Ziffer enthalten ('0'-'9')." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Passwörter müssen mindestens einen Kleinbuchstaben enthalten ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Passwörter müssen mindestens einen Großbuchstaben enthalten ('A'-'Z')." }; }
}
Palikar answered 14/1, 2019 at 7:59 Comment(0)
S
7

Based on the answers here, I made my own implementation for our multilanguage web site built on MVC Core 2.2, where the strings cannot be hard coded.

I'm using a basic resource file with auto generated designer to get the strings, and the code to do it looks like this:

public class LocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
    private ResourceManager ResourceManager { get; set; }

    public LocalizedIdentityErrorDescriber()
    {
        ResourceManager = Translations.ResourceManager;
    }

    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = Translations.Validation_DefaultError }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = Translations.Validation_ConcurrencyFailure }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = Translations.Validation_PasswordMismatch }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = Translations.Validation_InvalidToken }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = Translations.Validation_LoginAlreadyAssociated }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = string.Format(Translations.Validation_InvalidUserName, userName) }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = string.Format(Translations.Validation_InvalidEmail, email) }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = string.Format(Translations.Validation_DuplicateUserName, userName) }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = string.Format(Translations.Validation_DuplicateEmail, email) }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = string.Format(Translations.Validation_InvalidRoleName, role) }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = string.Format(Translations.Validation_DuplicateRoleName, role) }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = Translations.Validation_UserAlreadyHasPassword }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = Translations.Validation_UserLockoutNotEnabled }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = string.Format(Translations.Validation_UserAlreadyInRole, role) }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = string.Format(Translations.Validation_UserNotInRole, role) }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = string.Format(Translations.Validation_PasswordTooShort, length) }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = Translations.Validation_PasswordRequiresNonAlphanumeric }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = Translations.Validation_PasswordRequiresDigit }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = Translations.Validation_PasswordRequiresLower }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = Translations.Validation_PasswordRequiresUpper }; }
}

It is then integrated in the Identity pipeline in Startup.cs

services.AddDefaultIdentity<User>()
    .AddErrorDescriber<LocalizedIdentityErrorDescriber>()
    .AddDefaultTokenProviders();

Lastly, I defined the strings in my Translations.resx and sub resource files, where the keys are named Validation_DefaultError, Validation_PasswordMismatch etc.

Shull answered 4/10, 2019 at 12:39 Comment(0)
S
6

Polish version

public class CustomErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() {      return new IdentityError { Code = nameof(DefaultError), Description = $"Wystąpił nieanany błąd." }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Błąd współbieżności, obiekt został zmodyfikowany." }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Nieprawidłowe hasło." }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Nieprawidłowy token." }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Użytkownik o takiej nazwie już istnieje." }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Nazwa użytkownika \"'{userName}'\" jest nieprawidłowa, może posiadać tylko znaki i cyfry." }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"Email \"'{email}'\" jest nieprawidłowy." }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Nazwa użytkownika \"'{userName}'\" jest zajęta." }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"Adres \"'{email}'\" jest zajęty." }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Grupa \"'{role}'\" jest nieprawidłowa." }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Nazwa grupy \"'{role}'\" jest zajęta." }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Hasło użytkownika jest już ustawione." }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Blokada nie jest ustawiona dla tego użytkownika." }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Użytkownik ma już przypisaną grupę \"'{role}'\"." }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Użytkownik nie należy do grupy \"'{role}'\"." }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Hasło musi posiadać conajmniej {length} znaków." }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Hasło musi posiadać przynajmniej jeden znak alfanumeryczny." }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Hasło musi posiadać przynajmniej jedną cyfrę ('0'-'9')." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Hasło musi posiadać przynajmniej jedną małą literę ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Hasło musi posiadać przynajmniej jedną wielką literę ('A'-'Z')." }; }
    public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Hasło musi posiadać przynajmniej jeden znak specjalny." }; }
}
Sauls answered 22/12, 2018 at 21:17 Comment(0)
F
4

Here is Gerardo Grignoli's answer with French translation

/// <inheritdoc />
/// <summary>
/// Service to enable localization (french) for application facing identity errors.
/// </summary>
public class FrenchIdentityErrorDescriber : IdentityErrorDescriber
{
    /// <inheritdoc />
    public override IdentityError DefaultError() => new IdentityError { Code = nameof(DefaultError), Description = "Une erreur inconnue est survenue." };

    /// <inheritdoc />
    public override IdentityError ConcurrencyFailure() => new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Erreur de concurrence simultanée optimiste, l'objet a été modifié." };

    /// <inheritdoc />
    public override IdentityError PasswordMismatch() => new IdentityError { Code = nameof(PasswordMismatch), Description = "Mot de passe incorrect." };

    /// <inheritdoc />
    public override IdentityError InvalidToken() => new IdentityError { Code = nameof(InvalidToken), Description = "Jeton invalide." };

    /// <inheritdoc />
    public override IdentityError LoginAlreadyAssociated() => new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Un utilisateur avec ce nom de compte existe déjà." };

    /// <inheritdoc />
    public override IdentityError InvalidUserName(string userName) => new IdentityError { Code = nameof(InvalidUserName), Description = $"Le nom de compte '{userName}' est invalide. Seuls les lettres et chiffres sont autorisés." };

    /// <inheritdoc />
    public override IdentityError InvalidEmail(string email) => new IdentityError { Code = nameof(InvalidEmail), Description = $"L'email '{email}' est invalide." };

    /// <inheritdoc />
    public override IdentityError DuplicateUserName(string userName) => new IdentityError { Code = nameof(DuplicateUserName), Description = $"Le nom de compte '{userName}' est déjà utilisé." };

    /// <inheritdoc />
    public override IdentityError DuplicateEmail(string email) => new IdentityError { Code = nameof(DuplicateEmail), Description = $"L'email '{email} est déjà utilisée." };

    /// <inheritdoc />
    public override IdentityError InvalidRoleName(string role) => new IdentityError { Code = nameof(InvalidRoleName), Description = $"Le nom du rôle '{role}' est invalide." };

    /// <inheritdoc />
    public override IdentityError DuplicateRoleName(string role) => new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Le nom du rôle '{role}' est déjà utilisé." };

    /// <inheritdoc />
    public override IdentityError UserAlreadyHasPassword() => new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "L'utilisateur a déjà un mot de passe." };

    /// <inheritdoc />
    public override IdentityError UserLockoutNotEnabled() => new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Le verouillage n'est pas activé pour cet utilisateur." };

    /// <inheritdoc />
    public override IdentityError UserAlreadyInRole(string role) => new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"L'utilisateur a déjà le rôle '{role}'." };

    /// <inheritdoc />
    public override IdentityError UserNotInRole(string role) => new IdentityError { Code = nameof(UserNotInRole), Description = $"L'utilisateur n'a pas le rôle '{role}'." };

    /// <inheritdoc />
    public override IdentityError PasswordTooShort(int length) => new IdentityError { Code = nameof(PasswordTooShort), Description = $"Le mot de passe doit contenir au moins {length} caractères." };

    /// <inheritdoc />
    public override IdentityError PasswordRequiresNonAlphanumeric() => new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Le mot de passe doit contenir au moins un caractère non alpha-numérique." };

    /// <inheritdoc />
    public override IdentityError PasswordRequiresDigit() => new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Le mot de passe doit contenir au moins un chiffre ('0'-'9')." };

    /// <inheritdoc />
    public override IdentityError PasswordRequiresLower() => new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Le mot de passe doit contenir au moins un charactère minuscule ('a'-'z')." };

    /// <inheritdoc />
    public override IdentityError PasswordRequiresUpper() => new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Le mot de passe doit contenir au moins un charactère majuscule ('A'-'Z')." };
}
Freewheeling answered 6/6, 2018 at 21:13 Comment(0)
G
4

Hi Here My Solution to to translate identity errors:

 public string TranslateIdentityResult(string massage)
    {

        var list = new List<KeyValuePair<string, string>>() {
            new KeyValuePair<string, string>("An unknown failure has occured.", "حدث خطأ غير معروف"),
            new KeyValuePair<string, string>("Email '{0}' is already taken.", "هذا البريد '{0}' موجود بالفعل"),
            new KeyValuePair<string, string>("Name {0} is already taken.", "الاسم {0} مأخوذ بالفعل."),
            new KeyValuePair<string, string>("A user with that external login already exists.", "يوجد بالفعل مستخدم له معلومات تسجيل الدخول الخارجية."),
            new KeyValuePair<string, string>("Email '{0}' is invalid.", "البريد الإلكتروني '{0}' غير صحيح."),
            new KeyValuePair<string, string>("Invalid token.", "المفتاح غير صالح"),
            new KeyValuePair<string, string>("User name {0} is invalid, can only contain letters or digits.", "اسم المستخدم {0} غير صالح ، يمكن أن يحتوي فقط على أحرف أو أرقام."),
            new KeyValuePair<string, string>("Lockout is not enabled for this user.", "تأمين المستخدم غير متاح لهذا المستخدم"),
            new KeyValuePair<string, string>("Incorrect password.", "الرقم السري غير صحيح"),
            new KeyValuePair<string, string>("Passwords must have at least one digit ('0'-'9').", "الرقم السري يجب أ،ن يحتوي على الأقل رقم واحد (0-9)"),
            new KeyValuePair<string, string>("Passwords must have at least one lowercase ('a'-'z').", "يجب أن تحتوي كلمات المرور على حرف صغير واحد على الأقل ('a' - 'z')."),
            new KeyValuePair<string, string>("Passwords must have at least one non letter or digit character.", "يجب أن يكون لكلمة مرور حرف واحد على الأقل غير الحرف أو الرقم."),
            new KeyValuePair<string, string>("Passwords must have at least one uppercase ('A'-'Z').", "يجب أن تحتوي كلمات المرور على حرف كبير واحد على الأقل ('A' - 'Z')."),
            new KeyValuePair<string, string>("Passwords must be at least {0} characters.", "يجب أن تكون كلمات المرور على الأقل {0} حرفًا."),
            new KeyValuePair<string, string>("{0} cannot be null or empty.", "لا يمكن أن يكون {0} خاليًا أو فارغًا."),
            new KeyValuePair<string, string>("Role {0} does not exist.", "صلاحية {0} غير موجود."),
            new KeyValuePair<string, string>("User already has a password set.", "المستخدم لديه بالفعل كلمة مرور محددة."),
            new KeyValuePair<string, string>("User already in role.", "المستخدم بالفعل لديه هذي الصلاحية."),
            new KeyValuePair<string, string>("UserId not found.", "لم يتم العثور على هوية المستخدم."),
            new KeyValuePair<string, string>("User {0} does not exist.", "المستخدم {0} غير موجود."),
            new KeyValuePair<string, string>("User is not in role.", "المستخدم ليس لديه صلاحية.")
        };

        return list.Find(x => x.Key.Equals(massage)).Value;
    }

 private void AddErrors(IdentityResult result)
    {
        foreach (var error in result.Errors)
        {
            //if my function is not found error it will print it as it's
            foreach(var msg in error.Split('.'))
            {
                ModelState.AddModelError("", accBClass.TranslateIdentityResult(msg.TrimStart(' ')) ?? msg);
            }
        }
    }

Example

Greathearted answered 5/9, 2018 at 6:56 Comment(0)
S
3

1AmirJalali's method works perfectly. While setting culture in web.config works, it can be set dynamically also if required, here is how this can be achieved:

Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

In the code example above, cultureName, is name of the culture to be set. A list of cultures can be found under "Remarks" heading here: http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28v=vs.80%29.aspx

Hope this helps.

Scarecrow answered 12/5, 2014 at 10:32 Comment(0)
P
3

Here is IdentityErrorDescriber's Turkish Translation

using Microsoft.AspNetCore.Identity;


public class TurkishIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"Bilinmeyen bir hata meydana geldi." }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Bir eşzamanlılık hatası meydana geldi lütfen tekrar deneyin." }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Şifreler eşleşmiyor." }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Üretilen eşleştirme kodu geçerli değil." }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Bu bilgilere sahip bir kullanıcı sistemde zaten var." }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"'{userName}', bu kullanıcı adı geçersiz; sadece harf ve sayı kullanın." }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"'{email}', bu e-posta adresi geçersiz." }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"'{userName}', bu kullanıcı adı zaten kullanımda." }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"'{email}', bu e-posta adresi zaten kullanımda." }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"'{role}', bu rol adı geçerli değil." }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"'{role}', bu rol adı zaten kullanımda." }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Bu kullanıcı için zaten bir şifre atanmış durumda." }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Bu kullanıcı için giriş engelleme özelliği aktif değil." }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Kullanıcı zaten '{role}' adlı role sahip." }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Kullanıcı '{role}' adlı role sahip değil." }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Parola en az {length} uzunluğunda olmalı." }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Parola en az bir özel karakter içermelidir (örn. *,!_- vb.)." }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Parola en az bir rakam içermelidir." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Parola en az bir küçük harf içermelidir. ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Parola en az bir büyük harf içermelidir. ('A'-'Z')." }; }

}
Prior answered 22/7, 2020 at 13:9 Comment(1)
Eline sağlık fakat "PasswordContainseSequence" hata kodunu override edemedim. Bu sebeple aşağıdaki kodu yazdım. ``` public static string IdentityErrorToTurkish(string code, string description) { switch (code) { case "PasswordContainseSequence": description = "Parola sayısal sıra içeremez. Lütfen şifrenizi 123456 gibi ardışık yapmayınız."; break; default: description = $"Hata: {description}"; break; } return description; } ```Aircrewman
M
2

This issue was bothering me for quite some time already so I tried to come up with something generic, because solution with installing Identity.Core for particular culture is only working if the package is available at all :)

Here are steps how I achieved proper localization:

  1. Looked at the implementation of Microsoft.AspNet.Identity.PasswordValidator using dotPeak which is used by default in ApplicationUserManager,
  2. Then I came up with my own implementation of class CustomPasswordValidator : PasswordValidator and overrode the ValidateAsync method to not return IdentityResult with error messages, but rather with "codes" of these error messages all of them prefixed with "CustomValidator" string.
  3. Then in AccountController I changed AddErrors which is getting called from Register post to provide localized error messages from my very own resource files based on error codes.

Here is the CustomPasswordValidator and utility class PasswordValidatorCodes containing error codes and method to retrieve the localized error messages based on these codes (AccountStrings being a resource file):

public static class PasswordValidatorCodes
{
    public const string ErrorCodePrefix = "CustomPassword";
    public const string PasswordTooShort = ErrorCodePrefix + "TooShort";
    public const string PasswordRequireNonLetterOrDigit = ErrorCodePrefix + "RequireNonLetterOrDigit";
    public const string PasswordRequireDigit = ErrorCodePrefix + "RequireDigit";
    public const string PasswordRequireLower = ErrorCodePrefix + "RequireLower";
    public const string PasswordRequireUpper = ErrorCodePrefix + "RequireUpper";

    public static string GetLocalizedMessageForCode(string code)
    {
        switch (code)
        {
            case PasswordTooShort:
                return string.Format(AccountStrings.ValidationPasswordTooShort, CustomPasswordValidator.RequiredPasswordLength);
            case PasswordRequireNonLetterOrDigit:
                return AccountStrings.ValidationPasswordRequireNonLetterOrDigit;
            case PasswordRequireDigit:
                return AccountStrings.ValidationPasswordRequireDigit;
            case PasswordRequireLower:
                return AccountStrings.ValidationPasswordRequireLower;
            case PasswordRequireUpper:
                return AccountStrings.ValidationPasswordRequireUpper;
            default:
                throw new ArgumentException("code");
        }
    }
}

public class CustomPasswordValidator : PasswordValidator
{
    public const int RequiredPasswordLength = 6;

    public CustomPasswordValidator()
    {
        RequiredLength = RequiredPasswordLength;
        RequireNonLetterOrDigit = false;
        RequireDigit = true;
        RequireLowercase = true;
        RequireUppercase = false;
    }

    public override Task<IdentityResult> ValidateAsync(string item)
    {
        if (item == null) throw new ArgumentNullException("item");
        var list = new List<string>();

        if (string.IsNullOrWhiteSpace(item) || item.Length < RequiredLength)
        {
            list.Add(PasswordValidatorCodes.PasswordTooShort);
        }

        if (RequireNonLetterOrDigit && item.All(IsLetterOrDigit))
        {
            list.Add(PasswordValidatorCodes.PasswordRequireNonLetterOrDigit);
        }

        if (RequireDigit && item.All(c => !IsDigit(c)))
        {
            list.Add(PasswordValidatorCodes.PasswordRequireDigit);
        }

        if (RequireLowercase && item.All(c => !IsLower(c)))
        {
            list.Add(PasswordValidatorCodes.PasswordRequireLower);
        }

        if (RequireUppercase && item.All(c => !IsUpper(c)))
        {
            list.Add(PasswordValidatorCodes.PasswordRequireUpper);
        }

        return Task.FromResult(list.Count == 0
            ? IdentityResult.Success
            : new IdentityResult(list));
    }
}

And here is the modified AccountController.AddErrors method. As you can see I am adding an error to the model for property Password because if the Password doesn't pass the validation then I want the error message to be displayed by the Password field and not in validation summary. This is the only reason why my CustomPasswordValidator produces error codes rather than error messages directly:

private void AddErrors(IdentityResult result)
{
    foreach (var error in result.Errors)
    {
        if (error.StartsWith(PasswordValidatorCodes.ErrorCodePrefix))
        {
            ModelState.AddModelError("Password", PasswordValidatorCodes.GetLocalizedMessageForCode(error));
            continue;
        }
        ModelState.AddModelError(string.Empty, error);
    }
}

Last but not least, don't forget to modify the IdentityConfig file, i.e.:

manager.PasswordValidator = new CustomPasswordValidator();

UPDATE:

Only now I noticed that Marselus Chia (see other answers) has come up with the similar solution but for the VB.

Motorize answered 7/12, 2015 at 11:10 Comment(0)
G
2

I don't want to override the logic (i.e., re-invent the wheel), nor do I want to switch to ASP NET Core. All I want to do is override the error messages and use multiple resource files (per language) to tailor the user experience to their chosen language.

Here's my solution:

  1. I created an 'IdentityErrors.resx' resource file with the following:

    <data name="DefaultError" xml:space="preserve">
        <value>An unknown failure has occured.</value>
    </data>
    <data name="DuplicateEmail" xml:space="preserve">
        <value>Email '{0}' is already taken.</value>
    </data>
    <data name="DuplicateName" xml:space="preserve">
        <value>Name {0} is already taken.</value>
    </data>
    <data name="ExternalLoginExists" xml:space="preserve">
        <value>A user with that external login already exists.</value>
    </data>
    <data name="InvalidEmail" xml:space="preserve">
        <value>Email '{0}' is invalid.</value>
    </data>
    <data name="InvalidToken" xml:space="preserve">
        <value>Invalid token.</value>
    </data>
    <data name="InvalidUserName" xml:space="preserve">
        <value>User name {0} is invalid, can only contain letters or digits.</value>
    </data>
    <data name="LockoutNotEnabled" xml:space="preserve">
        <value>Lockout is not enabled for this user.</value>
    </data>
    <data name="NoTokenProvider" xml:space="preserve">
        <value>No IUserTokenProvider is registered.</value>
    </data>
    <data name="NoTwoFactorProvider" xml:space="preserve">
        <value>No IUserTwoFactorProvider for '{0}' is registered.</value>
    </data>
    <data name="PasswordMismatch" xml:space="preserve">
        <value>Incorrect password.</value>
    </data>
    <data name="PasswordRequireDigit" xml:space="preserve">
        <value>Passwords must have at least one digit ('0'-'9').</value>
    </data>
    <data name="PasswordRequireLower" xml:space="preserve">
        <value>Passwords must have at least one lowercase ('a'-'z').</value>
    </data>
    <data name="PasswordRequireNonLetterOrDigit" xml:space="preserve">
        <value>Passwords must have at least one non letter or digit character.</value>
    </data>
    <data name="PasswordRequireUpper" xml:space="preserve">
        <value>Passwords must have at least one uppercase ('A'-'Z').</value>
    </data>
    <data name="PasswordTooShort" xml:space="preserve">
        <value>Passwords must be at least {0} characters.</value>
    </data>
    <data name="PropertyTooShort" xml:space="preserve">
        <value>{0} cannot be null or empty.</value>
    </data>
    <data name="RoleNotFound" xml:space="preserve">
        <value>Role {0} does not exist.</value>
    </data>
    <data name="StoreNotIQueryableRoleStore" xml:space="preserve">
        <value>Store does not implement IQueryableRoleStore&amp;lt;TRole&amp;gt;.</value>
    </data>
    <data name="StoreNotIQueryableUserStore" xml:space="preserve">
        <value>Store does not implement IQueryableUserStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserClaimStore" xml:space="preserve">
        <value>Store does not implement IUserClaimStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserConfirmationStore" xml:space="preserve">
        <value>Store does not implement IUserConfirmationStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserEmailStore" xml:space="preserve">
        <value>Store does not implement IUserEmailStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserLockoutStore" xml:space="preserve">
        <value>Store does not implement IUserLockoutStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserLoginStore" xml:space="preserve">
        <value>Store does not implement IUserLoginStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserPasswordStore" xml:space="preserve">
        <value>Store does not implement IUserPasswordStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserPhoneNumberStore" xml:space="preserve">
        <value>Store does not implement IUserPhoneNumberStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserRoleStore" xml:space="preserve">
        <value>Store does not implement IUserRoleStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserSecurityStampStore" xml:space="preserve">
        <value>Store does not implement IUserSecurityStampStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="StoreNotIUserTwoFactorStore" xml:space="preserve">
        <value>Store does not implement IUserTwoFactorStore&amp;lt;TUser&amp;gt;.</value>
    </data>
    <data name="UserAlreadyHasPassword" xml:space="preserve">
        <value>User already has a password set.</value>
    </data>
    <data name="UserAlreadyInRole" xml:space="preserve">
        <value>User already in role.</value>
    </data>
    <data name="UserIdNotFound" xml:space="preserve">
        <value>UserId not found.</value>
    </data>
    <data name="UserNameNotFound" xml:space="preserve">
        <value>User {0} does not exist.</value>
    </data>
    <data name="UserNotInRole" xml:space="preserve">
        <value>User is not in role.</value>
    </data>
    
  2. I created a 'IdentityResultErrorMessages.cs' class:

    public class IdentityResultErrorMessages
    {
      public static List<String> GetResourceEquivalent(IEnumerable<string> errors)
      {
        List<String> errorList = new List<String>();
        if (errors != null)
        {
          foreach (String error in errors)
          {
            if (error.StartsWith("An unknown failure has occured."))
            {
              errorList.Add(IdentityErrors.DefaultError);
            }
            else if (error.StartsWith("Email '") && error.EndsWith("' is already taken."))
            {
              errorList.Add(String.Format(IdentityErrors.DuplicateEmail, error.Replace("Email '", "").Replace("' is already taken.", "")));
            }
            else if (error.StartsWith("Name ") && error.EndsWith(" is already taken."))
            {
              errorList.Add(String.Format(IdentityErrors.DuplicateName, error.Replace("Name ", "").Replace(" is already taken.", "")));
            }
            else if (error.StartsWith("A user with that external login already exists."))
            {
              errorList.Add(IdentityErrors.ExternalLoginExists);
            }
            else if (error.StartsWith("Email '") && error.EndsWith("' is invalid."))
            {
              errorList.Add(String.Format(IdentityErrors.InvalidEmail, error.Replace("Email '", "").Replace("' is invalid.", "")));
            }
            else if (error.StartsWith("Invalid token."))
            {
              errorList.Add(IdentityErrors.InvalidToken);
            }
            else if (error.StartsWith("User name ") && error.EndsWith(" is invalid, can only contain letters or digits."))
            {
              errorList.Add(String.Format(IdentityErrors.InvalidUserName, error.Replace("User name ", "").Replace(" is invalid, can only contain letters or digits.", "")));
            }
            else if (error.StartsWith("Lockout is not enabled for this user."))
            {
              errorList.Add(IdentityErrors.LockoutNotEnabled);
            }
            else if (error.StartsWith("No IUserTokenProvider is registered."))
            {
              errorList.Add(IdentityErrors.NoTokenProvider);
            }
            else if (error.StartsWith("No IUserTwoFactorProvider for '") && error.EndsWith("' is registered."))
            {
              errorList.Add(String.Format(IdentityErrors.NoTwoFactorProvider, error.Replace("No IUserTwoFactorProvider for '", "").Replace("' is registered.", "")));
            }
            else if (error.StartsWith("Incorrect password."))
            {
              errorList.Add(IdentityErrors.PasswordMismatch);
            }
            else if (error.StartsWith("Passwords must have at least one digit ('0'-'9')."))
            {
              errorList.Add(IdentityErrors.PasswordRequireDigit);
            }
            else if (error.StartsWith("Passwords must have at least one lowercase ('a'-'z')."))
            {
              errorList.Add(IdentityErrors.PasswordRequireLower);
            }
            else if (error.StartsWith("Passwords must have at least one non letter or digit character."))
            {
              errorList.Add(IdentityErrors.PasswordRequireNonLetterOrDigit);
            }
            else if (error.StartsWith("Passwords must have at least one uppercase ('A'-'Z')."))
            {
              errorList.Add(IdentityErrors.PasswordRequireUpper);
            }
            else if (error.StartsWith("Passwords must be at least ") && error.EndsWith(" characters."))
            {
              errorList.Add(String.Format(IdentityErrors.PasswordTooShort, error.Replace("Passwords must be at least ", "").Replace(" characters.", "")));
            }
            else if (error.EndsWith(" cannot be null or empty."))
            {
              errorList.Add(String.Format(IdentityErrors.PropertyTooShort, error.Replace(" cannot be null or empty.", "")));
            }
            else if (error.StartsWith("Role ") && error.EndsWith(" does not exist."))
            {
              errorList.Add(String.Format(IdentityErrors.RoleNotFound, error.Replace("Role ", "").Replace(" does not exist.", "")));
            }
            else if (error.StartsWith("Store does not implement IQueryableRoleStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIQueryableRoleStore);
            }
            else if (error.StartsWith("Store does not implement IQueryableUserStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIQueryableUserStore);
            }
            else if (error.StartsWith("Store does not implement IUserClaimStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserClaimStore);
            }
            else if (error.StartsWith("Store does not implement IUserConfirmationStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserConfirmationStore);
            }
            else if (error.StartsWith("Store does not implement IUserEmailStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserEmailStore);
            }
            else if (error.StartsWith("Store does not implement IUserLockoutStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserLockoutStore);
            }
            else if (error.StartsWith("Store does not implement IUserLoginStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserLoginStore);
            }
            else if (error.StartsWith("Store does not implement IUserPasswordStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserPasswordStore);
            }
            else if (error.StartsWith("Store does not implement IUserPhoneNumberStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserPhoneNumberStore);
            }
            else if (error.StartsWith("Store does not implement IUserRoleStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserRoleStore);
            }
            else if (error.StartsWith("Store does not implement IUserSecurityStampStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserSecurityStampStore);
            }
            else if (error.StartsWith("Store does not implement IUserTwoFactorStore"))
            {
              errorList.Add(IdentityErrors.StoreNotIUserTwoFactorStore);
            }
            else if (error.StartsWith("User already has a password set."))
            {
              errorList.Add(IdentityErrors.UserAlreadyHasPassword);
            }
            else if (error.StartsWith("User already in role."))
            {
              errorList.Add(IdentityErrors.UserAlreadyInRole);
            }
            else if (error.StartsWith("UserId not found."))
            {
              errorList.Add(IdentityErrors.UserIdNotFound);
            }
            else if (error.StartsWith("User ") && error.EndsWith(" does not exist."))
            {
              errorList.Add(String.Format(IdentityErrors.UserNameNotFound, error.Replace("User ", "").Replace(" does not exist.", "")));
            }
            else if (error.StartsWith("User is not in role."))
            {
              errorList.Add(IdentityErrors.UserNotInRole);
            }
          }
        }
        return errorList;
      }
    }
    
  3. I changed the Controller's AddErrors method to the following:

    private void AddErrors(IdentityResult result)
    {
      foreach (var error in IdentityResultErrorMessages.GetResourceEquivalent(result.Errors))
      {
        ModelState.AddModelError("", error);
      }
    }
    

Now, I can create resource files for the other language content I want to serve up on my website.

Grumous answered 12/12, 2017 at 3:5 Comment(1)
This solution fails as soon as someone changes the original english error messages. I would not recommend it to do it that way..Lastminute
J
2

In addition to @Gerardo Grinolli answer this translated versions for Russian:

public class CustomIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"Произошла неизвестная ошибка" }; }
    public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Ошибка оптимистичного контроля параллелизма, объект был изменён" }; }
    public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Некорретный пароль" }; }
    public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Недействительный токен" }; }
    public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Пользователь с таким логином уже существует" }; }
    public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Имя пользователя '{userName}' некорректно, может содержать только буквы и цифры" }; }
    public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"Email '{email}' некорректен" }; }
    public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Пользователь с именем '{userName}' уже существует" }; }
    public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"Email '{email}' уже используется" }; }
    public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Имя роли '{role}' некорректно" }; }
    public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Имя роли '{role}' уже используется" }; }
    public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Пользователь уже установил пароль" }; }
    public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Блокировка недоступна для этого пользователя" }; }
    public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Пользователю уже присвоена роль '{role}'." }; }
    public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"У пользователя нет роли '{role}'." }; }
    public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Пароль должен быть длиной не менее {length} символов" }; }
    public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Пароль должен быть содержать хотя бы один не буквенно-цифровой символ" }; }
    public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Пароль должен содержать хотя бы одну цифру ('0'-'9')." }; }
    public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Пароль должен содержать хотя бы один символ в нижнем регистре ('a'-'z')." }; }
    public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Пароль должен содержать хотя бы один символ в верхнем регистре ('A'-'Z')" }; }
}
Jalbert answered 28/11, 2018 at 13:26 Comment(0)
D
1

Let me share with you what I´ve done to accomplish this in Spanish. There you can customize the messages easily!

string Errores = result.Errors.FirstOrDefault();
Errores = Errores.Replace("Name " + Email.Text + " is already taken.", "- El mail " + Email.Text + " ya fue registrado. Intente recuperar la clave.<br/>");
Errores = Errores.Replace("Passwords must be at least 6 characters.", "- La clave debe contener por lo menos 6 caracteres.<br/>");
Errores = Errores.Replace("Passwords must have at least one non letter or digit character.", "- La clave debe contener por lo menos un caracter que no sea letra ni dígito. Por ejemplo: un punto.<br/>");
Errores = Errores.Replace("Passwords must have at least one digit ('0'-'9').", "- La clave debe contener al menos un dígito (entre 0 y 9).<br/>");
Errores = Errores.Replace("Passwords must have at least one uppercase ('A'-'Z').", "- La clave debe contener al menos una letra (entre A y Z).<br/>");
ErrorMessage.Text = "Errores:<br/><br/>" + Errores;
Decastro answered 8/6, 2015 at 13:20 Comment(0)
A
1

Ukrainian translation for Andrew Basarab answer

Resource file data:

<data name="ConcurrencyFailure" xml:space="preserve">
  <value>Помилка паралельності, об’єкт змінено.</value>
</data>
<data name="DefaultError" xml:space="preserve">
  <value>Сталася невідома помилка.</value>
</data>
<data name="DuplicateEmail" xml:space="preserve">
  <value>Адреса '{0}' зайнята.</value>
</data>
<data name="DuplicateRoleName" xml:space="preserve">
  <value>Ім'я групи '{0}' зайняте.</value>
</data>
<data name="DuplicateUserName" xml:space="preserve">
  <value>Ім'я користувача '{0}' зайняте.</value>
</data>
<data name="InvalidEmail" xml:space="preserve">
  <value>Неприпустима адреса Email '{0}'.</value>
</data>
<data name="InvalidRoleName" xml:space="preserve">
  <value>Неприпустима назва групи '{0}'.</value>
</data>
<data name="InvalidToken" xml:space="preserve">
  <value>Недійсний або невірний токен.</value>
</data>
<data name="InvalidUserName" xml:space="preserve">
  <value>Неприпустиме ім'я користувача '{0}', ім'я може містити тільки символи і цифри.</value>
</data>
<data name="LoginAlreadyAssociated" xml:space="preserve">
  <value>Користувач з таким іменем вже існує.</value>
</data>
<data name="PasswordMismatch" xml:space="preserve">
  <value>Невірний пароль.</value>
</data>
<data name="PasswordRequiresDigit" xml:space="preserve">
  <value>Пароль повинен мати хоча б одну цифру ('0'-'9').</value>
</data>
<data name="PasswordRequiresLower" xml:space="preserve">
  <value>Пароль повинен мати як мінімум одну малу літеру ('a'-'z').</value>
</data>
<data name="PasswordRequiresNonAlphanumeric" xml:space="preserve">
  <value>Пароль повинен мати хоча б один буквенно-цифровий символ.</value>
</data>
<data name="PasswordRequiresUniqueChars" xml:space="preserve">
  <value>Пароль повинен мати {0} спеціальних символів.</value>
</data>
<data name="PasswordRequiresUpper" xml:space="preserve">
  <value>Пароль повинен мати хоча б одну велику літеру ('A'-'Z').</value>
</data>
<data name="PasswordTooShort" xml:space="preserve">
  <value>Пароль повинен містити як мінімум {0} символів.</value>
</data>
<data name="UserAlreadyHasPassword" xml:space="preserve">
  <value>Пароль користувача вже встановлений.</value>
</data>
<data name="UserAlreadyInRole" xml:space="preserve">
  <value>Користувач вже має призначену групу '{0}'.</value>
</data>
<data name="UserLockoutNotEnabled" xml:space="preserve">
  <value>Блокування не встановлено для цього користувача.</value>
</data>
<data name="UserNotInRole" xml:space="preserve">
  <value>Користувач не входить до групи '{0}'.</value>
</data>
Aestivation answered 26/9, 2020 at 21:30 Comment(0)
T
0

My solution is to create new custom password validation class inherits from Microsoft.AspNet.Identity.PasswordValidator, Overrides the ValidateAsync which is the one that send out the error message. Customize the error message here and it works for me...

These class assume you have a global resource file names validator. The script from these class and the resource file sample can be found here ASP.NET Identity - Codeplex Sample Code

Here is my sample working code in vb.net


Imports System.Threading.Tasks 

Imports Microsoft.AspNet.Identity

Namespace MyNameSpace

Public Class MyPasswordValidator
    Inherits PasswordValidator
    Public Overrides Function ValidateAsync(item As String) As Task(Of IdentityResult)
        Dim errorMessage As String = String.Empty
        Dim bolminChar As Boolean = True
        Dim bolminDigit As Boolean = True
        Dim bolminLcase As Boolean = True
        Dim bolminUCase As Boolean = True
        Dim bolminNonAlfanum As Boolean = True

        If Not String.IsNullOrWhiteSpace(item) AndAlso item.Length >= Me.RequiredLength Then
            bolminChar = True
        Else
            bolminChar = False
            errorMessage = String.Format(CultureInfo.CurrentCulture, Resources.validator.PasswordTooShort & "<br/>", RequiredLength)
        End If

        If Me.RequireDigit Then
            Dim regex As New Regex("^(?=.*\d).+$")
            Dim match As Match = regex.Match(item)
            If match.Success Then
                bolminDigit = True
            Else
                bolminDigit = False
                errorMessage &= Resources.validator.PasswordRequireDigit & ".<br/>"
            End If
        End If

        If Me.RequireLowercase Then
            Dim LCrex As New Regex("^(?=.*[a-z]).+$")
            Dim LCMatch As Match = LCrex.Match(item)
            If LCMatch.Success Then
                bolminLcase = True
            Else
                bolminLcase = False
                errorMessage &= Resources.validator.PasswordRequireLower & "<br/>"
            End If
        End If

        If Me.RequireNonLetterOrDigit Then
            Dim NAFRex As New Regex("^(?=.*[-+_!@#$%=^\[\]\{\}()&*.,?]).+$")
            Dim NAFMatch As Match = NAFRex.Match(item)
            If NAFMatch.Success Then
                bolminNonAlfanum = True
            Else
                bolminNonAlfanum = False
                errorMessage &= Resources.validator.PasswordRequireNonLetterOrDigit & "<br/>"
            End If
        End If

        If Me.RequireUppercase Then
            Dim UCrex As New Regex("^(?=.*[A-Z]).+$")
            Dim UCMatch As Match = UCrex.Match(item)
            If UCMatch.Success Then
                bolminUCase = True
            Else
                bolminUCase = False
                errorMessage &= Resources.validator.PasswordRequireUpper & "<br/>"
            End If
        End If

        If bolminChar And bolminDigit And bolminLcase And bolminNonAlfanum And bolminUCase Then
            Return Task.FromResult(Of IdentityResult)(IdentityResult.Success)
        Else
            Return Task.FromResult(Of IdentityResult)(IdentityResult.Failed(New String() {errorMessage}))
        End If
        'Return MyBase.ValidateAsync(item)
    End Function
End Class

Public Class MyUserValidator
    Inherits UserValidator(Of applicationUser, int64)
    Private _manager As ApplicationUserManager

    Public Sub New(manager As ApplicationUserManager)
        MyBase.New(manager)
        _manager = manager
    End Sub

    Public Overrides Function ValidateAsync(item As applicationUser) As Task(Of IdentityResult)
        If item Is Nothing Then
            Throw New ArgumentNullException("item")
        End If

        Dim errors As New List(Of String)()
        Validateusername(item, errors)

        If Me.RequireUniqueEmail Then
            ValidateEmail(item, errors)
        End If

        If errors.Count > 0 Then
            Return Task.FromResult(Of IdentityResult)(IdentityResult.Failed(errors.ToArray()))
        End If
        Return Task.FromResult(Of IdentityResult)(IdentityResult.Success)
    End Function

    Private Sub Validateusername(User As applicationUser, errors As List(Of String))
        If String.IsNullOrWhiteSpace(User.UserName) Then
            errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.validator.PropertyTooShort, "Email")) '
        ElseIf Me.AllowOnlyAlphanumericUserNames AndAlso Not Regex.IsMatch(User.UserName, "^[A-Za-z0-9@_\.]+$") Then
            ' If any characters are not letters or digits, its an illegal user name
            errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.validator.InvalidUserName, User.UserName))
        Else
            Dim owner = _manager.FindByName(User.UserName)
            If owner IsNot Nothing AndAlso Not EqualityComparer(Of applicationUser).ReferenceEquals(owner.Id, User.Id) Then
                errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.validator.DuplicateName, User.UserName))
            End If
        End If
    End Sub

    Private Sub ValidateEmail(User As ApplicationUser, errors As List(Of String))
        Dim email As String = String.Empty

        If User.Id > 0 Then
            email = _manager.GetEmail(User.Id)
        End If
        If String.IsNullOrWhiteSpace(email) Then
            errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.validator.PropertyTooShort, "Email"))
            Return
        End If

        Try
            Dim m As New MailAddress(email)
        Catch ex As Exception
            errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.validator.InvalidEmail, email))
            Return
        End Try
        Dim owner = _manager.FindByEmail(email)
        If owner IsNot Nothing AndAlso Not EqualityComparer(Of ApplicationUser).ReferenceEquals(owner.Id, User.Id) Then
            errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.validator.DuplicateName, email))
        End If
    End Sub
End Class

Remember to update the setting in your identityConfig.vb file to used these class.

Trogon answered 11/4, 2015 at 13:22 Comment(0)
R
0

My solution was a little bit dirty but It works as expected. The idea is to assign all the errors that the IdentityResult object result brings when we register a new user:

var result = await UserManager.CreateAsync(user, model.Password);

To a new one that we will create. First, we need to create a List that will contain our custom errors:

var erroresEspanol = new List<string>();

Then, we need to iterate trough the errors inside result and add a new custom error for every one of them depending on which was the cause of it (Duplicate user, email, etc.):

foreach (var error in result.Errors)
            {
                if (error == ("Name " + model.Usuario + " is already taken."))
                {
                    erroresEspanol.Add("El Usuario " + model.Usuario + " ya existe.");
                }
                if (error.Substring(0, error.IndexOf(" ")) == "Email")
                {
                    erroresEspanol.Add("El Email " + model.Email + " ya fue ingresado.");
                }
                if (error.Substring(0, error.IndexOf(" ")) == "Passwords")
                {
                    erroresEspanol.Add("La contraseña debe contener mayúscula, minúscula y al menos 6 caracteres de longitud.");
                }
            }

So after that we just create a new IdentityResult object:

var resultado = new IdentityResult(erroresEspanol);

And pass it to the AddErrors method at the end of our Register action:

AddErrors(resultado);
Revelatory answered 20/7, 2016 at 15:34 Comment(0)
C
0

Having come across the same problem one can provide your own resource files to achieve this. Of course it requires a bit of reflection hacking! First you will need to be running with full security, ie set in your web.config:

<system.web>
  <securityPolicy>
     <trustLevel name="Full" policyFile="internal"/>
  </securityPolicy>
...

Next in your app start up code:

var ass = Assembly.Load("Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
Type hack = ass.GetType("Microsoft.AspNet.Identity.Resources");
var field = hack.GetField("resourceMan",
                        BindingFlags.Static |
                        BindingFlags.NonPublic);
// NOTE: this is where you set you own resource manager!
field.SetValue(null, new global::System.Resources.ResourceManager("WebApplication1.Resources", typeof(WebApplication1.Resources).Assembly));

Job done!

Corporal answered 16/9, 2016 at 17:20 Comment(1)
dude thanks a lot! For those who can't use .NET Core and want to translate the message this is the best solution I found so far.Legible
I
0

I managed to find a solution to create localized version of AspNet.Identity for cultures that no ready-to-use package is available for. Steps are:

  1. Download the source code from GitHub and open the src/Microsoft.AspNet.Identity.Core project in visual studio.
  2. Add a new item (Resource file) to the project. Name it Resources.aa-BB.resx which aa-BB is the culture you need to localize the assembly for. eg.: Resources.fa-IR.resx.
  3. Open the new created file and copy resource items from Resources.resx to it.
  4. Localize the texts as you want.
  5. Build the project.
  6. Go to the bin folder and under the Debug or Release directory you will see a folder named aa-BB (the culture you entered before). Copy the folder to the bin directory of your project.
  7. Make the changes that @1AmirJalali said (this post).
  8. Well done! Localization is complete. Try to share your localized package :)
Indiscrimination answered 14/6, 2018 at 7:52 Comment(0)
C
0

French version (with C# 9 syntax) :

public class FrenchIdentityErrorDescriber : IdentityErrorDescriber
{
    public override IdentityError DefaultError() => new() { Code = nameof(DefaultError), Description = "Une erreur est survenue." };
    public override IdentityError ConcurrencyFailure() => new() { Code = nameof(ConcurrencyFailure), Description = "Erreur de concurrence optimiste, l'objet a été modifié." };
    public override IdentityError PasswordMismatch() => new() { Code = nameof(PasswordMismatch), Description = "Mot de passe incorrect." };
    public override IdentityError InvalidToken() => new() { Code = nameof(InvalidToken), Description = "Jeton invalide." };
    public override IdentityError LoginAlreadyAssociated() => new() { Code = nameof(LoginAlreadyAssociated), Description = "Un utilisateur est déjà enregistré avec cet identifiant." };
    public override IdentityError InvalidUserName(string userName) => new() { Code = nameof(InvalidUserName), Description = $"Le nom d'utilisateur '{userName}' est invalide. Il ne peut contenir que des caractères alphanumériques." };
    public override IdentityError InvalidEmail(string email) => new() { Code = nameof(InvalidEmail), Description = $"L'email '{email}' est invalide" };
    public override IdentityError DuplicateUserName(string userName) => new() { Code = nameof(DuplicateUserName), Description = $"Le nom d'utilisateur '{userName}' est déjà pris." };
    public override IdentityError DuplicateEmail(string email) => new() { Code = nameof(DuplicateEmail), Description = $"L'adresse email '{email}' est déjà enregistrée." };
    public override IdentityError InvalidRoleName(string role) => new() { Code = nameof(InvalidRoleName), Description = $"Le rôle '{role}' est invalide." };
    public override IdentityError DuplicateRoleName(string role) => new() { Code = nameof(DuplicateRoleName), Description = $"Le rôle '{role}' existe déjà." };
    public override IdentityError UserAlreadyHasPassword() => new() { Code = nameof(UserAlreadyHasPassword), Description = "L'utilisateur possède déjà un mot de passe." };
    public override IdentityError UserLockoutNotEnabled() => new() { Code = nameof(UserLockoutNotEnabled), Description = "Le verrou de compte n'est pas actif pour l'utilisateur." };
    public override IdentityError UserAlreadyInRole(string role) => new() { Code = nameof(UserAlreadyInRole), Description = $"L'utilisateur possède déjà le rôle '{role}'." };
    public override IdentityError UserNotInRole(string role) => new() { Code = nameof(UserNotInRole), Description = $"L'utilisateur ne possède pas le rôle '{role}'." };
    public override IdentityError PasswordTooShort(int length) => new() { Code = nameof(PasswordTooShort), Description = $"Le mot de passe doit faire minimum {length} caractères." };
    public override IdentityError PasswordRequiresNonAlphanumeric() => new() { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Le mot de passe doit contenir au moins un caractère non alphanumérique." };
    public override IdentityError PasswordRequiresDigit() => new() { Code = nameof(PasswordRequiresDigit), Description = "Le mot de passe doit contenir au moins un chiffre ('0'-'9')." };
    public override IdentityError PasswordRequiresLower() => new() { Code = nameof(PasswordRequiresLower), Description = "Le mot de passe doit contenir au moins une minuscule ('a'-'z')." };
    public override IdentityError PasswordRequiresUpper() => new() { Code = nameof(PasswordRequiresUpper), Description = "Le mot de passe doit contenir au moins une majuscule ('A'-'Z')." };
}
Crust answered 29/10, 2021 at 13:9 Comment(0)
A
0

for PasswordContainseSequence example

        public static string IdentityErrorToTurkish(string code, string description)
        {
            switch (code)
            {
                case "PasswordContainseSequence": description = "Parola sayısal sıra içeremez. Lütfen şifrenizi 123456 gibi ardışık yapmayınız."; break;
                default: description = $"Hata: {description}"; break;
            }
            return description;
        }
Aircrewman answered 29/4, 2023 at 18:54 Comment(0)
L
0

I added this package to my project:

PiotrTrojan.AspNetCore.IdentityErrorLocalization

And I simply added this line of code in Program.cs

builder.Services.AddIdentity<User, IdentityRole>(options => { ....

}).AddEntityFrameworkStores() .AddPersianIdentityErrorDescriber();

Laurentian answered 5/7, 2023 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.