ASP.NET Core MVC の組み込み機能で多言語切り替え表示を行う
環境
- Visual Studio
-
- Visual Studio 2019
- ASP.NET Core
-
- 3.0
- 3.1
はじめに
ASP.NET Core MVC のローカライズの機能を使用して、多言語を切り替えて表示させます。
翻訳したテキストのリソースファイルの作成
テキストを管理するリソースファイル(Resx)を保存するフォルダを作成します。 場所はどこでもかまいませんが、ルート直下にしておきます。 このパスはのちの設定にも影響します。
プロジェクトを右クリックし「追加」「新しいフォルダ―」を選択します。
フォルダ名は「Resources」にしておきます。 このフォルダ名も任意に設定できますが、のちの設定でこのフォルダ名を指定することになります。
続いて言語ごとのテキストを入力するリソースファイルを作成します。
「Resources」フォルダを右クリックし「追加」「新しい項目」を選択します。
リソース ファイル (.resx) を選択します。 ファイル名は任意でかまいませんが、のちに指定する名称と一致させる必要があります。 ここでは「SharedResource.resx」としておきます。
.resx ファイルを作成したらダブルクリックで開き、テキストを識別する名称と実際に表示するテキストを入力します。 「SharedResource.resx」ファイルは該当する言語が存在しなかった場合に使用されるファイルとなりますが、 ここでは日本語で入力しています。英語など他の言語をデフォルトにしたい場合はその言語で入力してください。
ここではサンプルとして「Hello」と「Goodbye」を入力しています。大文字と小文字は区別されますので注意してください。
続けて他の言語のリソースファイルを作成します。言語を識別するにはファイル名を SharedResource.<カルチャコード>.resx のように指定します。 カルチャコードには ISO 639 と ISO 3166 の片方、または両方の組み合わせを指定できますが、 対応コードなどは随時変更される場合があるので、Microsoft のサイトの CultureInfo クラス のページなどを参考にしてください。
今回は en (英語) と es (スペイン語) を用意します。日本語はデフォルトにしているので用意していません。
それぞれのファイルにキーを全ファイルで統一させた状態で翻訳したテキストを入力します。
次にクラスだけを定義したファイルを用意します。これは先ほど作成したリソースファイルと同じ名前で作成します。
実際には中のクラス名だけ合わせればよいのでコードファイル自体の名前はなんでもかまわないのですが、分かりやすいように同じにしておきます。 コードを作成するフォルダはどこでもかまいません。
名前空間をプロジェクトのルートにし、空のクラスを作成します。
namespace LocalizationText
{
// クラス名は作成した .resx のファイル名と同じにする必要がある
public class SharedResource { }
}
各プログラムの修正
Startup.cs
Startup.cs を修正します。ConfigureServices メソッドの中を以下のように記述します。
services.AddMvc().AddViewLocalization メソッドがあればビュー側もコントローラー側も翻訳したテキストを 取得できることは確認していますが、 公式サイトにもあるように services.AddLocalization メソッドも併用して呼んでも問題はありません。
options.ResourcesPath には Resx ファイルがあるフォルダのパスを指定します。 両方指定した場合は services.AddMvc().AddViewLocalization メソッドの方が優先されます。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// Resx ファイルのあるフォルダを指定する。
// コントローラー側でしか使用しないならこちらでもよい。AddViewLocalization を使用するならこちらはなくても動作する。
//services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
// ローカライズに必要。Resx ファイルのフォルダパスを指定
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = "Resources"; });
}
続いて Startup.cs の Configure メソッドを修正します。 リソースファイルをただ読み込むだけであればこちらは不要ですが、 ユーザー側から任意に言語を指定できるようにするには必要なコードです。
ここでは ASP.NET Core MVC に標準で組み込まれている機能を使用しています。 以下のコードを記述するとユーザー環境に応じて「クエリ文字列」「Cookie」「Accept-Language HTTP ヘッダー」の いずれかで表示言語を切り替えることができます。 実際の動作確認方法は後ほど記載します。
切り替え可能な言語はここで配列 (supportedCultures) で指定しておきます。 デフォルトの言語に ja と指定していますが、今回 ja ファイルは作成していないので en, es 以外の言語が指定された場合は SharedResource.resx が使用されます。
UI とそれ以外でサポートする言語を分けることができますが、分けるメリットはあまりないので 同じ言語を指定しておきます。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
// 省略
}
// 標準の機能で切り替えたい言語を定義します。
var supportedCultures = new[]
{
new CultureInfo("ja"),
new CultureInfo("en"),
new CultureInfo("es"),
};
// 標準の言語切り替え機能を有効にします。対応しているのは「クエリ文字列」「Cookie」「Accept-Language HTTP ヘッダー」です。
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("ja"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseHttpsRedirection();
app.UseStaticFiles();
// 省略
}
Controllers\HomeController.cs
Controllers\HomeController.cs ファイルです。
コントローラー側でローカライズした言語を取得するには IStringLocalizer
ちなみに IStringLocalizer のほかに HTML をそのまま取得できる IHtmlLocalizer もあります。
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IStringLocalizer<SharedResource> _localizer;
// DI でローカライザーを取得します。
public HomeController(ILogger<HomeController> logger, IStringLocalizer<SharedResource> localizer)
{
_logger = logger;
_localizer = localizer;
}
public IActionResult Index()
{
// ローカライザーを使用して設定されている言語のリソースファイルからテキストを取得します。
ViewData["Message"] = _localizer["Goodbye"];
return View();
}
// 省略
}
Views\_ViewImports.cshtml
Views\_ViewImports.cshtml ファイルです。
ビュー側でローカライザーを使用するには IHtmlLocalizer
IHtmlLocalizer は Microsoft.AspNetCore.Mvc.Localization 名前空間にありますのでこれも using で定義しておきます。
ローカライザーを決まった箇所でしか使用しないのであれば個別のビューファイルに以下のコードを記載すればよいですが、 _ViewImports.cshtml ファイルに記述すれば自動的に全ビューファイルで使用することができるようになります。
@using LocalizationText
@using LocalizationText.Models
@using Microsoft.AspNetCore.Mvc.Localization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@* ビュー側でローカライザーを使用できるように定義します *@
@inject IHtmlLocalizer<SharedResource> Localizer
Views\Home\Index.cshtml
Views\Home\Index.cshtml ファイルです。 コントローラー側で取得したテキスト、ビュー側で直接取得したテキストをそれぞれ表示させるようにしています。 ビュー側のローカライザーもインデクサにキー文字列を指定してテキストを取得します。
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
@* ローカライザーから取得したテキストを表示します。 *@
<p>@Localizer["Hello"]</p>
<p>@ViewData["Message"]</p>
動作確認
クエリ文字列
URL のクエリ文字列にカルチャコードを指定することによって表示言語を切り替えることができます。 フォーマットは ?culture=<カルチャコード> になります。 UI と分けたい場合は ?culture=<カルチャコード>&ui-culture=<カルチャコード> になります。
以下は何も指定していない場合です。指定なしの場合は「SharedResource.resx」が使用されます。 (実際には別の判定が適用されているのですが…)
?culture=en を指定したパターンです。表示言語が英語になります。
?culture=es を指定したパターンです。表示言語がスペイン語になります。
?culture=ja を指定したパターンです。本来は SharedResource.ja.resx ファイルが使用されますが 存在していないので SharedResource.resx が使用されます。
試しに存在しない言語を指定してみます。 こちらも対応するファイルがないので SharedResource.resx が使用されます。
Cookie
Cookie によって表示言語を切り替えることができます。 通常はサーバー側から発行するのですが、今回はブラウザの機能で直接 Cookie を登録してみます。
各 Web ブラウザには開発者ツールが存在するのでそのツールを使用してクッキーを登録します。 下図では Edge で F12 キーを押して開発者ツールを表示させています。
対応するクッキーの名称は .AspNetCore.Culture となり、言語を指定する値には c=<カルチャーコード>|uic=<カルチャーコード> の形式で入力します。 Cookie の場合は UI 側のコードも入力必須です。 Cookie を登録したら Web ブラウザのページを更新して再表示してください。 サーバーに Cookie が送信されますので、サーバー側が指定した言語を取得するようになります。
下図では c=en|uic=en と入力して英語を表示させています。
c=es|uic=es と入力してスペイン語を表示させています。
Accept-Language HTTP ヘッダー
Accept-Language HTTP ヘッダーは Web ブラウザからサーバーにリクエストされたヘッダー情報を確認して それに合わせて言語を切り替える機能です。
Web ブラウザの設定で任意の Accept-Language を送信できるのですが、実はデフォルトでは OS の言語設定に合わせた Accept-Language が送信されるようになっています。 (実際に送信されるかどうかは OS, Web ブラウザに依存します。OS の言語に合わせて Web ブラウザに言語が初期設定されている、が正しいかもしれない)
そのため、例えば下図のように英語環境の OS の Web ブラウザでページを開くだけで en 情報が送信されるので自動的に SharedResource.en.resx が選択されて英語が表示されるようになります。
試しにクエリ文字列で存在しない言語を指定した場合、本来 SharedResource.resx が使用されるはずですが、 Accept-Language の方に en が存在しているため英語が表示されます。
クエリ文字列に ja を指定した場合はクエリ文字列が優先されるので日本語が表示されます。
まとめ
ここでは一番簡単な方法で多言語の切り替えを実装してみました。 ユーザーの環境に合わせて言語を切り替えるには、デフォルトの表示言語には Accept-Language HTTP ヘッダー を使用し、 ユーザーが任意の言語を選択した場合には Cookie の付加やクエリ文字列の付加(または直接入力)を行うのがよいでしょう。