none
多言語対応したアプリを1つのexeファイルで実現したい RRS feed

  • 質問

  • こんにちは。
    多言語対応したWPFアプリケーションを作成しております。
    プロジェクトの Properties にリソースとして英語と日本語の文字列テーブルを追加し、ビルドすると exe と dll ができます。

    ○プロジェクトのファイル構成
     MyProject/
      + Properties/
       + StringTable.ja-JP.resx    (日本語文字列テーブル)
         + StringTable.resx        (英語文字列テーブル)
           + StringTable.Designer.cs

    ○ビルド後のファイル
     + bin/Debug/
       + MyProject.exe
       + ja-JP/
         + MyProject.resources.dll


    多言語対応したまま、この2つのファイルを1つのexeにまとめたいのですが、可能でしょうか?

    StringTable.ja-JP.resxのビルドアクションをResourceにするとexeしかできないのですが、英語が表示されます。
    ILSpyでexeの中を確認したところ、Stringtable.ja-JPは見当たりませんでしたのでおそらくexe内に入っていないのでは無いかと推測されます。

    また、ILMergeにてexeとdllを結合してもやはり英語が表示されます。
    以下のように強制的に日本語を設定しても英語が表示されました。
    WindowクラスのLoadedイベントにて以下の用に日本語を設定しても英語が表示されました。

       StringTable.Culture = CultureInfo.GetCultureInfo("ja-JP");

    やはり自前でResourceManagerのようなものを作らないといけないのでしょうか?

    よろしくお願い致します。
    2013年1月22日 5:35

回答

  • だいぶ前の質問なので今更ですが、私も興味があってちょうど調べる機会があったので得た情報を記載しときます。

    まず、http://msdn.microsoft.com/ja-jp/library/vstudio/sb6a8618.aspxにある通り、標準の仕組みでのカルチャの切り替えはハブアンドスポークモデル前提になるため、別途サテライトアセンブリが必須になります。
    またリソースファイル名を「*.(カルチャ名).resx」とすると、そのファイルをコンパイラがサテライトアセンブリとして別途出力するため、メインプロジェクトのバイナリ内に含むことができなくなるようです。
    (この辺はビルドオプション等で回避できるかもしれませんが・・・)

    で、その上で単体のexeで複数言語のリソースを切り替える方法ですが、WPFで表示項目等を切り替えるだけなら独自の仕組みを比較的簡単に実装できます。

    <Window x:Class="WpfApplication29.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <StackPanel Orientation="Vertical">
                <TextBlock Text="{Binding Source={StaticResource resource},Path=Label1}"/>
                <TextBlock Text="{Binding Source={StaticResource resource},Path=Label2}"/>
                <TextBlock Text="{Binding Source={StaticResource resource},Path=Label3}"/>
            </StackPanel>
        </Grid>
    </Window>
    


        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                switch (System.Threading.Thread.CurrentThread.CurrentCulture.Name)
                { 
                    case "en-US":
                        this.Resources.Add("resource", new Properties.StringTable_en_US());
                        break;
    
                    default:
                        this.Resources.Add("resource", new Properties.StringTable());
                        break;
                }
    
                InitializeComponent();
            }
        }

    要は、Windowが初期化される前に、カルチャに該当するリソースを任意のキー名でWindow.Resourceに追加しておき、それをStaticResourceとして参照する、ということです。
    なお注意点が1つあって、各リソースファイルのアクセス修飾子はPublicにしておく必要があります。
    またラッパー等でObjectDataProvider経由で生成する等、工夫すれば動的変更も可能です。

    以上、参考まで。

    • 回答の候補に設定 佐伯玲 2013年3月11日 0:20
    • 回答としてマーク sikesike 2013年3月11日 2:25
    2013年3月9日 12:48

すべての返信

  • だいぶ前の質問なので今更ですが、私も興味があってちょうど調べる機会があったので得た情報を記載しときます。

    まず、http://msdn.microsoft.com/ja-jp/library/vstudio/sb6a8618.aspxにある通り、標準の仕組みでのカルチャの切り替えはハブアンドスポークモデル前提になるため、別途サテライトアセンブリが必須になります。
    またリソースファイル名を「*.(カルチャ名).resx」とすると、そのファイルをコンパイラがサテライトアセンブリとして別途出力するため、メインプロジェクトのバイナリ内に含むことができなくなるようです。
    (この辺はビルドオプション等で回避できるかもしれませんが・・・)

    で、その上で単体のexeで複数言語のリソースを切り替える方法ですが、WPFで表示項目等を切り替えるだけなら独自の仕組みを比較的簡単に実装できます。

    <Window x:Class="WpfApplication29.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <StackPanel Orientation="Vertical">
                <TextBlock Text="{Binding Source={StaticResource resource},Path=Label1}"/>
                <TextBlock Text="{Binding Source={StaticResource resource},Path=Label2}"/>
                <TextBlock Text="{Binding Source={StaticResource resource},Path=Label3}"/>
            </StackPanel>
        </Grid>
    </Window>
    


        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                switch (System.Threading.Thread.CurrentThread.CurrentCulture.Name)
                { 
                    case "en-US":
                        this.Resources.Add("resource", new Properties.StringTable_en_US());
                        break;
    
                    default:
                        this.Resources.Add("resource", new Properties.StringTable());
                        break;
                }
    
                InitializeComponent();
            }
        }

    要は、Windowが初期化される前に、カルチャに該当するリソースを任意のキー名でWindow.Resourceに追加しておき、それをStaticResourceとして参照する、ということです。
    なお注意点が1つあって、各リソースファイルのアクセス修飾子はPublicにしておく必要があります。
    またラッパー等でObjectDataProvider経由で生成する等、工夫すれば動的変更も可能です。

    以上、参考まで。

    • 回答の候補に設定 佐伯玲 2013年3月11日 0:20
    • 回答としてマーク sikesike 2013年3月11日 2:25
    2013年3月9日 12:48
  • 今手元で試しましたが、うまく動作しました。
    ご回答ありがとうございました。
    2013年3月11日 2:25