WPF ローカライズの方法はいくつかあるんですが、今回は英語版をベース(ニュートラル言語)として、日本語にローカライズされた文字列テーブルを追加する手順を説明します。OS の UI 言語設定に合わせてアプリ起動時に自動的に文言をローカライズすることを前提としています。
[1]
[アプリケーション] の [アセンブリ情報] で [ニュートラル言語] が [(なし)] になっていること、また "Resources.resx" という名前のリソース ファイルがすでにプロジェクト内に存在することを確認する。
[新しい項目の追加] で [アセンブリ リソース ファイル] を選び、"Resources.ja-JP.resx" という名前でプロジェクトの Properties フォルダーにファイルを追加する。
ちなみに [プロパティ] の [カスタム ツール] を [PublicResXFileCodeGenerator] にすると、空のファイル "Resources.ja-JP.Designer.cs" が自動生成されるようになるが、これは別に必要ないらしい。
[2]
ソリューション エクスプローラーで "Resources.resx" と "Resources.ja-JP.resx" をそれぞれダブルクリックして、同一の名前(例えば button1_Content)の英語および日本語リソース文字列をそれぞれに追加する。
ベースとなる英語版のリソースは、アクセス修飾子を Internal ではなく Public にしておくこと。
[3]
後は個別に XAML マークアップ拡張を使って YourAppProjName.Properties.Resources クラスの静的プロパティを割り当てれば自動的に文言をローカライズしてくれます。また、ビルド時にサテライト リソース アセンブリが暗黙的に生成されます。
<Window x:Class="YourAppProjName.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourAppProjName" xmlns:props="clr-namespace:YourAppProjName.Properties" > ... <Button Name="button1" Content="{x:Static props:Resources.button1_Content}"/> ... </Window>
エラーメッセージのローカライズなど、C# コード ビハインドで参照する場合は、いったんビルドした後に
global::YourAppProjName.Properties.Resources.button1_Content
のようなラッパープロパティが自動的に生成されているのでそれを使えばよいです。
プロパティ名が小文字で始まっていたり、アンダースコアが含まれていたりするのが気持ち悪い人は .NET 命名規則に合わせて命名しましょう。
ちなみに明示的にカルチャーを指定して、OS 設定によらず任意の言語に動的ローカライズする場合は、(MFC の場合と同様に)別途コード ビハインドでの処理が必要となるんですが、この方法に関してはまた機会があれば解説しましょう。
なお、下記のように App.xaml の Application.Resources に YourAppProjName.Properties.Resources クラスのインスタンスを追加して、バインディングを使ってローカライズする方法(Windows Phone アプリのサンプル含む)を見かけるんですが、これは NG です。
- http://code.msdn.microsoft.com/WindowsPhone-howtolearning-83f50324
- http://uchukamen.wordpress.com/2012/04/15/%E7%94%BB%E9%9D%A2%E3%81%AE%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%A9%E3%82%A4%E3%82%BA/
- http://d.hatena.ne.jp/bs-wp7/20110902/1314938780
- http://yohshiy.blog.fc2.com/blog-entry-232.html
<Application x:Class="YourAppProjName.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourAppProjName" xmlns:props="clr-namespace:YourAppProjName.Properties" StartupUri="MainWindow.xaml"> <Application.Resources> <!-- これは NG。 --> <props:Resources x:Key="MyLocalizedResourceKey" /> </Application.Resources> </Application>
<Button Name="button1" Content="{Binding Source={StaticResource MyLocalizedResourceKey}, Path=button1_Content}"/>
App.xaml で YourAppProjName.Properties.Resources クラスをインスタンス化してしまうと、起動時にハンドルされない例外 System.Windows.Markup.XamlParseException が発生してアプリが起動できなくなることがあります。
どうも上記例の MyLocalizedResourceKey や button1_Content の名前を変更したり、EXE とは別の関連 DLL アセンブリの C# コードを変更してビルドしたりした直後に発生する模様。
その後、なぜか EXE 側の C# コードになんらかの変更を加えて(タイム スタンプを更新して)ビルドし直さないと、ずっと例外が発生し続ける模様。
XAML だけが変更されたとき、リソース ファイルがビルドし直されないせいかと思ったんですが、単にリビルドを実行しても改善しません。出力ファイル・中間ファイルやソリューション ユーザー オプション ファイル(.suo)を削除してクリーン状態からリビルドし直してもダメです。必ず EXE 側 C# コードの編集が要るようになってしまいます。
ちなみに VS 2012 だけでなく、VS 2010 でも同様の現象が発生していたらしいです。
.NET 自体のバグという推測もあります。
(もしくは Visual Studio IDE 側のバグ?)
そもそもアクセスしているのは静的プロパティなので、インスタンス化の必要はないはずなわけですが……