WinForms/WPFアプリの多言語化 ── resx・サテライトアセンブリ・カルチャ切り替えの実務
· 小村 豪 · CSharp, .NET, WinForms, WPF, 多言語化, ローカライズ, リソース, UI, Windows開発, 技術相談
「海外拠点でも同じアプリを使いたい」「工場の現場に外国語話者のスタッフが増えたので画面を英語にもしたい」──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-JP→ja→ ニュートラルの順に探索されるため、翻訳が欠けてもアプリは落ちず、既定言語で表示されます2。 - WinFormsはデザイナー方式(
Localizable = true)と共有resx方式の併用が実務解です。 画面はデザイナー方式、メッセージボックスや共通文言は共有resxに寄せます(第4章)。 - WPFで公式ウォークスルーにあるLocBaml方式は、.NET(Core)では使えません1。現在の実務はresx+
x:Static(またはバインディング)方式が第一候補です(第5章)。 - 実行時の言語切り替えは「次回起動時に反映」を第一候補にします。 表示中の画面のリソースは自動では差し替わらないためです(第6章)。
- 文字列の翻訳は多言語化の半分でしかありません。 翻訳後の文字列長へのレイアウト追従、日付・数値の書式、フォント、右から左へ書く言語(RTL)への対応が残りの半分です(第7章)。
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章)。
4. WinFormsの実務 ── デザイナー方式と共有resx方式
WinFormsには2つの方式があり、実務では併用します。
4.1 画面はデザイナー方式(Localizable = true)
フォームのプロパティで Localizable を true にし、Language プロパティを対象言語(例: 英語)に切り替えてからラベルやボタンの Text を編集すると、Visual Studioが Form1.en.resx のような言語別resxを自動生成します5。
この方式の強みは、文字列だけでなくコントロールのサイズ・位置も言語別に保存されることです。日本語の「登録」が英語で「Register」になってボタンからはみ出す、という問題をデザイナー上で言語ごとに調整できます。一方で、言語数×フォーム数だけresxが増え、フォームのレイアウト変更のたびに全言語の確認が必要になる、という保守コストも生まれます。言語数が増える見込みがあるなら、次のレイアウト側の対策(第7章)で「調整しなくても崩れない」画面construction を優先してください。
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を第一候補に
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業務アプリの構成管理実務」の判断表を参照してください。
7. 文字列以外の多言語化 ── レイアウト・書式・フォント・RTL
翻訳が済んでも、多言語化にはまだ半分残っています。
- レイアウトの伸縮。 同じ意味の文言でも言語によって長さは大きく変わります(日本語「保存」→ドイツ語「Speichern」)。固定座標・固定サイズのレイアウトは翻訳のたびに崩れるため、WinFormsでは
TableLayoutPanelとAutoSizeを組み合わせて、文字列長に追従するレイアウトにするのが公式に案内されている方法です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とサテライトアセンブリという枯れた仕組みの上に成り立っており、仕組み自体は難しくありません。実務の成否を分けるのは、CurrentCulture と CurrentUICulture を区別した設計、ユーザーに見せる文字列を直書きしない規律、翻訳後の文字列長に耐えるレイアウト、そして「即時切り替えは本当に必要か」という要件の見極めです。WPFでは古いLocBaml方式の情報に引きずられず、resxベースで組むのが現在の実務解です。
既存アプリの多言語化の方式選定と影響範囲の見積もり、海外拠点展開に向けた画面・帳票・連携データの多言語対応は、コードベースの現状を見ながらの判断が必要になることが多いので、迷ったらご相談ください。
関連記事
- WinForms / WPF / WinUIの使い分け判断表
- Windowsアプリの UX 設計判断表
- 業務アプリの日時・タイムゾーン設計
- WinForms高DPI対応ガイド
- WPF高DPI対応ガイド
- appsettings.jsonだけじゃない ── Windows業務アプリの構成管理実務
- Windowsアプリの配布方法の選び方(MSI / MSIX / ClickOnce / xcopy / 自作アップデーター)
- Windowsユーザープロファイルの仕組み
関連する相談領域
合同会社小村ソフトでは、WinForms/WPFアプリの多言語対応の設計・実装、既存アプリを後から多言語化する際の方式選定と影響範囲の整理に関する技術相談を扱っています。
参考リンク
-
Microsoft Learn, WPF Globalization and Localization Overview. プロジェクトファイルの
UICulture設定によるサテライトアセンブリ生成、ルート要素のxml:langの役割、およびLocBamlが.NET FrameworkのWPF専用のサンプルツールであり.NETのWPFでは動作しないことについて。 ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Retrieve resources in .NET apps. リソースフォールバックプロセス(特定カルチャ→ニュートラルカルチャ→メインアセンブリの既定リソースの順に探索されること)について。 ↩ ↩2 ↩3
-
Microsoft Learn, CultureInfo.CurrentUICulture Property.
CurrentUICultureがリソースマネージャーのカルチャ固有リソース探索に使われること、既定値がOSのユーザーインターフェイス言語に由来すること、DefaultThreadCurrentUICultureによる全スレッド既定値の設定について。 ↩ ↩2 -
Microsoft Learn, Resources in .NET apps. resxリソースの作成・パッケージ化、メインアセンブリとサテライトアセンブリによるハブ&スポークモデル、
NeutralResourcesLanguage属性について。 ↩ ↩2 -
Microsoft Learn, Walkthrough: Localizing a Hybrid Application. Windowsフォームデザイナーで
LocalizableプロパティをtrueにしLanguageプロパティを切り替えて言語別resx(例: Form1.es-ES.resx)を生成する手順、InitializeComponent呼び出し前にCurrentUICultureを設定する例について。 ↩ -
Microsoft Learn, How to: Design a Windows Forms Layout that Responds Well to Localization.
TableLayoutPanelを使い、ローカライズによるTextプロパティの文字列長変化にコントロールのサイズが追従するレイアウトを作る方法について。 ↩ -
Microsoft Learn, Localize ClickOnce applications. 全サテライトアセンブリを1つの配置に含める方式がVisual Studioの既定であること、実行時にOSのカルチャに応じたサテライトアセンブリが使われることについて。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Windows業務アプリの印刷とPDF出力 ── System.Drawing.Printing / WPF / 帳票ライブラリの使い分け
PrintDocumentによるWinForms印刷、WPFのFlowDocument/FixedDocument印刷、PDF出力の選択肢を、要件別の判断表として整理します。改ページ制御やDPIのずれといった実装の落とし穴、Windowsサービスからの印刷、既定プリンター依...
Windowsアプリ 外注・受託開発を依頼する前に整理したいこと
Windowsアプリの外注・受託開発を依頼する前に、既存ソフト改修、装置連携、COM/ActiveX、配布・更新、保守の整理ポイントを解説します。
CSVは「ただのテキスト」ではない ── C#業務アプリのCSV実務(文字コード・Excel互換・インジェクション対策)
業務アプリのCSV入出力で事故が起きる典型パターン──Split(',')による自作パース、BOMなしUTF-8のExcel文字化け、先頭ゼロ落ち、CSVインジェクション──を整理し、RFC 4180のルール、.NETでのShift_JISの扱い(CodePagesEnco...
HttpClientをusingで囲んではいけない ── C#業務アプリのHTTP通信実務(生成パターン・タイムアウト・リトライ)
C#のHttpClientを毎回usingで生成するとソケット枯渇、staticにするとDNS変更に追従しない──この2大問題の仕組みと、PooledConnectionLifetime・IHttpClientFactoryによる正しい生成パターン、タイムアウト設計、Mic...
PerfViewとdotnet-traceで「遅い」を特定する ── .NETパフォーマンス調査の実務入門
業務アプリが「遅い」「CPUが張り付く」「たまに固まる」とき、どのツールで何を見ればよいのか。PerfViewとdotnet-traceの役割分担、CPUサンプリングの読み方(inclusive/exclusive)、ThreadTimeによるブロック時間の調査、Event...
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
UI スレッド / タイマーテーマ
WPF / WinForms、UI スレッド、async/await、タイマー設計を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
デスクトップアプリの多言語対応の設計と実装はWindowsアプリ開発の実務相談範囲だからです。
技術相談・設計レビュー
既存アプリを後から多言語化する際の方式選定と影響範囲の見積もりは設計レビューを伴う技術相談に該当するためです。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- 日本語だけで作った既存アプリを、後から多言語化できますか?
- できますが、作業の大半は「リソースの仕組みの導入」ではなく「コードに直書きされた文字列の洗い出しと置き換え」です。画面の文字列だけでなく、メッセージボックス、ログ、例外メッセージ、帳票、DBに保存している表示用文字列まで棚卸しが必要で、規模は画面数よりも文字列の散らばり具合で決まります。新規開発の段階から、ユーザーに見せる文字列だけでもresx経由にしておくと、将来の多言語化コストが桁違いに下がります。
- 翻訳は機械翻訳で済ませてよいですか?
- 社内ツールや暫定対応であれば機械翻訳から始めるのは現実的です。ただし業務アプリはボタンやメニューの短い単語(例:「登録」「取消」)が多く、文脈がないと機械翻訳の誤訳率が上がる領域です。最低限、実際にその言語を使う人に画面を触ってもらうレビューを1周入れることをおすすめします。また、翻訳の品質以前に「翻訳後の長い文字列でレイアウトが崩れない」ことをTableLayoutPanelやAutoSizeで先に担保しておく方が重要です。
- ログやエラーメッセージも翻訳すべきですか?
- ユーザーの画面に出すメッセージは翻訳し、ログファイルやイベントログに書く内容は翻訳しない(言語を固定する)のが実務の定石です。ログはユーザーではなく開発者・運用者が読むものであり、多言語のログは調査時の検索性を破壊します。書式(日付・数値)もログはCultureInfo.InvariantCultureに固定してください。CurrentCultureとCurrentUICultureを分けて扱う設計にしておくと、この使い分けが自然に実現できます。
- OSの表示言語とは別に、アプリだけ言語を切り替えられるようにすべきですか?
- 海外拠点への展開や、日本国内で外国語話者のスタッフが使う業務アプリでは、アプリ内の言語設定を持つ価値が高いです。既定ではOSの表示言語に従い(CurrentUICultureの既定値)、設定画面で明示的に選んだ場合だけ上書きする、という2段構えが無難です。切り替えの反映は「次回起動時」を仕様にするのが最も安全で、実装も運用説明も単純になります。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク