6
Help us understand the problem. What are the problem?

posted at

updated at

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

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

やりたいこと

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

前提

.NET Framework 4.7.2を使用。

やり方

Properties.Resources.resxを使う。

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

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

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

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

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

手順

Propertiesの準備

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

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

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

アクセス修飾子の設定をpublicにする。
これをしておくと、xamlのコードからここの名前を使って呼び出せるようになる。
image.png
※publicにしてないと、xaml編集中は問題ないが、実行時のInitializeComponent()で下記エラーになる。

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

image.png

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を右クリック > [追加] > [新しい項目] を選択する。
image.png

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

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

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

image.png

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

手順は以上。

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

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

一覧
image.png

WindowsPCの言語設定
image.png

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

  • 英語(米国)だったら、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」が使われる様子。

image.png

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

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

注意と今後やること

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

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

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

追記

.NET CoreのWPFプロジェクトだと、そもそもPropertiesの項目がない。
(下記は.NET core 3.0)
image.png
今後はPropertiesを使った言語切り替えはしてくれるな、ということか?
そういう意味でも正しい言語切り替えのやり方を調べたい。

追記2

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

気づいたこと

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

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

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

仕組みとしては、
image.pngimage.png

ビルドすると、上記のように、追加で作成したリソースの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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
6
Help us understand the problem. What are the problem?