国際化

方針

外国人にアプリケーションが使用されることを想定すると、

などを考慮する必要があります。国際化と地域化 - Wikipedia

Visual Studioによる国際化

Form

  1. Formをビューデザイナーで開く
  2. プロパティを表示して、[Language]が"(既定値)"であることを確認し、[Localizable]をtrueにする
    (Formのプロパティとして表示されるが、Formクラスのプロパティではない)
  3. Formを既定の言語で作成する
  4. Formのプロパティの[Language]で、対応させたい言語を指定する
  5. 多言語対応させたい部分を、Formで記述し直す

こうすることで"Form1.resx"と"Form1.ja.resx"のような、その言語用のリソース ファイルが作成され、その言語の表示にはこのファイルが用いられるようになります。

Formのプロパティの[Language]で指定した言語は、Form1.resxに

<metadata name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <value>ja</value>
</metadata>

のように記録されます。

LocalizableAttributeクラス

Localizableを有効にしたときリソース ファイルに記録されるようになるのは、LocalizableAttribute属性が付けられたメンバーです。LocalizableAttribute クラス (System.ComponentModel) | Microsoft Learn

[Localizable(true)]
public string MyProperty
{
    get;
    set;
}

このようなメンバーにビュー デザイナーから値を設定すると、*.Designer.csではなく*.resxファイルに記録されるようになります。

リソース

[ソリューション エクスプローラー]のプロジェクトのコンテキストメニューから、【追加 → 新しい項目】でリソース ファイルを作成します。そのときそのファイル名を"Resource1.resx"としたならば、それに対応する文化固有のファイルは

  • Resource1.ja.resx
  • Resource1.en-GB.resx

のように、拡張子の前にBCP 47 (RFC 4646) の文字を追加します。たとえばそこで"String1"の名前で定義した文字列は、

string sample = Resource1.String1;

とすることで取得できます。これは自動で作成されたコードによってResourceManagerを介して処理されますが、これを明示的に行うには次のようにします。

Assembly assembly = Assembly.GetExecutingAssembly();
string applicationName = assembly.GetName().Name;
string baseName = applicationName + ".Resource1";

// ResourceManagerを作成する
ResourceManager resourceManager = new ResourceManager(baseName, assembly);

// リソースの値を取得する
string sample = resourceManager.GetString("String1");
ステップ 7 ハンズオン: .NET Framework を活用し、コードによる Windows アプリケーションの国際化を行う | Microsoft Learn

さらにResource2.ja.resxのようにリソース ファイルを追加できますが、これらはコンパイル時にja\project_name.resources.dllのファイルに統合されて格納されます。

カルチャ

対応カルチャの取得

リソースとして追加し実行時に読み込まれたカルチャは、次のようにすることで確認できます。

List<CultureInfo> result = new List<CultureInfo>();

// 指定の型の情報に基づいてサテライト アセンブリから検索する ResourceManager を作成する
// 指定の型によっては、NeutralResourcesLanguageAttributeで指定した言語も含まれる
ResourceManager resourceManager = new ResourceManager(typeof(Form1));

// すべてのカルチャの情報を取得する
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in cultures)
{
    if (!culture.Equals(CultureInfo.InvariantCulture))
    {
        // 指定のカルチャのリソース セットを取得する。そのとき、まだ読み込まれていなければ読み込む
        if (resourceManager.GetResourceSet(culture, true, false) != null)
        {
            result.Add(culture);
        }
    }
}
c# - Programmatic way to get all the available languages (in satellite assemblies) - Stack Overflow

カルチャの変更

UIのカルチャを変更することで、適用されるカルチャを変更できます。

CultureInfo.CurrentUICulture = CultureInfo.CreateSpecificCulture("en");

この変更をリソースに適用させるには、それらが読み込まれる前にこれを変更します。

コントロールへの適用

すでに読み込まれているコントロールのカルチャは、ComponentResourceManager.ApplyResources()で変更できます。

public virtual void ApplyResources (
    object value,
    string objectName,
    System.Globalization.CultureInfo culture
    );
ApplyResources(Object, String, CultureInfo) - ComponentResourceManager.ApplyResources メソッド (System.ComponentModel) | Microsoft Learn

cultureを省略すると、CultureInfo.CurrentUICultureが適用されます。ApplyResources - ComponentResourceManager.cs

ComponentResourceManager resources = new ComponentResourceManager(typeof(Form1));
resources.ApplyResources(this, "$this"); // Formから呼び出したときは、Form自身
resources.ApplyResources(button1, button1.Name);
c# - How do I change the culture of a WinForms application at runtime - Stack Overflow

リソース フォールバック プロセス (resource fallback process)

指定のカルチャに合致しなかった場合に、階層をさかのぼって適するリソースが探索される処理です。たとえば"ja-JP"が用意されていなかったときは、その上位となるニュートラル カルチャ (neutral culture) である"ja"があればそれが、なければ既定のカルチャ (default culture) が適用されます。 リソース フォールバック プロセス - .NET アプリでのリソースのパッケージ化と配置 - .NET | Microsoft Learn Step 7 : - ステップ 7 ハンズオン: Visual Studio .NET 2003 を使用して、Windows アプリケーションの UI の国際化を行う | Microsoft Learn

Microsoft Learnから検索