5
10

More than 1 year has passed since last update.

WPF 多言語化対応

Last updated at Posted at 2022-02-07

多言語対応とは

WPFアプリケーションのGUIやメッセージボックスで出力する文字列を国際化(多言語化)することである。 (※)
今回はアプリケーション内で動的に変更する方法を2種類紹介する。

本来の国際化は、数値や日時の表現方法、UIレイアウトの自動調整まで含まれるが本説明では文字列の多言語化のみ行う。

多言語化対応① (resx使用編)

多言語リソース設定

項目 説明
Properties [追加]→[新しい項目]→[リソースファイル]を選択することで新規作成可能
Resources.resx Defaultで定義してあるリソースファイル
ResourcesTest.resx 今回は規定値以外のリソースファイルで多言語化対応が可能かも実験

多言語リソース設定(補足)

.resxの前にある拡張子はロケールID(LCID : LoCale Identifiers)であり各カルチャを示している。
言語コード (ISO-639, RFC 4656)に則っている。

例)
 ja-JPの場合、jaがjapanese(日本語),JPがJAPAN(日本[場所])となる
 2つに分ける理由は、言語だけでは場所が特定できないものや、
 場所によって複数の公用語を持つ場合を想定している

 
 今回はResourcesTest.resx無印の規定カルチャを英語圏(English)として使用している。


多言語リソース設定(ファイル内容)

[名前] にリソース名、[値] にリソース値 (実際に画面に表示する文字列) を入力する。
他のリソースでは、先に作った Resources.resx と同じキー([名前])を用意し、
リソース値に対象の文字列を設定する。
image.png


多言語リソース設定(出力ファイル)

Multilingual.resources.dllはサテライトアセンブリと呼ばれ、カルチャに固有のリソースのみを含んだアセンブリである。
リソースはカルチャ毎のフォルダ内にあるサテライトアセンブリをロードして画面に出力する。
image.png


多言語リソースの動的切り替え

■ ResourceServiceクラスを用意して、切り替えプロパティを定義

ResourceService.cs
    public class ResourceService : INotifyPropertyChanged
    {
        // シングルトン対策
        public static ResourceService Current { get; } = new ResourceService();

        // INotifyPropertyChanged対策
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// リソースを取得
        /// </summary>
        public ResourcesTest ResourcesTest => new ResourcesTest();

        /// <summary>
        /// リソースのカルチャーを変更
        /// </summary>
        /// <param name="name">カルチャー名</param>
        public void ChangeCulture(string name)
        {
            ResourcesTest.Culture = CultureInfo.GetCultureInfo(name);
            RaisePropertyChanged("ResourcesTest");

            var dictionary = new ResourceDictionary();
            try
            {
                var language = (name == "ja-JP") ? "Japanese" :
                               (name == "zh-CN") ? "Chinese" :
                              /*else...*/          "English";
                dictionary.Source = new Uri("/Multilingual;component/Resources/" + language + ".xaml", UriKind.Relative);
            }
            catch (Exception)
            {
                return;
            }
        }

■ xamlでのリソース表現方法

MainWindow.xaml
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="140"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0"
                       Text="{Binding Source={x:Static local:ResourceService.Current}, Path=ResourcesTest.UI_0000, Mode=OneWay}"
                       FontSize="16" Foreground="White"
                       HorizontalAlignment="Left" VerticalAlignment="Center"
                       Margin="5,0,0,0"/>
            <ComboBox Grid.Column="1"
                      SelectedIndex="{Binding LanguageIndex.Value}"
                      HorizontalAlignment="Stretch" VerticalAlignment="Center"
                      Height="24" Margin="5">
                <ComboBoxItem Content="English"/>
                <ComboBoxItem Content="日本語 (ja-JP)"/>
                <ComboBoxItem Content="中文 (zh-CN)"/>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction Command="{Binding ChangeLanguageCommand}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
        </Grid>

■ 言語変更イベント定義
csファイル内でもResourcesTest.MSG_xxxxの様な形式でリソース文字を取得可能

MainWindowViewModel.cs
    class MainWindowViewModel : BindableBase, IDisposable
    {
        /// <summary>
        /// まとめてDisposeするためのオブジェクト
        /// </summary>
        protected CompositeDisposable Disposable { get; } = new CompositeDisposable();
        public void Dispose()
        {
            Disposable.Dispose();
        }

        private string[] cultures = { "en-US", "ja-JP", "zh-CN" };

        public ReactivePropertySlim<int> LanguageIndex { get; set; } = new ReactivePropertySlim<int>(1);

        public ReactiveCommand ChangeLanguageCommand { get; set; } = new ReactiveCommand();
        public ReactiveCommand PushResxCommand { get; set; } = new ReactiveCommand();
        public ReactiveCommand PushXamlCommand { get; set; } = new ReactiveCommand();

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindowViewModel()
        {
            // CommandBinding
            ChangeLanguageCommand.Subscribe(() =>
            {
                if (LanguageIndex.Value < 0) return;
                ResourceService.Current.ChangeCulture(cultures[LanguageIndex.Value]);
            });
            PushResxCommand.Subscribe(() =>
            {
                MessageBox.Show(ResourcesTest.MSG_0001, ResourcesTest.MSG_0000);
            });
            PushXamlCommand.Subscribe(() =>
            {
                MessageBox.Show(ResourceService.GetResource("Message"), ResourceService.GetResource("Title"));
            });
        }
    }

多言語化対応② (xaml使用編)

多言語リソース設定

xamlでテキストを管理し、GUI(xaml)ではStaticResource / DynamicResourceを使って表現する。


多言語リソース設定(ファイル内容)

image.png


多言語リソースの動的切り替え

ResourceServiceクラス内(resx編と共有したかったため)で、変更する。

ResourceService.cs
    public class ResourceService : INotifyPropertyChanged
    {
        /// <summary>
        /// リソースのカルチャーを変更
        /// </summary>
        /// <param name="name">カルチャー名</param>
        public void ChangeCulture(string name)
        {
            //
            // resx編の処理は省略
            //

            Application.Current.Resources.MergedDictionaries[0] = dictionary;
        }

        public static string GetResource(string key)
        {
            return Application.Current.Resources.MergedDictionaries[0][key] as string;
        }

xamlでのリソース表現方法
image.png

参考サイト

WPF アプリの国際化 (多言語対応) と、実行中の動的な言語切り替え
WPFアプリケーションを多言語対応する方法のまとめ

5
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
10