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

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

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

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

IHtmlLocalizerIViewLocalizer、および❌は ASP.NET Core MVC の機能であり、Blazor アプリでは ''IHtmlLocalizer''。

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

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

その他の一般的な情報については、「ASP.NET Core でのグローバリゼーションとローカリゼーション」を参照してください。

Note

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

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

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

グローバリゼーション

@bind 属性ディレクティブでは、アプリがサポートするユーザーの@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

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

インバリアント グローバリゼーション

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

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

または、次の方法でインバリアント グローバリゼーションを構成します。

  • runtimeconfig.jsonの場合:

    {
      "runtimeOptions": {
        "configProperties": {
          "System.Globalization.Invariant": true
        }
      }
    }
    
  • 環境変数を使用:

    • キー: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
    • 値: true または 1

詳細については、「グローバリゼーションのランタイム構成オプション」 (.NET ドキュメント) を参照してください。

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

次の 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) は、N2です。 この N2 形式は、すべての数値型でサポートされ、グループ区切り記号を含み、小数点以下 2 桁まで表示されます。

必要に応じて、CultureExample1 コンポーネントの Shared/NavMenu.razor のナビゲーションにメニュー項目を追加します。

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 サーバー アプリは、Blazorを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Program.csの場合:

builder.Services.AddLocalization();

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

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

Program.cs のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Program.cs」を参照してください。

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

Note

一部のブラウザーでは、要求とブラウザー独自の 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 が applicationCultureBlazor スタート オプションで始まるときに 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 の値は、applicationCultureに準拠している必要があります。 Blazor スタートアップの詳細については、「ASP.NET Core Blazor Startup」を参照してください。

カルチャ Blazor のスタート オプションを設定する代わりに、C# コードでカルチャを設定することもできます。 Program.csCultureInfo.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 サーバー アプリは、Blazorを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Program.csの場合:

builder.Services.AddLocalization();

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

app.UseRequestLocalization("en-US");

UseRequestLocalization のカルチャ値は、UseRequestLocalizationに準拠している必要があります。

Program.cs のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Program.cs」を参照してください。

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

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

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

アプリに Microsoft.Extensions.Localization パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

プロジェクト ファイルで 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>

Note

前の例ではグローバル メソッドでクライアントが汚染されます。 実稼働アプリでのより適切なアプローチについては、「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.cs から次の行を削除します。

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

前の行を、次のコードで置き換えます。 このコードは、AddLocalization を使用してアプリのサービス コレクションに Blazor のローカライズ サービスを追加し、Blazorを使用して 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 相互運用機能を使用して、ユーザーのカルチャの選択をブラウザーのローカル ストレージに設定します。
  • 更新されたカルチャを使用する、要求したコンポーネント (forceLoad: true) を再読み込みします。

CultureSelector コンポーネントは、アプリ全体で使用するために 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<main> 要素の終了タグ内に、CultureSelector コンポーネントを追加します。

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

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

アプリに Microsoft.Extensions.Localization パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

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

Program.csの場合:

builder.Services.AddLocalization();

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

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

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

app.UseRequestLocalization(localizationOptions);

Program.cs のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Program.cs」を参照してください。

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

Pages/_Host.cshtml ファイルを変更するには、次の名前空間が必要です。

Pages/_Host.cshtml:

@page "/"
@namespace {NAMESPACE}.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@{
    Layout = "_Layout";
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

<component type="typeof(App)" render-mode="ServerPrerendered" />

前の例では、{NAMESPACE} プレースホルダーはアプリのアセンブリ名です。

Program.cs のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Program.cs」を参照してください。

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

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

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

    app.MapControllers();
    

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

    app.MapControllers();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    

ユーザーがカルチャを選択できるように UI を提供するには、ローカライズ でのリダイレクト ベースのアプローチをお勧めします。 アプリでは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャが保持されます。 コントローラーによって、ユーザーが選択したカルチャが 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 コンポーネントは、新しいカルチャで CultureControllerSet メソッドを呼び出す方法を示しています。 コンポーネントは、アプリ全体で使用するために 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」セクションに示されている CultureExample1 コンポーネントを使用して、前述の例のしくみを確認します。

ローカリゼーション

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」セクションに従って、カルチャの選択をまだサポートしていない場合は、アプリに パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

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

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

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

using System.Globalization;

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

builder.Services.AddLocalization();

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

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

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

Program.csの場合:

builder.Services.AddLocalization();

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

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

app.UseRequestLocalization(localizationOptions);

Program.cs のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Program.cs」を参照してください。

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

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

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

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

Note

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

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 フォルダーを右クリックし、[Pages>>>> の順に選択します。 そのファイルに CultureExample2.es.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前 に設定し、 に設定します。 ファイルを保存します。

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 文字列を使用する方法を示しています。 次の例の Razor マークアップ @Loc["Greeting"] では、前のリソース ファイルで設定されている 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 のナビゲーションにメニュー項目を追加します。

その他の技術情報

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

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

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

IHtmlLocalizerIViewLocalizer、および❌は ASP.NET Core MVC の機能であり、Blazor アプリでは ''IHtmlLocalizer''。

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

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

その他の一般的な情報については、「ASP.NET Core でのグローバリゼーションとローカリゼーション」を参照してください。

Note

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

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

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

グローバリゼーション

@bind 属性ディレクティブでは、アプリがサポートするユーザーの@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

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

インバリアント グローバリゼーション

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

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

または、次の方法でインバリアント グローバリゼーションを構成します。

  • runtimeconfig.jsonの場合:

    {
      "runtimeOptions": {
        "configProperties": {
          "System.Globalization.Invariant": true
        }
      }
    }
    
  • 環境変数を使用:

    • キー: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
    • 値: true または 1

詳細については、「グローバリゼーションのランタイム構成オプション」 (.NET ドキュメント) を参照してください。

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

次の 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) は、N2です。 この N2 形式は、すべての数値型でサポートされ、グループ区切り記号を含み、小数点以下 2 桁まで表示されます。

必要に応じて、CultureExample1 コンポーネントの Shared/NavMenu.razor のナビゲーションにメニュー項目を追加します。

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 サーバー アプリは、Blazorを使用してローカライズされます。 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

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

Note

一部のブラウザーでは、要求とブラウザー独自の 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 が applicationCultureBlazor スタート オプションで始まるときに 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 の値は、applicationCultureに準拠している必要があります。 Blazor スタートアップの詳細については、「ASP.NET Core Blazor Startup」を参照してください。

カルチャ Blazor のスタート オプションを設定する代わりに、C# コードでカルチャを設定することもできます。 Program.csCultureInfo.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 サーバー アプリは、Blazorを使用してローカライズされます。 AddLocalization を使用して、ローカライズ サービスをアプリに追加します。

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

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

app.UseRequestLocalization("en-US");

UseRequestLocalization のカルチャ値は、UseRequestLocalizationに準拠している必要があります。

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

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

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

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

アプリに Microsoft.Extensions.Localization パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

プロジェクト ファイルで 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>

Note

前の例ではグローバル メソッドでクライアントが汚染されます。 実稼働アプリでのより適切なアプローチについては、「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.cs から次の行を削除します。

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

前の行を、次のコードで置き換えます。 このコードは、AddLocalization を使用してアプリのサービス コレクションに Blazor のローカライズ サービスを追加し、Blazorを使用して 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>

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

アプリに Microsoft.Extensions.Localization パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

Blazor サーバー アプリは、Blazorを使用してローカライズされます。 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

次の例では、ローカライズ ミドルウェアによって読み取ることができる 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

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

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

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

    endpoints.MapControllers();
    

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

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

ユーザーがカルチャを選択できるように UI を提供するには、ローカライズ でのリダイレクト ベースのアプローチをお勧めします。 アプリでは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャが保持されます。 コントローラーによって、ユーザーが選択したカルチャが 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」セクションに示されている CultureExample1 コンポーネントを使用して、前述の例のしくみを確認します。

ローカリゼーション

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」セクションに従って、カルチャの選択をまだサポートしていない場合は、アプリに パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

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

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

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

using System.Globalization;

Program.csAddLocalization を使用して、アプリのサービスコレクションに 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

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

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

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

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

Note

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

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 フォルダーを右クリックし、[Pages>>>> の順に選択します。 そのファイルに CultureExample2.es.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前 に設定し、 に設定します。 ファイルを保存します。

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 文字列を使用する方法を示しています。 次の例の Razor マークアップ @Loc["Greeting"] では、前のリソース ファイルで設定されている 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 のナビゲーションにメニュー項目を追加します。

その他の技術情報

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

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

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

IHtmlLocalizerIViewLocalizer、および❌は ASP.NET Core MVC の機能であり、Blazor アプリでは ''IHtmlLocalizer''。

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

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

その他の一般的な情報については、「ASP.NET Core でのグローバリゼーションとローカリゼーション」を参照してください。

Note

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

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

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

グローバリゼーション

@bind 属性ディレクティブでは、アプリがサポートするユーザーの@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

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

インバリアント グローバリゼーション

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

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

または、次の方法でインバリアント グローバリゼーションを構成します。

  • runtimeconfig.jsonの場合:

    {
      "runtimeOptions": {
        "configProperties": {
          "System.Globalization.Invariant": true
        }
      }
    }
    
  • 環境変数を使用:

    • キー: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
    • 値: true または 1

詳細については、「グローバリゼーションのランタイム構成オプション」 (.NET ドキュメント) を参照してください。

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

次の 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) は、N2です。 この N2 形式は、すべての数値型でサポートされ、グループ区切り記号を含み、小数点以下 2 桁まで表示されます。

必要に応じて、CultureExample1 コンポーネントの Shared/NavMenu.razor のナビゲーションにメニュー項目を追加します。

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

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

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

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

Blazor サーバー アプリは、Blazorを使用してローカライズされます。 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

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

Note

一部のブラウザーでは、要求とブラウザー独自の 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) リンカーの構成によって、明示的に要求されたロケールを除き、国際化情報が削除されます。 詳細については、「Configure the Linker for ASP.NET Core Blazor」を参照してください。

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

Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

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

app.UseRequestLocalization("en-US");

UseRequestLocalization のカルチャ値は、UseRequestLocalizationに準拠している必要があります。

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

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

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

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

アプリに Microsoft.Extensions.Localization パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

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.cs から次の行を削除します。

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

前の行を、次のコードで置き換えます。 このコードは、AddLocalization を使用してアプリのサービス コレクションに Blazor のローカライズ サービスを追加し、Blazorを使用して 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>

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

アプリに Microsoft.Extensions.Localization パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

Blazor サーバー アプリは、Blazorを使用してローカライズされます。 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

次の例では、ローカライズ ミドルウェアによって読み取ることができる 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

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

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

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

    endpoints.MapControllers();
    

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

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

ユーザーがカルチャを選択できるように UI を提供するには、ローカライズ でのリダイレクト ベースのアプローチをお勧めします。 アプリでは、コントローラーへのリダイレクトによって、ユーザーが選択したカルチャが保持されます。 コントローラーによって、ユーザーが選択したカルチャが 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」セクションに示されている CultureExample1 コンポーネントを使用して、前述の例のしくみを確認します。

ローカリゼーション

アプリで、この記事の「ユーザー設定によってカルチャを動的に設定する」セクションに従って、カルチャの選択をまだサポートしていない場合は、アプリに パッケージを追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の「パッケージをインストールして管理する」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

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

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

using System.Globalization;

Program.csAddLocalization を使用して、アプリのサービスコレクションに 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 のミドルウェア パイプラインでのローカライズ ミドルウェアの順序付けについては、「Startup.Configure」を参照してください。

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

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

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

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

Note

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

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 フォルダーを右クリックし、[Pages>>>> の順に選択します。 そのファイルに CultureExample2.es.resx という名前を付けます。 エディターが表示されたら、新しいエントリのデータを指定します。 名前 に設定し、 に設定します。 ファイルを保存します。

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 文字列を使用する方法を示しています。 次の例の Razor マークアップ @Loc["Greeting"] では、前のリソース ファイルで設定されている 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 のナビゲーションにメニュー項目を追加します。

その他の技術情報