ASP.NET Core アプリのコンテンツをローカライズ可能にする

作成者: Hisham Bin AteyaDamien BowdenBart CalixtoNadeem Afana

アプリをローカライズするためのタスクの 1 つは、ローカライズ可能なコンテンツを、異なるカルチャ用にそのコンテンツを置き換えやすくするコードでラップすることです。

IStringLocalizer

IStringLocalizerIStringLocalizer<T> は、ローカライズされたアプリの開発時に生産性が向上するように設計されています。 IStringLocalizer では、ResourceManagerResourceReader を使用して、実行時にカルチャ固有のリソースを提供します。 インターフェイスには、ローカライズされた文字列を返すためのインデクサーと IEnumerable があります。 IStringLocalizer では、既定の言語文字列をリソース ファイルに格納する必要はありません。 ローカリゼーションの対象となるアプリを開発することができ、開発の早い段階でリソース ファイルを作成する必要はありません。

次のコード例は、ローカライズのために文字列 "About Title" をラップする方法を示しています。

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.Controllers;

[Route("api/[controller]")]
public class AboutController : Controller
{
    private readonly IStringLocalizer<AboutController> _localizer;

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

    [HttpGet]
    public string Get()
    {
        return _localizer["About Title"];
    }
}

前のコードの IStringLocalizer<T> の実装は、依存関係の挿入で説明したものです。 "About Title" のローカライズされた値が見つからない場合、インデクサーのキー、つまり文字列 "About Title" が返されます。

アプリで、既定の言語のリテラル文字列をそのままにし、ローカライザーにそれらをラップすることができるので、アプリの開発に専念することができます。 既定の言語でアプリを開発し、既定のリソース ファイルを最初に作成せずに、ローカライズ手順に向けて準備します。

または、従来のアプローチを使用し、既定の言語文字列を取得するキーを提供できます。 多くの開発者にとって、既定の言語の .resx ファイルを使用せずに、文字列リテラルをラップするだけの新しいワークフローは、アプリをローカライズする際のオーバーヘッドの削減になります。 従来のワークフローを好む開発者もいます。長い文字列リテラルの操作が容易で、ローカライズされた文字列を更新しやすいためです。

IHtmlLocalizer

HTML を格納しているリソースには、IHtmlLocalizer<TResource> の実装を使用します。 IHtmlLocalizer は、リソース文字列で書式設定される引数を HTML エンコードしますが、リソース文字列自体は HTML エンコードしません。 次の強調表示されたコードでは、name パラメーターの値のみが HTML エンコードされます。

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers;

public class BookController : Controller
{
    private readonly IHtmlLocalizer<BookController> _localizer;

    public BookController(IHtmlLocalizer<BookController> localizer)
    {
        _localizer = localizer;
    }

    public IActionResult Hello(string name)
    {
        ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

        return View();
    }

注: 一般に、HTML ではなく、テキストのみをローカライズします。

IStringLocalizerFactory

最下位のレベルでは、IStringLocalizerFactory依存関係の挿入から取得できます。

public class TestController : Controller
{
    private readonly IStringLocalizer _localizer;
    private readonly IStringLocalizer _localizer2;

    public TestController(IStringLocalizerFactory factory)
    {
        var type = typeof(SharedResource);
        var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
        _localizer = factory.Create(type);
        _localizer2 = factory.Create("SharedResource", assemblyName.Name);
    }       

    public IActionResult About()
    {
        ViewData["Message"] = _localizer["Your application description page."] 
            + " loc 2: " + _localizer2["Your application description page."];

        return View();
    }

上記のコードは、2 つの各ファクトリ作成メソッドを示しています。

共有リソース

ローカライズされた文字列は、コントローラーまたは領域で仕切るか、1 つのコンテナーにすることができます。 サンプル アプリでは、共有されるリソースのために SharedResource というマーカー クラスを使用しています。 マーカー クラスは呼び出されることはありません。

// Dummy class to group shared resources

namespace Localization;

public class SharedResource
{
}

次のサンプルでは、InfoControllerSharedResource のローカライザーが使用されています。

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

ビューのローカリゼーション

IViewLocalizer サービスは、ビューのローカライズされた文字列を提供します。 ViewLocalizer クラスは、このインターフェイスを実装し、ビューのファイル パスからリソースの場所を見つけます。 次のコードは、IViewLocalizer の既定の実装の使用方法を示しています。

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

IViewLocalizer の既定の実装は、ビューのファイル名に基づいてリソース ファイルを見つけます。 グローバルな共有リソース ファイルを使用するオプションはありません。 ViewLocalizer は、IHtmlLocalizer を使用してローカライザーを実装するので、Razor は、ローカライズされた文字列を HTML エンコードしません。 リソース文字列をパラメーター化することができます。IViewLocalizer は、パラメーターを HTML エンコードしますが、リソース文字列は HTML エンコードしません。 次の Razor マークアップがあるとします。

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

フランス語のリソース ファイルには、次の値を含めることができます。

キー [値]
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

描画されたビューには、リソース ファイルからの HTML マークアップが含まれます。

一般に、HTML ではなく、"テキストのみをローカライズ" します。

ビュー内の共有リソース ファイルを使用するには、IHtmlLocalizer<T> を挿入します。

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

DataAnnotations のローカリゼーション

DataAnnotations エラー メッセージは IStringLocalizer<T> を使用してローカライズします。 オプション ResourcesPath = "Resources" を使用して、RegisterViewModel のエラー メッセージを次のいずれかのパスに格納できます。

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
using System.ComponentModel.DataAnnotations;

namespace Localization.ViewModels.Account;

public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.",
                                                                 MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage =
                            "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

非検証属性はローカライズされます。

複数のクラスに 1 つのリソース文字列を使う方法

次のコードは、複数のクラスに検証属性の 1 つのリソース文字列を使用する方法を示しています。

    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });

上記のコードでは、SharedResource は、.resx ファイルに対応するクラスであり、ここに検証メッセージが格納されます。 この方法では、DataAnnotations は、各クラスのリソースではなく、SharedResource のみを使用します。

ローカライズ サービスを構成する

ローカライズ サービスは、Program.cs で構成されます。

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

builder.Services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization により、サービス コンテナーにローカライズ サービスが追加されます (IStringLocalizer<T>IStringLocalizerFactory の実装を含む)。 また、上記のコードでは、リソース パスが "Resources" に設定されます。

  • AddViewLocalization は、ローカライズされたビュー ファイルのサポートを追加します。 このサンプルでは、ビューのローカライズはビュー ファイルのサフィックスに基づいています。 たとえば、Index.fr.cshtml ファイルの "fr" です。

  • AddDataAnnotationsLocalization は、IStringLocalizer 抽象化を介してローカライズされた DataAnnotations 検証メッセージのサポートを追加します。

Note

小数フィールドに小数点のコンマを入力できない場合があります。 小数点にコンマ (",") を使い、英語 (米国) 以外の日付形式を使う英語以外のロケールの jQuery 検証をサポートするには、アプリをグローバル化する手順を行う必要があります。 小数点のコンマを追加する手順については、こちらの GitHub コメント 4076 を参照してください

次のステップ

アプリのローカライズには、次のタスクも含まれます。

その他のリソース

作成者: Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya

アプリをローカライズするためのタスクの 1 つは、ローカライズ可能なコンテンツを、異なるカルチャ用にそのコンテンツを置き換えやすくするコードでラップすることです。

IStringLocalizer

IStringLocalizerIStringLocalizer<T> は、ローカライズされたアプリの開発時に生産性が向上するように設計されています。 IStringLocalizer では、ResourceManagerResourceReader を使用して、実行時にカルチャ固有のリソースを提供します。 インターフェイスには、ローカライズされた文字列を返すためのインデクサーと IEnumerable があります。 IStringLocalizer では、既定の言語文字列をリソース ファイルに格納する必要はありません。 ローカリゼーションの対象となるアプリを開発することができ、開発の早い段階でリソース ファイルを作成する必要はありません。

次のコード例は、ローカライズのために文字列 "About Title" をラップする方法を示しています。

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

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

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

前のコードの IStringLocalizer<T> の実装は、依存関係の挿入で説明したものです。 "About Title" のローカライズされた値が見つからない場合、インデクサーのキー、つまり文字列 "About Title" が返されます。

アプリで、既定の言語のリテラル文字列をそのままにし、ローカライザーにそれらをラップすることができるので、アプリの開発に専念することができます。 既定の言語でアプリを開発し、既定のリソース ファイルを最初に作成せずに、ローカライズ手順に向けて準備します。

または、従来のアプローチを使用し、既定の言語文字列を取得するキーを提供できます。 多くの開発者にとって、既定の言語の .resx ファイルを使用せずに、文字列リテラルをラップするだけの新しいワークフローは、アプリをローカライズする際のオーバーヘッドの削減になります。 従来のワークフローを好む開発者もいます。長い文字列リテラルの操作が容易で、ローカライズされた文字列を更新しやすいためです。

IHtmlLocalizer

HTML を格納しているリソースには、IHtmlLocalizer<T> の実装を使用します。 IHtmlLocalizer は、リソース文字列で書式設定される引数を HTML エンコードしますが、リソース文字列自体は HTML エンコードしません。 次の強調表示されたコードでは、name パラメーターの値のみが HTML エンコードされます。

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers
{
    public class BookController : Controller
    {
        private readonly IHtmlLocalizer<BookController> _localizer;

        public BookController(IHtmlLocalizer<BookController> localizer)
        {
            _localizer = localizer;
        }

        public IActionResult Hello(string name)
        {
            ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

            return View();
        }

Note

一般に、HTML ではなく、テキストのみをローカライズします。

IStringLocalizerFactory

最下位のレベルでは、依存関係の挿入から IStringLocalizerFactory を取得できます。

{
    public class TestController : Controller
    {
        private readonly IStringLocalizer _localizer;
        private readonly IStringLocalizer _localizer2;

        public TestController(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(type);
            _localizer2 = factory.Create("SharedResource", assemblyName.Name);
        }       

        public IActionResult About()
        {
            ViewData["Message"] = _localizer["Your application description page."] 
                + " loc 2: " + _localizer2["Your application description page."];

上記のコードは、2 つの各ファクトリ作成メソッドを示しています。

共有リソース

ローカライズされた文字列は、コントローラーまたは領域で仕切るか、1 つのコンテナーにすることができます。 サンプル アプリでは、共有されるリソースのために SharedResource というダミー クラスを使用しています。

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

一部の開発者は、Startup クラスを使用してグローバル文字列または共有文字列を格納します。 次のサンプルでは、InfoControllerSharedResource のローカライザーが使用されています。

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

ビューのローカリゼーション

IViewLocalizer サービスは、ビューのローカライズされた文字列を提供します。 ViewLocalizer クラスは、このインターフェイスを実装し、ビューのファイル パスからリソースの場所を見つけます。 次のコードは、IViewLocalizer の既定の実装の使用方法を示しています。

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

IViewLocalizer の既定の実装は、ビューのファイル名に基づいてリソース ファイルを見つけます。 グローバルな共有リソース ファイルを使用するオプションはありません。 ViewLocalizer は、IHtmlLocalizer を使用してローカライザーを実装するので、Razor は、ローカライズされた文字列を HTML エンコードしません。 リソース文字列をパラメーター化することができます。IViewLocalizer は、パラメーターを HTML エンコードしますが、リソース文字列は HTML エンコードしません。 次の Razor マークアップがあるとします。

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

フランス語のリソース ファイルには、次の値を含めることができます。

キー [値]
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

描画されたビューには、リソース ファイルからの HTML マークアップが含まれます。

Note

一般に、HTML ではなく、テキストのみをローカライズします。

ビュー内の共有リソース ファイルを使用するには、IHtmlLocalizer<T> を挿入します。

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

DataAnnotations のローカリゼーション

DataAnnotations エラー メッセージは IStringLocalizer<T> を使用してローカライズします。 オプション ResourcesPath = "Resources" を使用して、RegisterViewModel のエラー メッセージを次のいずれかのパスに格納できます。

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

ASP.NET Core MVC 1.1.0 以降では、非検証属性がローカライズされます。

複数のクラスに 1 つのリソース文字列を使う方法

次のコードは、複数のクラスに検証属性の 1 つのリソース文字列を使用する方法を示しています。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

上記のコードでは、SharedResource は、.resx ファイルに対応するクラスであり、ここに検証メッセージが格納されます。 この方法では、DataAnnotations は、各クラスのリソースではなく、SharedResource のみを使用します。

ローカライズ サービスを構成する

ローカライズ サービスは、Startup.ConfigureServices メソッドで構成されます。

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization により、サービス コンテナーにローカライズ サービスが追加されます (IStringLocalizer<T>IStringLocalizerFactory の実装を含む)。 また、上記のコードでは、リソース パスが "Resources" に設定されます。

  • AddViewLocalization は、ローカライズされたビュー ファイルのサポートを追加します。 このサンプルでは、ビューのローカライズはビュー ファイルのサフィックスに基づいています。 たとえば、Index.fr.cshtml ファイルの "fr" です。

  • AddDataAnnotationsLocalization は、IStringLocalizer 抽象化を介してローカライズされた DataAnnotations 検証メッセージのサポートを追加します。

Note

小数フィールドに小数点のコンマを入力できない場合があります。 小数点にコンマ (",") を使い、英語 (米国) 以外の日付形式を使う英語以外のロケールの jQuery 検証をサポートするには、アプリをグローバル化する手順を行う必要があります。 小数点のコンマを追加する手順については、こちらの GitHub コメント 4076 を参照してください

次のステップ

アプリのローカライズには、次のタスクも含まれます。

その他のリソース