koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

.NET Core 3 以降で任意の言語にローカライズする

ASP.NET Core のWebアプリケーションで国際化対応したければこのドキュメントに従えばよい。

docs.microsoft.com

アクセスしてきているユーザーの言語向けの表示を行うことができる。

今回、ユーザーの言語でなく任意の言語で表示したかったのだけれど、すんなりはできなかったのでメモしておく。

カルチャ指定インタフェースが変化している

.NET Core 2 までは IStringLocalizer などのローカライズした文字列を得るためのインタフェースに WithCulture という任意のカルチャを指定してそのカルチャでローカライズするインスタンスを取得することができた。

これは .NET Core 3 で非推奨になり、.NET 5 で消えてしまった。

IStringLocalizer.WithCulture(CultureInfo) メソッド (Microsoft.Extensions.Localization) | Microsoft Docs

ではどうやってローカライズされる言語が決まるのかというとこういうことらしい。

This method is obsolete. Use CurrentCulture and CurrentUICulture instead.

CurrentCultureCurrentUICulture を設定しておくとそのカルチャでローカライズされるらしい。これは System.Globalization.CultureInfo の静的なプロパティとしてアクセスでき、実体はスレッドごとに管理されているようだ。

CultureInfo.CurrentCulture プロパティ (System.Globalization) | Microsoft Docs

本気か? 現在のカルチャで解決されるのは親切だとしても、任意のカルチャでローカライズするインタフェースが消え去るとかある? マジで?

スレッド毎管理に注意する

現在のカルチャはスレッド毎に管理されるので、昨今の非同期処理が頻繁に登場するプログラムではローカライズを実行するスレッドと、カルチャを設定するスレッドに気を使う必要がある。

特に ASP.NET Core MVC の非同期なコントローラメソッド内で CurrentCulture を設定しても、Razorテンプレートのレンダリング時には反映されない。何故ならスレッドが違うからだ。

気をつけられたい。

僕は面倒くさかったのでテンプレートの側で CurrentCulture を設定することで任意のカルチャでローカライズした。

抜粋するとこんな感じ。

@inject IHtmlLocalizer<SharedResource> SharedLocalizer
@{
    // レンダリング時に使うカルチャを指定する
    CultureInfo.CurrentCulture = new CultureInfo("ja");
    CultureInfo.CurrentUICulture = new CultureInfo("ja");
}
@SharedLocalizer["This is a pen."]

本気か? まぁ期待通りのローカライズにはなったのでよし。