web-dev-qa-db-ja.com

ASP.Netコアのローカリゼーション

ASP.Netコア機能 ローカリゼーションの新しいサポート

私のプロジェクトでは、必要な言語は1つだけです。ほとんどのテキストと注釈については自分の言語で指定できますが、ASP.NetCore自体からのテキストの場合は英語です。

例:

  • パスワードには、少なくとも1つの大文字(「A」から「Z」)が必要です。
  • パスワードには少なくとも1桁の数字(「0」から「9」)が必要です。
  • ユーザー名「[email protected]」はすでに使用されています。
  • E-postフィールドは有効なEメールアドレスではありません。
  • 値 ''は無効です。

カルチャを手動で設定しようとしましたが、言語はまだ英語です。

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の言語を変更したり、デフォルトのテキストを上書きしたりするにはどうすればよいですか?

13
Tedd Hansen

リストされているエラーメッセージはASP.NETCore Identityで定義されており、 IdentityErrorDescriber によって提供されます。これまで翻訳されたリソースファイルは見つかりませんでした。ローカライズされていないと思います。私のシステム(ドイツ語ロケール)では、CultureInfoが正しく設定されていても、それらも翻訳されません。

カスタムIdentityErrorDescriberを構成して、独自のメッセージとその翻訳を返すことができます。それは例えば記述されています。 in MVC Core ValidationSummaryのデフォルトのエラーメッセージを変更するにはどうすればよいですか?

Startup.csConfigureメソッドでは、IdentityErrorDescriberから継承されたErrorDescriberクラスを次のように接続できます。

 services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddErrorDescriber<TranslatedIdentityErrorDescriber>();

他のデフォルトモデルのエラーメッセージ(無効な番号など)については、ModelBindingMessageProviderで独自のアクセサ関数を提供できます。このプロバイダーはASP.NETCore MVCによって使用され、Startup.csでも構成できます。

services.AddMvc(
            options => 
            options.ModelBindingMessageProvider.ValueIsInvalidAccessor = s => $"My not valid text for {s}");
14
Ralf Bönning

この質問に対する包括的な回答と、.netコアソースコードを読んだ後にどのように解決策を思いついたのかを説明しましょう。

詳細を説明する前に、まずNuGetMicrosoft.Extensions.Localizationを使用してこのパッケージをインストールします。

asp.netの完全なフレームワークで覚えているかもしれませんが、カルチャ間の切り替えは非常に簡単でした。

System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

しかし、.netコアでは、カルチャは現在のスレッドに結び付けられていません。 asp.netコアエンジンにはパイプラインがあり、このパイプラインにさまざまなミドルウェアを追加できるため、 RequestLocalizationMiddleware はローカリゼーションを処理するためのミドルウェアクラスです。複数のプロバイダーがある可能性があるため、すべてのカルチャを反復処理します。 QueryStringRequestCultureProviderCookieRequestCultureProviderAcceptLanguageHeaderRequestCultureProvider 、…などのプロバイダー

リクエストローカリゼーションミドルウェアが最初のプロバイダーから現在のロケールを取得できるとすぐに、他のロケールを無視し、パイプライン内の次のミドルウェアにリクエストを渡すため、リスト内のプロバイダーの順序が非常に重要になります。

私は個人的にカルチャをブラウザのCookieに保存することを好みます。そのため、 CookieRequestCultureProvider はリストの最初のカルチャプロバイダーではないため、リストの一番上に移動します。スタートアップでこの部分を構成します。 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が機能しています。必要に応じて、変更できます。

startup.csのConfigure(IApplicationBuilder app、IHostingEnvironment env)の下に以下のコードを追加することを忘れないでください

   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プロジェクトのルートパスに同じ名前の空のクラスを作成することを覚えておいてください。つまり、SharedResource.csとクラスがあります。中の同じ名前。

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を挿入する場合、対応するリソースファイルを[リソース]> [コントローラー]フォルダー(HomeController.resx、HomeController.fa-IR.resx)に配置する必要があります。 、HomeController.de-DE.resx)ファイル名の(たとえばドット)でパスを区切ることもできます。つまり、Resources/Controllers/HomeControllerです。 resxはResources/Controllers.HomeController.resx内のファイルにすることができます。ビュー内にローカリゼーションを行うには、IViewLocalizerをビューに挿入する必要があります。それに応じて、リソース/ビューフォルダー内のビューのリソースファイルが必要です。モデルは、すべてのViewModelをWebプロジェクトルートパスの事前に作成されたフォルダー内にModelsという名前で配置してください。フォルダーに別の名前がある場合、または別の名前が必要な場合は、Resourceフォルダーの下のModelsフォルダーの名前を変更することを忘れないでください。次に、モデルに注釈を付けるだけです。たとえば、ViewModelプロパティに[DisplayName( "User Emailaddress")]で注釈を付けてから、モデル内の対応するリソースファイルにリソースを作成します(ファイルの名前はモデルクラス名と一致する必要があります)同じキー( "ユーザーの電子メールアドレス")を使用します。

すでに開始した場所で終了しましょう。つまり、CookieRequestCultureProviderです。前に言ったように、私はそれをCookieに保存することを好みますが、 cookie parsing は予想とは少し異なるため、少し注意が必要です。変更するコードを以下に追加してください。文化、preferredCultureのみをあなたの文化の好みに置き換えます

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コアWebアプリがローカライズされました:)

RboeとTeddHansenの優れた回答に基づいて、私は自分で使用するためにIStringLocalizerベースのIdentityErrorDescriberを作成しました。多言語サポートが必要な場合に備えて、ここで共有したいと思います:)

基本的な考え方は、通常の方法でデフォルト言語と他の言語のリソースファイルを作成することです。 ( https://docs.Microsoft.com/en-us/aspnet/core/fundamentals/localization

(私のクラス名を保持している場合)にあります:

/Resources/yournamespace.LocalizedIdentityErrorDescriber.resx
/Resources /yournamespace。LocalizedIdentityErrorDescriber.fr.resx
等...

これらの中で、キーとしてエラーコード(例:DefaultError、ConcurrencyError)を使用します。

次に、以下のクラスを追加します

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
    }

    [...]
4

誰かがそれを必要とする場合に備えて、ロシアの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>();
    // ...   
}

誰かがそれを必要とする場合に備えて、ノルウェーの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 tall."
        };
    }

    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)."
        };
    }
}
2
Tedd Hansen

疑問に思っている人のために、現在選択されている文化のメッセージをローカライズすることが可能であれば、そうです。 asp.netコア2.2では、クラスLocalizedIdentityErrorDescriberを作成できます。ここでIdentityResourcesは、ダミークラスの名前です(ここで説明します: グローバリゼーションとローカリゼーション ):

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 \(上記のダミークラスの名前)(。culture).resx。デフォルトの言語文化では、空白のままにする必要があります。そして、「。」を忘れないでください。デフォルトでない場合は、カルチャ名の前。 IdentityResourcesファイルは次のようになります。 enter image description here

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を設定する必要があり、ここにコード例があります: グローバリゼーションとローカリゼーション 。それが誰かを助けることを願っています。

1
r.mirzojonov

誰かがそれを必要とする場合に備えて、スウェーデンの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')." }; }
}
0
Fred