WEPサイトの多言語対応を考える(C#)

多言語対応で検索すると、フロント側だけ、サーバー側だけを対象とした記事ばかりがヒットします。
言い換えるとjavascriptだけの対応もしくはC#だけの対応の記事ばかりです。

よくあるのはjsはすべての言語情報を保持した辞書jsonを保持させて切り替えパターン。
C#だとResources.resx使うパターン。

それぞれ参考にはなるものの、現実にはサーバー側が返すメッセージがあったり、サーバーが応答が返らないときに出すメッセージはjsに埋め込んでいたりして、簡単に分離できるケースばかりではないんじゃなかろうか。

私が感じる問題点をいくつか列挙します。

  • 全言語の情報を保持したJSONって無駄なデータ多くない?
    日英くらいならいいけど、言語が増えるほど無駄が増大する。
  • ページごとに辞書JSON作るの大変そう。
  • 辞書JSONだとエディタで入力補完効かない?
  • js/C#両プランを採用するとResources.resxとjsonでファイル管理が煩雑。
  • Resources.resxを複数ファイルで横断管理するのは大変

理想だけを語るなら、
翻訳用の辞書ファイルは1か所で管理したい。
辞書ファイルはKey, En, Jp, … のような表形式で一括管理。
ビルド時に辞書ファイルからResources.resxとjs用の辞書を生成。
ついでにjsで補完を効かせたいので、d.tsファイルも自動生成。

ということで便利なものないかなーと検索していたら見つけたのがこのVisualStudioの拡張機能。

ResXManager

Resources.resxは複数ファイルになるとキーのコピペが面倒だと感じていたのですが、なんと便利な拡張機能がありました。
まさにKey, En, Jp, … のような表形式で一括管理でき理想通りです。
自力で辞書管理アプリを作ろうかとも思っていたのですが、ここまで出来上がったライブラリがあるなら使った方が楽ですね。ソース上からResources.resxに転記する機能もあったりして非常に便利です。

ということで辞書ファイルの管理はResources.resxで一本化を狙います。
ここからjs用の辞書ファイルを生成できれば理想は達成できそうです。

ちなみにResxの管理画面からResources.resxを更新した時、Resources.Designer.csが更新されないケースが発生しました。直接Resources.resxを開いて編集すれば更新されるのですが、Key名を変えたりした時にDesigner.csが更新されないと正しくコンパイルエラーにならないので少し困ります。
解決方法はわかりませんが、ソリューションエクスプローラーのResources.resxを右クリックから「カスタムツールの実行」で再生成できます。

jsの辞書管理の方式

jsonとはせずにjsファイルで配布するのがいいかなと思ってます。
jsとjsonは連想配列ならフォーマットはほぼ同じですし、jsの方が柔軟に対応できます。

#dictionary.json

const dictionary = {
    Msg: 'aaa',
    ButtonText: 'bbb'
}
// module exportするなりご自由に。

辞書ファイル生成とともにd.tsも生成する。

#dictionary.d.ts

declare const dic: {
    Msg: string,
    ButtonText: string,

}

各ページごとに辞書ファイルを生成するか、全ページの辞書ファイルを生成するかは状況によりけり。
今回は全ページ共通で1つの辞書ファイルを作成し、全ページで読み込ませます。
ファイルサイズが肥大化する上にロードにも時間が掛かりますが、初回ロード後はブラウザのキャッシュで2回目以降のリクエストは速くなるはずです。

個別ページで辞書を作成する場合は、各ページごとに辞書jsへのリンクを貼るか、
サーバーサイドでレンダリングしているなら、html内のscriptタグ内に直書きするのもありでしょう。Resources.resxから当該ページのjsで使われているKeyValueのみを展開しているケースを実際に業務でも見かけました。ただし、このやり方は個人的には好きじゃないですね。Resources.resxに記載した上に、htmlにも列挙が必要なので完全に2度手間です。

辞書jsの生成

ビルドイベントでビルド後に生成させることにします。
コマンドラインで実行できるようにするため、辞書jsを生成するだけのコンソールアプリケーションを作成します。このexeに対してResources.resxのパスを渡して変換させます。

以下のページが非常に参考になります。

Specify build events (C#) - Visual Studio (Windows)
UsebuildeventsinVisualStudiotospecifycommandsthatrunbeforethebuildstartsorafterthebuildfinishesforC#programs.

サーバー内の辞書切り替え

var culture = "ja-JP";

Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);

コメント