ASP.Net 核心本地化
ASP.Net Core localization
ASP.Net 核心功能 new support for localization.
在我的项目中我只需要一种语言。对于大多数文本和注释,我可以用我的语言指定内容,但是对于来自 ASP.Net Core 本身的文本,语言是英语。
示例:
- 密码必须至少有一个大写字母 ('A'-'Z')。
- 密码必须至少包含一位数字 ('0'-'9')。
- 用户名'x@x.com'已被占用。
- E-post 字段不是有效的电子邮件地址。
- 值“”无效。
我试过手动设置文化,但语言仍然是英语。
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("nb-NO"),
SupportedCultures = new List<CultureInfo> { new CultureInfo("nb-NO") },
SupportedUICultures = new List<CultureInfo> { new CultureInfo("nb-NO") }
});
如何更改 ASP.Net Core 的语言,或覆盖其默认文本?
列出的错误消息在 ASP.NET Core Identity 中定义并由 IdentityErrorDescriber
提供。到目前为止我还没有找到翻译的资源文件,我认为它们没有本地化。在我的系统(德语语言环境)上,尽管 CultureInfo
设置正确,但它们也没有被翻译。
您可以将自定义 IdentityErrorDescriber 配置为 return 您自己的消息及其翻译。它被描述为例如在
在 Startup.cs
的 Configure
方法中,您可以连接继承自 IdentityErrorDescriber
的错误描述符 class,例如
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<TranslatedIdentityErrorDescriber>();
对于其他默认模型错误消息(如无效数字),您可以在 ModelBindingMessageProvider
中提供自己的访问器函数。此提供程序由 ASP.NET 核心 MVC 使用,也可以在 Startup.cs
中配置。
services.AddMvc(
options =>
options.ModelBindingMessageProvider.ValueIsInvalidAccessor = s => $"My not valid text for {s}");
挪威语 IdentityErrorDescriber,以备不时之需。
public class NorwegianIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError()
{
return new IdentityError()
{
Code = "DefaultError",
Description = "En ukjent feil har oppstått."
};
}
public override IdentityError ConcurrencyFailure()
{
return new IdentityError()
{
Code = "ConcurrencyFailure",
Description = "Optimistisk samtidighet feilet, objektet har blitt endret."
};
}
public override IdentityError PasswordMismatch()
{
return new IdentityError()
{
Code = "PasswordMismatch",
Description = "Feil passord."
};
}
public override IdentityError InvalidToken()
{
return new IdentityError()
{
Code = "InvalidToken",
Description = "Feil token."
};
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError()
{
Code = "LoginAlreadyAssociated",
Description = "En bruker med dette brukernavnet finnes allerede."
};
}
public override IdentityError InvalidUserName(string userName)
{
IdentityError identityError = new IdentityError();
identityError.Code = "InvalidUserName";
string str = $"Brkernavnet '{userName}' er ikke gyldig. Det kan kun inneholde bokstaver og tall.";
identityError.Description = str;
return identityError;
}
public override IdentityError InvalidEmail(string email)
{
IdentityError identityError = new IdentityError();
identityError.Code = "InvalidEmail";
string str = $"E-post '{email}' er ugyldig.";
identityError.Description = str;
return identityError;
}
public override IdentityError DuplicateUserName(string userName)
{
IdentityError identityError = new IdentityError();
identityError.Code = "DuplicateUserName";
string str = $"Brukernavn '{userName}' er allerede tatt.";
identityError.Description = str;
return identityError;
}
public override IdentityError DuplicateEmail(string email)
{
IdentityError identityError = new IdentityError();
identityError.Code = "DuplicateEmail";
string str = $"E-post '{email}' er allerede tatt.";
identityError.Description = str;
return identityError;
}
public override IdentityError InvalidRoleName(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "InvalidRoleName";
string str = $"Rollenavn '{role}' er ugyldig.";
identityError.Description = str;
return identityError;
}
public override IdentityError DuplicateRoleName(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "DuplicateRoleName";
string str = $"Rollenavn '{role}' er allerede tatt.";
identityError.Description = str;
return identityError;
}
public virtual IdentityError UserAlreadyHasPassword()
{
return new IdentityError()
{
Code = "UserAlreadyHasPassword",
Description = "Bruker har allerede passord satt."
};
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError()
{
Code = "UserLockoutNotEnabled",
Description = "Utestenging er ikke slått på for denne brukeren."
};
}
public override IdentityError UserAlreadyInRole(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "UserAlreadyInRole";
string str = $"Brukeren er allerede i rolle '{role}'.";
identityError.Description = str;
return identityError;
}
public override IdentityError UserNotInRole(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "UserNotInRole";
string str = $"Bruker er ikke i rolle '{role}'.";
identityError.Description = str;
return identityError;
}
public override IdentityError PasswordTooShort(int length)
{
IdentityError identityError = new IdentityError();
identityError.Code = "PasswordTooShort";
string str = $"Passordet må være på minimum {length} tegn.";
identityError.Description = str;
return identityError;
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError()
{
Code = "PasswordRequiresNonAlphanumeric",
Description = "Passordet må inneholde minst ett spesialtegn."
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError()
{
Code = "PasswordRequiresDigit",
Description = "Passordet må inneholde minst ett siffer."
};
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError()
{
Code = "PasswordRequiresLower",
Description = "Passordet må inneholde minst en liten bokstav (a-z)."
};
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError()
{
Code = "PasswordRequiresUpper",
Description = "Passordet må inneholde minst en stor bokstav (A-Z)."
};
}
}
基于 rboe 和 Tedd Hansen 的出色回答,我写了一个基于 IStringLocalizer
的 IdentityErrorDescriber
供我自己使用,我想我会在这里分享它以防有人需要多语言支持:)
基本思想是以通常的方式为您的默认语言和任何其他语言创建一个资源文件。
(https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization)
位于(如果您保留我的 class 姓名):
/Resources/你的命名空间.LocalizedIdentityErrorDescriber.resx
/Resources/你的命名空间.LocalizedIdentityErrorDescriber.fr.resx
等...
在其中,您将使用错误代码(例如:DefaultError、ConcurrencyError)作为键。
然后在下方添加class
LocalizedIdentityErrorDescriber.cs
public class LocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
/// <summary>
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// used to localize the strings
/// </summary>
private readonly IStringLocalizer<LocalizedIdentityErrorDescriber> localizer;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizedIdentityErrorDescriber"/> class.
/// </summary>
/// <param name="localizer">
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// that we will use to localize the strings
/// </param>
public LocalizedIdentityErrorDescriber(IStringLocalizer<LocalizedIdentityErrorDescriber> localizer)
{
this.localizer = localizer;
}
/// <summary>
/// Returns the default <see cref="IdentityError" />.
/// </summary>
/// <returns>The default <see cref="IdentityError" /></returns>
public override IdentityError DefaultError()
{
return this.GetErrorByCode("DefaultError");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a concurrency failure.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a concurrency failure.</returns>
public override IdentityError ConcurrencyFailure()
{
return this.GetErrorByCode("ConcurrencyFailure");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password mismatch.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password mismatch.</returns>
public override IdentityError PasswordMismatch()
{
return this.GetErrorByCode("PasswordMismatch");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an invalid token.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an invalid token.</returns>
public override IdentityError InvalidToken()
{
return this.GetErrorByCode("InvalidToken");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an external login is already associated with an account.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an external login is already associated with an account.</returns>
public override IdentityError LoginAlreadyAssociated()
{
return this.GetErrorByCode("LoginAlreadyAssociated");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.
/// </summary>
/// <param name="userName">The user name that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.</returns>
public override IdentityError InvalidUserName(string userName)
{
return this.FormatErrorByCode("InvalidUserName", (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.
/// </summary>
/// <param name="email">The email that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.</returns>
public override IdentityError InvalidEmail(string email)
{
return this.FormatErrorByCode("InvalidEmail", (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.
/// </summary>
/// <param name="userName">The user name that already exists.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.</returns>
public override IdentityError DuplicateUserName(string userName)
{
return this.FormatErrorByCode("DuplicateUserName", (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.
/// </summary>
/// <param name="email">The email that is already associated with an account.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.</returns>
public override IdentityError DuplicateEmail(string email)
{
return this.FormatErrorByCode("DuplicateEmail", (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name is invalid.
/// </summary>
/// <param name="role">The invalid role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name is invalid.</returns>
public override IdentityError InvalidRoleName(string role)
{
return this.FormatErrorByCode("InvalidRoleName", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name already exists.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name already exists.</returns>
public override IdentityError DuplicateRoleName(string role)
{
return this.FormatErrorByCode("DuplicateRoleName", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user already has a password.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a user already has a password.</returns>
public override IdentityError UserAlreadyHasPassword()
{
return this.GetErrorByCode("UserAlreadyHasPassword");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating user lockout is not enabled.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating user lockout is not enabled..</returns>
public override IdentityError UserLockoutNotEnabled()
{
return this.GetErrorByCode("UserLockoutNotEnabled");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.</returns>
public override IdentityError UserAlreadyInRole(string role)
{
return this.FormatErrorByCode("UserAlreadyInRole", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.</returns>
public override IdentityError UserNotInRole(string role)
{
return this.FormatErrorByCode("UserNotInRole", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.
/// </summary>
/// <param name="length">The length that is not long enough.</param>
/// <returns>An <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.</returns>
public override IdentityError PasswordTooShort(int length)
{
return this.FormatErrorByCode("PasswordTooShort", (object)length);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character.</returns>
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return this.GetErrorByCode("PasswordRequiresNonAlphanumeric");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a numeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a numeric character.</returns>
public override IdentityError PasswordRequiresDigit()
{
return this.GetErrorByCode("PasswordRequiresDigit");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter.</returns>
public override IdentityError PasswordRequiresLower()
{
return this.GetErrorByCode("PasswordRequiresLower");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter.</returns>
public override IdentityError PasswordRequiresUpper()
{
return this.GetErrorByCode("PasswordRequiresUpper");
}
/// <summary>Returns a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError GetErrorByCode(string code)
{
return new IdentityError()
{
Code = code,
Description = this.localizer.GetString(code)
};
}
/// <summary>Formats a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <param name="parameters">The parameters to format the string with.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError FormatErrorByCode(string code, params object[] parameters)
{
return new IdentityError
{
Code = code,
Description = string.Format(this.localizer.GetString(code, parameters))
};
}
}
并初始化一切:
Startup.cs
[...]
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<LocalizedIdentityErrorDescriber>();
services.AddLocalization(options => options.ResourcesPath = "Resources");
// Your service configuration code
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
// Your service configuration code cont.
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// your configuration code
app.UseRequestLocalization(
new RequestLocalizationOptions()
{
DefaultRequestCulture = new RequestCulture("fr"),
SupportedCultures = SupportedCultures,
SupportedUICultures = SupportedCultures
});
app.UseStaticFiles();
app.UseIdentity();
// your configuration code
}
[...]
和俄罗斯的 IdentityErrorDescriber,以备不时之需。
public class RussianIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError ConcurrencyFailure()
{
return new IdentityError
{
Code = "ConcurrencyFailure",
Description = "Сбой в параллельных запросах. Возможно объект был изменен."
};
}
public override IdentityError DefaultError()
{
return new IdentityError
{
Code = "DefaultError",
Description = "Произошла неизвестная ошибка при авторизации."
};
}
public override IdentityError DuplicateEmail(string email)
{
return new IdentityError
{
Code = "DuplicateEmail",
Description = $"E-mail '{email}' уже используется."
};
}
public override IdentityError DuplicateRoleName(string role)
{
return new IdentityError
{
Code = "DuplicateRoleName",
Description = $"Роль с именем '{role}' уже существует."
};
}
public override IdentityError DuplicateUserName(string userName)
{
return new IdentityError
{
Code = "DuplicateUserName",
Description = $"Пользователь '{userName}' уже зарегистрирован."
};
}
public override IdentityError InvalidEmail(string email)
{
return new IdentityError
{
Code = "InvalidEmail",
Description = $"E-mail '{email}' содержит неверный формат."
};
}
public override IdentityError InvalidRoleName(string role)
{
return new IdentityError
{
Code = "InvalidRoleName",
Description = $"Имя роли '{role}' задано не верно (содержит не допустимые символы либо длину)."
};
}
public override IdentityError InvalidToken()
{
return new IdentityError
{
Code = "InvalidToken",
Description = "Неправильно указан код подтверждения (token)."
};
}
public override IdentityError InvalidUserName(string userName)
{
return new IdentityError
{
Code = "InvalidUserName",
Description = $"Имя пользователя '{userName}' указано не верно (содержит не допустимые символы либо длину)."
};
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError
{
Code = "LoginAlreadyAssociated",
Description = "Данный пользователь уже привязан к аккаунту."
};
}
public override IdentityError PasswordMismatch()
{
return new IdentityError
{
Code = "PasswordMismatch",
Description = "Пароли не совпадают."
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError
{
Code = "PasswordRequiresDigit",
Description = "Пароль должен содержать минимум одну цифру."
};
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError
{
Code = "PasswordRequiresLower",
Description = "Пароль должен содержать минимум одну строчную букву."
};
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError
{
Code = "PasswordRequiresNonAlphanumeric",
Description = "Пароль должен содержать минимум один специальный символ (не буквенно-цифровой)."
};
}
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
{
return new IdentityError
{
Code = "PasswordRequiresUniqueChars",
Description = $"Пароль должен содержать минимум '{uniqueChars}' не повторяющихся символов."
};
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError
{
Code = "PasswordRequiresUpper",
Description = "Пароль должен содержать минимум одну заглавную букву."
};
}
public override IdentityError PasswordTooShort(int length)
{
return new IdentityError
{
Code = "PasswordTooShort",
Description = $"Пароль слишком короткий. Минимальное количество символов: '{length}'."
};
}
public override IdentityError RecoveryCodeRedemptionFailed()
{
return new IdentityError
{
Code = "RecoveryCodeRedemptionFailed",
Description = "Не удалось использовать код восстановления."
};
}
public override IdentityError UserAlreadyHasPassword()
{
return new IdentityError
{
Code = "UserAlreadyHasPassword",
Description = "Пароль для пользователя уже задан."
};
}
public override IdentityError UserAlreadyInRole(string role)
{
return new IdentityError
{
Code = "UserAlreadyInRole",
Description = $"Роль '{role}' уже привязана к пользователю."
};
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError
{
Code = "UserLockoutNotEnabled",
Description = "Блокировка пользователя отключена."
};
}
public override IdentityError UserNotInRole(string role)
{
return new IdentityError
{
Code = "UserNotInRole",
Description = $"Пользователь должен иметь роль: '{role}'"
};
}
}
In `Startup.cs` set `RussianIdentityErrorDescriber `
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<RussianIdentityErrorDescriber>();
// ...
}
如果您正在寻找波兰语,这里是:
public class PolishLocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError()
{
return new IdentityError
{
Code = nameof(DefaultError),
Description = "Wystąpił nieznany błąd."
};
}
public override IdentityError ConcurrencyFailure()
{
return new IdentityError
{
Code = nameof(ConcurrencyFailure),
Description = "Błąd współbieżności, obiekt został już zmodyfikowany."
};
}
public override IdentityError PasswordMismatch()
{
return new IdentityError
{
Code = nameof(PasswordMismatch),
Description = "Niepoprawne hasło."
};
}
public override IdentityError InvalidToken()
{
return new IdentityError
{
Code = nameof(InvalidToken),
Description = "Nieprawidłowy token."
};
}
public override IdentityError RecoveryCodeRedemptionFailed()
{
return new IdentityError
{
Code = nameof(RecoveryCodeRedemptionFailed),
Description = "Pobranie kodu odzyskiwania nie powiodło się."
};
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError
{
Code = nameof(LoginAlreadyAssociated),
Description = "Użytkownik o tym loginie już istnieje."
};
}
public override IdentityError InvalidUserName(string userName)
{
return new IdentityError
{
Code = nameof(InvalidUserName),
Description =
$"Nazwa użytkownika '{userName}' jest nieprawidłowa, może zawierać tylko litery lub cyfry."
};
}
public override IdentityError InvalidEmail(string email)
{
return new IdentityError
{
Code = nameof(InvalidEmail),
Description = $"Adres e-mail '{email}' jest nieprawidłowy."
};
}
public override IdentityError DuplicateUserName(string userName)
{
return new IdentityError
{
Code = nameof(DuplicateUserName),
Description = $"Nazwa '{userName}' jest już zajęta."
};
}
public override IdentityError DuplicateEmail(string email)
{
return new IdentityError
{
Code = nameof(DuplicateEmail),
Description = $"Adres e-mail '{email}' jest już zajęty."
};
}
public override IdentityError InvalidRoleName(string role)
{
return new IdentityError
{
Code = nameof(InvalidRoleName),
Description = $"Nazwa roli '{role}' już niepoprawna."
};
}
public override IdentityError DuplicateRoleName(string role)
{
return new IdentityError
{
Code = nameof(DuplicateRoleName),
Description = $"Rola '{role}' już istnieje."
};
}
public override IdentityError UserAlreadyHasPassword()
{
return new IdentityError
{
Code = nameof(UserAlreadyHasPassword),
Description = "Użytkownik ma już ustawione hasło."
};
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError
{
Code = nameof(UserLockoutNotEnabled),
Description = "Blokada konta nie jest włączona dla tego użytkownika."
};
}
public override IdentityError UserAlreadyInRole(string role)
{
return new IdentityError
{
Code = nameof(UserAlreadyInRole),
Description = $"Użytkownik korzysta już z roli '{role}'."
};
}
public override IdentityError UserNotInRole(string role)
{
return new IdentityError
{
Code = nameof(UserNotInRole),
Description = $"Użytkownika nie ma w roli '{role}'."
};
}
public override IdentityError PasswordTooShort(int length)
{
return new IdentityError
{
Code = nameof(PasswordTooShort),
Description = $"Hasło musi składać się z co najmniej {length} znaków."
};
}
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
{
return new IdentityError
{
Code = nameof(PasswordRequiresUniqueChars),
Description = $"Hasło musi składać się z co najmniej {uniqueChars} unikalnych znaków."
};
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError
{
Code = nameof(PasswordRequiresNonAlphanumeric),
Description = "Hasło musi zawierać co najmniej jeden znak niebędący literą lub cyfrą."
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError
{
Code = nameof(PasswordRequiresDigit),
Description = "Hasło musi zawierać co najmniej jedną cyfrę (0-9)."
};
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError
{
Code = nameof(PasswordRequiresLower),
Description = "Hasło musi zawierać co najmniej jedną małą literę (a-z)."
};
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError
{
Code = nameof(PasswordRequiresUpper),
Description = "Hasło musi zawierać co najmniej jedną wielką literę (A-Z)."
};
}
}
让我对这个问题有一个全面的回答,并描述我是如何在阅读.net core源代码后得出解决方案的。
在进一步描述之前,首先使用 NuGet 安装此包 Microsoft.Extensions.Localization
你们可能还记得 asp.net 完整框架,文化之间的切换非常简单
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
但在 .net 核心中,区域性不再与当前线程相关联。 asp.net 核心引擎有一个管道,我们可以向这个管道添加不同的中间件,所以 RequestLocalizationMiddleware is the middleware class for handling localization, we might have multiple providers so it will iterate through all the culture providers like QueryStringRequestCultureProvider, CookieRequestCultureProvider, AcceptLanguageHeaderRequestCultureProvider, …
只要请求本地化中间件可以从第一个提供者那里获得当前语言环境,它就会忽略其他人并将请求传递给管道中的下一个中间件,因此列表中提供者的顺序非常重要。
我个人更喜欢将文化存储在浏览器cookie中,所以由于CookieRequestCultureProvider不是列表中的第一个文化提供者我将其移至列表顶部,这部分的配置在Startup.cs > ConfigureServices 如下
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fa-IR"),
new CultureInfo("de-DE")
};
options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
var defaultCookieRequestProvider =
options.RequestCultureProviders.FirstOrDefault(rcp =>
rcp.GetType() == typeof(CookieRequestCultureProvider));
if (defaultCookieRequestProvider != null)
options.RequestCultureProviders.Remove(defaultCookieRequestProvider);
options.RequestCultureProviders.Insert(0,
new CookieRequestCultureProvider()
{
CookieName = ".AspNetCore.Culture",
Options = options
});
});
让我描述一下上面的代码,我们的应用程序默认文化是 en-US 我们只支持英语,波斯语,德国所以如果浏览器具有不同的语言环境或您设置的语言不是这 3 种语言,则应用必须切换到默认文化。在上面的代码中,我只是从列表中删除 CookieCultureProvider 并将其添加为列表中的第一个提供者(*我已经描述了它必须是第一个的原因*)。默认的 CookieName 对我有用,你可以根据需要更改它。
不要忘记在 Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs
下面添加下面的代码
var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
到目前为止一切顺利。要有资源文件你必须指定资源的路径,我在web项目根路径中分别指定了Controller、Views、ViewModels和SharedResources的资源,层次结构如下
|-Resoures
|---Controllers
|---Views
|---Models
|---SharedResource.resx
|---SharedResource.fa-IR.resx
|---SharedResource.de-DE.resx
请记住,对于 SharedResource,在 Web 项目根路径中创建一个具有相同名称的空 class 我的意思是 SharedResource.cs class里面同名
在 Startup.cs 中添加以下代码片段以指定资源路径和其余部分。
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
AddViewLocalization(
LanguageViewLocationExpanderFormat.Suffix,
opts => { opts.ResourcesPath = "Resources/Views"; }) // this line is not required, it is just for more clarification
.AddDataAnnotationsLocalization();
使用此配置,例如当您在控制器中注入 IStringLocalizer 时,您必须在 Resources > Controllers 文件夹中有相应的资源文件(它们是 HomeController.resx、HomeController.fa-IR.resx, HomeController.de-DE.resx) 我们也可以在文件名中用 .(比如点)分隔路径我的意思是 Resources/Controllers/HomeController.resx 可以是 Resources/Controllers.HomeController.resx 中的文件,你必须将 IViewLocalizer 注入到视图中才能相应地在视图中进行本地化 你必须在 [=75= 中为视图提供资源文件] 文件夹,对于 ViewModels,因为我们将文件夹命名为 Models,请将所有 ViewModels 放入 Web 项目根路径中预先创建的名为 Models 的文件夹中,如果该文件夹有其他名称或者您更喜欢其他名称,请不要忘记重命名资源文件夹下的模型文件夹。然后你只需要注释模型,例如用[DisplayName("User Emailaddress")]注释ViewModel属性然后在模型内部相应的资源文件中创建资源(文件名必须与模型匹配class 名称)具有相同的密钥("User Emailaddress")。
让我们从已经开始的地方结束,我的意思是 CookieRequestCultureProvider。正如我之前所说,我更喜欢将它存储在 cookie 中,但这有点棘手,因为 cookie parsing 与您可能期望的有点不同,只需在下面添加您想要更改区域性的代码,只需替换preferedCulture 与您的文化偏好
var preferedCulture = "fa-IR"; // get the culture from user, i just mock it here in a variable
if (HttpContext.Response.Cookies.ContainsKey(".AspNetCore.Culture"))
{
HttpContext.Response.Cookies.Delete(".AspNetCore.Culture");
}
HttpContext.Response.Cookies.Append(".AspNetCore.Culture",
$"c={preferedCulture}|uic={preferedCulture}", new CookieOptions {Expires = DateTime.UtcNow.AddYears(1)});
好了,我们的 sp.net 核心网络应用程序现已本地化:)
对于那些想知道是否可以将消息本地化为当前所选文化的人,是的,这是可能的。在 asp.net core 2.2 你可以创建一个 class LocalizedIdentityErrorDescriber where IdentityResources是你的假人的名字 class(这里有描述:Globalization and localization):
public class LocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
/// <summary>
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// used to localize the strings
/// </summary>
private readonly IStringLocalizer<IdentityResources> localizer;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizedIdentityErrorDescriber"/> class.
/// </summary>
/// <param name="localizer">
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// that we will use to localize the strings
/// </param>
public LocalizedIdentityErrorDescriber(IStringLocalizer<IdentityResources> localizer)
{
this.localizer = localizer;
}
/// <summary>
/// Returns the default <see cref="IdentityError" />.
/// </summary>
/// <returns>The default <see cref="IdentityError" /></returns>
public override IdentityError DefaultError()
{
return this.GetErrorByCode(nameof(DefaultError));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a concurrency failure.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a concurrency failure.</returns>
public override IdentityError ConcurrencyFailure()
{
return this.GetErrorByCode(nameof(ConcurrencyFailure));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password mismatch.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password mismatch.</returns>
public override IdentityError PasswordMismatch()
{
return this.GetErrorByCode(nameof(PasswordMismatch));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an invalid token.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an invalid token.</returns>
public override IdentityError InvalidToken()
{
return this.GetErrorByCode(nameof(InvalidToken));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an external login is already associated with an account.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an external login is already associated with an account.</returns>
public override IdentityError LoginAlreadyAssociated()
{
return this.GetErrorByCode(nameof(LoginAlreadyAssociated));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.
/// </summary>
/// <param name="userName">The user name that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.</returns>
public override IdentityError InvalidUserName(string userName)
{
return this.FormatErrorByCode(nameof(InvalidUserName), (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.
/// </summary>
/// <param name="email">The email that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.</returns>
public override IdentityError InvalidEmail(string email)
{
return this.FormatErrorByCode(nameof(InvalidEmail), (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.
/// </summary>
/// <param name="userName">The user name that already exists.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.</returns>
public override IdentityError DuplicateUserName(string userName)
{
return this.FormatErrorByCode(nameof(DuplicateUserName), (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.
/// </summary>
/// <param name="email">The email that is already associated with an account.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.</returns>
public override IdentityError DuplicateEmail(string email)
{
return this.FormatErrorByCode(nameof(DuplicateEmail), (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name is invalid.
/// </summary>
/// <param name="role">The invalid role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name is invalid.</returns>
public override IdentityError InvalidRoleName(string role)
{
return this.FormatErrorByCode(nameof(InvalidRoleName), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name already exists.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name already exists.</returns>
public override IdentityError DuplicateRoleName(string role)
{
return this.FormatErrorByCode(nameof(DuplicateRoleName), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user already has a password.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a user already has a password.</returns>
public override IdentityError UserAlreadyHasPassword()
{
return this.GetErrorByCode(nameof(UserAlreadyHasPassword));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating user lockout is not enabled.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating user lockout is not enabled..</returns>
public override IdentityError UserLockoutNotEnabled()
{
return this.GetErrorByCode(nameof(UserLockoutNotEnabled));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.</returns>
public override IdentityError UserAlreadyInRole(string role)
{
return this.FormatErrorByCode(nameof(UserAlreadyInRole), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.</returns>
public override IdentityError UserNotInRole(string role)
{
return this.FormatErrorByCode(nameof(UserNotInRole), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.
/// </summary>
/// <param name="length">The length that is not long enough.</param>
/// <returns>An <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.</returns>
public override IdentityError PasswordTooShort(int length)
{
return this.FormatErrorByCode(nameof(PasswordTooShort), (object)length);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character.</returns>
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return this.GetErrorByCode(nameof(PasswordRequiresNonAlphanumeric));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a numeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a numeric character.</returns>
public override IdentityError PasswordRequiresDigit()
{
return this.GetErrorByCode(nameof(PasswordRequiresDigit));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter.</returns>
public override IdentityError PasswordRequiresLower()
{
return this.GetErrorByCode(nameof(PasswordRequiresLower));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter.</returns>
public override IdentityError PasswordRequiresUpper()
{
return this.GetErrorByCode(nameof(PasswordRequiresUpper));
}
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
{
return this.FormatErrorByCode(nameof(PasswordRequiresUniqueChars), (object)uniqueChars);
}
public override IdentityError RecoveryCodeRedemptionFailed()
{
return this.GetErrorByCode(nameof(RecoveryCodeRedemptionFailed));
}
/// <summary>Returns a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError GetErrorByCode(string code)
{
return new IdentityError()
{
Code = code,
Description = this.localizer.GetString(code)
};
}
/// <summary>Formats a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <param name="parameters">The parameters to format the string with.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError FormatErrorByCode(string code, params object[] parameters)
{
return new IdentityError
{
Code = code,
Description = string.Format(this.localizer.GetString(code, parameters))
};
}
}
然后为您的语言创建资源文件,如下所示:Resources\(虚拟名称 class 如上所述)(.culture).resx。对于您的默认语言文化,应留空。并且不要忘记“。”如果它不是默认的,则在区域性名称之前。您的 IdentityResources 文件应如下所示:
在Startup.cs中添加以下行:
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<nameofyourdbcontext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<LocalizedIdentityErrorDescriber>(); // this line is important
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en"), // english
new CultureInfo("tr"), // turkish
new CultureInfo("ru") // russian
};
options.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new CookieRequestCultureProvider()); // type of CultureProvider you want.
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var localizationOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
// IT IS IMPORTANT TO CALL UseRequestLocalization BEFORE UseMvc
app.UseRequestLocalization(localizationOptions.Value);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
现在你差不多完成了,但你需要设置 Culture cookie,这里有一个代码示例:Globalization and localization。
希望对大家有帮助。
瑞典语 IdentityErrorDescriber,以备不时之需。
public class SwedishIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = "Ett okänt fel har inträffat." }; }
public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Objektet har ändrats sedan uppläsning." }; }
public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Felaktigt lösenord." }; }
public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Ogiltigt token." }; }
public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "En användare med den här inloggningen finns redan." }; }
public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Användarnamnet '{userName}' är ogiltigt, kan endast innehålla bokstäver eller siffror." }; }
public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"E-postadressen {email} är ogiltig." }; }
public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Användarnamnet '{userName}' finns redan." }; }
public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"E-postadressen {email} finns redan." }; }
public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Rollen '{role}' är ogiltig." }; }
public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Rollen '{role}' finns redan." }; }
public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Användaren har redan angett ett lösenord." }; }
public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Lockout är inte aktiverat för den här användaren." }; }
public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Användaren har redan rollen '{role}'." }; }
public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Användaren har inte rollen '{role}'." }; }
public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Lösenordet måste ha minst {length} tecken." }; }
public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Lösenordet måste ha minst ett icke alfanumeriskt tecken." }; }
public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Lösenordet måste innehålla minst en siffra ('0'-'9')." }; }
public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Lösenordet måste innehålla minst en gemen ('a'-'z')." }; }
public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Lösenordet måste innehålla minst en versal ('A'-'Z')." }; }
}
ASP.Net 核心功能 new support for localization.
在我的项目中我只需要一种语言。对于大多数文本和注释,我可以用我的语言指定内容,但是对于来自 ASP.Net Core 本身的文本,语言是英语。
示例:
- 密码必须至少有一个大写字母 ('A'-'Z')。
- 密码必须至少包含一位数字 ('0'-'9')。
- 用户名'x@x.com'已被占用。
- E-post 字段不是有效的电子邮件地址。
- 值“”无效。
我试过手动设置文化,但语言仍然是英语。
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("nb-NO"),
SupportedCultures = new List<CultureInfo> { new CultureInfo("nb-NO") },
SupportedUICultures = new List<CultureInfo> { new CultureInfo("nb-NO") }
});
如何更改 ASP.Net Core 的语言,或覆盖其默认文本?
列出的错误消息在 ASP.NET Core Identity 中定义并由 IdentityErrorDescriber
提供。到目前为止我还没有找到翻译的资源文件,我认为它们没有本地化。在我的系统(德语语言环境)上,尽管 CultureInfo
设置正确,但它们也没有被翻译。
您可以将自定义 IdentityErrorDescriber 配置为 return 您自己的消息及其翻译。它被描述为例如在
在 Startup.cs
的 Configure
方法中,您可以连接继承自 IdentityErrorDescriber
的错误描述符 class,例如
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<TranslatedIdentityErrorDescriber>();
对于其他默认模型错误消息(如无效数字),您可以在 ModelBindingMessageProvider
中提供自己的访问器函数。此提供程序由 ASP.NET 核心 MVC 使用,也可以在 Startup.cs
中配置。
services.AddMvc(
options =>
options.ModelBindingMessageProvider.ValueIsInvalidAccessor = s => $"My not valid text for {s}");
挪威语 IdentityErrorDescriber,以备不时之需。
public class NorwegianIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError()
{
return new IdentityError()
{
Code = "DefaultError",
Description = "En ukjent feil har oppstått."
};
}
public override IdentityError ConcurrencyFailure()
{
return new IdentityError()
{
Code = "ConcurrencyFailure",
Description = "Optimistisk samtidighet feilet, objektet har blitt endret."
};
}
public override IdentityError PasswordMismatch()
{
return new IdentityError()
{
Code = "PasswordMismatch",
Description = "Feil passord."
};
}
public override IdentityError InvalidToken()
{
return new IdentityError()
{
Code = "InvalidToken",
Description = "Feil token."
};
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError()
{
Code = "LoginAlreadyAssociated",
Description = "En bruker med dette brukernavnet finnes allerede."
};
}
public override IdentityError InvalidUserName(string userName)
{
IdentityError identityError = new IdentityError();
identityError.Code = "InvalidUserName";
string str = $"Brkernavnet '{userName}' er ikke gyldig. Det kan kun inneholde bokstaver og tall.";
identityError.Description = str;
return identityError;
}
public override IdentityError InvalidEmail(string email)
{
IdentityError identityError = new IdentityError();
identityError.Code = "InvalidEmail";
string str = $"E-post '{email}' er ugyldig.";
identityError.Description = str;
return identityError;
}
public override IdentityError DuplicateUserName(string userName)
{
IdentityError identityError = new IdentityError();
identityError.Code = "DuplicateUserName";
string str = $"Brukernavn '{userName}' er allerede tatt.";
identityError.Description = str;
return identityError;
}
public override IdentityError DuplicateEmail(string email)
{
IdentityError identityError = new IdentityError();
identityError.Code = "DuplicateEmail";
string str = $"E-post '{email}' er allerede tatt.";
identityError.Description = str;
return identityError;
}
public override IdentityError InvalidRoleName(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "InvalidRoleName";
string str = $"Rollenavn '{role}' er ugyldig.";
identityError.Description = str;
return identityError;
}
public override IdentityError DuplicateRoleName(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "DuplicateRoleName";
string str = $"Rollenavn '{role}' er allerede tatt.";
identityError.Description = str;
return identityError;
}
public virtual IdentityError UserAlreadyHasPassword()
{
return new IdentityError()
{
Code = "UserAlreadyHasPassword",
Description = "Bruker har allerede passord satt."
};
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError()
{
Code = "UserLockoutNotEnabled",
Description = "Utestenging er ikke slått på for denne brukeren."
};
}
public override IdentityError UserAlreadyInRole(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "UserAlreadyInRole";
string str = $"Brukeren er allerede i rolle '{role}'.";
identityError.Description = str;
return identityError;
}
public override IdentityError UserNotInRole(string role)
{
IdentityError identityError = new IdentityError();
identityError.Code = "UserNotInRole";
string str = $"Bruker er ikke i rolle '{role}'.";
identityError.Description = str;
return identityError;
}
public override IdentityError PasswordTooShort(int length)
{
IdentityError identityError = new IdentityError();
identityError.Code = "PasswordTooShort";
string str = $"Passordet må være på minimum {length} tegn.";
identityError.Description = str;
return identityError;
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError()
{
Code = "PasswordRequiresNonAlphanumeric",
Description = "Passordet må inneholde minst ett spesialtegn."
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError()
{
Code = "PasswordRequiresDigit",
Description = "Passordet må inneholde minst ett siffer."
};
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError()
{
Code = "PasswordRequiresLower",
Description = "Passordet må inneholde minst en liten bokstav (a-z)."
};
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError()
{
Code = "PasswordRequiresUpper",
Description = "Passordet må inneholde minst en stor bokstav (A-Z)."
};
}
}
基于 rboe 和 Tedd Hansen 的出色回答,我写了一个基于 IStringLocalizer
的 IdentityErrorDescriber
供我自己使用,我想我会在这里分享它以防有人需要多语言支持:)
基本思想是以通常的方式为您的默认语言和任何其他语言创建一个资源文件。 (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization)
位于(如果您保留我的 class 姓名):
/Resources/你的命名空间.LocalizedIdentityErrorDescriber.resx
/Resources/你的命名空间.LocalizedIdentityErrorDescriber.fr.resx
等...
在其中,您将使用错误代码(例如:DefaultError、ConcurrencyError)作为键。
然后在下方添加class
LocalizedIdentityErrorDescriber.cs
public class LocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
/// <summary>
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// used to localize the strings
/// </summary>
private readonly IStringLocalizer<LocalizedIdentityErrorDescriber> localizer;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizedIdentityErrorDescriber"/> class.
/// </summary>
/// <param name="localizer">
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// that we will use to localize the strings
/// </param>
public LocalizedIdentityErrorDescriber(IStringLocalizer<LocalizedIdentityErrorDescriber> localizer)
{
this.localizer = localizer;
}
/// <summary>
/// Returns the default <see cref="IdentityError" />.
/// </summary>
/// <returns>The default <see cref="IdentityError" /></returns>
public override IdentityError DefaultError()
{
return this.GetErrorByCode("DefaultError");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a concurrency failure.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a concurrency failure.</returns>
public override IdentityError ConcurrencyFailure()
{
return this.GetErrorByCode("ConcurrencyFailure");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password mismatch.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password mismatch.</returns>
public override IdentityError PasswordMismatch()
{
return this.GetErrorByCode("PasswordMismatch");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an invalid token.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an invalid token.</returns>
public override IdentityError InvalidToken()
{
return this.GetErrorByCode("InvalidToken");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an external login is already associated with an account.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an external login is already associated with an account.</returns>
public override IdentityError LoginAlreadyAssociated()
{
return this.GetErrorByCode("LoginAlreadyAssociated");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.
/// </summary>
/// <param name="userName">The user name that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.</returns>
public override IdentityError InvalidUserName(string userName)
{
return this.FormatErrorByCode("InvalidUserName", (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.
/// </summary>
/// <param name="email">The email that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.</returns>
public override IdentityError InvalidEmail(string email)
{
return this.FormatErrorByCode("InvalidEmail", (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.
/// </summary>
/// <param name="userName">The user name that already exists.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.</returns>
public override IdentityError DuplicateUserName(string userName)
{
return this.FormatErrorByCode("DuplicateUserName", (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.
/// </summary>
/// <param name="email">The email that is already associated with an account.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.</returns>
public override IdentityError DuplicateEmail(string email)
{
return this.FormatErrorByCode("DuplicateEmail", (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name is invalid.
/// </summary>
/// <param name="role">The invalid role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name is invalid.</returns>
public override IdentityError InvalidRoleName(string role)
{
return this.FormatErrorByCode("InvalidRoleName", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name already exists.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name already exists.</returns>
public override IdentityError DuplicateRoleName(string role)
{
return this.FormatErrorByCode("DuplicateRoleName", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user already has a password.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a user already has a password.</returns>
public override IdentityError UserAlreadyHasPassword()
{
return this.GetErrorByCode("UserAlreadyHasPassword");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating user lockout is not enabled.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating user lockout is not enabled..</returns>
public override IdentityError UserLockoutNotEnabled()
{
return this.GetErrorByCode("UserLockoutNotEnabled");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.</returns>
public override IdentityError UserAlreadyInRole(string role)
{
return this.FormatErrorByCode("UserAlreadyInRole", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.</returns>
public override IdentityError UserNotInRole(string role)
{
return this.FormatErrorByCode("UserNotInRole", (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.
/// </summary>
/// <param name="length">The length that is not long enough.</param>
/// <returns>An <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.</returns>
public override IdentityError PasswordTooShort(int length)
{
return this.FormatErrorByCode("PasswordTooShort", (object)length);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character.</returns>
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return this.GetErrorByCode("PasswordRequiresNonAlphanumeric");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a numeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a numeric character.</returns>
public override IdentityError PasswordRequiresDigit()
{
return this.GetErrorByCode("PasswordRequiresDigit");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter.</returns>
public override IdentityError PasswordRequiresLower()
{
return this.GetErrorByCode("PasswordRequiresLower");
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter.</returns>
public override IdentityError PasswordRequiresUpper()
{
return this.GetErrorByCode("PasswordRequiresUpper");
}
/// <summary>Returns a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError GetErrorByCode(string code)
{
return new IdentityError()
{
Code = code,
Description = this.localizer.GetString(code)
};
}
/// <summary>Formats a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <param name="parameters">The parameters to format the string with.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError FormatErrorByCode(string code, params object[] parameters)
{
return new IdentityError
{
Code = code,
Description = string.Format(this.localizer.GetString(code, parameters))
};
}
}
并初始化一切:
Startup.cs
[...]
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<LocalizedIdentityErrorDescriber>();
services.AddLocalization(options => options.ResourcesPath = "Resources");
// Your service configuration code
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
// Your service configuration code cont.
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// your configuration code
app.UseRequestLocalization(
new RequestLocalizationOptions()
{
DefaultRequestCulture = new RequestCulture("fr"),
SupportedCultures = SupportedCultures,
SupportedUICultures = SupportedCultures
});
app.UseStaticFiles();
app.UseIdentity();
// your configuration code
}
[...]
和俄罗斯的 IdentityErrorDescriber,以备不时之需。
public class RussianIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError ConcurrencyFailure()
{
return new IdentityError
{
Code = "ConcurrencyFailure",
Description = "Сбой в параллельных запросах. Возможно объект был изменен."
};
}
public override IdentityError DefaultError()
{
return new IdentityError
{
Code = "DefaultError",
Description = "Произошла неизвестная ошибка при авторизации."
};
}
public override IdentityError DuplicateEmail(string email)
{
return new IdentityError
{
Code = "DuplicateEmail",
Description = $"E-mail '{email}' уже используется."
};
}
public override IdentityError DuplicateRoleName(string role)
{
return new IdentityError
{
Code = "DuplicateRoleName",
Description = $"Роль с именем '{role}' уже существует."
};
}
public override IdentityError DuplicateUserName(string userName)
{
return new IdentityError
{
Code = "DuplicateUserName",
Description = $"Пользователь '{userName}' уже зарегистрирован."
};
}
public override IdentityError InvalidEmail(string email)
{
return new IdentityError
{
Code = "InvalidEmail",
Description = $"E-mail '{email}' содержит неверный формат."
};
}
public override IdentityError InvalidRoleName(string role)
{
return new IdentityError
{
Code = "InvalidRoleName",
Description = $"Имя роли '{role}' задано не верно (содержит не допустимые символы либо длину)."
};
}
public override IdentityError InvalidToken()
{
return new IdentityError
{
Code = "InvalidToken",
Description = "Неправильно указан код подтверждения (token)."
};
}
public override IdentityError InvalidUserName(string userName)
{
return new IdentityError
{
Code = "InvalidUserName",
Description = $"Имя пользователя '{userName}' указано не верно (содержит не допустимые символы либо длину)."
};
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError
{
Code = "LoginAlreadyAssociated",
Description = "Данный пользователь уже привязан к аккаунту."
};
}
public override IdentityError PasswordMismatch()
{
return new IdentityError
{
Code = "PasswordMismatch",
Description = "Пароли не совпадают."
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError
{
Code = "PasswordRequiresDigit",
Description = "Пароль должен содержать минимум одну цифру."
};
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError
{
Code = "PasswordRequiresLower",
Description = "Пароль должен содержать минимум одну строчную букву."
};
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError
{
Code = "PasswordRequiresNonAlphanumeric",
Description = "Пароль должен содержать минимум один специальный символ (не буквенно-цифровой)."
};
}
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
{
return new IdentityError
{
Code = "PasswordRequiresUniqueChars",
Description = $"Пароль должен содержать минимум '{uniqueChars}' не повторяющихся символов."
};
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError
{
Code = "PasswordRequiresUpper",
Description = "Пароль должен содержать минимум одну заглавную букву."
};
}
public override IdentityError PasswordTooShort(int length)
{
return new IdentityError
{
Code = "PasswordTooShort",
Description = $"Пароль слишком короткий. Минимальное количество символов: '{length}'."
};
}
public override IdentityError RecoveryCodeRedemptionFailed()
{
return new IdentityError
{
Code = "RecoveryCodeRedemptionFailed",
Description = "Не удалось использовать код восстановления."
};
}
public override IdentityError UserAlreadyHasPassword()
{
return new IdentityError
{
Code = "UserAlreadyHasPassword",
Description = "Пароль для пользователя уже задан."
};
}
public override IdentityError UserAlreadyInRole(string role)
{
return new IdentityError
{
Code = "UserAlreadyInRole",
Description = $"Роль '{role}' уже привязана к пользователю."
};
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError
{
Code = "UserLockoutNotEnabled",
Description = "Блокировка пользователя отключена."
};
}
public override IdentityError UserNotInRole(string role)
{
return new IdentityError
{
Code = "UserNotInRole",
Description = $"Пользователь должен иметь роль: '{role}'"
};
}
}
In `Startup.cs` set `RussianIdentityErrorDescriber `
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<RussianIdentityErrorDescriber>();
// ...
}
如果您正在寻找波兰语,这里是:
public class PolishLocalizedIdentityErrorDescriber : IdentityErrorDescriber { public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = "Wystąpił nieznany błąd." }; } public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Błąd współbieżności, obiekt został już zmodyfikowany." }; } public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Niepoprawne hasło." }; } public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Nieprawidłowy token." }; } public override IdentityError RecoveryCodeRedemptionFailed() { return new IdentityError { Code = nameof(RecoveryCodeRedemptionFailed), Description = "Pobranie kodu odzyskiwania nie powiodło się." }; } public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "Użytkownik o tym loginie już istnieje." }; } public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Nazwa użytkownika '{userName}' jest nieprawidłowa, może zawierać tylko litery lub cyfry." }; } public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"Adres e-mail '{email}' jest nieprawidłowy." }; } public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Nazwa '{userName}' jest już zajęta." }; } public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"Adres e-mail '{email}' jest już zajęty." }; } public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Nazwa roli '{role}' już niepoprawna." }; } public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Rola '{role}' już istnieje." }; } public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Użytkownik ma już ustawione hasło." }; } public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Blokada konta nie jest włączona dla tego użytkownika." }; } public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Użytkownik korzysta już z roli '{role}'." }; } public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Użytkownika nie ma w roli '{role}'." }; } public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Hasło musi składać się z co najmniej {length} znaków." }; } public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) { return new IdentityError { Code = nameof(PasswordRequiresUniqueChars), Description = $"Hasło musi składać się z co najmniej {uniqueChars} unikalnych znaków." }; } public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Hasło musi zawierać co najmniej jeden znak niebędący literą lub cyfrą." }; } public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Hasło musi zawierać co najmniej jedną cyfrę (0-9)." }; } public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Hasło musi zawierać co najmniej jedną małą literę (a-z)." }; } public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Hasło musi zawierać co najmniej jedną wielką literę (A-Z)." }; } }
让我对这个问题有一个全面的回答,并描述我是如何在阅读.net core源代码后得出解决方案的。
在进一步描述之前,首先使用 NuGet 安装此包 Microsoft.Extensions.Localization
你们可能还记得 asp.net 完整框架,文化之间的切换非常简单
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
但在 .net 核心中,区域性不再与当前线程相关联。 asp.net 核心引擎有一个管道,我们可以向这个管道添加不同的中间件,所以 RequestLocalizationMiddleware is the middleware class for handling localization, we might have multiple providers so it will iterate through all the culture providers like QueryStringRequestCultureProvider, CookieRequestCultureProvider, AcceptLanguageHeaderRequestCultureProvider, …
只要请求本地化中间件可以从第一个提供者那里获得当前语言环境,它就会忽略其他人并将请求传递给管道中的下一个中间件,因此列表中提供者的顺序非常重要。
我个人更喜欢将文化存储在浏览器cookie中,所以由于CookieRequestCultureProvider不是列表中的第一个文化提供者我将其移至列表顶部,这部分的配置在Startup.cs > ConfigureServices 如下
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fa-IR"),
new CultureInfo("de-DE")
};
options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
var defaultCookieRequestProvider =
options.RequestCultureProviders.FirstOrDefault(rcp =>
rcp.GetType() == typeof(CookieRequestCultureProvider));
if (defaultCookieRequestProvider != null)
options.RequestCultureProviders.Remove(defaultCookieRequestProvider);
options.RequestCultureProviders.Insert(0,
new CookieRequestCultureProvider()
{
CookieName = ".AspNetCore.Culture",
Options = options
});
});
让我描述一下上面的代码,我们的应用程序默认文化是 en-US 我们只支持英语,波斯语,德国所以如果浏览器具有不同的语言环境或您设置的语言不是这 3 种语言,则应用必须切换到默认文化。在上面的代码中,我只是从列表中删除 CookieCultureProvider 并将其添加为列表中的第一个提供者(*我已经描述了它必须是第一个的原因*)。默认的 CookieName 对我有用,你可以根据需要更改它。
不要忘记在 Configure(IApplicationBuilder app, IHostingEnvironment env) in Startup.cs
下面添加下面的代码 var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
到目前为止一切顺利。要有资源文件你必须指定资源的路径,我在web项目根路径中分别指定了Controller、Views、ViewModels和SharedResources的资源,层次结构如下
|-Resoures
|---Controllers
|---Views
|---Models
|---SharedResource.resx
|---SharedResource.fa-IR.resx
|---SharedResource.de-DE.resx
请记住,对于 SharedResource,在 Web 项目根路径中创建一个具有相同名称的空 class 我的意思是 SharedResource.cs class里面同名
在 Startup.cs 中添加以下代码片段以指定资源路径和其余部分。
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
AddViewLocalization(
LanguageViewLocationExpanderFormat.Suffix,
opts => { opts.ResourcesPath = "Resources/Views"; }) // this line is not required, it is just for more clarification
.AddDataAnnotationsLocalization();
使用此配置,例如当您在控制器中注入 IStringLocalizer 时,您必须在 Resources > Controllers 文件夹中有相应的资源文件(它们是 HomeController.resx、HomeController.fa-IR.resx, HomeController.de-DE.resx) 我们也可以在文件名中用 .(比如点)分隔路径我的意思是 Resources/Controllers/HomeController.resx 可以是 Resources/Controllers.HomeController.resx 中的文件,你必须将 IViewLocalizer 注入到视图中才能相应地在视图中进行本地化 你必须在 [=75= 中为视图提供资源文件] 文件夹,对于 ViewModels,因为我们将文件夹命名为 Models,请将所有 ViewModels 放入 Web 项目根路径中预先创建的名为 Models 的文件夹中,如果该文件夹有其他名称或者您更喜欢其他名称,请不要忘记重命名资源文件夹下的模型文件夹。然后你只需要注释模型,例如用[DisplayName("User Emailaddress")]注释ViewModel属性然后在模型内部相应的资源文件中创建资源(文件名必须与模型匹配class 名称)具有相同的密钥("User Emailaddress")。
让我们从已经开始的地方结束,我的意思是 CookieRequestCultureProvider。正如我之前所说,我更喜欢将它存储在 cookie 中,但这有点棘手,因为 cookie parsing 与您可能期望的有点不同,只需在下面添加您想要更改区域性的代码,只需替换preferedCulture 与您的文化偏好
var preferedCulture = "fa-IR"; // get the culture from user, i just mock it here in a variable
if (HttpContext.Response.Cookies.ContainsKey(".AspNetCore.Culture"))
{
HttpContext.Response.Cookies.Delete(".AspNetCore.Culture");
}
HttpContext.Response.Cookies.Append(".AspNetCore.Culture",
$"c={preferedCulture}|uic={preferedCulture}", new CookieOptions {Expires = DateTime.UtcNow.AddYears(1)});
好了,我们的 sp.net 核心网络应用程序现已本地化:)
对于那些想知道是否可以将消息本地化为当前所选文化的人,是的,这是可能的。在 asp.net core 2.2 你可以创建一个 class LocalizedIdentityErrorDescriber where IdentityResources是你的假人的名字 class(这里有描述:Globalization and localization):
public class LocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
/// <summary>
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// used to localize the strings
/// </summary>
private readonly IStringLocalizer<IdentityResources> localizer;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizedIdentityErrorDescriber"/> class.
/// </summary>
/// <param name="localizer">
/// The <see cref="IStringLocalizer{LocalizedIdentityErrorDescriber}"/>
/// that we will use to localize the strings
/// </param>
public LocalizedIdentityErrorDescriber(IStringLocalizer<IdentityResources> localizer)
{
this.localizer = localizer;
}
/// <summary>
/// Returns the default <see cref="IdentityError" />.
/// </summary>
/// <returns>The default <see cref="IdentityError" /></returns>
public override IdentityError DefaultError()
{
return this.GetErrorByCode(nameof(DefaultError));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a concurrency failure.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a concurrency failure.</returns>
public override IdentityError ConcurrencyFailure()
{
return this.GetErrorByCode(nameof(ConcurrencyFailure));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password mismatch.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password mismatch.</returns>
public override IdentityError PasswordMismatch()
{
return this.GetErrorByCode(nameof(PasswordMismatch));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an invalid token.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an invalid token.</returns>
public override IdentityError InvalidToken()
{
return this.GetErrorByCode(nameof(InvalidToken));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating an external login is already associated with an account.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating an external login is already associated with an account.</returns>
public override IdentityError LoginAlreadyAssociated()
{
return this.GetErrorByCode(nameof(LoginAlreadyAssociated));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.
/// </summary>
/// <param name="userName">The user name that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified user <paramref name="userName" /> is invalid.</returns>
public override IdentityError InvalidUserName(string userName)
{
return this.FormatErrorByCode(nameof(InvalidUserName), (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.
/// </summary>
/// <param name="email">The email that is invalid.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is invalid.</returns>
public override IdentityError InvalidEmail(string email)
{
return this.FormatErrorByCode(nameof(InvalidEmail), (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.
/// </summary>
/// <param name="userName">The user name that already exists.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="userName" /> already exists.</returns>
public override IdentityError DuplicateUserName(string userName)
{
return this.FormatErrorByCode(nameof(DuplicateUserName), (object)userName);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.
/// </summary>
/// <param name="email">The email that is already associated with an account.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specified <paramref name="email" /> is already associated with an account.</returns>
public override IdentityError DuplicateEmail(string email)
{
return this.FormatErrorByCode(nameof(DuplicateEmail), (object)email);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name is invalid.
/// </summary>
/// <param name="role">The invalid role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name is invalid.</returns>
public override IdentityError InvalidRoleName(string role)
{
return this.FormatErrorByCode(nameof(InvalidRoleName), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating the specified <paramref name="role" /> name already exists.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating the specific role <paramref name="role" /> name already exists.</returns>
public override IdentityError DuplicateRoleName(string role)
{
return this.FormatErrorByCode(nameof(DuplicateRoleName), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user already has a password.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a user already has a password.</returns>
public override IdentityError UserAlreadyHasPassword()
{
return this.GetErrorByCode(nameof(UserAlreadyHasPassword));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating user lockout is not enabled.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating user lockout is not enabled..</returns>
public override IdentityError UserLockoutNotEnabled()
{
return this.GetErrorByCode(nameof(UserLockoutNotEnabled));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is already in the specified <paramref name="role" />.</returns>
public override IdentityError UserAlreadyInRole(string role)
{
return this.FormatErrorByCode(nameof(UserAlreadyInRole), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.
/// </summary>
/// <param name="role">The duplicate role.</param>
/// <returns>An <see cref="IdentityError" /> indicating a user is not in the specified <paramref name="role" />.</returns>
public override IdentityError UserNotInRole(string role)
{
return this.FormatErrorByCode(nameof(UserNotInRole), (object)role);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.
/// </summary>
/// <param name="length">The length that is not long enough.</param>
/// <returns>An <see cref="IdentityError" /> indicating a password of the specified <paramref name="length" /> does not meet the minimum length requirements.</returns>
public override IdentityError PasswordTooShort(int length)
{
return this.FormatErrorByCode(nameof(PasswordTooShort), (object)length);
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a non-alphanumeric character.</returns>
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return this.GetErrorByCode(nameof(PasswordRequiresNonAlphanumeric));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a numeric character, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a numeric character.</returns>
public override IdentityError PasswordRequiresDigit()
{
return this.GetErrorByCode(nameof(PasswordRequiresDigit));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain a lower case letter.</returns>
public override IdentityError PasswordRequiresLower()
{
return this.GetErrorByCode(nameof(PasswordRequiresLower));
}
/// <summary>
/// Returns an <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter, which is required by the password policy.
/// </summary>
/// <returns>An <see cref="IdentityError" /> indicating a password entered does not contain an upper case letter.</returns>
public override IdentityError PasswordRequiresUpper()
{
return this.GetErrorByCode(nameof(PasswordRequiresUpper));
}
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
{
return this.FormatErrorByCode(nameof(PasswordRequiresUniqueChars), (object)uniqueChars);
}
public override IdentityError RecoveryCodeRedemptionFailed()
{
return this.GetErrorByCode(nameof(RecoveryCodeRedemptionFailed));
}
/// <summary>Returns a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError GetErrorByCode(string code)
{
return new IdentityError()
{
Code = code,
Description = this.localizer.GetString(code)
};
}
/// <summary>Formats a localized <see cref="IdentityError"/> for the provided code.</summary>
/// <param name="code">The error's code.</param>
/// <param name="parameters">The parameters to format the string with.</param>
/// <returns>A localized <see cref="IdentityError"/>.</returns>
private IdentityError FormatErrorByCode(string code, params object[] parameters)
{
return new IdentityError
{
Code = code,
Description = string.Format(this.localizer.GetString(code, parameters))
};
}
}
然后为您的语言创建资源文件,如下所示:Resources\(虚拟名称 class 如上所述)(.culture).resx。对于您的默认语言文化,应留空。并且不要忘记“。”如果它不是默认的,则在区域性名称之前。您的 IdentityResources 文件应如下所示:
在Startup.cs中添加以下行:
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<nameofyourdbcontext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<LocalizedIdentityErrorDescriber>(); // this line is important
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en"), // english
new CultureInfo("tr"), // turkish
new CultureInfo("ru") // russian
};
options.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new CookieRequestCultureProvider()); // type of CultureProvider you want.
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var localizationOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
// IT IS IMPORTANT TO CALL UseRequestLocalization BEFORE UseMvc
app.UseRequestLocalization(localizationOptions.Value);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
现在你差不多完成了,但你需要设置 Culture cookie,这里有一个代码示例:Globalization and localization。 希望对大家有帮助。
瑞典语 IdentityErrorDescriber,以备不时之需。
public class SwedishIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = "Ett okänt fel har inträffat." }; }
public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Objektet har ändrats sedan uppläsning." }; }
public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Felaktigt lösenord." }; }
public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Ogiltigt token." }; }
public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "En användare med den här inloggningen finns redan." }; }
public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"Användarnamnet '{userName}' är ogiltigt, kan endast innehålla bokstäver eller siffror." }; }
public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"E-postadressen {email} är ogiltig." }; }
public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"Användarnamnet '{userName}' finns redan." }; }
public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"E-postadressen {email} finns redan." }; }
public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Rollen '{role}' är ogiltig." }; }
public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Rollen '{role}' finns redan." }; }
public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "Användaren har redan angett ett lösenord." }; }
public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Lockout är inte aktiverat för den här användaren." }; }
public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"Användaren har redan rollen '{role}'." }; }
public override IdentityError UserNotInRole(string role) { return new IdentityError { Code = nameof(UserNotInRole), Description = $"Användaren har inte rollen '{role}'." }; }
public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Lösenordet måste ha minst {length} tecken." }; }
public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Lösenordet måste ha minst ett icke alfanumeriskt tecken." }; }
public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Lösenordet måste innehålla minst en siffra ('0'-'9')." }; }
public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Lösenordet måste innehålla minst en gemen ('a'-'z')." }; }
public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Lösenordet måste innehålla minst en versal ('A'-'Z')." }; }
}