WinForms/WPFアプリの多言語化 ── resx・サテライトアセンブリ・カルチャ切り替えの実務

· 更新日: · · CSharp, .NET, WinForms, WPF, 多言語化, ローカライズ, リソース, UI, Windows開発, 技術相談

更新履歴(4件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
既定言語を宣言する書き方(AssemblyInfoとSDKスタイルの両方)と、実行中に言語を切り替える場合の実装例をWinForms・WPFそれぞれに追加しました。あわせてBAMLやLocBamlなどの用語の説明、デザイナー方式の操作手順を追加しています。
本文に英単語が紛れ込んでいた誤記を「画面構成」に修正しました。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589985)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「WinForms/WPFアプリの多言語化 ── resx・サテライトアセンブリ・カルチャ切り替えの実務」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589985 https://staging.comcomponent.com/blog/winforms-wpf-localization-guide/

DOI(最新版)
10.5281/zenodo.21589985
DOI(この版)
10.5281/zenodo.21732967

「海外拠点でも同じアプリを使いたい」「工場の現場に外国語話者のスタッフが増えたので画面を英語にもしたい」──Windowsデスクトップアプリの多言語化は、要望としてはシンプルですが、いざ着手すると「resxをどう使うのか」「WPFは方式が複数あってどれが正解か分からない」「実行中に言語を切り替えられるのか」と、判断に迷うポイントが連続します。

この記事では、WinForms/WPFの業務アプリを想定して、.NETのローカライズの土台(カルチャとリソースフォールバック)、resxとサテライトアセンブリの仕組み、フレームワーク別の現実的な方式、実行時切り替え、そして文字列以外(書式・レイアウト・RTL)の論点までを実務で判断に迷う順に整理します。

1. まず結論(判断表)

多言語化の方式は、フレームワークと要件の組み合わせで決まります。

状況 推奨方式 理由
WinForms・画面のラベル/ボタンが中心 フォームの Localizable = true + 言語別resx(デザイナー方式) コントロールの文字列とサイズ・位置を言語別に調整でき、Visual Studioだけで完結する
WinForms/WPF共通・メッセージや共有文言が多い 共有resx(Resources.resx + Resources.ja.resx 等)+ 生成される型付きクラス 文字列をコードから型安全に参照できる。画面とロジックで同じ文言を共有できる
WPF 共有resx + x:Static バインディング LocBaml方式は.NET(Core)のWPFでは使えない1。resx方式ならWinFormsと知識を共有できる
実行中の言語切り替えが必須 resx + 変更通知の仕組み(または画面の再生成) 方式選定より先に「本当に再起動なし切り替えが必要か」を要件として確認する(第6章)
翻訳を外部に委託する resxベースで設計し、キーと訳文の対応表で受け渡し resxはXMLなのでそのままでも受け渡せるが、文脈情報(どの画面のどのボタンか)を添える運用が品質を左右する

結論を先に書きます。

  • CurrentCulture(書式)と CurrentUICulture(リソース言語)は別物です。 この区別が、多言語化設計全体の土台になります(第2章)。
  • リソースの実体は「ニュートラル言語のリソース+言語別サテライトアセンブリ」で、フォールバックは自動です。 ja-JPja → ニュートラルの順に探索されるため、翻訳が欠けてもアプリは落ちず、既定言語で表示されます2
  • WinFormsはデザイナー方式(Localizable = true)と共有resx方式の併用が実務解です。 画面はデザイナー方式、メッセージボックスや共通文言は共有resxに寄せます(第4章)。
  • WPFで公式ウォークスルーにあるLocBaml方式は、.NET(Core)では使えません1。現在の実務はresx+x:Static(またはバインディング)方式が第一候補です(第5章)。
  • 実行時の言語切り替えは「次回起動時に反映」を第一候補にします。 表示中の画面のリソースは自動では差し替わらないためです(第6章)。
  • 文字列の翻訳は多言語化の半分でしかありません。 翻訳後の文字列長へのレイアウト追従、日付・数値の書式、フォント、右から左へ書く言語(RTL)への対応が残りの半分です(第7章)。

この記事の知識マップ

WinForms/WPFアプリの多言語化を、CurrentCulture(書式)とCurrentUICulture(リソース言語)を分けて設計する土台から整理する記事で、resxが本体のニュートラルリソースと言語別サテライトアセンブリに分かれ、CurrentUICultureを起点に特定カルチャからニュートラルへ自動フォールバックする仕組みを説明する。WinFormsはLocalizableプロパティによるデザイナー方式と共有resx方式を併用し、WPFは.NET(Core)では動かないLocBaml方式ではなくresx+x:Staticバインディングを第一候補とする。翻訳後もレイアウトの伸縮・RTL対応・InvariantCultureへのログ書式固定など文字列以外の対応が残ることも指摘する。

WinForms/WPFの多言語化の知識マップresxとサテライトアセンブリによるリソースフォールバックの仕組み、CurrentCultureとCurrentUICultureの役割分担、WinFormsのデザイナー方式とWPFのresxと静的リソース参照による方式、RTLやInvariantCultureなど文字列以外の対応の関係を示す図利用する利用する前提とする利用する前提とするで構成できる利用する前提とする両立しない前提とする利用する利用する推奨される対応推奨される対応で構成できるで構成できる自動化する推奨される対応原因になり得る利用する利用する利用する利用するresxリソースファイルサテライトアセンブリCultureInfo.CurrentUICultureWindows FormsWPFリソースフォールバックNeutralResourcesLanguage属性デザイナー方式(Localizable=true)LocBaml.NET(Core以降)BAML(Binary Application Markup Language)x:Static参照(resx)TableLayoutPanel+AutoSizeによる可変レイアウト右から左へ書く言語(RTL)対応ClickOnceCultureInfo.InvariantCulture多言語ログによる検索性の低下CultureInfo.CurrentCulture

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全23件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. 土台 ── CurrentCulture と CurrentUICulture の違い

.NETのカルチャ(文化圏設定)には、役割の異なる2つのプロパティがあります3

プロパティ 決めるもの
CultureInfo.CurrentCulture 日付・数値・通貨の書式 2026/07/07 と表示するか 7/7/2026 と表示するか
CultureInfo.CurrentUICulture どの言語のリソースを読み込むか ボタンに「保存」と出すか「Save」と出すか

この2つは独立して設定できます。たとえば「画面は英語、でも日付や通貨は日本の書式」という組み合わせ(日本国内の外国語話者向け業務アプリでよくある要件)は、CurrentUICulture = en かつ CurrentCulture = ja-JP で自然に表現できます。

既定値はどちらもOSの設定に由来するので、「何もしなければOSに従う」が出発点です。アプリ全体で言語を明示的に切り替える場合は、スレッドごとに設定するのではなく、既定値を差し替えます。

using System.Globalization;

// 以降に作られるすべてのスレッドの既定カルチャを差し替える
// (UIスレッド生成前=Application.Run前に実行する)
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en"); // リソース言語
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("ja-JP"); // 書式

Thread.CurrentThread.CurrentUICulture への代入はそのスレッドにしか効きません。async/awaitやバックグラウンド処理でスレッドをまたぐ業務アプリでは、DefaultThreadCurrentUICulture / DefaultThreadCurrentCulture で既定値ごと変える方が事故がありません3

なお、ログ・ファイル出力・システム間連携の書式はユーザーのカルチャに追従させず CultureInfo.InvariantCulture に固定します。日付書式の設計全般は「業務アプリの日時・タイムゾーン設計」を参照してください。

3. リソースの仕組み ── resx・サテライトアセンブリ・フォールバック

.NETのローカライズは「ハブ&スポーク」モデルです。既定言語(ニュートラル)のリソースを本体アセンブリに埋め込み、言語別のリソースはサテライトアセンブリという別DLLに分離します4

ビルドすると、言語別resxは次のような出力構成になります。

MyApp.exe                     ← 本体(ニュートラルリソースを含む)
MyApp.dll
ja/MyApp.resources.dll        ← 日本語のサテライトアセンブリ
en/MyApp.resources.dll        ← 英語のサテライトアセンブリ

実行時、リソースマネージャーは CurrentUICulture を起点に、特定カルチャ(ja-JP)→ニュートラルカルチャ(ja)→既定(本体)の順でリソースを探します2。この自動フォールバックのおかげで、翻訳が1件欠けていてもアプリは落ちず、既定言語の文字列が表示されます。逆に言えば「英語画面のはずなのに一部だけ日本語が混ざる」のは翻訳漏れのサインで、テスト観点として使えます(第8章)。

実務では次の2点を押さえておきます。

  • 既定言語がどのカルチャなのかを NeutralResourcesLanguage 属性で宣言しておくと、既定カルチャのときにサテライトを探しに行く無駄がなくなり、フォールバックの終点が明確になります4
  • サテライトアセンブリは「本体と一緒に配布して初めて機能する」ため、インストーラーやコピー配布の設計に言語フォルダーを含める必要があります(第8章)。

NeutralResourcesLanguage の宣言方法はプロジェクト形式によって2通りあります。まず、AssemblyInfo.cs を手で持つ旧形式(.NET Frameworkの既定)の場合です。

// Properties/AssemblyInfo.cs
using System.Resources;

// 本体アセンブリに埋め込んだリソースが日本語であることを宣言する
[assembly: NeutralResourcesLanguage("ja-JP")]

SDKスタイルのプロジェクト(.NET 5以降の既定)では、AssemblyInfo.cs がビルド時に自動生成されるため、プロジェクトファイル側のプロパティで指定します。

<!-- MyApp.csproj -->
<PropertyGroup>
  <NeutralLanguage>ja-JP</NeutralLanguage>
</PropertyGroup>

Visual Studioからは、プロジェクトのプロパティの [パッケージ] > [全般] にある「アセンブリの中立言語」で同じ設定ができます。なおSDKスタイルのプロジェクトで両方を書くと、属性が二重定義になってビルドエラー(CS0579)になります。どちらか一方にしてください。

4. WinFormsの実務 ── デザイナー方式と共有resx方式

WinFormsには2つの方式があり、実務では併用します。

4.1 画面はデザイナー方式(Localizable = true)

フォームのプロパティで Localizabletrue にし、Language プロパティを対象言語(例: 英語)に切り替えてからラベルやボタンの Text を編集すると、Visual Studioが Form1.en.resx のような言語別resxを自動生成します5。手順を操作の順に書き下すと次のとおりです。

  1. デザイナーでフォームを開き、コントロールではなくフォーム自体(背景部分)をクリックして選択する
  2. プロパティウィンドウ(F4)で LocalizableTrue にする。この時点で、コントロールの文字列・サイズ・位置が既定言語用の Form1.resx に書き出される
  3. 同じプロパティウィンドウの Language を「(既定値)」から対象言語(例: English)に切り替える
  4. その状態でラベルやボタンの Text・サイズ・位置を編集する。編集内容は Form1.en.resx に保存され、既定言語のresxは変更されない
  5. 作業が終わったら Language を「(既定値)」に戻す

5を忘れたまま通常のレイアウト変更を続けると、その変更が既定言語ではなく編集中の言語のresxにだけ入り、「日本語のときだけボタンの位置がおかしい」という形で後から発覚します。デザイナー方式を使うチームでは、Language の戻し忘れを最初に共有しておいてください。

この方式の強みは、文字列だけでなくコントロールのサイズ・位置も言語別に保存されることです。日本語の「登録」が英語で「Register」になってボタンからはみ出す、という問題をデザイナー上で言語ごとに調整できます。一方で、言語数×フォーム数だけresxが増え、フォームのレイアウト変更のたびに全言語の確認が必要になる、という保守コストも生まれます。言語数が増える見込みがあるなら、次のレイアウト側の対策(第7章)で「調整しなくても崩れない」画面構成を優先してください。

4.2 メッセージ・共通文言は共有resx方式

メッセージボックスの文言、確認ダイアログ、ステータスバーの表示などコードから使う文字列は、プロジェクト共通の Resources.resx に集約し、言語別に Resources.en.resx などを追加します。resxからは型付きクラスが自動生成されるため、コードからはキーの打ち間違いなしに参照できます。

// 生成された型付きクラス経由で参照する。
// 返る文字列はCurrentUICultureに応じて自動で切り替わる
MessageBox.Show(
    Properties.Resources.ConfirmDeleteMessage,
    Properties.Resources.ConfirmTitle,
    MessageBoxButtons.YesNo);

ここで最重要のルールは、ユーザーに見せる文字列をコードに直書きしないことです。多言語化の工数は、仕組みの導入ではなく「散らばった直書き文字列の回収」に費やされます。1言語で運用している段階でも、resx経由にしておく価値はここにあります。

5. WPFの実務 ── LocBamlではなくresxを第一候補に

この章に出てくる用語を先に整理しておきます。

用語 読み方・正式名称 意味
BAML Binary Application Markup Language XAMLをビルド時にコンパイルした2進形式。WPFアプリではXAMLそのものではなく、このBAMLがアセンブリに埋め込まれて実行時に読み込まれる
LocBaml ── BAMLから翻訳対象の文字列を抜き出し、訳文を差し込んで言語別のBAMLを作り直す、.NET Framework時代のサンプルツール1
x:Static ── XAMLから、C#側の静的なプロパティ・フィールド・定数の値そのものを読み込むための記法。読み込みは画面が構築される瞬間の1回だけで、後から値が変わっても画面には反映されない
サテライトアセンブリ ── 言語別リソースだけを収めた 言語コード/MyApp.resources.dll(第3章)

WPFの多言語化は情報が錯綜しやすい領域です。公式ドキュメントのウォークスルーには、UICulture をプロジェクトファイルに設定してBAMLリソースを生成し、LocBamlツールで翻訳を差し込む方式が載っていますが、LocBamlは.NET FrameworkのWPF専用のサンプルツールであり、.NET(Core)のWPFでは動きません1。現在新規に選ぶ方式ではないと考えてください。

実務の第一候補は、WinFormsと同じ共有resx方式をXAMLから参照する形です。

<!-- resxのアクセス修飾子をPublicにしたうえでx:Staticで参照する -->
<Window xmlns:res="clr-namespace:MyApp.Properties"
        Title="{x:Static res:Resources.MainWindowTitle}">
    <Button Content="{x:Static res:Resources.SaveButton}" />
</Window>

この方式の利点は、リソースの仕組み(サテライトアセンブリ・フォールバック)がWinFormsと完全に共通で、混在ソリューションでも文言を一元管理できることです。x:Static は起動時に解決される静的参照なので、実行時切り替えが必要な場合はバインディング+変更通知に発展させます(第6章)。

XAML側では、あわせてルート要素の xml:lang を設定しておくと、ハイフネーションやフォントフォールバック、数字の表示などWPFの言語依存機能が正しく働きます1

WinForms/WPFどちらで作るかの判断自体は「WinForms / WPF / WinUIの使い分け判断表」を参照してください。

6. 実行時の言語切り替え ── 「次回起動時に反映」を第一候補に

設定画面で言語を選ばせる要件では、反映タイミングを2案から選びます。

  • 案A: 次回起動時に反映(推奨)。 選択された言語を設定ファイルに保存し、起動時の Application.Run 前(WPFなら Application 起動前)に DefaultThreadCurrentUICulture を設定します。実装が単純で、画面の再構築に伴う不具合(入力中データの喪失、イベントハンドラーの二重登録など)が構造的に起きません。
  • 案B: 即時反映。 CurrentUICulture を変更しても表示済みの画面の文字列は自動では差し替わりません。WinFormsのデザイナー方式なら ComponentResourceManager.ApplyResources で開いているフォームに再適用する、WPFなら文字列をバインディング+変更通知で供給する、いずれにしても「全画面がリソース再適用に対応している」ことが前提の作り込みになります。

業務アプリでは、言語を変える頻度(通常、導入時に1回)に対して案Bの実装・テストコストが見合わないことが多く、案Aを既定とし、案Bは要件として本当に必要な場合だけにすることをおすすめします。言語設定の保存先は、ユーザーごとの設定なので %LOCALAPPDATA% 配下が適切です。設定の置き場所の判断は「Windows業務アプリの構成管理実務」の判断表を参照してください。

6.1 言語設定の保存と読み込み(案Aの実装)

案Aは、次の程度のコードで足ります。保存先は Environment.SpecialFolder.LocalApplicationData(= %LOCALAPPDATA%)配下に自前のフォルダーを作ります。

using System;
using System.Globalization;
using System.IO;

internal static class LanguageSetting
{
    private static readonly string Dir = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
        "MyCompany", "MyApp");

    private static readonly string FilePath = Path.Combine(Dir, "language.txt");

    // 設定画面で選ばれた言語を保存する(例: "en", "ja-JP")
    public static void Save(string cultureName)
    {
        Directory.CreateDirectory(Dir);
        File.WriteAllText(FilePath, cultureName);
    }

    // 起動時、Application.Run(WPFならApplication起動)より前に呼ぶ。
    // 保存が無い・壊れている場合は何もしない = OSの表示言語に従う
    public static void ApplyOnStartup()
    {
        if (!File.Exists(FilePath)) return;

        var name = File.ReadAllText(FilePath).Trim();
        if (name.Length == 0) return;

        try
        {
            CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(name);
        }
        catch (CultureNotFoundException)
        {
            // 未知のカルチャ名。設定を無視してOSの表示言語のままにする
        }
    }
}

ポイントは、設定ファイルが無い状態を「OSに従う」の意味にしておくことです。初回起動時やファイルが壊れたときに例外で止まらず、CurrentUICulture の既定値(第2章)にそのまま落ちます。

6.2 案B(即時反映)を実装する場合の最小形

要件上どうしても即時反映が必要な場合に備えて、実装の骨格を示します。どちらも「全画面がこの仕組みに乗っている」ことが前提である点は変わりません。

WinFormsでデザイナー方式(Localizable = true)を使っている場合は、ComponentResourceManager で言語別resxを開いているフォームに再適用します。

using System.ComponentModel;
using System.Globalization;
using System.Windows.Forms;

public partial class MainForm : Form
{
    // 言語切り替え後、開いている各フォームで呼ぶ
    public void ApplyCurrentLanguage(CultureInfo culture)
    {
        CultureInfo.DefaultThreadCurrentUICulture = culture;
        CultureInfo.CurrentUICulture = culture; // 実行中のUIスレッドにも効かせる

        var resources = new ComponentResourceManager(GetType());

        // フォーム自身(タイトル・サイズ)は "$this" というキーで保存されている
        resources.ApplyResources(this, "$this");
        ApplyRecursive(Controls, resources);
    }

    private static void ApplyRecursive(
        Control.ControlCollection controls, ComponentResourceManager resources)
    {
        foreach (Control control in controls)
        {
            resources.ApplyResources(control, control.Name);
            ApplyRecursive(control.Controls, resources); // 入れ子のパネルも辿る
        }
    }
}

この再帰は Control しか辿らないため、メニューやツールバーの項目(ToolStripItemControl ではありません)は別途 ToolStrip.Items をたどって同じ処理を掛ける必要があります。「メニューだけ言語が変わらない」のはこれが原因です。

WPFでは x:Static(値を1回読むだけの記法)からバインディングに置き換え、言語切り替え時に変更通知を投げます。

using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;

// 文字列の供給元。XAMLからはこのインスタンスにバインドする
public sealed class Loc : INotifyPropertyChanged
{
    public static Loc Instance { get; } = new Loc();

    private Loc() { }

    // インデクサー経由でresxのキーを引く。見つからなければキー名をそのまま返す
    public string this[string key] =>
        Properties.Resources.ResourceManager.GetString(key, CultureInfo.CurrentUICulture) ?? key;

    public event PropertyChangedEventHandler PropertyChanged;

    public void ChangeLanguage(CultureInfo culture)
    {
        CultureInfo.DefaultThreadCurrentUICulture = culture;
        CultureInfo.CurrentUICulture = culture;

        // インデクサー全体の変更通知。Binding.IndexerName の中身は "Item[]"
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Binding.IndexerName));
    }
}
<!-- resxのアクセス修飾子はInternalまたはPublicにしておく -->
<Window xmlns:loc="clr-namespace:MyApp">
    <Button Content="{Binding Path=[SaveButton], Source={x:Static loc:Loc.Instance}}" />
</Window>

第5章の x:Static 直参照との違いは、バインディングなので変更通知を受け取れる点だけです。裏側のresxとサテライトアセンブリの仕組みは同じなので、あとから案Aから案Bへ移る場合もリソースの作り直しは不要で、XAMLの参照方法を差し替える作業になります。

7. 文字列以外の多言語化 ── レイアウト・書式・フォント・RTL

翻訳が済んでも、多言語化にはまだ半分残っています。

  • レイアウトの伸縮。 同じ意味の文言でも言語によって長さは大きく変わります(日本語「保存」→ドイツ語「Speichern」)。固定座標・固定サイズのレイアウトは翻訳のたびに崩れるため、WinFormsでは TableLayoutPanelAutoSize を組み合わせて、文字列長に追従するレイアウトにするのが公式に案内されている方法です6。WPFはレイアウトシステムがもともと可変なので、幅の決め打ちを避けるだけで大半は対応できます。あわせて、高DPI環境での崩れ対策(「WinForms高DPI対応ガイド」「WPF高DPI対応ガイド」)と同時に設計すると手戻りがありません。
  • 日付・数値・通貨の書式。 画面表示は CurrentCulture に任せ、独自の ToString("yyyy/MM/dd") の決め打ちを画面コードから減らします。逆にファイル・ログ・連携データは InvariantCulture に固定します(第2章)。
  • フォント。 対象言語の文字がフォントに含まれるかを確認します。中国語(簡体字/繁体字)や韓国語を追加する場合、日本語向けフォント指定のままでは字形が不自然になることがあります(いわゆるCJK字形の問題)。UIフォントの指定を1か所に集約しておくと、言語追加時の変更が楽になります。
  • 右から左へ書く言語(RTL)。 アラビア語・ヘブライ語対応では、文字列の翻訳に加えて画面の左右反転が必要です。WinFormsは RightToLeft / RightToLeftLayout プロパティ、WPFは FlowDirection プロパティで制御します。RTL対応は「後から足す」と全画面の見直しになるため、対象言語に入る可能性があるなら最初から要件に含めてください。
  • 画像・アイコンの中の文字。 画像に焼き込まれた文字列はリソースの仕組みでは切り替わりません。文字入り画像を避け、画像+テキストラベルの構成にしておくのが安全です。

UI設計全般の判断は「Windowsアプリの UX 設計判断表」も参照してください。

8. 運用 ── 翻訳の受け渡し・漏れ検出・配布

最後に、仕組みができた後の運用面です。

  • 翻訳の受け渡しには文脈を添える。 resxのキーと原文だけ渡すと、「OK」「開く」のような短い文言の訳質が安定しません。キー・原文・訳文に「表示される画面と用途」を添えた対応表(スプレッドシート等)でやり取りし、受領後にresxへ反映する運用が現実的です。
  • 翻訳漏れはフォールバックで見つける。 リソースフォールバックにより、翻訳漏れは「その言語の画面に既定言語が混ざる」形で現れます2。言語別resxのキー一覧をニュートラルresxと突き合わせる簡単なチェック(スクリプトやテストコード)をCIに入れておくと、リリース前に機械的に検出できます。
  • 配布にサテライトアセンブリを含める。 ja/ en/ などの言語フォルダーごと配布しないと、その言語だけフォールバックして「翻訳したのに反映されない」状態になります。手作業コピーで言語フォルダーが漏れるのは定番の事故なので、インストーラー(MSI/MSIX等)にディレクトリ構造ごと含めます。ClickOnce配布では、既定で全言語のサテライトアセンブリが配置に含まれます7。配布方式全体の判断は「Windowsアプリの配布方法の選び方」を参照してください。

まとめ

デスクトップアプリの多言語化は、resxとサテライトアセンブリという枯れた仕組みの上に成り立っており、仕組み自体は難しくありません。実務の成否を分けるのは、CurrentCultureCurrentUICulture を区別した設計、ユーザーに見せる文字列を直書きしない規律、翻訳後の文字列長に耐えるレイアウト、そして「即時切り替えは本当に必要か」という要件の見極めです。WPFでは古いLocBaml方式の情報に引きずられず、resxベースで組むのが現在の実務解です。

既存アプリの多言語化の方式選定と影響範囲の見積もり、海外拠点展開に向けた画面・帳票・連携データの多言語対応は、コードベースの現状を見ながらの判断が必要になることが多いので、迷ったらご相談ください。

関連記事

関連する相談領域

合同会社小村ソフトでは、WinForms/WPFアプリの多言語対応の設計・実装、既存アプリを後から多言語化する際の方式選定と影響範囲の整理に関する技術相談を扱っています。

参考リンク

  1. Microsoft Learn, WPF Globalization and Localization Overview. プロジェクトファイルのUICulture設定によるサテライトアセンブリ生成、ルート要素のxml:langの役割、およびLocBamlが.NET FrameworkのWPF専用のサンプルツールであり.NETのWPFでは動作しないことについて。  2 3 4 5

  2. Microsoft Learn, Retrieve resources in .NET apps. リソースフォールバックプロセス(特定カルチャ→ニュートラルカルチャ→メインアセンブリの既定リソースの順に探索されること)について。  2 3

  3. Microsoft Learn, CultureInfo.CurrentUICulture Property. CurrentUICultureがリソースマネージャーのカルチャ固有リソース探索に使われること、既定値がOSのユーザーインターフェイス言語に由来すること、DefaultThreadCurrentUICultureによる全スレッド既定値の設定について。  2

  4. Microsoft Learn, Resources in .NET apps. resxリソースの作成・パッケージ化、メインアセンブリとサテライトアセンブリによるハブ&スポークモデル、NeutralResourcesLanguage属性について。  2

  5. Microsoft Learn, Walkthrough: Localizing a Hybrid Application. WindowsフォームデザイナーでLocalizableプロパティをtrueにしLanguageプロパティを切り替えて言語別resx(例: Form1.es-ES.resx)を生成する手順、InitializeComponent呼び出し前にCurrentUICultureを設定する例について。 

  6. Microsoft Learn, How to: Design a Windows Forms Layout that Responds Well to Localization. TableLayoutPanelを使い、ローカライズによるTextプロパティの文字列長変化にコントロールのサイズが追従するレイアウトを作る方法について。 

  7. Microsoft Learn, Localize ClickOnce applications. 全サテライトアセンブリを1つの配置に含める方式がVisual Studioの既定であること、実行時にOSのカルチャに応じたサテライトアセンブリが使われることについて。 

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

日本語だけで作った既存アプリを、後から多言語化できますか?
できますが、作業の大半は「リソースの仕組みの導入」ではなく「コードに直書きされた文字列の洗い出しと置き換え」です。画面の文字列だけでなく、メッセージボックス、ログ、例外メッセージ、帳票、DBに保存している表示用文字列まで棚卸しが必要で、規模は画面数よりも文字列の散らばり具合で決まります。新規開発の段階から、ユーザーに見せる文字列だけでもresx経由にしておくと、将来の多言語化コストが桁違いに下がります。
翻訳は機械翻訳で済ませてよいですか?
社内ツールや暫定対応であれば機械翻訳から始めるのは現実的です。ただし業務アプリはボタンやメニューの短い単語(例:「登録」「取消」)が多く、文脈がないと機械翻訳の誤訳率が上がる領域です。最低限、実際にその言語を使う人に画面を触ってもらうレビューを1周入れることをおすすめします。また、翻訳の品質以前に「翻訳後の長い文字列でレイアウトが崩れない」ことをTableLayoutPanelやAutoSizeで先に担保しておく方が重要です。
ログやエラーメッセージも翻訳すべきですか?
ユーザーの画面に出すメッセージは翻訳し、ログファイルやイベントログに書く内容は翻訳しない(言語を固定する)のが実務の定石です。ログはユーザーではなく開発者・運用者が読むものであり、多言語のログは調査時の検索性を破壊します。書式(日付・数値)もログはCultureInfo.InvariantCultureに固定してください。CurrentCultureとCurrentUICultureを分けて扱う設計にしておくと、この使い分けが自然に実現できます。
OSの表示言語とは別に、アプリだけ言語を切り替えられるようにすべきですか?
海外拠点への展開や、日本国内で外国語話者のスタッフが使う業務アプリでは、アプリ内の言語設定を持つ価値が高いです。既定ではOSの表示言語に従い(CurrentUICultureの既定値)、設定画面で明示的に選んだ場合だけ上書きする、という2段構えが無難です。切り替えの反映は「次回起動時」を仕様にするのが最も安全で、実装も運用説明も単純になります。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る