ASP.NET Core のグローバリゼーションおよびローカリゼーション

作成者: Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya

多言語の Web サイトにすると、サイトはより幅広い対象ユーザーにリーチできます。 ASP.NET Core は、さまざまな言語と文化にローカライズするためのサービスとミドルウェアを提供します。

国際化には、System.Globalizationローカリゼーションが含まれます。 グローバリゼーションとは異なるカルチャをサポートするアプリを設計するプロセスです。 グローバリゼーションによって、特定の地域に関連する定義済みの言語セットの入出力と表示のサポートが追加されます。

ローカリゼーションとは、ローカライズのために既に処理されているグローバル化されたアプリを特定のカルチャ/ロケールに適合させるプロセスです。 詳細については、本ドキュメントの末尾にある「グローバリゼーションとローカリゼーションの用語」を参照してください。

アプリのローカリゼーションには、以下のものが関与します。

  1. アプリのコンテンツをローカライズできるようにする
  2. サポートする言語およびカルチャのローカライズされたリソースを提供する
  3. 要求ごとに言語/カルチャを選択するための戦略を実装する

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

アプリのコンテンツをローカライズできるようにする

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 ファイルを使用せずに、文字列リテラルをラップするだけの新しいワークフローは、多くの開発者にとって、アプリをローカライズする際のオーバーヘッドの削減になります。 他の開発者は、長い文字列リテラルの操作が容易で、ローカライズされた文字列を更新しやすい従来のワークフローを好みます。

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 を取得できます。

{
    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)]

フランス語のリソース ファイルには次の値が含まれます。

Key [値]
<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 以上では、非検証属性がローカライズされます。 ASP.NET Core MVC 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 のみを使用します。

サポートする言語およびカルチャのローカライズされたリソースを提供する

SupportedCultures と SupportedUICultures

ASP.NET Core では、SupportedCulturesSupportedUICultures という 2 つのカルチャ値を指定できます。 日付、数値、および通貨の書式設定など、カルチャに依存する関数の結果は、SupportedCulturesCultureInfo オブジェクトによって決まります。 テキストの並べ替え順序、大文字と小文字の表記規則、文字列比較も SupportedCultures によって決まります。 サーバーがカルチャを取得する方法の詳細については、「StringComparer.CurrentCulture」を参照してください。 .resx ファイルからのどの翻訳文字列が ResourceManager によって検索されるのかが SupportedUICultures で決まります。 ResourceManager は、CurrentUICulture によって決定されるカルチャ固有の文字列を単に検索します。 .NET のすべてのスレッドに CurrentCulture オブジェクトと CurrentUICultureオブジェクトがあります。 ASP.NET Core は、カルチャに依存する関数を表示するときに、これらの値を検査します。 たとえば、現在のスレッドのカルチャが "en-US" (英語、米国) に設定されている場合は、DateTime.Now.ToLongDateString() は、"Thursday, February 18, 2016" を表示しますが、CurrentCulture が "es-ES" (スペイン語、スペイン) に設定されている場合、出力は "jueves, 18 de febrero de 2016" になります。

リソース ファイル

リソース ファイルは、ローカライズ可能な文字列をコードから分離するために役立つメカニズムです。 既定以外の言語の翻訳された文字列は、 .resx リソース ファイルで分離されています。 たとえば、翻訳された文字列を含む Welcome.es.resx という名前のスペイン語のリソース ファイルを作成したい場合があります。 "es" は、スペイン語の言語コードです。 Visual Studio でこのリソース ファイルを作成するには、次の手順を実行します。

  1. ソリューション エクスプローラーで、リソース ファイルが格納されているフォルダーを右クリックし、[追加]>[新しい項目] の順に選択します。

    入れ子になったコンテキスト メニュー: ソリューション エクスプローラーで Resources のコンテキスト メニューが開かれています。[追加] の 2 つ目のコンテキスト メニューが開かれており、[新しい項目] コマンドが強調表示されています。

  2. インストールされているテンプレートの検索ボックスに、「resource」と入力し、ファイルに名前を付けます。

    [新しい項目の追加] ダイアログ

  3. キーの値 (ネイティブの文字列) を [名前] 列に入力し、翻訳された文字列を [値] 列に入力します。

    Welcome.es.resx ファイル (スペイン語の Welcome リソース ファイル) と、[名前] 列の Hello という単語と、[値] 列の Hola という単語 (スペイン語のこんにちは)

    Visual Studio に Welcome.es.resx ファイルが表示されます。

    Welcome スペイン語リソース ファイルを表示しているソリューション エクスプローラー

リソース ファイルの名前付け

リソースの名前は、クラスの完全な型名からアセンブリ名を除いたものになります。 たとえば、メイン アセンブリが LocalizationWebsite.Web.dll であるプロジェクト内のクラス LocalizationWebsite.Web.Startup のフランス語のリソースは、Startup.fr.resx という名前になります。 クラス LocalizationWebsite.Web.Controllers.HomeController のリソースは、Controllers.HomeController.fr.resx という名前になります。 対象となるクラスの名前空間が、アセンブリ名と同じでない場合は、完全な型名が必要です。 たとえば、同じプロジェクトで、型 ExtraNamespace.Tools のリソースは、ExtraNamespace.Tools.fr.resx という名前になります。

サンプル プロジェクトで、ConfigureServices メソッドにより ResourcesPath が "Resources" に設定されるので、ホーム コントローラーのフランス語のリソース ファイルの相対パスは、Resources/Controllers.HomeController.fr.resx です。 あるいは、フォルダーを使用してリソース ファイルを整理することもできます。 ホーム コントローラーのパスは、Resources/Controllers/HomeController.fr.resx です。 ResourcesPath オプションを使用しない場合、 .resx ファイルは、プロジェクトの基本ディレクトリに置かれます。 HomeController のリソース ファイルは、Controllers.HomeController.fr.resx という名前になります。 ドットまたはパスの名前付け規則の選択は、リソース ファイルを整理する方法によって決まります。

リソース名 ドットまたはパスの名前付け
Resources/Controllers.HomeController.fr.resx ドット
Resources/Controllers/HomeController.fr.resx パス

Razor ビューの @inject IViewLocalizer を使用するリソース ファイルは同様のパターンに従います。 ビューのリソース ファイルには、ドットの名前付けまたはパスの名前付けを使用して名前を付けることができます。 Razor ビューのリソース ファイルは、関連するビュー ファイルのパスを模倣します。 ResourcesPath を "Resources" に設定すると仮定すると、Views/Home/About.cshtml ビューに関連付けられるフランス語のリソース ファイルは、次のいずれかになります。

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

ResourcesPath オプションを使用しない場合、ビューの .resx ファイルは、ビューと同じフォルダーに配置されます。

RootNamespaceAttribute

アセンブリのルート名前空間がアセンブリ名と異なると、RootNamespaceAttribute 属性によってアセンブリのルート名前空間が提供されます。

警告

これは、プロジェクト名が有効な .NET 識別子でない場合に発生する可能性があります。 たとえば、my-project-name.csproj ではルート名前空間 my_project_name が使用されるので、アセンブリ名 my-project-name はこのエラーにつながります。

アセンブリのルート名前空間がアセンブリ名と異なる場合:

  • 既定では、ローカライズが機能しません。
  • アセンブリ内でのリソースの検索方法が原因で、ローカライズが失敗します。 RootNamespace はビルド時の値で、実行中のプロセスでは使用できません。

RootNamespaceAssemblyName と異なる場合、AssemblyInfo.cs (パラメーターの値は実際の値に置き換えられます) に次を含めてください。

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

上記のコードにより、resx ファイルが正常に解決できるようになります。

カルチャ フォールバック動作

リソースを探すとき、ローカリゼーションは、"カルチャ フォールバック" を行います。 要求されたカルチャが存在しない場合、そのカルチャの親カルチャに戻ります。 なお、CultureInfo.Parent プロパティは親カルチャを示します。 つまり、通常は (必ずではありませんが) ISO から国の識別子が削除されます。 たとえば、メキシコで使われているスペイン語は、"es-MX" です。 これには、どの国にも固有でないスペイン語の "es" が親として付いています。

カルチャ "fr-CA" が使用された、"ようこそ" リソースの要求をサイトで受信するとします。 ローカリゼーション システムでは、次の順番でリソースを検索し、最初の一致を選択します。

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (NeutralResourcesLanguage が "fr-CA" の場合)

例として、".fr" カルチャ指定子を削除し、カルチャを French に設定した場合、既定のリソース ファイルは read で文字列がローカライズされます。 リソース マネージャーは、要求されたカルチャを満たすものがない場合、既定またはフォールバックのリソースを指定します。 要求されたカルチャのリソースが見つからないときにキーのみを返す場合は、既定のリソース ファイルを使用することはできません。

Visual Studio でリソース ファイルを生成する

Visual Studio で、ファイル名にカルチャを指定せずにリソース ファイルを作成する場合 (たとえば、Welcome.resx)、Visual Studio は各文字列のプロパティを使用して、C# クラスを作成します。 通常、ASP.NET Core ではこれを行いません。 一般的に既定の .resx リソース ファイル (カルチャ名のない .resx ファイル) は使用しません。 カルチャ名を含む .resx ファイル (たとえば Welcome.fr.resx) を作成することをお勧めします。 カルチャ名を含む .resx ファイルを作成すると、Visual Studio はクラス ファイルを生成しません。

その他のカルチャを追加する

各言語とカルチャの組み合わせ (既定の言語以外) ごとに一意のリソース ファイルが必要です。 ISO 言語コードがファイル名の一部となるリソース ファイル (たとえば、en-usfr-caen-gb) を新規作成することで、異なるカルチャとロケールのリソース ファイルを作成することができます。 Welcome.es-MX.resx (スペイン語/メキシコ) のように、ファイル名と .resx ファイル拡張子の間にこれらの ISO コードが置かれます。

要求ごとに言語/カルチャを選択するための戦略を実装する

ローカリゼーションを構成する

ローカリゼーションは、Startup.ConfigureServices メソッドで構成されます。

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

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization は、ローカリゼーション サービスをサービス コンテナーに追加します。 上記のコードは、リソース パスを "Resources" に設定します。

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

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

ローカリゼーション ミドルウェア

要求時に現在のカルチャが、ローカリゼーション ミドルウェアで設定されます。 ローカリゼーション ミドルウェアは、Startup.Configure メソッドで有効になります。 要求のカルチャをチェックする可能性があるすべてのミドルウェア (たとえば app.UseMvcWithDefaultRoute()) の前に、ローカリゼーション ミドルウェアを構成する必要があります。

var supportedCultures = new[] { "en-US", "fr" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

コードのコメントを英語以外の言語に翻訳し表示したい場合、こちらの GitHub ディスカッション イシューにてお知らせください。

UseRequestLocalizationRequestLocalizationOptions オブジェクトを初期化します。 すべての要求で、RequestLocalizationOptionsRequestCultureProvider のリストが列挙され、要求のカルチャを正常に決定できる最初のプロバイダーが使用されます。 既定のプロバイダーは RequestLocalizationOptions クラスから派生します。

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

既定のリストは、最も具体的なものから最も具体的でないものの順番になります。 記事の後半では、この順序を変更する方法、さらにカスタム カルチャ プロバイダーを追加する方法も説明します。 要求のカルチャを判断できるプロバイダーがない場合、DefaultRequestCulture が使用されます。

QueryStringRequestCultureProvider

いくつかのアプリでは、クエリ文字列を使用して、CultureInfoを設定します。 cookie または Accept-language ヘッダーのアプローチを使用するアプリの場合、URL にクエリ文字列を追加すると、デバッグおよびコードのテストに役立ちます。 既定では、QueryStringRequestCultureProvider が、RequestCultureProvider リストの最初のローカリゼーション プロバイダーとして登録されます。 クエリ文字列パラメーター cultureui-culture を渡します。 次の例では、特定のカルチャ (言語および地域) をスペイン語/メキシコに設定します。

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

2 つのいずれかのみ (culture または ui-culture) を渡した場合、クエリ文字列プロバイダーは、渡した 1 つのパラメーターを使用して両方の値を設定します。 たとえば、カルチャだけを設定すると、CultureUICulture の両方が設定されます。

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

多くの場合、実稼働アプリケーションは、ASP.NET Core カルチャ cookie を使用してカルチャを設定するためのメカニズムを提供します。 cookie を作成するには、MakeCookieValue メソッドを使用します。

CookieRequestCultureProviderDefaultCookieName は、ユーザーの優先するカルチャ情報を追跡するために使用される既定の cookie 名を返します。 既定の cookie 名は .AspNetCore.Culture です。

cookie の形式は c=%LANGCODE%|uic=%LANGCODE% です。ここで、cCulture であり、uicUICulture です。たとえば、次のようになります。

c=en-UK|uic=en-US

カルチャ情報と UI カルチャの 1 つのみを指定した場合、指定したカルチャが、カルチャ情報と UI カルチャの両方に使用されます。

Accept-Language HTTP ヘッダー

Accept-language ヘッダーは、ほとんどのブラウザーで設定可能であり、当初はユーザーの言語を指定するためのものでした。 この設定は、ブラウザーが何を送信するように設定されているか、基になるオペレーティング システムから何を継承するかを示します。 ブラウザーの要求からの Accept Language HTTP ヘッダーは、ユーザーの優先言語を検出するための確実な方法ではありません (「Setting language preferences in a browser」(ブラウザーの優先言語を設定する) を参照してください)。 実稼働アプリには、ユーザーがカルチャの選択をカスタマイズする方法を含める必要があります。

IE で Accept-Language HTTP ヘッダーを設定する

  1. 歯車アイコンから、 [インターネット オプション] をタップします。

  2. [言語] をタップします。

    インターネット オプション

  3. [言語の優先順位の設定] をタップします。

  4. [言語の追加] をタップします。

  5. 言語を追加します。

  6. 言語をタップして、 [上へ移動] をタップします。

Content-Language HTTP ヘッダー

Content-Language エンティティ ヘッダーは、

  • 対象ユーザー用に想定した言語を説明するために使用されます。
  • ユーザーが、そのユーザー独自の優先言語に従って区別することを可能にします。

エンティティ ヘッダーは、HTTP 要求と応答の両方で使用されます。

プロパティ ApplyCurrentCultureToResponseHeaders を設定することによって Content-Language ヘッダーを追加できます。

Content-Language ヘッダーを追加すると、

  • RequestLocalizationMiddleware で CurrentUICulture を使って Content-Language を設定できるようになります。
  • 応答ヘッダーの Content-Language を明示的に設定する必要がなくなります。
app.UseRequestLocalization(new RequestLocalizationOptions
{
    ApplyCurrentCultureToResponseHeaders = true
});

カスタム プロバイダーを使用する

お客様がデータベースに言語とカルチャを格納できるようにしたいとします。 ユーザーのためにこれらの値を検索するプロバイダーを記述することもできます。 次のコードは、カスタム プロバイダーを追加する方法を示しています。

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return await Task.FromResult(new ProviderCultureResult("en"));
    }));
});

ローカリゼーション プロバイダーを追加または削除するには、RequestLocalizationOptions を使用します。

要求カルチャ プロバイダーの順序を変更する

RequestLocalizationOptions の既定の要求カルチャ プロバイダーは次の 3 つです: QueryStringRequestCultureProviderCookieRequestCultureProviderAcceptLanguageHeaderRequestCultureProvider。 次に示すように、RequestLocalizationOptions.RequestCultureProviders プロパティを使用して、これらのプロバイダーの順序を変更できます。

    app.UseRequestLocalization(options =>
    {
        var questStringCultureProvider = options.RequestCultureProviders[0];    
        options.RequestCultureProviders.RemoveAt(0);
        options.RequestCultureProviders.Insert(1, questStringCultureProvider);
    });

上の例では、QueryStringRequestCultureProviderCookieRequestCultureProvider の順序を入れ替えているので、RequestLocalizationMiddleware は最初に cookie からカルチャを探し、次にクエリ文字列から探します。

前述のように、AddInitialRequestCultureProvider を使用してカスタム プロバイダーを追加します。このプロバイダーは、順序を 0 に設定しているので、他のプロバイダーよりも優先されます。

プログラムでカルチャを設定する

この GitHub のサンプル Localization.StarterWeb プロジェクトには、Culture を設定するための UI が含まれています。 Views/Shared/_SelectLanguagePartial.cshtml ファイルを使用して、サポートされているカルチャの一覧からカルチャを選択することができます。

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

Views/Shared/_SelectLanguagePartial.cshtml ファイルは、レイアウト ファイルの footer セクションに追加されるので、すべてのビューで使用できます。

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

SetLanguage メソッドはカルチャ cookie を設定します。

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

_SelectLanguagePartial.cshtml をこのプロジェクトのサンプル コードに接続することはできません。 GitHubLocalization.StarterWeb プロジェクトには、依存関係の挿入コンテナーを介して Razor 部分に RequestLocalizationOptions をフローするコードがあります。

モデル バインド ルート データとクエリ文字列

モデル バインド ルート データとクエリ文字列のグローバリゼーション動作」を参照してください。

グローバリゼーションとローカリゼーションの用語

アプリをローカライズするプロセスでは、最新のソフトウェア開発でよく使用される関連する文字セットの基本的な理解と、それらに関連した問題の理解も必要です。 すべてのコンピューターは、テキストを数値 (コード) として格納しますが、さまざまなシステムが異なる数値を使用して同じテキストを格納します。 ローカリゼーション プロセスとは、特定のカルチャ/ロケール用にアプリのユーザー インターフェイス (UI) を変換することを指します。

ローカライズ化は、グローバル化されたアプリのローカリゼーションの準備ができていることを確認するための中間プロセスです。

カルチャ名の RFC 4646 形式は <languagecode2>-<country/regioncode2> です。ここで、<languagecode2> は言語コードであり、<country/regioncode2> はサブカルチャ コードです。 たとえば、スペイン語 (チリ) は es-CL、英語 (米国) は en-US、英語 (オーストラリア) は en-AU です。 RFC 4646 は、言語に関連付けられた ISO 639 の 2 文字の小文字カルチャ コードと、国または地域に関連付けられた ISO 3166 の 2 文字の大文字サブカルチャ コードの組み合わせです。 詳細については、「System.Globalization.CultureInfo」を参照してください。

多くの場合、国際化は "I18N" に省略されます。 省略形は、最初と最後の文字およびそれらの間の文字の数になります。したがって、18 は、最初の "I" と最後の "N" の間の文字の数を表します。 同じことが、グローバリゼーション (G11N) とローカリゼーション (L10N) にも当てはまります。

用語:

  • グローバリゼーション (G11N):アプリが別の言語と地域をサポートするようにするプロセス。
  • ローカリゼーション (L10N):特定の言語と地域向けにアプリをカスタマイズするプロセス。
  • 国際化 (I18N):グローバリゼーションとローカリゼーションの両方を示します。
  • カルチャ:言語および必要に応じて地域です。
  • ニュートラル カルチャ:指定した言語のみを含み、地域は含まないカルチャ。 (例: "en"、"es")。
  • 特定のカルチャ:指定した言語と地域を含むカルチャ。 (例: "en-US"、"en-GB"、"es-CL")。
  • 親カルチャ:特定のカルチャを含むニュートラル カルチャ。 (たとえば、"en" は "en-US" および "en-GB" の親カルチャです)。
  • ロケール:ロケールはカルチャと同じです。

Note

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

Note

ASP.NET Core 3.0 より前の Web アプリでは、要求されたカルチャがサポートされていない場合、要求ごとに LogLevel.Warning の種類のログが 1 つ書き込まれます。 要求ごとに 1 つの LogLevel.Warning をログに記録すると、冗長な情報を含む大きなログ ファイルが作成される可能性があります。 この動作は、ASP.NET 3.0 で変更されています。 RequestLocalizationMiddleware によって LogLevel.Debug の種類のログが書き込まれるため、運用ログのサイズが縮小されます。

その他のリソース

作成者: Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya

多言語の Web サイトにすると、サイトはより幅広い対象ユーザーにリーチできます。 ASP.NET Core は、さまざまな言語と文化にローカライズするためのサービスとミドルウェアを提供します。

国際化には、System.Globalizationローカリゼーションが含まれます。 グローバリゼーションとは異なるカルチャをサポートするアプリを設計するプロセスです。 グローバリゼーションによって、特定の地域に関連する定義済みの言語セットの入出力と表示のサポートが追加されます。

ローカリゼーションとは、ローカライズのために既に処理されているグローバル化されたアプリを特定のカルチャ/ロケールに適合させるプロセスです。 詳細については、本ドキュメントの末尾にある「グローバリゼーションとローカリゼーションの用語」を参照してください。

アプリのローカリゼーションには、以下のものが関与します。

  1. アプリのコンテンツをローカライズできるようにする
  2. サポートする言語およびカルチャのローカライズされたリソースを提供する
  3. 要求ごとに言語/カルチャを選択するための戦略を実装する

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

アプリのコンテンツをローカライズできるようにする

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 ファイルを使用せずに、文字列リテラルをラップするだけの新しいワークフローは、多くの開発者にとって、アプリをローカライズする際のオーバーヘッドの削減になります。 他の開発者は、長い文字列リテラルの操作が容易で、ローカライズされた文字列を更新しやすい従来のワークフローを好みます。

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 を取得できます。

{
    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)]

フランス語のリソース ファイルには次の値が含まれます。

Key [値]
<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; }
}

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

複数のクラスに 1 つのリソース文字列を使用する

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

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

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

サポートする言語およびカルチャのローカライズされたリソースを提供する

SupportedCultures と SupportedUICultures

ASP.NET Core では、SupportedCulturesSupportedUICultures という 2 つのカルチャ値を指定できます。 日付、数値、および通貨の書式設定など、カルチャに依存する関数の結果は、SupportedCulturesCultureInfo オブジェクトによって決まります。 テキストの並べ替え順序、大文字と小文字の表記規則、文字列比較も SupportedCultures によって決まります。 サーバーによるカルチャの取得方法の詳細については、CultureInfo.CurrentCultureCultureInfo.CurrentUICulture に関する記事を参照してください。 SupportedUICultures は、 .resx ファイルからのどの翻訳文字列が ResourceManager によって検索されるかを決定します。 ResourceManager では、CurrentUICulture によって決定されるカルチャ固有の文字列が検索されます。 .NET のすべてのスレッドに CurrentCulture オブジェクトと CurrentUICultureオブジェクトがあります。 フレームワークでは、カルチャに依存する関数を表示するときに、これらの値が検査されます。 現在のスレッドのカルチャが en-US (英語、米国) に設定されている場合は、DateTime.Now.ToLongDateString() によって Thursday, February 18, 2016 が表示されます。ただし、CurrentCulturees-ES (スペイン語、スペイン) に設定されている場合は、出力は jueves, 18 de febrero de 2016 になります。

リソース ファイル

リソース ファイルは、ローカライズ可能な文字列をコードから分離するために役立つメカニズムです。 既定以外の言語の翻訳された文字列は、 .resx リソース ファイルで分離されています。 たとえば、翻訳された文字列を含む Welcome.es.resx という名前のスペイン語のリソース ファイルを作成したい場合があります。 "es" は、スペイン語の言語コードです。 Visual Studio でこのリソース ファイルを作成するには、次の手順を実行します。

  1. ソリューション エクスプローラーで、リソース ファイルが格納されているフォルダーを右クリックし、[追加]>[新しい項目] の順に選択します。

    入れ子になったコンテキスト メニュー: ソリューション エクスプローラーで Resources のコンテキスト メニューが開かれています。[追加] の 2 つ目のコンテキスト メニューが開かれており、[新しい項目] コマンドが強調表示されています。

  2. インストールされているテンプレートの検索ボックスに、「resource」と入力し、ファイルに名前を付けます。

    [新しい項目の追加] ダイアログ

  3. キーの値 (ネイティブの文字列) を [名前] 列に入力し、翻訳された文字列を [値] 列に入力します。

    Welcome.es.resx ファイル (スペイン語の Welcome リソース ファイル) と、[名前] 列の Hello という単語と、[値] 列の Hola という単語 (スペイン語のこんにちは)

    Visual Studio に Welcome.es.resx ファイルが表示されます。

    Welcome スペイン語リソース ファイルを表示しているソリューション エクスプローラー

リソース ファイルの名前付け

リソースの名前は、クラスの完全な型名からアセンブリ名を除いたものになります。 たとえば、メイン アセンブリが LocalizationWebsite.Web.dll であるプロジェクト内のクラス LocalizationWebsite.Web.Startup のフランス語のリソースは、Startup.fr.resx という名前になります。 クラス LocalizationWebsite.Web.Controllers.HomeController のリソースは、Controllers.HomeController.fr.resx という名前になります。 対象となるクラスの名前空間が、アセンブリ名と同じでない場合は、完全な型名が必要です。 たとえば、同じプロジェクトで、型 ExtraNamespace.Tools のリソースは、ExtraNamespace.Tools.fr.resx という名前になります。

サンプル プロジェクトで、ConfigureServices メソッドにより ResourcesPath が "Resources" に設定されるので、ホーム コントローラーのフランス語のリソース ファイルの相対パスは、Resources/Controllers.HomeController.fr.resx です。 あるいは、フォルダーを使用してリソース ファイルを整理することもできます。 ホーム コントローラーのパスは、Resources/Controllers/HomeController.fr.resx です。 ResourcesPath オプションを使用しない場合、 .resx ファイルは、プロジェクトの基本ディレクトリに置かれます。 HomeController のリソース ファイルは、Controllers.HomeController.fr.resx という名前になります。 ドットまたはパスの名前付け規則の選択は、リソース ファイルを整理する方法によって決まります。

リソース名 ドットまたはパスの名前付け
Resources/Controllers.HomeController.fr.resx ドット
Resources/Controllers/HomeController.fr.resx パス

Razor ビューの @inject IViewLocalizer を使用するリソース ファイルは同様のパターンに従います。 ビューのリソース ファイルには、ドットの名前付けまたはパスの名前付けを使用して名前を付けることができます。 Razor ビューのリソース ファイルは、関連するビュー ファイルのパスを模倣します。 ResourcesPath を "Resources" に設定すると仮定すると、Views/Home/About.cshtml ビューに関連付けられるフランス語のリソース ファイルは、次のいずれかになります。

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

ResourcesPath オプションを使用しない場合、ビューの .resx ファイルは、ビューと同じフォルダーに配置されます。

RootNamespaceAttribute

アセンブリのルート名前空間がアセンブリ名と異なると、RootNamespaceAttribute 属性によってアセンブリのルート名前空間が提供されます。

警告

これは、プロジェクト名が有効な .NET 識別子でない場合に発生する可能性があります。 たとえば、my-project-name.csproj ではルート名前空間 my_project_name が使用されるので、アセンブリ名 my-project-name はこのエラーにつながります。

アセンブリのルート名前空間がアセンブリ名と異なる場合:

  • 既定では、ローカライズが機能しません。
  • アセンブリ内でのリソースの検索方法が原因で、ローカライズが失敗します。 RootNamespace はビルド時の値で、実行中のプロセスでは使用できません。

RootNamespaceAssemblyName と異なる場合、AssemblyInfo.cs (パラメーターの値は実際の値に置き換えられます) に次を含めてください。

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

上記のコードにより、resx ファイルが正常に解決できるようになります。

カルチャ フォールバック動作

リソースを探すとき、ローカリゼーションは、"カルチャ フォールバック" を行います。 要求されたカルチャが存在しない場合、そのカルチャの親カルチャに戻ります。 なお、CultureInfo.Parent プロパティは親カルチャを示します。 つまり、通常は (必ずではありませんが) ISO から国の識別子が削除されます。 たとえば、メキシコで使われているスペイン語は、"es-MX" です。 これには、どの国にも固有でないスペイン語の "es" が親として付いています。

カルチャ "fr-CA" が使用された、"ようこそ" リソースの要求をサイトで受信するとします。 ローカリゼーション システムでは、次の順番でリソースを検索し、最初の一致を選択します。

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (NeutralResourcesLanguage が "fr-CA" の場合)

例として、".fr" カルチャ指定子を削除し、カルチャを French に設定した場合、既定のリソース ファイルは read で文字列がローカライズされます。 リソース マネージャーは、要求されたカルチャを満たすものがない場合、既定またはフォールバックのリソースを指定します。 要求されたカルチャのリソースが見つからないときにキーのみを返す場合は、既定のリソース ファイルを使用することはできません。

Visual Studio でリソース ファイルを生成する

Visual Studio で、ファイル名にカルチャを指定せずにリソース ファイルを作成する場合 (たとえば、Welcome.resx)、Visual Studio は各文字列のプロパティを使用して、C# クラスを作成します。 通常、ASP.NET Core ではこれを行いません。 一般的に既定の .resx リソース ファイル (カルチャ名のない .resx ファイル) は使用しません。 カルチャ名を含む .resx ファイル (たとえば Welcome.fr.resx) を作成することをお勧めします。 カルチャ名を含む .resx ファイルを作成すると、Visual Studio はクラス ファイルを生成しません。

その他のカルチャを追加する

各言語とカルチャの組み合わせ (既定の言語以外) ごとに一意のリソース ファイルが必要です。 ISO 言語コードがファイル名の一部となるリソース ファイル (たとえば、en-usfr-caen-gb) を新規作成することで、異なるカルチャとロケールのリソース ファイルを作成することができます。 Welcome.es-MX.resx (スペイン語/メキシコ) のように、ファイル名と .resx ファイル拡張子の間にこれらの ISO コードが置かれます。

要求ごとに言語/カルチャを選択するための戦略を実装する

ローカリゼーションを構成する

ローカリゼーションは、Startup.ConfigureServices メソッドで構成されます。

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

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization は、ローカリゼーション サービスをサービス コンテナーに追加します。 上記のコードは、リソース パスを "Resources" に設定します。

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

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

ローカリゼーション ミドルウェア

要求時に現在のカルチャが、ローカリゼーション ミドルウェアで設定されます。 ローカリゼーション ミドルウェアは、Startup.Configure メソッドで有効になります。 要求のカルチャをチェックする可能性があるすべてのミドルウェア (たとえば app.UseMvcWithDefaultRoute()) の前に、ローカリゼーション ミドルウェアを構成する必要があります。 RouteDataRequestCultureProvider を使用する場合、ローカリゼーション ミドルウェアはルーティング ミドルウェアの後に配置される必要があります。 ミドルウェアの順序の詳細については、「ASP.NET Core のミドルウェア」を参照してください。

var supportedCultures = new[] { "en-US", "fr" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

コードのコメントを英語以外の言語に翻訳し表示したい場合、こちらの GitHub ディスカッション イシューにてお知らせください。

UseRequestLocalizationRequestLocalizationOptions オブジェクトを初期化します。 すべての要求で、RequestLocalizationOptionsRequestCultureProvider のリストが列挙され、要求のカルチャを正常に決定できる最初のプロバイダーが使用されます。 既定のプロバイダーは RequestLocalizationOptions クラスから派生します。

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

既定のリストは、最も具体的なものから最も具体的でないものの順番になります。 記事の後半では、この順序を変更する方法、さらにカスタム カルチャ プロバイダーを追加する方法も説明します。 要求のカルチャを判断できるプロバイダーがない場合、DefaultRequestCulture が使用されます。

QueryStringRequestCultureProvider

いくつかのアプリでは、クエリ文字列を使用して、CultureInfoを設定します。 cookie または Accept-language ヘッダーのアプローチを使用するアプリの場合、URL にクエリ文字列を追加すると、デバッグおよびコードのテストに役立ちます。 既定では、QueryStringRequestCultureProvider が、RequestCultureProvider リストの最初のローカリゼーション プロバイダーとして登録されます。 クエリ文字列パラメーター cultureui-culture を渡します。 次の例では、特定のカルチャ (言語および地域) をスペイン語/メキシコに設定します。

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

2 つのいずれかのみ (culture または ui-culture) を渡した場合、クエリ文字列プロバイダーは、渡した 1 つのパラメーターを使用して両方の値を設定します。 たとえば、カルチャだけを設定すると、CultureUICulture の両方が設定されます。

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

多くの場合、実稼働アプリケーションは、ASP.NET Core カルチャ cookie を使用してカルチャを設定するためのメカニズムを提供します。 cookie を作成するには、MakeCookieValue メソッドを使用します。

CookieRequestCultureProviderDefaultCookieName は、ユーザーの優先するカルチャ情報を追跡するために使用される既定の cookie 名を返します。 既定の cookie 名は .AspNetCore.Culture です。

cookie の形式は c=%LANGCODE%|uic=%LANGCODE% です。ここで、cCulture であり、uicUICulture です。たとえば、次のようになります。

c=en-UK|uic=en-US

カルチャ情報と UI カルチャの 1 つのみを指定した場合、指定したカルチャが、カルチャ情報と UI カルチャの両方に使用されます。

Accept-Language HTTP ヘッダー

Accept-language ヘッダーは、ほとんどのブラウザーで設定可能であり、当初はユーザーの言語を指定するためのものでした。 この設定は、ブラウザーが何を送信するように設定されているか、基になるオペレーティング システムから何を継承するかを示します。 ブラウザーの要求からの Accept Language HTTP ヘッダーは、ユーザーの優先言語を検出するための確実な方法ではありません (「Setting language preferences in a browser」(ブラウザーの優先言語を設定する) を参照してください)。 実稼働アプリには、ユーザーがカルチャの選択をカスタマイズする方法を含める必要があります。

IE で Accept-Language HTTP ヘッダーを設定する

  1. 歯車アイコンから、 [インターネット オプション] をタップします。

  2. [言語] をタップします。

    インターネット オプション

  3. [言語の優先順位の設定] をタップします。

  4. [言語の追加] をタップします。

  5. 言語を追加します。

  6. 言語をタップして、 [上へ移動] をタップします。

カスタム プロバイダーを使用する

お客様がデータベースに言語とカルチャを格納できるようにしたいとします。 ユーザーのためにこれらの値を検索するプロバイダーを記述することもできます。 次のコードは、カスタム プロバイダーを追加する方法を示しています。

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return await Task.FromResult(new ProviderCultureResult("en"));
    }));
});

ローカリゼーション プロバイダーを追加または削除するには、RequestLocalizationOptions を使用します。

要求カルチャ プロバイダーの順序を変更する

RequestLocalizationOptions の既定の要求カルチャ プロバイダーは次の 3 つです: QueryStringRequestCultureProviderCookieRequestCultureProviderAcceptLanguageHeaderRequestCultureProvider。 次に示すように、[RequestLocalizationOptions.RequestCultureProviders]](xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.RequestCultureProviders) プロパティを使用して、これらのプロバイダーの順序を変更できます。

    app.UseRequestLocalization(options =>
    {
        var questStringCultureProvider = options.RequestCultureProviders[0];    
        options.RequestCultureProviders.RemoveAt(0);
        options.RequestCultureProviders.Insert(1, questStringCultureProvider);
    });

上の例では、QueryStringRequestCultureProviderCookieRequestCultureProvider の順序を入れ替えているので、RequestLocalizationMiddleware は最初に cookie からカルチャを探し、次にクエリ文字列から探します。

前述のように、AddInitialRequestCultureProvider を使用してカスタム プロバイダーを追加します。このプロバイダーは、順序を 0 に設定しているので、他のプロバイダーよりも優先されます。

プログラムでカルチャを設定する

この GitHub のサンプル Localization.StarterWeb プロジェクトには、Culture を設定するための UI が含まれています。 Views/Shared/_SelectLanguagePartial.cshtml ファイルを使用して、サポートされているカルチャの一覧からカルチャを選択することができます。

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

Views/Shared/_SelectLanguagePartial.cshtml ファイルは、レイアウト ファイルの footer セクションに追加されるので、すべてのビューで使用できます。

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

SetLanguage メソッドはカルチャ cookie を設定します。

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

_SelectLanguagePartial.cshtml をこのプロジェクトのサンプル コードに接続することはできません。 GitHubLocalization.StarterWeb プロジェクトには、依存関係の挿入コンテナーを介して Razor 部分に RequestLocalizationOptions をフローするコードがあります。

モデル バインド ルート データとクエリ文字列

モデル バインド ルート データとクエリ文字列のグローバリゼーション動作」を参照してください。

グローバリゼーションとローカリゼーションの用語

アプリをローカライズするプロセスでは、最新のソフトウェア開発でよく使用される関連する文字セットの基本的な理解と、それらに関連した問題の理解も必要です。 すべてのコンピューターは、テキストを数値 (コード) として格納しますが、さまざまなシステムが異なる数値を使用して同じテキストを格納します。 ローカリゼーション プロセスとは、特定のカルチャ/ロケール用にアプリのユーザー インターフェイス (UI) を変換することを指します。

ローカライズ化は、グローバル化されたアプリのローカリゼーションの準備ができていることを確認するための中間プロセスです。

カルチャ名の RFC 4646 形式は <languagecode2>-<country/regioncode2> です。ここで、<languagecode2> は言語コードであり、<country/regioncode2> はサブカルチャ コードです。 たとえば、スペイン語 (チリ) は es-CL、英語 (米国) は en-US、英語 (オーストラリア) は en-AU です。 RFC 4646 は、言語に関連付けられた ISO 639 の 2 文字の小文字カルチャ コードと、国または地域に関連付けられた ISO 3166 の 2 文字の大文字サブカルチャ コードの組み合わせです。 詳細については、「System.Globalization.CultureInfo」を参照してください。

多くの場合、国際化は "I18N" に省略されます。 省略形は、最初と最後の文字およびそれらの間の文字の数になります。したがって、18 は、最初の "I" と最後の "N" の間の文字の数を表します。 同じことが、グローバリゼーション (G11N) とローカリゼーション (L10N) にも当てはまります。

用語:

  • グローバリゼーション (G11N):アプリが別の言語と地域をサポートするようにするプロセス。
  • ローカリゼーション (L10N):特定の言語と地域向けにアプリをカスタマイズするプロセス。
  • 国際化 (I18N):グローバリゼーションとローカリゼーションの両方を示します。
  • カルチャ:言語および必要に応じて地域です。
  • ニュートラル カルチャ:指定した言語のみを含み、地域は含まないカルチャ。 (例: "en"、"es")。
  • 特定のカルチャ:指定した言語と地域を含むカルチャ。 (例: "en-US"、"en-GB"、"es-CL")。
  • 親カルチャ:特定のカルチャを含むニュートラル カルチャ。 (たとえば、"en" は "en-US" および "en-GB" の親カルチャです)。
  • ロケール:ロケールはカルチャと同じです。

Note

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

Note

ASP.NET Core 3.0 より前の Web アプリでは、要求されたカルチャがサポートされていない場合、要求ごとに LogLevel.Warning の種類のログが 1 つ書き込まれます。 要求ごとに 1 つの LogLevel.Warning をログに記録すると、冗長な情報を含む大きなログ ファイルが作成される可能性があります。 この動作は、ASP.NET 3.0 で変更されています。 RequestLocalizationMiddleware によって LogLevel.Debug の種類のログが書き込まれるため、運用ログのサイズが縮小されます。

その他のリソース