.NET でアプリケーションを国際化するために文字列等のリソースを別のファイルに分離するには、大きく分けて3つの方法があります。参考記事

LocBAML を使う

ここに書いてあるんですが…はっきり言ってめんどくさいです。まずツールを自分でビルドしなければいけないというのがイケてない。

というわけでそれ以上は調べてません。

Resources.resx を使う

  • 昔 (.NET 1.1) からある方法
  • Visual Studio には GUI エディタがある
  • コードからリソースの中身にアクセスするための静的プロパティを持つクラスを自動生成させることができる
  • xaml から参照する場合、上記クラスのアクセス修飾子を internal ではなく public にする必要がある(.NET Framework のアセンブリから参照しようとするため)
  • xaml から参照する場合、初回ビルド時にエラーになる。xaml の方を touch してまたビルドすると成功する(ビルド順序の関係?)
  • Windows フォームから参照することが比較的容易(らしい)
  • この方法でデフォルト以外のカルチャのリソースを作ると、サテライトアセンブリが生成される

リソースディクショナリを使う

  • 比較的新しい (Silverlight / .NET 2.0) 方法
  • GUI エディタは無い
  • コードからリソースの中身にアクセスするには自前で書かなければいけない(大したコードではない)
  • WPF との親和性が高い。また、WPF の「スタイル」や「テンプレート」といったものをリソースとして分離する場合は、リソースディクショナリを使う必要がある
  • Windows フォームから参照するのには向いていない(らしい)
  • サテライトアセンブリは生成されない
  • 実は、カルチャによって適切なリソースディクショナリを選択する仕組みは存在しない(らしい)ので、自前でコードを書く必要がある(大したコードではない)

WPF アプリケーションの場合は Resources.resx とリソースディクショナリとで一長一短という所でしょうか。

リソースディクショナリを使う場合の具体例

デフォルトのカルチャを英語とし、日本語カルチャの場合は日本語リソースが使われるようにするものとします。

まず英語と日本語のリソースディクショナリを用意します。

Dictionary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="HogeFuga">HogeFuga</system:String>
</ResourceDictionary>

Dictionary.ja.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="HogeFuga">ほげふが</system:String>
</ResourceDictionary>

アプリケーションのリソースから参照させます。

App.xaml

<Application x:Class="ResourceDictionarySample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

前述のとおり、カルチャによって選択する仕組みは自前で実装する必要があります。デフォルトのカルチャは InitializeComponent() で読み込み、追加のカルチャは自前コードで読み込みます。MergedDictionaries の仕組みを使うことで、日本語のリソースディクショナリにあるリソースはそれが使われ、ないリソースは英語のリソースディクショナリから検索されるようになります。これにより、リソースを部分的or段階的に地域化するのが容易になります。

App.xaml.cs

    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            string uiCulture = Thread.CurrentThread.CurrentUICulture.ToString();

            if (uiCulture.StartsWith("ja"))
            {
                ResourceDictionary dic = new ResourceDictionary();
                dic.Source = new Uri("Dictionary.ja.xaml", UriKind.Relative);
                this.Resources.MergedDictionaries.Add(dic);
            }
        }
    }

実際に UI の xaml から参照します。

MainWindow.xaml

<Window x:Class="ResourceDictionarySample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow">
    <StackPanel>
        <Button Content="{StaticResource HogeFuga}"/>
    </StackPanel>
</Window>

コードから参照する場合はこうなります。

MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            MessageBox.Show((String)Application.Current.FindResource("HogeFuga"));
        }
    }

この例では、デフォルトのカルチャのリソースディクショナリのファイル名は App.xaml に書き、それ以外のカルチャのリソースディクショナリのファイル名は App.xaml.cs に書いています。リソースディクショナリの指定を全部 App.xaml.cs の方に書いても同じ実行結果を得ることができますが、App.xaml に書いておくと MainWindow.xaml のデザインビューでもリソースを取得して表示されるようになるため、そちらの方が便利なのではないかと思います。App.xaml と App.xaml.cs とで記述場所が分散してしまうのがイケてませんが…

Trackback

no comment untill now

Add your comment now