[WPF/xaml] Propertiesでxamlの画面を多言語対応する&現在の言語と地域のコードを取得する


もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

やりたいこと

WPF(画面はxaml)のアプリで、OSの言語設定を切り替えると、その設定に合った言語でUIの文言を表示できるようにしたい。( = 多言語対応したい)

前提

.NET Framework 4.7.2を使用。

やり方

Properties.Resources.resxを使う。

元々下図のようになっているのを、

表示したい言語の分のリソースを追加する形になる。

この場合だと、下記のようになる。

リソースファイル名 OS言語設定
Resources.fi.resx フィンランド語
Resources.ja.resx 日本語
Resources.resx 英語

今回は、デフォルトの言語 = 英語、としてやってみる。
※デフォルト言語のリソースが、ロケールがファイル名についてないResources.resxになるということ。

手順

Propertiesの準備

.NET Frameworkでプロジェクトを作成する。
作成したら、プロジェクトの下のPropertiesを開く。

Resources.resxをダブルクリックして開く。

言語別で表示分けしたい文言をここに設定する。(標準の言語は今回英語にするので、英語で入力。)
まず呼び出すときの名前を付けて、その値も入力する。
※一つ追加したら、その下に空欄が追加されるので、複数登録したかったら下に追加していけばいい。

アクセス修飾子の設定をpublicにする。
これをしておくと、xamlのコードからここの名前を使って呼び出せるようになる。

※publicにしてないと、xaml編集中は問題ないが、実行時のInitializeComponent()で下記エラーになる。

System.Windows.Markup.XamlParseException: '''System.Windows.Markup.StaticExtension' の値の指定時に例外がスローされました。' 行番号 '12'、行位置 '10'。'
ArgumentException: 'WpfApp52.Properties.Resources.MyString1' StaticExtension 値は、列挙値、静的フィールド、または静的プロパティに解決できません。

xaml画面の準備

xaml画面に、下記2点追加する。

  • Propertiesへのネームスペースの定義を追加する。
    書き方は、xmlns:properties="clr-namespace:プロジェクト名.Properties"
  • 言語別に表示したい文字列のためのTextBlockを追加する。
    書き方は、{x:Static 追加したネームスペース:Resources.追加したリソースの名前}
<Window x:Class="WpfApp52.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:properties="clr-namespace:WpfApp52.Properties" ★ネームスペース追加(「WpfApp52」はプロジェクト名)
        xmlns:local="clr-namespace:WpfApp52"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <!-- ★言語別に表示したい文字列のためのTextBlockを追加する -->
        <TextBlock Text="{x:Static properties:Resources.MyString1}" />
    </Grid>
</Window>

ここまでで、デフォルトの言語の表示はできた。
これだけだとデフォルトの英語だけになるので、ほかの言語のリソースを追加する。

他の言語用のResources.resxの追加

まずは、日本語のリソースを追加する。

Propertiesを右クリック > [追加] > [新しい項目] を選択する。

[リソースファイル]を追加する。名前は、Resources.ja.resxにしておく。

デフォルト言語のリソースと同じように、下記を行う。

  • リソースの名前とその値を追加
  • アクセス修飾子をpublicにする

これで、日本語用リソースの追加完了。
今WindowsのOS言語設定を日本語にしているので、画面エディタ上で文言が日本語リソースのものになった。

手順は以上。

Resource.〇〇.resxの〇〇の名付け方

下記を参考に付ける。
https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392381(v=msdn.10)?redirectedfrom=MSDN

一覧

WindowsPCの言語設定

例えば、言語設定の画面の設定が、

  • 英語(米国)だったら、enをつければいいのでResource.en.resx
  • スペイン語 (アルゼンチン)だったら、es-arをつければいいのでResource.es-ar.resx

とする。

ちなみに、es-arのように、ハイフンで2つをつなげているものは、〇〇-△△〇〇言語コード△△地域コードらしい。
だから、ja-jpだと、日本語-日本es-arだったら、そのままだが、スペイン語-アルゼンチン、を表している。

現在の言語と地域のコードをC#でとってくる

下記のようなコードで、現在のロケール設定を取ってこれる。
https://docs.microsoft.com/ja-jp/dotnet/api/system.globalization.cultureinfo.currentculture?view=netcore-3.1

// ja
string code1 = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
// ja-JP
string code2 = CultureInfo.CurrentUICulture.Name;

// 細かいこと調べられてないので、参考程度に。

ニュートラル言語設定とresxの関係

プロジェクトのプロパティの中にある「ニュートラル言語」の設定を例えば日本語にしていると、「Resources.ja.resx」があったとしても「Resources.resx」の方が日本語として扱われる。

ニュートラル言語に設定している言語のリソースとして「Resources.resx」が使われる様子。

なので、ニュートラル言語を設定するのであれば、その言語に対応するリソースを「Resources.resx」に書かないといけない。

また、ニュートラル言語を「なし」にしていると、今現在のWindowsの表示言語設定に対応する「Resources.〇〇.resx」があればその中の情報を使い、対応するのがなければ「Resources.resx」が使われる様子。(やってみた限りそう見えた)

注意と今後やること

この方法は、上記手順だけではアプリ起動後、動的に言語切り替えはできないもののお手軽ではあるが、xaml上でエラーになり、画面エディタが使えなくなる場合がある。
今回の実験だとそういうことは起きなかったが、実際仕事のアプリではそういうエラーになっていた。そうなるとき、ならないときの違いはよくわからない。

wpfとしては、「リソースディクショナリ」を使って多言語対応することを推奨しているようで、そっちのやり方ならそういうことが起きないっぽい。(未検証)

下の「参考」に挙げた「WPFアプリの文字列のローカライズ(多言語化)」
のページにその方法が書かれていたので、次回試したい。

追記

.NET CoreのWPFプロジェクトだと、そもそもPropertiesの項目がない。
(下記は.NET core 3.0)

今後はPropertiesを使った言語切り替えはしてくれるな、ということか?
そういう意味でも正しい言語切り替えのやり方を調べたい。

追記2

追加でいろいろ手順をやると、動的にも言語切り替えできるらしい。こちら参照。

気づいたこと

OSの言語設定が、追加したリソースの中にない言語だったとき

デフォルトのリソールResources.resxは、現在のOSの言語設定が、用意したリソース(今回だったら日本語)の中にないものだった場合に表示する、という動きをするみたい。
なので、上の状態でOSの言語設定を「フランス語」にすると、デフォルトのリソースが使われて英語表示になる。

追加したリソースの実体の見方

仕組みとしては、

ビルドすると、上記のように、追加で作成したリソースのdll(ここではjpフォルダの中のWpfApp51.resources.dll)が作成される。
※別プロジェクト作って実験したのでPJ名が上の方と変わっている。
※試しにフィンランド語のResources.fi.resxも追加したのでfiフォルダも追加されている。

OSの言語設定を切り替えたときには、各言語のフォルダの中の<PJ名>.resources.dllがリソースとして使われて、言語の切り替えが行われる。

標準の言語のリソースはどこに行ったかというと、exe(今回だとWpfApp51.exe)の中に含まれているらしい。(だから、「標準」として使われて、追加のリソースがない時はそれが使われる)

参考

ロケールの動的変更の仕方
http://grabacr.net/archives/1647

WPFアプリの文字列のローカライズ(多言語化)
ローカライズのやり方の種類をいくつか挙げているページ。
→今回のやり方は、このページの「4.Resources.resxを使う方法」にあたる。
https://nishy-software.com/ja/dev-sw/wpf-app-localize-strings/


CultureInfoや CultureInfo.CurrentCultureのMS docs説明
https://docs.microsoft.com/ja-jp/dotnet/api/system.globalization.cultureinfo.currentculture?view=netcore-3.1

MSのロケールIDの一覧
https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392381(v=msdn.10)?redirectedfrom=MSDN

jaとja-jpの違い
http://hensa40.cutegirl.jp/archives/3190

ja=ニュートラルカルチャ、ja-jp=特定のカルチャ、優先順位は?
https://www.atmarkit.co.jp/fdotnet/dotnettips/314winmultilang/winmultilang.html