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

Razor コンポーネントを使用すると、異なるカルチャや言語のユーザーにグローバル化およびローカライズされたコンテンツをレンダリングできます。 グローバリゼーションの場合、Blazor から数値と日付の書式設定が提供されます。 ローカライズの場合、Blazor により .NET リソース システムを使用したコンテンツのレンダリングが行われます。

サポートされている ASP.NET Core のローカライズ機能は限られています。

✔️ IStringLocalizerIStringLocalizer<T> は、Blazor アプリでサポートされています。

❌、IHtmlLocalizerIViewLocalizerデータ注釈のローカライズは ASP.NET Core の MVC シナリオであり、 Blazor アプリでは サポートされていません

この記事では、次に基づいて Blazor のグローバリゼーションとローカライズ機能を使用する方法について説明します。

  • ブラウザーの設定でのユーザー言語設定に基づきブラウザーによって設定された Accept-Language ヘッダー
  • Accept-Language ヘッダーの値に基づいていない、アプリによって設定されたカルチャ。 設定は、すべてのユーザーに対して静的にするか、アプリ ロジックに基づいて動的にすることができます。 設定がユーザー設定に基づく場合、通常は今後のアクセス時に再読み込みするために設定が保存されます。

追加の一般情報については、ASP.NET Core のグローバリゼーションおよびローカリゼーション を参照してください。

注意

多くの場合、グローバリゼーションとローカライズの概念を扱う場合、''言語'' と ''カルチャ'' という用語は区別なく使用されます。

この記事の場合、言語 とは、ユーザーがブラウザーの設定で行った選択を指します。 ユーザーの言語選択は、Accept-Language ヘッダーのブラウザー要求で送信されます。 ブラウザーの設定では、通常、UI で「言語」という単語が使用されます。

カルチャ は、.NET と Blazor API のメンバーに関連します。 たとえば、ユーザーの要求には、ユーザーの観点から 言語 を指定する Accept-Language ヘッダーを含めることができますが、アプリでは最終的に、ユーザーが要求した言語から CurrentCulture (「カルチャ」) プロパティが設定されます。 API では通常、メンバー名に "culture" という単語が使用されます。

グローバリゼーション

@bind 属性ディレクティブでは、アプリがサポートするユーザーの優先言語に基づいて形式を適用し、表示向けの値を解析します。 @bind では、値を解析および書式設定するための System.Globalization.CultureInfo を提供する @bind:culture パラメーターをサポートしています。

現在のカルチャは、System.Globalization.CultureInfo.CurrentCulture プロパティからアクセスできます。

CultureInfo.InvariantCulture は、次のフィールド型 ({TYPE} プレースホルダーが型の <input type="{TYPE}" />) に使用されます。

  • date
  • number

前のフィールドの型は次のようになります。

  • 適切なブラウザー ベースの書式ルールを使用して表示されます。
  • 自由形式のテキストを含めることはできません。
  • ブラウザーの実装に基づいてユーザー操作の特性を指定します。

datenumber フィールド型を使用する場合、Blazor から現在のカルチャの値をレンダリングするサポートが組み込みで提供されるため、@bind:culture でカルチャを指定することはお勧めしません。

次のフィールドの型には、特定の書式設定の要件がありますが、すべての主要なブラウザーでサポートされていないため、Blazor では現在サポートされていません。

  • datetime-local
  • month
  • week

前述の型の現在のブラウザー サポートについては、使用可能なものに関するページを参照してください。

デモンストレーション コンポーネント

次の CultureExample1 コンポーネントを使用して、この記事で説明する Blazor のグローバリゼーションとローカライズの概念を示せます。

Pages/CultureExample1.razor:

@page "/culture-example-1"
@using System.Globalization

<h1>Culture Example 1</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

前の例 (.ToString("N2")) の数値文字列形式 (N2) は、標準の .NET 数値書式指定子です。 この N2 形式は、すべての数値型でサポートされ、グループ区切り記号を含み、小数点以下 2 桁まで表示されます。

CultureExample1 コンポーネント向けに、Shared/NavMenu.razor のナビゲーション メニュー <ul> 要素にリスト項目を追加します。

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 1
    </NavLink>
</li>

Accept-Language ヘッダーからカルチャを動的に設定する

Accept-Language ヘッダーはブラウザーによって設定され、ブラウザー設定でのユーザーの言語設定によって制御されます。 ブラウザー設定では、ユーザーは優先順に 1 つ以上の優先言語を設定します。 設定の順序は、ヘッダー内の言語ごとに品質値 (q、0-1) を設定するためにブラウザーによって使用されます。 次の例では、英語 (米国) または英語を優先して、英語 (米国)、英語、およびスペイン語 (チリ) を指定しています。

Accept-Language: en-US,en;q=0.9,es-CL;q=0.8

アプリのカルチャは、アプリのサポートされているカルチャに一致する最初に要求された言語を照合することで設定されます。

アプリのプロジェクト ファイル (.csproj) で BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure (Startup.cs) でアプリでサポートされているカルチャを指定します。 次の例では、英語 (米国) とスペイン語 (チリ) でサポートされるカルチャを構成しています。

app.UseRequestLocalization(new RequestLocalizationOptions()
    .AddSupportedCultures(new[] { "en-US", "es-CL" })
    .AddSupportedUICultures(new[] { "en-US", "es-CL" }));

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、グローバリゼーションのしくみを確認します。 英語 (米国) (en-US) で要求を発行します。 ブラウザーの言語設定で、スペイン語 (チリ) (es-CL) に切り替えます。 Web ページを再度要求します。

注意

一部のブラウザーでは、要求とブラウザー独自の UI 設定の両方に既定の言語設定を使用する必要があります。 これにより、すべての設定 UI 画面が読むことができない言語になる可能性があるため、理解できる言語に戻すのが困難になる可能性があります。 Opera などのブラウザーは、Web ページ要求に既定の言語を設定しても、ブラウザーの設定 UI は使用言語のままにしてよいため、テストに最適です。

カルチャが英語 (米国) (en-US) の場合、表示されるコンポーネントでは、月/日の日付書式設定 (6/7)、12 時間制の時刻 (AM/PM)、および数値でコンマ、小数点値で点の区切り記号 (1,999.69) が使用されます。

  • 日付: 6/7/2021 6:45:22 AM
  • 数値: 1,999.69

カルチャがスペイン語 (チリ) (es-CL) の場合、レンダリングされるコンポーネントでは、日/月の日付書式設定 (7/6)、24 時間制の時刻、および数値でピリオド、小数点値でコンマの区切り記号 (1.999,69) が使用されます。

  • 日付: 7/6/2021 6:49:38
  • 数値: 1.999,69

カルチャを静的に設定する

アプリのプロジェクト ファイル (.csproj) で BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

アプリのカルチャは、Blazor が applicationCulture Blazor スタート オプションで始まるときに JavaScript で設定できます。 次の例では、英語 (米国) (en-US) カルチャを使用して構成しています。

  • wwwroot/index.html では、Blazor の <script> タグに autostart="false" を追加して Blazor 自動開始を防止します。

    <script src="_framework/blazor.webassembly.js" autostart="false"></script>
    
  • Blazor の <script> タグの後、</body> 終了タグの前に、次の <script> ブロックを追加します。

    <script>
      Blazor.start({
        applicationCulture: 'en-US'
      });
    </script>
    

applicationCulture の値は、BCP-47 言語タグ形式に準拠している必要があります。 Blazor スタートアップの詳細については、「ASP.NET Core Blazor の起動」を参照してください。

カルチャ Blazor のスタート オプションを設定する代わりに、C# コードでカルチャを設定することもできます。 Program.Main (Program.cs) で CultureInfo.DefaultThreadCurrentCultureCultureInfo.DefaultThreadCurrentUICulture を設定します。

System.Globalization 名前空間を Program.cs に追加します。

using System.Globalization;

WebAssemblyHostBuilder (await builder.Build().RunAsync();) をビルドして実行する行の前にカルチャ設定を追加します。

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure (Startup.cs) で静的カルチャを指定します。 次の例では、英語 (米国) を構成しています。

app.UseRequestLocalization("en-US");

UseRequestLocalization のカルチャ値は、BCP-47 言語タグ形式に準拠している必要があります。

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、グローバリゼーションのしくみを確認します。 英語 (米国) (en-US) で要求を発行します。 ブラウザーの言語設定で、スペイン語 (チリ) (es-CL) に切り替えます。 Web ページを再度要求します。 要求された言語がスペイン語 (チリ) である場合、アプリのカルチャは英語 (米国) (en-US) のままです。

アプリのローカライズを必要としない場合は、一般的に英語 (米国) (en-US) に基づくインバリアント カルチャをサポートするようにアプリを構成します。 アプリのプロジェクト ファイル (.csproj) で InvariantGlobalization プロパティを true に設定します。

<PropertyGroup>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

ユーザー設定によってカルチャを動的に設定する

アプリがユーザーの好みを格納する可能性がある場所の例としては、ブラウザーのローカル ストレージ (Blazor WebAssembly アプリ で一般的)、ローカライズ用の cookie またはデータベース (Blazor Server アプリで一般的)、外部データベースに接続され Web API によってアクセスされる外部サービスがあります。 次の例は、ブラウザーのローカル ストレージを使用する方法を示しています。

アプリのプロジェクト ファイル (.csproj) に、Microsoft.Extensions.Localization パッケージのパッケージ参照を追加します。

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

プロジェクト ファイルで BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Blazor WebAssembly アプリ内のアプリのカルチャは、Blazor フレームワークの API を使用して設定されます。 ユーザーのカルチャの選択は、ブラウザーのローカル ストレージに保存できます。

wwwroot/index.html ファイルの Blazor の <script> タグの後、</body> 終了タグの前に、JS 関数を指定して、ユーザーが選択したカルチャをブラウザーのローカル ストレージで取得および設定します。

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

注意

前の例ではグローバル メソッドでクライアントが汚染されます。 実稼働アプリでのより適切なアプローチについては、「JavaScript モジュール内の JavaScript 分離」を参照してください。

例:

export function getBlazorCulture() {
  return window.localStorage['BlazorCulture'];
};
export function setBlazorCulture(value) {
  window.localStorage['BlazorCulture'] = value;
};

上記の関数を使用する場合は、このセクションの JS 相互運用機能呼び出しを blazorCulture.get から getBlazorCulture に、blazorCulture.set から setBlazorCulture に変更します。

System.GlobalizationMicrosoft.JSInterop の名前空間を Program.cs の先頭に追加します。

using System.Globalization;
using Microsoft.JSInterop;

Program.Main から次の行を削除します。

-await builder.Build().RunAsync();

前の行を、次のコードで置き換えます。 このコードは、AddLocalization を使用してアプリのサービス コレクションに Blazor のローカライズ サービスを追加し、JS 相互運用機能を使用して JS を呼び出し、ローカル ストレージからユーザーが選択したカルチャを取得します。 ローカル ストレージにユーザーのカルチャが含まれていない場合、コードは英語 (米国) (en-US) の既定値を設定します。

builder.Services.AddLocalization();

var host = builder.Build();

CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");

if (result != null)
{
    culture = new CultureInfo(result);
}
else
{
    culture = new CultureInfo("en-US");
    await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

次の CultureSelector コンポーネントは、JS 相互運用機能を使用して、ユーザーが選択したカルチャをブラウザーのローカル ストレージに設定する方法を示しています。 コンポーネントは、アプリ全体で使用するために Shared フォルダーに配置されます。

Shared/CultureSelector.razor:

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CL"),
    };

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var js = (IJSInProcessRuntime)JSRuntime;
                js.InvokeVoid("blazorCulture.set", value.Name);

                Nav.NavigateTo(Nav.Uri, forceLoad: true);
            }
        }
    }
}

Shared/MainLayout.razor<div class="main"> 要素の </div> 終了タグ内に、CultureSelector コンポーネントを追加します。

<div class="bottom-row px-4">
    <CultureSelector />
</div>

アプリがユーザーの好みを格納する可能性がある場所の例としては、ブラウザーのローカル ストレージ (Blazor WebAssembly アプリ で一般的)、ローカライズ用の cookie またはデータベース (Blazor Server アプリで一般的)、外部データベースに接続され Web API によってアクセスされる外部サービスがあります。 以下の例では、ローカライズ cookie の使用方法を示しています。

アプリのプロジェクト ファイル (.csproj) に、Microsoft.Extensions.Localization パッケージのパッケージ参照を追加します。

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />
</ItemGroup>

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

アプリの既定とサポートされるカルチャを RequestLocalizationOptions.SetDefaultCulture に設定します。

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure で以下を行います。

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

app.UseRequestLocalization(localizationOptions);

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

次の例では、ローカライズ ミドルウェアによって読み取ることができる cookie で現在のカルチャを設定する方法を示します。

次の名前空間を Pages/_Layout.cshtml ファイルの先頭に追加します。

@using System.Globalization
@using Microsoft.AspNetCore.Localization

Pages/_Layout.cshtml<body> 開始タグの直後に、次の Razor 式を追加します。

@{
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

アプリがコントローラー アクションを処理するように構成されていない場合:

  • Startup.ConfigureServices でサービス コレクションに対して AddControllers を呼び出して、MVC サービスを追加します。

    services.AddControllers();
    
  • IEndpointRouteBuilderMapControllers を呼び出し、Startup.Configure でコントローラー エンドポイント ルーティングを追加します。

    endpoints.MapControllers();
    

    次の例は、行が追加された後の UseEndpoints への呼び出しを示しています。

    app.UseEndpoints(endpoints =>
    {
    +   endpoints.MapControllers();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    

ユーザーがカルチャを選択できるように UI を提供するには、ローカライズ cookie での リダイレクト ベースのアプローチ をお勧めします。 アプリでは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャが保持されます。 コントローラーによって、ユーザーが選択したカルチャが cookie に設定され、ユーザーは元の URI にリダイレクトされます。 このプロセスは、ユーザーがセキュリティで保護されたリソースにアクセスしようとしたときに、Web アプリで発生する処理に似ています。ユーザーがサインイン ページにリダイレクトされ、元のリソースに戻されます。

Controllers/CultureController.cs:

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

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

警告

LocalRedirect アクションの結果を使用して、オープン リダイレクト攻撃を防ぎます。 詳細については、「ASP.NET Core でのオープンリダイレクト攻撃の防止」を参照してください。

次の CultureSelector コンポーネントでは、ユーザーがカルチャを選択したときに、最初のリダイレクトを実行する方法を示しています。 コンポーネントは、アプリ全体で使用するために Shared フォルダーに配置されます。

Shared/CultureSelector.razor:

@using  System.Globalization
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CL"),
    };

    protected override void OnInitialized()
    {
        Culture = CultureInfo.CurrentCulture;
    }

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var uri = new Uri(Nav.Uri)
                    .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var cultureEscaped = Uri.EscapeDataString(value.Name);
                var uriEscaped = Uri.EscapeDataString(uri);

                Nav.NavigateTo(
                    $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                    forceLoad: true);
            }
        }
    }
}

Shared/MainLayout.razor<div class="main"> 要素の </div> 終了タグ内に、CultureSelector コンポーネントを追加します。

<div class="bottom-row px-4">
    <CultureSelector />
</div>

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、前述の例のしくみを確認します。

ローカライズ

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」セクションに基づくカルチャの選択をまだサポートしていない場合は、Microsoft.Extensions.Localization パッケージのパッケージ参照をアプリのプロジェクト ファイル (.csproj) に追加します。

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

アプリのプロジェクト ファイル (.csproj) で BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Program.Main (Program.cs) で、System.Globalization の名前空間をファイルの先頭に追加します。

using System.Globalization;

Program.MainAddLocalization を使用して、アプリのサービスコレクションに Blazor のローカライズ サービスを追加します。

builder.Services.AddLocalization();

ローカライズ ミドルウェアを使用して、アプリのカルチャを設定します。

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」に従って、カルチャの選択をまだサポートしていない場合は、次の手順を実行します。

  • AddLocalization を使用して、ローカライズ サービスをアプリに追加します。
  • アプリの既定とサポートされるカルチャを Startup.Configure (Startup.cs) で指定します。 次の例では、英語 (米国) とスペイン語 (チリ) でサポートされるカルチャを構成しています。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure で以下を行います。

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

app.UseRequestLocalization(localizationOptions);

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

アプリでユーザーのカルチャ設定の格納に基づきリソースをローカライズする必要がある場合は、ローカライズ カルチャ cookie を使用します。 cookie を使用すると、WebSocket 接続によってカルチャを正しく伝達できることを確実にします。 ローカライズ スキームが URL パスまたはクエリ文字列に基づいている場合は、スキームが WebSockets を使用できない可能性があるため、カルチャを保持できません。 したがって、ローカライズ カルチャ cookie の使用をお勧めします。 この記事の「ユーザー設定によってカルチャを動的に設定する」セクションを参照して、ユーザーが選択したカルチャを保持する Pages/_Layout.cshtml ファイルの Razor 式の例を参照してください。

このセクションのローカライズされたリソースの例は、この記事の前の例と連動しています。アプリのサポートされているカルチャは、既定のロケールとして英語 (en)、ユーザー選択可能またはブラウザー指定の代替ロケールとしてスペイン語 (es) になっています。

ロケールごとにリソースを作成します。 次の例では、既定の Greeting 文字列のリソースが作成されます。

  • 英語: Hello, World!
  • スペイン語 (es): ¡Hola, Mundo!

注意

次のリソース ファイルを Visual Studio に追加するには、プロジェクトの Pages フォルダーを右クリックし、[追加] > [新しい項目] > [リソースファイル] の順に選択します。 そのファイルに CultureExample2.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前Greeting に設定し、Hello, World! に設定します。 ファイルを保存します。

Pages/CultureExample2.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, World!</value>
  </data>
</root>

注意

次のリソース ファイルを Visual Studio に追加するには、プロジェクトの Pages フォルダーを右クリックし、[追加] > [新しい項目] > [リソースファイル] の順に選択します。 そのファイルに CultureExample2.es.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前Greeting に設定し、¡Hola, Mundo! に設定します。 ファイルを保存します。

Pages/CultureExample2.es.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>¡Hola, Mundo!</value>
  </data>
</root>

次のコンポーネントは、IStringLocalizer<T> でローカライズされた Greeting 文字列を使用する方法を示しています。

Microsoft.Extensions.Localization の名前空間をアプリの _Imports.razor ファイルに追加します。

@using Microsoft.Extensions.Localization

Pages/CultureExample2.razor:

@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc

<h1>Culture Example 2</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Greeting</h2>

<p>
    @Loc["Greeting"]
</p>

<p>
    @greeting
</p>

@code {
    private string greeting;

    protected override void OnInitialized()
    {
        greeting = Loc["Greeting"];
    }
}

CultureExample2 コンポーネント向けに、Shared/NavMenu.razor のナビゲーション メニュー <ul> 要素にリスト項目を追加します。

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-2">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 2
    </NavLink>
</li>

その他の技術情報

Razor コンポーネントを使用すると、異なるカルチャや言語のユーザーにグローバル化およびローカライズされたコンテンツをレンダリングできます。 グローバリゼーションの場合、Blazor から数値と日付の書式設定が提供されます。 ローカライズの場合、Blazor により .NET リソース システムを使用したコンテンツのレンダリングが行われます。

サポートされている ASP.NET Core のローカライズ機能は限られています。

✔️ IStringLocalizerIStringLocalizer<T> は、Blazor アプリでサポートされています。

❌、IHtmlLocalizerIViewLocalizerデータ注釈のローカライズは ASP.NET Core の MVC シナリオであり、 Blazor アプリでは サポートされていません

この記事では、次に基づいて Blazor のグローバリゼーションとローカライズ機能を使用する方法について説明します。

  • ブラウザーの設定でのユーザー言語設定に基づきブラウザーによって設定された Accept-Language ヘッダー
  • Accept-Language ヘッダーの値に基づいていない、アプリによって設定されたカルチャ。 設定は、すべてのユーザーに対して静的にするか、アプリ ロジックに基づいて動的にすることができます。 設定がユーザー設定に基づく場合、通常は今後のアクセス時に再読み込みするために設定が保存されます。

追加の一般情報については、ASP.NET Core のグローバリゼーションおよびローカリゼーション を参照してください。

注意

多くの場合、グローバリゼーションとローカライズの概念を扱う場合、''言語'' と ''カルチャ'' という用語は区別なく使用されます。

この記事の場合、言語 とは、ユーザーがブラウザーの設定で行った選択を指します。 ユーザーの言語選択は、Accept-Language ヘッダーのブラウザー要求で送信されます。 ブラウザーの設定では、通常、UI で「言語」という単語が使用されます。

カルチャ は、.NET と Blazor API のメンバーに関連します。 たとえば、ユーザーの要求には、ユーザーの観点から 言語 を指定する Accept-Language ヘッダーを含めることができますが、アプリでは最終的に、ユーザーが要求した言語から CurrentCulture (「カルチャ」) プロパティが設定されます。 API では通常、メンバー名に "culture" という単語が使用されます。

グローバリゼーション

@bind 属性ディレクティブでは、アプリがサポートするユーザーの優先言語に基づいて形式を適用し、表示向けの値を解析します。 @bind では、値を解析および書式設定するための System.Globalization.CultureInfo を提供する @bind:culture パラメーターをサポートしています。

現在のカルチャは、System.Globalization.CultureInfo.CurrentCulture プロパティからアクセスできます。

CultureInfo.InvariantCulture は、次のフィールド型 ({TYPE} プレースホルダーが型の <input type="{TYPE}" />) に使用されます。

  • date
  • number

前のフィールドの型は次のようになります。

  • 適切なブラウザー ベースの書式ルールを使用して表示されます。
  • 自由形式のテキストを含めることはできません。
  • ブラウザーの実装に基づいてユーザー操作の特性を指定します。

datenumber フィールド型を使用する場合、Blazor から現在のカルチャの値をレンダリングするサポートが組み込みで提供されるため、@bind:culture でカルチャを指定することはお勧めしません。

次のフィールドの型には、特定の書式設定の要件がありますが、すべての主要なブラウザーでサポートされていないため、Blazor では現在サポートされていません。

  • datetime-local
  • month
  • week

前述の型の現在のブラウザー サポートについては、使用可能なものに関するページを参照してください。

デモンストレーション コンポーネント

次の CultureExample1 コンポーネントを使用して、この記事で説明する Blazor のグローバリゼーションとローカライズの概念を示せます。

Pages/CultureExample1.razor:

@page "/culture-example-1"
@using System.Globalization

<h1>Culture Example 1</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

前の例 (.ToString("N2")) の数値文字列形式 (N2) は、標準の .NET 数値書式指定子です。 この N2 形式は、すべての数値型でサポートされ、グループ区切り記号を含み、小数点以下 2 桁まで表示されます。

CultureExample1 コンポーネント向けに、Shared/NavMenu.razor のナビゲーション メニュー <ul> 要素にリスト項目を追加します。

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 1
    </NavLink>
</li>

Accept-Language ヘッダーからカルチャを動的に設定する

Accept-Language ヘッダーはブラウザーによって設定され、ブラウザー設定でのユーザーの言語設定によって制御されます。 ブラウザー設定では、ユーザーは優先順に 1 つ以上の優先言語を設定します。 設定の順序は、ヘッダー内の言語ごとに品質値 (q、0-1) を設定するためにブラウザーによって使用されます。 次の例では、英語 (米国) または英語を優先して、英語 (米国)、英語、およびスペイン語 (チリ) を指定しています。

Accept-Language: en-US,en;q=0.9,es-CL;q=0.8

アプリのカルチャは、アプリのサポートされているカルチャに一致する最初に要求された言語を照合することで設定されます。

アプリのプロジェクト ファイル (.csproj) で BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure (Startup.cs) でアプリでサポートされているカルチャを指定します。 次の例では、英語 (米国) とスペイン語 (チリ) でサポートされるカルチャを構成しています。

app.UseRequestLocalization(new RequestLocalizationOptions()
    .AddSupportedCultures(new[] { "en-US", "es-CL" })
    .AddSupportedUICultures(new[] { "en-US", "es-CL" }));

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、グローバリゼーションのしくみを確認します。 英語 (米国) (en-US) で要求を発行します。 ブラウザーの言語設定で、スペイン語 (チリ) (es-CL) に切り替えます。 Web ページを再度要求します。

注意

一部のブラウザーでは、要求とブラウザー独自の UI 設定の両方に既定の言語設定を使用する必要があります。 これにより、すべての設定 UI 画面が読むことができない言語になる可能性があるため、理解できる言語に戻すのが困難になる可能性があります。 Opera などのブラウザーは、Web ページ要求に既定の言語を設定しても、ブラウザーの設定 UI は使用言語のままにしてよいため、テストに最適です。

カルチャが英語 (米国) (en-US) の場合、表示されるコンポーネントでは、月/日の日付書式設定 (6/7)、12 時間制の時刻 (AM/PM)、および数値でコンマ、小数点値で点の区切り記号 (1,999.69) が使用されます。

  • 日付: 6/7/2021 6:45:22 AM
  • 数値: 1,999.69

カルチャがスペイン語 (チリ) (es-CL) の場合、レンダリングされるコンポーネントでは、日/月の日付書式設定 (7/6)、24 時間制の時刻、および数値でピリオド、小数点値でコンマの区切り記号 (1.999,69) が使用されます。

  • 日付: 7/6/2021 6:49:38
  • 数値: 1.999,69

カルチャを静的に設定する

アプリのプロジェクト ファイル (.csproj) で BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

アプリのカルチャは、Blazor が applicationCulture Blazor スタート オプションで始まるときに JavaScript で設定できます。 次の例では、英語 (米国) (en-US) カルチャを使用して構成しています。

  • wwwroot/index.html では、Blazor の <script> タグに autostart="false" を追加して Blazor 自動開始を防止します。

    <script src="_framework/blazor.webassembly.js" autostart="false"></script>
    
  • Blazor の <script> タグの後、</body> 終了タグの前に、次の <script> ブロックを追加します。

    <script>
      Blazor.start({
        applicationCulture: 'en-US'
      });
    </script>
    

applicationCulture の値は、BCP-47 言語タグ形式に準拠している必要があります。 Blazor スタートアップの詳細については、「ASP.NET Core Blazor の起動」を参照してください。

カルチャ Blazor のスタート オプションを設定する代わりに、C# コードでカルチャを設定することもできます。 Program.Main (Program.cs) で CultureInfo.DefaultThreadCurrentCultureCultureInfo.DefaultThreadCurrentUICulture を設定します。

System.Globalization 名前空間を Program.cs に追加します。

using System.Globalization;

WebAssemblyHostBuilder (await builder.Build().RunAsync();) をビルドして実行する行の前にカルチャ設定を追加します。

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure (Startup.cs) で静的カルチャを指定します。 次の例では、英語 (米国) を構成しています。

app.UseRequestLocalization("en-US");

UseRequestLocalization のカルチャ値は、BCP-47 言語タグ形式に準拠している必要があります。

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、グローバリゼーションのしくみを確認します。 英語 (米国) (en-US) で要求を発行します。 ブラウザーの言語設定で、スペイン語 (チリ) (es-CL) に切り替えます。 Web ページを再度要求します。 要求された言語がスペイン語 (チリ) である場合、アプリのカルチャは英語 (米国) (en-US) のままです。

アプリのローカライズを必要としない場合は、一般的に英語 (米国) (en-US) に基づくインバリアント カルチャをサポートするようにアプリを構成します。 アプリのプロジェクト ファイル (.csproj) で InvariantGlobalization プロパティを true に設定します。

<PropertyGroup>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

ユーザー設定によってカルチャを動的に設定する

アプリがユーザーの好みを格納する可能性がある場所の例としては、ブラウザーのローカル ストレージ (Blazor WebAssembly アプリ で一般的)、ローカライズ用の cookie またはデータベース (Blazor Server アプリで一般的)、外部データベースに接続され Web API によってアクセスされる外部サービスがあります。 次の例は、ブラウザーのローカル ストレージを使用する方法を示しています。

アプリのプロジェクト ファイル (.csproj) に、Microsoft.Extensions.Localization パッケージのパッケージ参照を追加します。

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

プロジェクト ファイルで BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Blazor WebAssembly アプリ内のアプリのカルチャは、Blazor フレームワークの API を使用して設定されます。 ユーザーのカルチャの選択は、ブラウザーのローカル ストレージに保存できます。

wwwroot/index.html ファイルの Blazor の <script> タグの後、</body> 終了タグの前に、JS 関数を指定して、ユーザーが選択したカルチャをブラウザーのローカル ストレージで取得および設定します。

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

注意

前の例ではグローバル メソッドでクライアントが汚染されます。 実稼働アプリでのより適切なアプローチについては、「JavaScript モジュール内の JavaScript 分離」を参照してください。

例:

export function getBlazorCulture() {
  return window.localStorage['BlazorCulture'];
};
export function setBlazorCulture(value) {
  window.localStorage['BlazorCulture'] = value;
};

上記の関数を使用する場合は、このセクションの JS 相互運用機能呼び出しを blazorCulture.get から getBlazorCulture に、blazorCulture.set から setBlazorCulture に変更します。

System.GlobalizationMicrosoft.JSInterop の名前空間を Program.cs の先頭に追加します。

using System.Globalization;
using Microsoft.JSInterop;

Program.Main から次の行を削除します。

-await builder.Build().RunAsync();

前の行を、次のコードで置き換えます。 このコードは、AddLocalization を使用してアプリのサービス コレクションに Blazor のローカライズ サービスを追加し、JS 相互運用機能を使用して JS を呼び出し、ローカル ストレージからユーザーが選択したカルチャを取得します。 ローカル ストレージにユーザーのカルチャが含まれていない場合、コードは英語 (米国) (en-US) の既定値を設定します。

builder.Services.AddLocalization();

var host = builder.Build();

CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");

if (result != null)
{
    culture = new CultureInfo(result);
}
else
{
    culture = new CultureInfo("en-US");
    await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

次の CultureSelector コンポーネントは、JS 相互運用機能を使用して、ユーザーが選択したカルチャをブラウザーのローカル ストレージに設定する方法を示しています。 コンポーネントは、アプリ全体で使用するために Shared フォルダーに配置されます。

Shared/CultureSelector.razor:

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CL"),
    };

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var js = (IJSInProcessRuntime)JSRuntime;
                js.InvokeVoid("blazorCulture.set", value.Name);

                Nav.NavigateTo(Nav.Uri, forceLoad: true);
            }
        }
    }
}

Shared/MainLayout.razor<div class="main"> 要素の </div> 終了タグ内に、CultureSelector コンポーネントを追加します。

<div class="bottom-row px-4">
    <CultureSelector />
</div>

アプリがユーザーの好みを格納する可能性がある場所の例としては、ブラウザーのローカル ストレージ (Blazor WebAssembly アプリ で一般的)、ローカライズ用の cookie またはデータベース (Blazor Server アプリで一般的)、外部データベースに接続され Web API によってアクセスされる外部サービスがあります。 以下の例では、ローカライズ cookie の使用方法を示しています。

アプリのプロジェクト ファイル (.csproj) に、Microsoft.Extensions.Localization パッケージのパッケージ参照を追加します。

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />
</ItemGroup>

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

アプリの既定とサポートされるカルチャを RequestLocalizationOptions.SetDefaultCulture に設定します。

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure で以下を行います。

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

app.UseRequestLocalization(localizationOptions);

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

次の例では、ローカライズ ミドルウェアによって読み取ることができる cookie で現在のカルチャを設定する方法を示します。

次の名前空間を Pages/_Host.cshtml ファイルの先頭に追加します。

@using System.Globalization
@using Microsoft.AspNetCore.Localization

Pages/_Host.cshtml<body> 開始タグの直後に、次の Razor 式を追加します。

@{
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

アプリがコントローラー アクションを処理するように構成されていない場合:

  • Startup.ConfigureServices でサービス コレクションに対して AddControllers を呼び出して、MVC サービスを追加します。

    services.AddControllers();
    
  • IEndpointRouteBuilderMapControllers を呼び出し、Startup.Configure でコントローラー エンドポイント ルーティングを追加します。

    endpoints.MapControllers();
    

    次の例は、行が追加された後の UseEndpoints への呼び出しを示しています。

    app.UseEndpoints(endpoints =>
    {
    +   endpoints.MapControllers();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    

ユーザーがカルチャを選択できるように UI を提供するには、ローカライズ cookie での リダイレクト ベースのアプローチ をお勧めします。 アプリでは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャが保持されます。 コントローラーによって、ユーザーが選択したカルチャが cookie に設定され、ユーザーは元の URI にリダイレクトされます。 このプロセスは、ユーザーがセキュリティで保護されたリソースにアクセスしようとしたときに、Web アプリで発生する処理に似ています。ユーザーがサインイン ページにリダイレクトされ、元のリソースに戻されます。

Controllers/CultureController.cs:

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

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

警告

LocalRedirect アクションの結果を使用して、オープン リダイレクト攻撃を防ぎます。 詳細については、「ASP.NET Core でのオープンリダイレクト攻撃の防止」を参照してください。

次の CultureSelector コンポーネントでは、ユーザーがカルチャを選択したときに、最初のリダイレクトを実行する方法を示しています。 コンポーネントは、アプリ全体で使用するために Shared フォルダーに配置されます。

Shared/CultureSelector.razor:

@using  System.Globalization
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CL"),
    };

    protected override void OnInitialized()
    {
        Culture = CultureInfo.CurrentCulture;
    }

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var uri = new Uri(Nav.Uri)
                    .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var cultureEscaped = Uri.EscapeDataString(value.Name);
                var uriEscaped = Uri.EscapeDataString(uri);

                Nav.NavigateTo(
                    $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                    forceLoad: true);
            }
        }
    }
}

Shared/MainLayout.razor<div class="main"> 要素の </div> 終了タグ内に、CultureSelector コンポーネントを追加します。

<div class="bottom-row px-4">
    <CultureSelector />
</div>

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、前述の例のしくみを確認します。

ローカライズ

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」セクションに基づくカルチャの選択をまだサポートしていない場合は、Microsoft.Extensions.Localization パッケージのパッケージ参照をアプリのプロジェクト ファイル (.csproj) に追加します。

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

アプリのプロジェクト ファイル (.csproj) で BlazorWebAssemblyLoadAllGlobalizationData プロパティを true に設定します。

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Program.Main (Program.cs) で、System.Globalization の名前空間をファイルの先頭に追加します。

using System.Globalization;

Program.MainAddLocalization を使用して、アプリのサービスコレクションに Blazor のローカライズ サービスを追加します。

builder.Services.AddLocalization();

ローカライズ ミドルウェアを使用して、アプリのカルチャを設定します。

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」に従って、カルチャの選択をまだサポートしていない場合は、次の手順を実行します。

  • AddLocalization を使用して、ローカライズ サービスをアプリに追加します。
  • アプリの既定とサポートされるカルチャを Startup.Configure (Startup.cs) で指定します。 次の例では、英語 (米国) とスペイン語 (チリ) でサポートされるカルチャを構成しています。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure で以下を行います。

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

app.UseRequestLocalization(localizationOptions);

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

アプリでユーザーのカルチャ設定の格納に基づきリソースをローカライズする必要がある場合は、ローカライズ カルチャ cookie を使用します。 cookie を使用すると、WebSocket 接続によってカルチャを正しく伝達できることを確実にします。 ローカライズ スキームが URL パスまたはクエリ文字列に基づいている場合は、スキームが WebSockets を使用できない可能性があるため、カルチャを保持できません。 したがって、ローカライズ カルチャ cookie の使用をお勧めします。 この記事の「ユーザー設定によってカルチャを動的に設定する」セクションを参照して、ユーザーが選択したカルチャを保持する Pages/_Host.cshtml ファイルの Razor 式の例を参照してください。

このセクションのローカライズされたリソースの例は、この記事の前の例と連動しています。アプリのサポートされているカルチャは、既定のロケールとして英語 (en)、ユーザー選択可能またはブラウザー指定の代替ロケールとしてスペイン語 (es) になっています。

ロケールごとにリソースを作成します。 次の例では、既定の Greeting 文字列のリソースが作成されます。

  • 英語: Hello, World!
  • スペイン語 (es): ¡Hola, Mundo!

注意

次のリソース ファイルを Visual Studio に追加するには、プロジェクトの Pages フォルダーを右クリックし、[追加] > [新しい項目] > [リソースファイル] の順に選択します。 そのファイルに CultureExample2.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前Greeting に設定し、Hello, World! に設定します。 ファイルを保存します。

Pages/CultureExample2.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, World!</value>
  </data>
</root>

注意

次のリソース ファイルを Visual Studio に追加するには、プロジェクトの Pages フォルダーを右クリックし、[追加] > [新しい項目] > [リソースファイル] の順に選択します。 そのファイルに CultureExample2.es.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前Greeting に設定し、¡Hola, Mundo! に設定します。 ファイルを保存します。

Pages/CultureExample2.es.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>¡Hola, Mundo!</value>
  </data>
</root>

次のコンポーネントは、IStringLocalizer<T> でローカライズされた Greeting 文字列を使用する方法を示しています。

Microsoft.Extensions.Localization の名前空間をアプリの _Imports.razor ファイルに追加します。

@using Microsoft.Extensions.Localization

Pages/CultureExample2.razor:

@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc

<h1>Culture Example 2</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Greeting</h2>

<p>
    @Loc["Greeting"]
</p>

<p>
    @greeting
</p>

@code {
    private string greeting;

    protected override void OnInitialized()
    {
        greeting = Loc["Greeting"];
    }
}

CultureExample2 コンポーネント向けに、Shared/NavMenu.razor のナビゲーション メニュー <ul> 要素にリスト項目を追加します。

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-2">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 2
    </NavLink>
</li>

その他の技術情報

Razor コンポーネントを使用すると、異なるカルチャや言語のユーザーにグローバル化およびローカライズされたコンテンツをレンダリングできます。 グローバリゼーションの場合、Blazor から数値と日付の書式設定が提供されます。 ローカライズの場合、Blazor により .NET リソース システムを使用したコンテンツのレンダリングが行われます。

サポートされている ASP.NET Core のローカライズ機能は限られています。

✔️ IStringLocalizerIStringLocalizer<T> は、Blazor アプリでサポートされています。

❌、IHtmlLocalizerIViewLocalizerデータ注釈のローカライズは ASP.NET Core の MVC シナリオであり、 Blazor アプリでは サポートされていません

この記事では、次に基づいて Blazor のグローバリゼーションとローカライズ機能を使用する方法について説明します。

  • ブラウザーの設定でのユーザー言語設定に基づきブラウザーによって設定された Accept-Language ヘッダー
  • Accept-Language ヘッダーの値に基づいていない、アプリによって設定されたカルチャ。 設定は、すべてのユーザーに対して静的にするか、アプリ ロジックに基づいて動的にすることができます。 設定がユーザー設定に基づく場合、通常は今後のアクセス時に再読み込みするために設定が保存されます。

追加の一般情報については、ASP.NET Core のグローバリゼーションおよびローカリゼーション を参照してください。

注意

多くの場合、グローバリゼーションとローカライズの概念を扱う場合、''言語'' と ''カルチャ'' という用語は区別なく使用されます。

この記事の場合、言語 とは、ユーザーがブラウザーの設定で行った選択を指します。 ユーザーの言語選択は、Accept-Language ヘッダーのブラウザー要求で送信されます。 ブラウザーの設定では、通常、UI で「言語」という単語が使用されます。

カルチャ は、.NET と Blazor API のメンバーに関連します。 たとえば、ユーザーの要求には、ユーザーの観点から 言語 を指定する Accept-Language ヘッダーを含めることができますが、アプリでは最終的に、ユーザーが要求した言語から CurrentCulture (「カルチャ」) プロパティが設定されます。 API では通常、メンバー名に "culture" という単語が使用されます。

グローバリゼーション

@bind 属性ディレクティブでは、アプリがサポートするユーザーの優先言語に基づいて形式を適用し、表示向けの値を解析します。 @bind では、値を解析および書式設定するための System.Globalization.CultureInfo を提供する @bind:culture パラメーターをサポートしています。

現在のカルチャは、System.Globalization.CultureInfo.CurrentCulture プロパティからアクセスできます。

CultureInfo.InvariantCulture は、次のフィールド型 ({TYPE} プレースホルダーが型の <input type="{TYPE}" />) に使用されます。

  • date
  • number

前のフィールドの型は次のようになります。

  • 適切なブラウザー ベースの書式ルールを使用して表示されます。
  • 自由形式のテキストを含めることはできません。
  • ブラウザーの実装に基づいてユーザー操作の特性を指定します。

datenumber フィールド型を使用する場合、Blazor から現在のカルチャの値をレンダリングするサポートが組み込みで提供されるため、@bind:culture でカルチャを指定することはお勧めしません。

次のフィールドの型には、特定の書式設定の要件がありますが、すべての主要なブラウザーでサポートされていないため、Blazor では現在サポートされていません。

  • datetime-local
  • month
  • week

前述の型の現在のブラウザー サポートについては、使用可能なものに関するページを参照してください。

デモンストレーション コンポーネント

次の CultureExample1 コンポーネントを使用して、この記事で説明する Blazor のグローバリゼーションとローカライズの概念を示せます。

Pages/CultureExample1.razor:

@page "/culture-example-1"
@using System.Globalization

<h1>Culture Example 1</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

前の例 (.ToString("N2")) の数値文字列形式 (N2) は、標準の .NET 数値書式指定子です。 この N2 形式は、すべての数値型でサポートされ、グループ区切り記号を含み、小数点以下 2 桁まで表示されます。

CultureExample1 コンポーネント向けに、Shared/NavMenu.razor のナビゲーション メニュー <ul> 要素にリスト項目を追加します。

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 1
    </NavLink>
</li>

Accept-Language ヘッダーからカルチャを動的に設定する

Accept-Language ヘッダーはブラウザーによって設定され、ブラウザー設定でのユーザーの言語設定によって制御されます。 ブラウザー設定では、ユーザーは優先順に 1 つ以上の優先言語を設定します。 設定の順序は、ヘッダー内の言語ごとに品質値 (q、0-1) を設定するためにブラウザーによって使用されます。 次の例では、英語 (米国) または英語を優先して、英語 (米国)、英語、およびスペイン語 (チリ) を指定しています。

Accept-Language: en-US,en;q=0.9,es-CL;q=0.8

アプリのカルチャは、アプリのサポートされているカルチャに一致する最初に要求された言語を照合することで設定されます。

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure (Startup.cs) でアプリでサポートされているカルチャを指定します。 次の例では、英語 (米国) とスペイン語 (チリ) でサポートされるカルチャを構成しています。

app.UseRequestLocalization(new RequestLocalizationOptions()
    .AddSupportedCultures(new[] { "en-US", "es-CL" })
    .AddSupportedUICultures(new[] { "en-US", "es-CL" }));

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、グローバリゼーションのしくみを確認します。 英語 (米国) (en-US) で要求を発行します。 ブラウザーの言語設定で、スペイン語 (チリ) (es-CL) に切り替えます。 Web ページを再度要求します。

注意

一部のブラウザーでは、要求とブラウザー独自の UI 設定の両方に既定の言語設定を使用する必要があります。 これにより、すべての設定 UI 画面が読むことができない言語になる可能性があるため、理解できる言語に戻すのが困難になる可能性があります。 Opera などのブラウザーは、Web ページ要求に既定の言語を設定しても、ブラウザーの設定 UI は使用言語のままにしてよいため、テストに最適です。

カルチャが英語 (米国) (en-US) の場合、表示されるコンポーネントでは、月/日の日付書式設定 (6/7)、12 時間制の時刻 (AM/PM)、および数値でコンマ、小数点値で点の区切り記号 (1,999.69) が使用されます。

  • 日付: 6/7/2021 6:45:22 AM
  • 数値: 1,999.69

カルチャがスペイン語 (チリ) (es-CL) の場合、レンダリングされるコンポーネントでは、日/月の日付書式設定 (7/6)、24 時間制の時刻、および数値でピリオド、小数点値でコンマの区切り記号 (1.999,69) が使用されます。

  • 日付: 7/6/2021 6:49:38
  • 数値: 1.999,69

カルチャを静的に設定する

既定では、Blazor WebAssembly アプリに対する中間言語 (IL) リンカーの構成によって、明示的に要求されたロケールを除き、国際化情報が削除されます。 詳細については、「ASP.NET Core Blazor 用のリンカーを構成する」を参照してください。

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure (Startup.cs) で静的カルチャを指定します。 次の例では、英語 (米国) を構成しています。

app.UseRequestLocalization("en-US");

UseRequestLocalization のカルチャ値は、BCP-47 言語タグ形式に準拠している必要があります。

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、グローバリゼーションのしくみを確認します。 英語 (米国) (en-US) で要求を発行します。 ブラウザーの言語設定で、スペイン語 (チリ) (es-CL) に切り替えます。 Web ページを再度要求します。 要求された言語がスペイン語 (チリ) である場合、アプリのカルチャは英語 (米国) (en-US) のままです。

アプリのローカライズを必要としない場合は、一般的に英語 (米国) (en-US) に基づくインバリアント カルチャをサポートするようにアプリを構成します。 アプリのプロジェクト ファイル (.csproj) で InvariantGlobalization プロパティを true に設定します。

<PropertyGroup>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

ユーザー設定によってカルチャを動的に設定する

アプリがユーザーの好みを格納する可能性がある場所の例としては、ブラウザーのローカル ストレージ (Blazor WebAssembly アプリ で一般的)、ローカライズ用の cookie またはデータベース (Blazor Server アプリで一般的)、外部データベースに接続され Web API によってアクセスされる外部サービスがあります。 次の例は、ブラウザーのローカル ストレージを使用する方法を示しています。

アプリのプロジェクト ファイル (.csproj) に、Microsoft.Extensions.Localization パッケージのパッケージ参照を追加します。

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

Blazor WebAssembly アプリ内のアプリのカルチャは、Blazor フレームワークの API を使用して設定されます。 ユーザーのカルチャの選択は、ブラウザーのローカル ストレージに保存できます。

wwwroot/index.html ファイルの Blazor の <script> タグの後、</body> 終了タグの前に、JS 関数を指定して、ユーザーが選択したカルチャをブラウザーのローカル ストレージで取得および設定します。

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

System.GlobalizationMicrosoft.JSInterop の名前空間を Program.cs の先頭に追加します。

using System.Globalization;
using Microsoft.JSInterop;

Program.Main から次の行を削除します。

-await builder.Build().RunAsync();

前の行を、次のコードで置き換えます。 このコードは、AddLocalization を使用してアプリのサービス コレクションに Blazor のローカライズ サービスを追加し、JS 相互運用機能を使用して JS を呼び出し、ローカル ストレージからユーザーが選択したカルチャを取得します。 ローカル ストレージにユーザーのカルチャが含まれていない場合、コードは英語 (米国) (en-US) の既定値を設定します。

builder.Services.AddLocalization();

var host = builder.Build();

CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");

if (result != null)
{
    culture = new CultureInfo(result);
}
else
{
    culture = new CultureInfo("en-US");
    await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

次の CultureSelector コンポーネントは、JS 相互運用機能を使用して、ユーザーが選択したカルチャをブラウザーのローカル ストレージに設定する方法を示しています。 コンポーネントは、アプリ全体で使用するために Shared フォルダーに配置されます。

Shared/CultureSelector.razor:

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CL"),
    };

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var js = (IJSInProcessRuntime)JSRuntime;
                js.InvokeVoid("blazorCulture.set", value.Name);

                Nav.NavigateTo(Nav.Uri, forceLoad: true);
            }
        }
    }
}

Shared/MainLayout.razor<div class="main"> 要素の </div> 終了タグ内に、CultureSelector コンポーネントを追加します。

<div class="bottom-row px-4">
    <CultureSelector />
</div>

アプリがユーザーの好みを格納する可能性がある場所の例としては、ブラウザーのローカル ストレージ (Blazor WebAssembly アプリ で一般的)、ローカライズ用の cookie またはデータベース (Blazor Server アプリで一般的)、外部データベースに接続され Web API によってアクセスされる外部サービスがあります。 以下の例では、ローカライズ cookie の使用方法を示しています。

アプリのプロジェクト ファイル (.csproj) に、Microsoft.Extensions.Localization パッケージのパッケージ参照を追加します。

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />
</ItemGroup>

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

Blazor Server アプリは、ローカライズ ミドルウェアを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

アプリの既定とサポートされるカルチャを RequestLocalizationOptions.SetDefaultCulture に設定します。

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure で以下を行います。

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

app.UseRequestLocalization(localizationOptions);

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

次の例では、ローカライズ ミドルウェアによって読み取ることができる cookie で現在のカルチャを設定する方法を示します。

次の名前空間を Pages/_Host.cshtml ファイルの先頭に追加します。

@using System.Globalization
@using Microsoft.AspNetCore.Localization

Pages/_Host.cshtml<body> 開始タグの直後に、次の Razor 式を追加します。

@{
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

アプリがコントローラー アクションを処理するように構成されていない場合:

  • Startup.ConfigureServices でサービス コレクションに対して AddControllers を呼び出して、MVC サービスを追加します。

    services.AddControllers();
    
  • IEndpointRouteBuilderMapControllers を呼び出し、Startup.Configure でコントローラー エンドポイント ルーティングを追加します。

    endpoints.MapControllers();
    

    次の例は、行が追加された後の UseEndpoints への呼び出しを示しています。

    app.UseEndpoints(endpoints =>
    {
    +   endpoints.MapControllers();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    

ユーザーがカルチャを選択できるように UI を提供するには、ローカライズ cookie での リダイレクト ベースのアプローチ をお勧めします。 アプリでは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャが保持されます。 コントローラーによって、ユーザーが選択したカルチャが cookie に設定され、ユーザーは元の URI にリダイレクトされます。 このプロセスは、ユーザーがセキュリティで保護されたリソースにアクセスしようとしたときに、Web アプリで発生する処理に似ています。ユーザーがサインイン ページにリダイレクトされ、元のリソースに戻されます。

Controllers/CultureController.cs:

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

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

警告

LocalRedirect アクションの結果を使用して、オープン リダイレクト攻撃を防ぎます。 詳細については、「ASP.NET Core でのオープンリダイレクト攻撃の防止」を参照してください。

次の CultureSelector コンポーネントでは、ユーザーがカルチャを選択したときに、最初のリダイレクトを実行する方法を示しています。 コンポーネントは、アプリ全体で使用するために Shared フォルダーに配置されます。

Shared/CultureSelector.razor:

@using  System.Globalization
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CL"),
    };

    protected override void OnInitialized()
    {
        Culture = CultureInfo.CurrentCulture;
    }

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var uri = new Uri(Nav.Uri)
                    .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var cultureEscaped = Uri.EscapeDataString(value.Name);
                var uriEscaped = Uri.EscapeDataString(uri);

                Nav.NavigateTo(
                    $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                    forceLoad: true);
            }
        }
    }
}

Shared/MainLayout.razor<div class="main"> 要素の </div> 終了タグ内に、CultureSelector コンポーネントを追加します。

<div class="bottom-row px-4">
    <CultureSelector />
</div>

デモンストレーション コンポーネント」セクションに示されている CultureExample1 コンポーネントを使用して、前述の例のしくみを確認します。

ローカライズ

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」セクションに基づくカルチャの選択をまだサポートしていない場合は、Microsoft.Extensions.Localization パッケージのパッケージ参照をアプリのプロジェクト ファイル (.csproj) に追加します。

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

前のパッケージ参照の {VERSION} プレースホルダーは、パッケージのバージョンです。

既定では、Blazor WebAssembly アプリに対する中間言語 (IL) リンカーの構成によって、明示的に要求されたロケールを除き、国際化情報が削除されます。 詳細については、「ASP.NET Core Blazor 用のリンカーを構成する」を参照してください。

Program.Main (Program.cs) で、System.Globalization の名前空間をファイルの先頭に追加します。

using System.Globalization;

Program.MainAddLocalization を使用して、アプリのサービスコレクションに Blazor のローカライズ サービスを追加します。

builder.Services.AddLocalization();

ローカライズ ミドルウェアを使用して、アプリのカルチャを設定します。

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」に従って、カルチャの選択をまだサポートしていない場合は、次の手順を実行します。

  • AddLocalization を使用して、ローカライズ サービスをアプリに追加します。
  • アプリの既定とサポートされるカルチャを Startup.Configure (Startup.cs) で指定します。 次の例では、英語 (米国) とスペイン語 (チリ) でサポートされるカルチャを構成しています。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

ルーティング ミドルウェアが処理パイプラインに追加された直後に、Startup.Configure で以下を行います。

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

app.UseRequestLocalization(localizationOptions);

Startup.Configure のミドルウェア パイプラインでローカライズ ミドルウェアを順序付けする方法については、「ASP.NET Core のミドルウェア」を参照してください。

アプリでユーザーのカルチャ設定の格納に基づきリソースをローカライズする必要がある場合は、ローカライズ カルチャ cookie を使用します。 cookie を使用すると、WebSocket 接続によってカルチャを正しく伝達できることを確実にします。 ローカライズ スキームが URL パスまたはクエリ文字列に基づいている場合は、スキームが WebSockets を使用できない可能性があるため、カルチャを保持できません。 したがって、ローカライズ カルチャ cookie の使用をお勧めします。 この記事の「ユーザー設定によってカルチャを動的に設定する」セクションを参照して、ユーザーが選択したカルチャを保持する Pages/_Host.cshtml ファイルの Razor 式の例を参照してください。

このセクションのローカライズされたリソースの例は、この記事の前の例と連動しています。アプリのサポートされているカルチャは、既定のロケールとして英語 (en)、ユーザー選択可能またはブラウザー指定の代替ロケールとしてスペイン語 (es) になっています。

ロケールごとにリソースを作成します。 次の例では、既定の Greeting 文字列のリソースが作成されます。

  • 英語: Hello, World!
  • スペイン語 (es): ¡Hola, Mundo!

注意

次のリソース ファイルを Visual Studio に追加するには、プロジェクトの Pages フォルダーを右クリックし、[追加] > [新しい項目] > [リソースファイル] の順に選択します。 そのファイルに CultureExample2.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前Greeting に設定し、Hello, World! に設定します。 ファイルを保存します。

Pages/CultureExample2.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, World!</value>
  </data>
</root>

注意

次のリソース ファイルを Visual Studio に追加するには、プロジェクトの Pages フォルダーを右クリックし、[追加] > [新しい項目] > [リソースファイル] の順に選択します。 そのファイルに CultureExample2.es.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前Greeting に設定し、¡Hola, Mundo! に設定します。 ファイルを保存します。

Pages/CultureExample2.es.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>¡Hola, Mundo!</value>
  </data>
</root>

次のコンポーネントは、IStringLocalizer<T> でローカライズされた Greeting 文字列を使用する方法を示しています。

Microsoft.Extensions.Localization の名前空間をアプリの _Imports.razor ファイルに追加します。

@using Microsoft.Extensions.Localization

Pages/CultureExample2.razor:

@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc

<h1>Culture Example 2</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Greeting</h2>

<p>
    @Loc["Greeting"]
</p>

<p>
    @greeting
</p>

@code {
    private string greeting;

    protected override void OnInitialized()
    {
        greeting = Loc["Greeting"];
    }
}

CultureExample2 コンポーネント向けに、Shared/NavMenu.razor のナビゲーション メニュー <ul> 要素にリスト項目を追加します。

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-2">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 2
    </NavLink>
</li>

その他の技術情報