Skip to content

MS_ResourceFiles

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

リソースファイル

概要

  • リソースファイル(マネージリソースファイル)は、

    • 文字列や画像などのリソース情報を Key-Value で保持する、
      拡張子が .resources または .resx のファイルのことである。

    • いろいろな言語のリソースファイルを用意すると、
      多言語対応のアプリケーションを作成できる。

    • アセンブリ・ファイル(dll, exe)に含められる。

  • 参考

補足(2 つの用途): リソースファイルには、
性質の異なる 2 つの用途が混在しているため、
先に切り分けておくと読みやすい。

① 埋め込みリソース(画像・アイコン・テキスト)
     → 「1 ファイルにまとめて配布したい」という配置の話

② ローカライズ(多言語対応)
     → 「言語ごとに文言を差し替えたい」という国際化の話

本ページは①を特徴で、②を多言語対応で扱っている。
実務で主に使われるのは②である
(①は現在、埋め込みリソース(EmbeddedResource)を直接使う方が多い)。

特徴

仕組み

  • *.resx ファイル と *.designer.cs(vb)ファイルから成る。

  • *.resx ファイル
    埋め込まれたリソースとして埋め込まれる XML ファイル。

  • *.designer.cs(vb)ファイル
    埋め込まれたリソースを読み取るコードが自動生成される。

補足(ビルド時の流れ): .resx がどう変換されるかを
押さえておくと、後述のサテライト アセンブリの話が理解しやすい。

Strings.resx      ──(ResGen)──> Strings.resources ──┐
Strings.ja.resx   ──(ResGen)──> Strings.ja.resources ─┤
                                                       ↓
  Strings.resources    → 本体アセンブリ(MyApp.dll)に埋め込み
  Strings.ja.resources → [AL.exe](MS_NuGetMSB3086) で
                          ja\MyApp.resources.dll(サテライト)を生成

Strings.Designer.cs ← ResXFileCodeGenerator が自動生成
  (ResourceManager 経由でアクセスする厳密に型指定されたプロパティ)

AL.exe が見つからないと MSB3086 になるのは、
このサテライト アセンブリ生成の段階である。

メッセージ等の隠蔽化が可能

  • アセンブリ・ファイル(dll, exe)に含められるため、改ざんされにくい。

  • ただし、リソースファイルの修正を反映するには再ビルドが必要。
    ※ ILSpy 等の逆アセンブルツールにてリソースファイルの内容が
    抽出されることは防げない

補足(隠蔽の目的で使わない): 原文自身が注記している通り、
リソースは容易に抽出できる(ILSpy で丸見え)。

リソースファイルが提供するのは
  ・「うっかり編集される」ことの防止(設定ファイルと違い、外に出ない)
  ・配布物の一体化
であって、
  ・秘密情報の保護
ではない。

接続文字列・API キーをリソースに入れてはならない
それらは .NET Core config
ユーザー シークレット / 環境変数 / Key Vault に置く。

また、「再ビルドが必要」という性質は運用上の制約でもある。
文言を運用中に変えたい場合は、
DB や外部ファイルから読む仕組み(後述のIStringLocalizer
カスタム実装等)を検討する。

実行中の差し替えが可能

移行メモ(表現): 「実行中の差し替えが可能」は、
サテライト アセンブリ(ja\MyApp.resources.dll)を
差し替えられる
、という意味である
(本体アセンブリに埋め込んだ既定リソースは差し替えられない)。

ReleaseAllResources() でキャッシュを解放すれば
次回のアクセスで再読み込みされるが、
ファイルがロックされている場合は差し替え自体ができない点に注意する。

文字列以外も扱うことが可能

リソースファイルに画像などのバイナリファイルを文字列と同様に含めることが可能である。
この際、BASE64 エンコードされた文字列が resx ファイルに格納される。

補足(バイナリは別ファイル参照が望ましい): .resx
BASE64 で直接埋め込むと、

  • .resx が肥大し、差分が読めなくなる(Git で扱いにくい)
  • マージ競合が解決不能になる

という問題が出る。
.resx からは「ファイルへの相対パス」で参照する形
(Visual Studio の既定動作)にしておく方がよい。

<data name="Logo" type="System.Resources.ResXFileRef, System.Windows.Forms">
  <value>Resources\logo.png;System.Drawing.Bitmap, System.Drawing</value>
</data>

**単に「DLL に画像を埋め込みたい」**だけなら、
.resx を使わず EmbeddedResource で足りる。

<ItemGroup>
  <EmbeddedResource Include="Assets\logo.png" />
</ItemGroup>
using var s = Assembly.GetExecutingAssembly()
    .GetManifestResourceStream("MyApp.Assets.logo.png");

多言語化対応が可能

カルチャを使用し、対応したリソースファイルから
情報を取得することで文言や、UI 要素の多言語対応が可能となる(詳細は後述)。

詳細

作成方法

リソースファイルの作成方法には下記の様なものがある。

Visual Studio 上でリソースファイルを作成、編集する

  • Visual Studio でリソースを作成、編集できる。

  • 通常 Key-Value だが、画像 / アイコン / テキスト・ファイルも追加できる。

  • Visual Studio でリソース中に改行コードを入れる方法

リソース作成画面にて

[Shift]+[Enter]キー

を押下すると改行コードを挿入できる。

.NET プログラムからリソースファイルを作成する方法

リソースファイルを作成する API が用意されている。

テキストファイルからリソースファイルを作成する方法

.txt ファイルからリソースファイルを作成する Resgen.exe が用意されている。

補足(翻訳のやり取りは XLIFF / CSV で): 実務では、
翻訳会社や現地担当者とファイルをやり取りする必要がある。
.resx をそのまま渡すのは扱いにくいため、
中間形式に変換するのが一般的である。

形式 用途
XLIFF 翻訳業界の標準形式。多くの翻訳ツールが対応
CSV / Excel 手軽。社内翻訳向け
Multilingual App Toolkit Visual Studio 拡張。.resx ↔ XLIFF

キーの命名規則を先に決めておくことが重要で、
後から一括変換するのは非常に手間がかかる。

使用方法

リソースファイルの使用方法には下記の様なものがある。

Visual Studio 上で既存のリソースファイルを開く

  • *.resx ファイルを開く。

  • カスタム・ツールを設定する。

    • ダブルクリックしてデザイナの DDL から Internal or Public を選択する。
    • プロパティ・グリッドのカスタム・ツールに以下を設定する。
      • ResXFileCodeGenerator(Internal)
      • PublicResXFileCodeGenerator(Public)
  • これにより、

    • *.resx ファイルと、
    • *.designer.cs(vb)ファイルが

グループ化される。

移行メモ(表記): 原文の「デザイナの DDL」は
**ドロップダウン リスト(DDL)**を指すと読めるが、
データベースの DDL と紛らわしいため注記しておく
(実際にはリソース エディター上部の「アクセス修飾子」の
ドロップダウンを指す)。

Internal、Public の選定基準と利用方法

  • Internal
    エントリ・アセンブリ ※1 内でのみ使用する場合コチラを選択する。
    (※ 1: 現在の AppDomain のエントリポイントを含むアセンブリ)

  • Public

補足(MissingManifestResourceException の原因): 原文が
参考に挙げているこの例外は、リソース周りで最頻出のトラブルである。

原因の大半は「リソース名の解決に失敗している」

  期待される名前: <既定の名前空間>.<フォルダ>.<ファイル名>
  例:             MyApp.Resources.Strings

【よくあるずれ】
  ・プロジェクトの既定の名前空間を変更した
  ・.resx を別フォルダに移動した
  ・ビルド アクションが「埋め込まれたリソース」になっていない
  ・ライブラリ側とアプリ側でルート名前空間が違う(原文の指摘)

確認方法:

// 実際に埋め込まれているリソース名を列挙する
foreach (var n in Assembly.GetExecutingAssembly().GetManifestResourceNames())
    Console.WriteLine(n);

ResourceManager を自分で作る場合は、
この名前を正確に渡す必要がある。

var rm = new ResourceManager("MyApp.Resources.Strings",
                             typeof(SomeTypeInThatAssembly).Assembly);

.NET プログラムからリソースファイルを使用する方法

  • *.designer.cs(vb)に実装された、
    プロパティ・プロシージャ経由でリソースにアクセスできる。

  • リソースファイルを使用する API が用意されている。

  • 参考

制限事項

  • リソースの名前に "="(半角イコール) を含めることができません。
  • リソースの値に LF(Line Feed) を含めることができません。

移行メモ(制限の背景): これらは
.txt 形式(Resgen.exe が扱う name=value 形式)の制限であり、
.resx(XML)では該当しない
.resx なら = も LF も格納できる)。
原文のテキストファイルからリソースファイルを作成する方法
対応する注意事項と読むのが妥当である。

多言語対応

スレッド毎に保持している CurrentUICulture に設定されている
カルチャを使用して、
対応したリソースファイルから情報を取得することで文言や、
UI 要素の多言語対応が可能となる。

補足(CurrentCultureCurrentUICulture は別物): 混同されやすいが、
役割が明確に分かれている

CurrentCulture CurrentUICulture
用途 書式(日付・数値・通貨・並べ替え) リソースの選択(文言)
1,234.56 / 2026/08/19 Strings.ja.resx を選ぶ
設定元 OS の地域設定 OS の表示言語
// 日本語 UI・米国式の数値書式、という組み合わせもあり得る
Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja-JP");  // 文言
Thread.CurrentThread.CurrentCulture   = new CultureInfo("en-US");  // 書式

**「文言は日本語なのに日付が 8/19/2026 になる」**といった現象は、
この 2 つを取り違えていることが原因である。

リソースの構造

  • ファイル名と拡張子の間にカルチャ名を挿入して
    カルチャ向けのリソースファイルを作成する。

  • 下位カルチャ用のリソースファイルには差分のみ定義可能。

R1.resx       既定カルチャ用リソースファイル
├R1.ja.resx     日本語用リソースファイル
├R1.en.resx     英語用リソースファイル
├R1.zh-Hans.resx  簡体字中国語用リソースファイル
└R1.zh-Hant.resx  繁体字中国語用リソースファイル

R2.resx       既定カルチャ用リソースファイル
├R2.ja-JP.resx   日本語(日本)用リソースファイル
└R2.en-US.resx   英語(米国)用リソースファイル

補足(「既定カルチャ」に何を入れるか): 拡張子なしの R1.resx
何語を入れるかは、設計判断である。

方針 利点 欠点
英語を既定にする 国際的に無難。未翻訳でも読める 日本語のみの案件では冗長
日本語を既定にする 国内案件では自然 未対応言語で日本語が出る
キー名だけ入れる 未翻訳が一目で分かる 事故時に表示が崩壊する

NeutralResourcesLanguage 属性
「既定リソースは何語か」を明示しておくと、
その言語ではサテライトの探索をスキップするため起動が速くなる。

[assembly: NeutralResourcesLanguage("ja-JP",
           UltimateResourceFallbackLocation.MainAssembly)]

フォールバック機能

リソースファイルのフォールバック機能とは

  • 使用するリソースファイルをシステムが判断することを指す。
  • CurrentUICulture のカルチャと一致するリソースファイルが
    存在しない場合、親カルチャ用のリソースファイルを順に検索する。

補足(探索の順序): 具体的には次の順に探す。

CurrentUICulture = "zh-Hant-TW" の場合

  ① zh-Hant-TW\MyApp.resources.dll   (特定カルチャ)
  ② zh-Hant\MyApp.resources.dll      (中立カルチャ)
  ③ zh\MyApp.resources.dll           (親)
  ④ 本体アセンブリの既定リソース      (最終フォールバック)

  ④ にも無ければ MissingManifestResourceException

下位カルチャで差分のみ定義できる(原文の記述)のは、
この段階的な探索によるものである。

R1.resx      : Yes / No / Cancel / Save / Delete
R1.ja.resx   : はい / いいえ / キャンセル      ← Save/Delete は未定義
  → 日本語環境では Save/Delete は英語のまま表示される

フォールバックのカスタマイズ

  • Parent プロパティで上位のカルチャを取得可能なので単純なアルゴリズムで作成可能。
  • また、メッセージを言語毎に用意するのであれば
    TwoLetterISOLanguageName プロパティで 2 階層目の値を取得することが可能なため、
    その値で分岐すれば良い。

参考

サテライトアセンブリ

補足(配置と配布の注意点): サテライト アセンブリは
アプリの実行フォルダ直下のカルチャ名フォルダに置かれる。

bin\Release\net8.0\
  MyApp.dll
  ja\MyApp.resources.dll
  en\MyApp.resources.dll
  zh-Hans\MyApp.resources.dll

実務上の注意:

論点 内容
配布漏れ カルチャ フォルダのコピー忘れで「英語になる」
不要な言語 SatelliteResourceLanguages絞れる(サイズ削減)
単一ファイル発行 サテライトも埋め込まれる(.NET 5+)
NuGet で配る NuGetパッケージの開発と公開 の Localized Package
<!-- 日本語と英語だけを出力する(他言語のサテライトを作らない) -->
<PropertyGroup>
  <SatelliteResourceLanguages>ja;en</SatelliteResourceLanguages>
</PropertyGroup>

NuGet パッケージが多言語のサテライトを持っていると
出力が膨らむ
ため、上記で絞るのは実用的な最適化である。

UI の多言語対応

リソースファイルを使用することで、UI の多言語対応が可能である。

Windows FormsASP.NET Web Forms
実装の方法が異なる。

Windows Formsの場合

ASP.NETの場合

WPF/Silverlightの場合

補足(ASP.NET Core の方式/最新化): ASP.NET Core では
IStringLocalizer / IViewLocalizer という抽象を通す方式に
変わっている。

// Program.cs
builder.Services.AddLocalization(o => o.ResourcesPath = "Resources");
builder.Services.AddControllersWithViews()
    .AddViewLocalization()
    .AddDataAnnotationsLocalization();

var cultures = new[] { "ja", "en" };
app.UseRequestLocalization(new RequestLocalizationOptions()
    .SetDefaultCulture("ja")
    .AddSupportedCultures(cultures)
    .AddSupportedUICultures(cultures));
public class HomeController(IStringLocalizer<HomeController> L) : Controller
{
    public IActionResult Index() { ViewData["Title"] = L["Welcome"]; ... }
}
@inject IViewLocalizer L
<h1>@L["Welcome"]</h1>

本ページとの主な違い:

.NET Framework ASP.NET Core
アクセス Designer.cs の型付きプロパティ IStringLocalizer(DI)
キーが無いとき 例外 キー名がそのまま返る(落ちない)
カルチャの決定 スレッドに設定 RequestLocalizationMiddleware(URL / Cookie / ヘッダー)
差し替え サテライト DLL IStringLocalizer を自作(DB / JSON も可)

**「キーが無くても落ちない」**のは実務上大きな違いで、
未翻訳の項目があっても画面は表示される
(代わりに、未翻訳の検出は別途行う必要がある)。

また、IStringLocalizer を自作すれば
DB や JSON から文言を読める
ため、
本ページのメッセージ等の隠蔽化が可能で述べた
「再ビルドが必要」という制約を回避できる。

参考

Microsoft Learn

.NET Tips (VB.NET,C#...)


Tags: 移行, .NET開発, 国際化対応

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally