アプリケーションは、ローカライズされたリソースを取得するために、 ResourceManager クラスで表される .NET Framework Resource Manager に依存します。 Resource Manager は、リソースのパッケージ化とデプロイにハブ アンド スポーク モデルが使用されることを前提としています。 ハブは、非ローカライズ可能な実行可能コードと、ニュートラル カルチャまたは既定のカルチャと呼ばれる 1 つのカルチャのリソースを含むメイン アセンブリです。 既定のカルチャは、アプリケーションのフォールバック カルチャです。ローカライズされたリソースが見つからない場合にリソースが使用されるカルチャです。 各スポークは、1 つのカルチャのリソースを含むサテライト アセンブリに接続しますが、コードは含まれません。
このモデルにはいくつかの利点があります。
- アプリケーションをデプロイした後は、新しいカルチャのリソースを段階的に追加できます。 カルチャ固有のリソースの後続の開発にはかなりの時間が必要な場合があるため、これにより、最初にメイン アプリケーションを解放し、後でカルチャ固有のリソースを配信できます。
- アプリケーションを再コンパイルすることなく、アプリケーションのサテライト アセンブリを更新および変更できます。
- アプリケーションは、特定のカルチャに必要なリソースを含むサテライト アセンブリのみを読み込む必要があります。 これにより、システム リソースの使用が大幅に削減される可能性があります。
ただし、このモデルには欠点もあります。
- 複数のリソース セットを管理する必要があります。
- 複数の構成をテストする必要があるため、アプリケーションのテストの初期コストが増加します。 長期的には、複数の並列国際バージョンをテストして維持するよりも、複数のサテライトで 1 つのコア アプリケーションをテストする方が簡単でコストが低くなることに注意してください。
リソースの名前付け規則
アプリケーションのリソースをパッケージ化するときは、共通言語ランタイムで想定されるリソースの名前付け規則を使用して名前を付ける必要があります。 ランタイムは、カルチャ名でリソースを識別します。 各カルチャには一意の名前が付けられます。通常は、言語に関連付けられた 2 文字の小文字カルチャ名と、必要に応じて、国または地域に関連付けられた 2 文字の大文字のサブカルチャ名の組み合わせです。 サブカルチャ名は、ダッシュ (-) で区切られたカルチャ名に従います。 たとえば、日本で話されている日本語の ja-JP、米国で話されている英語の en-US、ドイツで話されているドイツ語の de-DE、オーストリアで話されているドイツ語の de-AT などがあります。 Windows でサポートされている言語/地域名の一覧の [言語タグ] 列を参照してください。 カルチャ名は 、BCP 47 で定義されている標準に従います。
注
中国語 (簡体字) の zh-Hans
など、2 文字のカルチャ名にはいくつかの例外があります。
詳細については、「 リソース ファイルの作成 」および 「サテライト アセンブリの作成」を参照してください。
リソース フォールバック プロセス
リソースをパッケージ化およびデプロイするためのハブ アンド スポーク モデルでは、フォールバック プロセスを使用して適切なリソースを見つけます。 使用できないローカライズされたリソースをアプリケーションが要求した場合、共通言語ランタイムはカルチャの階層を検索して、ユーザーのアプリケーションの要求に最も近い適切なフォールバック リソースを検索し、最後の手段としてのみ例外をスローします。 階層の各レベルで、適切なリソースが見つかった場合、ランタイムはそれを使用します。 リソースが見つからない場合、検索は次のレベルで続行されます。
参照のパフォーマンスを向上させるには、 NeutralResourcesLanguageAttribute 属性をメイン アセンブリに適用し、メイン アセンブリで動作するニュートラル言語の名前を渡します。
.NET Framework リソースフォールバック プロセス
.NET Framework リソース フォールバック プロセスには、次の手順が含まれます。
ヒント
<relativeBindForResources> 構成要素を使用して、リソース フォールバック プロセスと、ランタイムがリソース アセンブリをプローブするプロセスを最適化できます。 詳細については、 リソースフォールバックプロセスの最適化を参照してください。
ランタイムは最初に、アプリケーションの要求されたカルチャに一致するアセンブリの グローバル アセンブリ キャッシュ をチェックします。
グローバル アセンブリ キャッシュには、多くのアプリケーションで共有されているリソース アセンブリを格納できます。 これにより、作成するすべてのアプリケーションのディレクトリ構造に特定のリソース セットを含める必要ができなくなります。 ランタイムは、アセンブリへの参照を検索すると、要求されたリソースをアセンブリで検索します。 アセンブリ内のエントリが見つかると、要求されたリソースが使用されます。 エントリが見つからない場合は、検索を続行します。
ランタイムは次に、現在実行中のアセンブリのディレクトリで、要求されたカルチャに一致するサブディレクトリをチェックします。 サブディレクトリが見つかると、そのサブディレクトリで、要求されたカルチャの有効なサテライト アセンブリが検索されます。 ランタイムは、要求されたリソースをサテライト アセンブリで検索します。 アセンブリ内のリソースが見つかると、そのリソースが使用されます。 リソースが見つからない場合は、検索を続行します。
ランタイムは次に、Windows インストーラーにクエリを実行して、サテライト アセンブリをオンデマンドでインストールするかどうかを判断します。 その場合は、インストールを処理し、アセンブリを読み込み、そのアセンブリまたは要求されたリソースを検索します。 アセンブリ内のリソースが見つかると、そのリソースが使用されます。 リソースが見つからない場合は、検索を続行します。
ランタイムは AppDomain.AssemblyResolve イベントを発生させ、サテライト アセンブリが見つからないことを示します。 イベントを処理することを選択した場合、イベント ハンドラーは、参照にリソースが使用されるサテライト アセンブリへの参照を返すことができます。 それ以外の場合、イベント ハンドラーは
null
を返し、検索を続行します。ランタイムは次に、要求されたカルチャの親アセンブリについて、グローバル アセンブリ キャッシュをもう一度検索します。 親アセンブリがグローバル アセンブリ キャッシュに存在する場合、ランタイムは要求されたリソースをアセンブリで検索します。
親カルチャは、適切なフォールバック カルチャとして定義されます。 例外をスローするよりは何らかのリソースを提供する方がよいので、親をフォールバック候補として考えます。 このプロセスでは、リソースを再利用することもできます。 子カルチャで要求されたリソースをローカライズする必要がない場合にのみ、親レベルで特定のリソースを含める必要があります。 たとえば、
en
(ニュートラル英語)、en-GB
(英国で話されている英語)、en-US
(米国で話されている英語) のサテライト アセンブリを提供する場合、en
サテライトには一般的な用語が含まれ、en-GB
およびen-US
サテライトは、異なる用語についてのみオーバーライドを提供できます。ランタイムは次に、現在実行中のアセンブリのディレクトリをチェックして、親ディレクトリが含まれているかどうかを確認します。 親ディレクトリが存在する場合、ランタイムは、親カルチャの有効なサテライト アセンブリのディレクトリを検索します。 アセンブリが見つかると、ランタイムは要求されたリソースをアセンブリで検索します。 リソースが見つかると、リソースが使用されます。 リソースが見つからない場合は、検索を続行します。
ランタイムは次に、Windows インストーラーに対してクエリを実行して、親サテライト アセンブリをオンデマンドでインストールするかどうかを判断します。 その場合は、インストールを処理し、アセンブリを読み込み、そのアセンブリまたは要求されたリソースを検索します。 アセンブリ内のリソースが見つかると、そのリソースが使用されます。 リソースが見つからない場合は、検索を続行します。
ランタイムは AppDomain.AssemblyResolve イベントを発生させ、適切なフォールバック リソースが見つからないことを示します。 イベントを処理することを選択した場合、イベント ハンドラーは、参照にリソースが使用されるサテライト アセンブリへの参照を返すことができます。 それ以外の場合、イベント ハンドラーは
null
を返し、検索を続行します。ランタイムは次に、前の 3 つの手順と同様に、多くの潜在的なレベルを通じて親アセンブリを検索します。 各カルチャの親は 1 つだけで、CultureInfo.Parent プロパティによって定義されていますが、親がそれ自身の親を持つ可能性があります。 カルチャの Parent プロパティが CultureInfo.InvariantCultureを返すと、親カルチャの検索は停止します。リソースフォールバックの場合、インバリアント カルチャは親カルチャまたはリソースを持つ可能性のあるカルチャとは見なされません。
最初に指定されたカルチャーとそのすべての親カルチャーを検索してもリソースが見つからない場合、既定(フォールバック)カルチャーのリソースが使用されます。 通常、既定のカルチャのリソースはメイン アプリケーション アセンブリに含まれます。 ただし、Satellite 属性のLocation プロパティにNeutralResourcesLanguageAttributeの値を指定して、リソースの最終的なフォールバック位置がメイン アセンブリではなくサテライト アセンブリであることを示すことができます。
注
既定のリソースは、メイン アセンブリでコンパイルできる唯一のリソースです。 NeutralResourcesLanguageAttribute属性を使用してサテライト アセンブリを指定しない限り、最終的なフォールバック (最終親) になります。 そのため、メイン アセンブリには常に既定のリソース セットを含めるのが推奨されます。 これは、例外がスローされるのを防ぐのに役立ちます。 既定のリソースを含めることで、ファイルはすべてのリソースにフォールバックを提供し、カルチャに固有でない場合でも、少なくとも 1 つのリソースが常にユーザーに存在することを確認します。
最後に、ランタイムが既定の (フォールバック) カルチャのリソースを見つけられない場合は、リソースが見つからなかったことを示す MissingManifestResourceException または MissingSatelliteAssemblyException 例外がスローされます。
たとえば、アプリケーションがスペイン語 (メキシコ) ( es-MX
カルチャ) 用にローカライズされたリソースを要求するとします。 ランタイムは、最初にグローバル アセンブリ キャッシュを検索して、 es-MX
に一致するが見つからないアセンブリを検索します。 ランタイムは、現在実行中のアセンブリのディレクトリで、 es-MX
ディレクトリを検索します。 これに失敗すると、ランタイムはグローバル アセンブリ キャッシュを再度検索し、適切なフォールバック カルチャ (この場合は es
(スペイン語) を反映する親アセンブリを検索します。 親アセンブリが見つからない場合、ランタイムは、対応するリソースが見つかるまで、親アセンブリのすべての潜在的なレベルの es-MX
カルチャを検索します。 リソースが見つからない場合、ランタイムは既定のカルチャにリソースを使用します。
.NET Framework リソース フォールバック プロセスを最適化する
次の条件では、ランタイムがサテライト アセンブリ内のリソースを検索するプロセスを最適化できます。
サテライト アセンブリは、コード アセンブリと同じ場所に配置されます。 コード アセンブリが グローバル アセンブリ キャッシュにインストールされている場合、サテライト アセンブリもグローバル アセンブリ キャッシュにインストールされます。 コード アセンブリがディレクトリにインストールされている場合、サテライト アセンブリはそのディレクトリのカルチャ固有のフォルダーにインストールされます。
サテライト アセンブリは必要に応じてインストールされません。
アプリケーション コードは、 AppDomain.AssemblyResolve イベントを処理しません。
サテライト アセンブリのプローブを最適化するには、次の例に示すように、<relativeBindForResources> 要素を含め、そのenabled
属性をアプリケーション構成ファイルでtrue
に設定します。
<configuration>
<runtime>
<relativeBindForResources enabled="true" />
</runtime>
</configuration>
サテライト アセンブリ用に最適化されたプローブはオプトイン機能です。 つまり、> 要素がアプリケーションの構成ファイルに存在し、その属性がenabled
に設定されていない限り、ランタイムはtrue
に記載されている手順に従います。 この場合、サテライト アセンブリのプローブプロセスは次のように変更されます。
ランタイムは、親コード アセンブリの場所を使用してサテライト アセンブリをプローブします。 親アセンブリがグローバル アセンブリ キャッシュにインストールされている場合、ランタイムはキャッシュ内をプローブしますが、アプリケーションのディレクトリにはプローブしません。 親アセンブリがアプリケーション ディレクトリにインストールされている場合、ランタイムはアプリケーション ディレクトリにプローブしますが、グローバル アセンブリ キャッシュにはプローブしません。
ランタイムは、サテライト アセンブリのオンデマンド インストールについて Windows インストーラーに対してクエリを実行しません。
特定のリソース アセンブリのプローブが失敗した場合、ランタイムは AppDomain.AssemblyResolve イベントを発生させません。
.NET Core リソースフォールバック プロセス
.NET Core リソース フォールバック プロセスには、次の手順が含まれます。
ランタイムは、指定されたカルチャのサテライト アセンブリを読み込もうとします。
現在実行中のアセンブリのディレクトリで、要求されたカルチャに一致するサブディレクトリを確認します。 サブディレクトリが見つかると、そのサブディレクトリで要求されたカルチャの有効なサテライト アセンブリが検索され、読み込まれます。
注
大文字と小文字を区別するファイルシステムを持つオペレーティングシステム(LinuxやmacOS)では、文化名サブディレクトリの検索は大文字と小文字を区別します。 サブディレクトリ名は、 CultureInfo.Name の大文字と小文字が完全に一致している必要があります (たとえば、
es
やes-MX
)。注
プログラマが AssemblyLoadContextからカスタム アセンブリ読み込みコンテキストを派生させた場合、状況は複雑になります。 実行中のアセンブリがカスタム コンテキストに読み込まれた場合、ランタイムはサテライト アセンブリをカスタム コンテキストに読み込みます。 詳細については、このドキュメントの範囲外です。 AssemblyLoadContextを参照してください。
サテライト アセンブリが見つからない場合、 AssemblyLoadContext は AssemblyLoadContext.Resolving イベントを発生させ、サテライト アセンブリが見つからないことを示します。 イベントを処理する場合、イベント ハンドラーはサテライト アセンブリへの参照を読み込んで返すことができます。
サテライト アセンブリがまだ見つからない場合、AssemblyLoadContext によって AppDomain によって AppDomain.AssemblyResolve イベントがトリガーされ、サテライト アセンブリが見つからないことを示します。 イベントを処理する場合、イベント ハンドラーはサテライト アセンブリへの参照を読み込んで返すことができます。
サテライト アセンブリが見つかった場合、ランタイムは要求されたリソースを検索します。 アセンブリ内のリソースが見つかると、そのリソースが使用されます。 リソースが見つからない場合は、検索を続行します。
注
サテライト アセンブリ内のリソースを見つけるために、ランタイムでは現在の ResourceManager の CultureInfo.Name によって要求されたリソース ファイルが検索されます。 リソース ファイル内で、要求されたリソース名を検索します。 どちらかが見つからない場合、リソースは見つからないものとして扱われます。
ランタイムは次に、ステップ 1 と 2 を繰り返すたびに、多くの潜在的なレベルを通じて親カルチャ アセンブリを検索します。
親カルチャは、適切なフォールバック カルチャとして定義されます。 例外をスローするよりは何らかのリソースを提供する方がよいので、親をフォールバック候補として考えます。 このプロセスでは、リソースを再利用することもできます。 子カルチャで要求されたリソースをローカライズする必要がない場合にのみ、親レベルで特定のリソースを含める必要があります。 たとえば、
en
(ニュートラル英語)、en-GB
(英国で話されている英語)、en-US
(米国で話されている英語) のサテライト アセンブリを提供する場合、en
サテライトには一般的な用語が含まれ、en-GB
およびen-US
サテライトは、異なる用語についてのみオーバーライドを提供します。各カルチャの親は 1 つだけで、CultureInfo.Parent プロパティによって定義されていますが、親がそれ自身の親を持つ可能性があります。 カルチャの Parent プロパティが CultureInfo.InvariantCultureを返すと、親カルチャの検索は停止します。 リソース フォールバックの場合、インバリアント カルチャは、親カルチャまたはリソースを持つ可能性のあるカルチャとは見なされません。
最初に指定されたカルチャーとそのすべての親カルチャーを検索してもリソースが見つからない場合、既定(フォールバック)カルチャーのリソースが使用されます。 通常、既定のカルチャのリソースはメイン アプリケーション アセンブリに含まれます。 ただし、Satellite プロパティに Location の値を指定して、リソースの最終的なフォールバック場所がメイン アセンブリではなくサテライト アセンブリであることを示すことができます。
注
既定のリソースは、メイン アセンブリでコンパイルできる唯一のリソースです。 NeutralResourcesLanguageAttribute属性を使用してサテライト アセンブリを指定しない限り、最終的なフォールバック (最終親) になります。 そのため、メイン アセンブリには常に既定のリソース セットを含めるのが推奨されます。 これは、例外がスローされるのを防ぐのに役立ちます。 既定のリソース ファイルを含めることで、すべてのリソースにフォールバックを提供し、カルチャに固有でない場合でも、少なくとも 1 つのリソースが常にユーザーに存在するようにします。
最後に、ランタイムで既定の (フォールバック) カルチャのリソース ファイルが見つからない場合は、リソースが見つからなかったことを示す MissingManifestResourceException または MissingSatelliteAssemblyException 例外がスローされます。 リソース ファイルが見つかったが、要求されたリソースが存在しない場合、要求は
null
返します。
サテライト アセンブリへの最終的な復帰
必要に応じて、メイン アセンブリからリソースを削除し、ランタイムが特定のカルチャに対応するサテライト アセンブリから最終的なフォールバック リソースを読み込む必要があることを指定できます。 フォールバック プロセスを制御するには、 NeutralResourcesLanguageAttribute(String, UltimateResourceFallbackLocation) コンストラクターを使用し、Resource Manager がメイン アセンブリまたはサテライト アセンブリからフォールバック リソースを抽出するかどうかを指定する UltimateResourceFallbackLocation パラメーターの値を指定します。
次の .NET Framework の例では、 NeutralResourcesLanguageAttribute 属性を使用して、フランス語 (fr
) 言語のサテライト アセンブリにアプリケーションのフォールバック リソースを格納します。 この例には、 Greeting
という名前の単一の文字列リソースを定義する 2 つのテキスト ベースのリソース ファイルがあります。 1 つ目の resources.fr.txtには、フランス語のリソースが含まれています。
Greeting=Bon jour!
2 つ目のリソース (ru.txt) には、ロシア語のリソースが含まれています。
Greeting=Добрый день
これら 2 つのファイルは、コマンド ラインから リソース ファイル ジェネレーター (resgen.exe) を実行して.resources ファイルにコンパイルされます。 フランス語リソースの場合、コマンドは次のようになります。
resgen.exe resources.fr.txt
ロシア語リソースの場合、コマンドは次のようになります。
resgen.exe resources.ru.txt
.resources ファイルは、次のようにフランス語リソースのコマンド ラインから アセンブリ リンカー (al.exe) を実行してダイナミック リンク ライブラリに埋め込まれます。
al /t:lib /embed:resources.fr.resources /culture:fr /out:fr\Example1.resources.dll
ロシア語リソースの場合は、次のようになります。
al /t:lib /embed:resources.ru.resources /culture:ru /out:ru\Example1.resources.dll
アプリケーションのソース コードは、Example1.csまたはExample1.vbという名前のファイルに存在します。 既定のアプリケーション リソースが fr サブディレクトリにあることを示す NeutralResourcesLanguageAttribute 属性が含まれています。 Resource Manager がインスタンス化され、 Greeting
リソースの値が取得され、コンソールに表示されます。
using System;
using System.Reflection;
using System.Resources;
[assembly:NeutralResourcesLanguage("fr", UltimateResourceFallbackLocation.Satellite)]
public class Example
{
public static void Main()
{
ResourceManager rm = new ResourceManager("resources",
typeof(Example).Assembly);
string greeting = rm.GetString("Greeting");
Console.WriteLine(greeting);
}
}
Imports System.Reflection
Imports System.Resources
<Assembly: NeutralResourcesLanguage("fr", UltimateResourceFallbackLocation.Satellite)>
Module Example
Public Sub Main()
Dim rm As New ResourceManager("resources", GetType(Example).Assembly)
Dim greeting As String = rm.GetString("Greeting")
Console.WriteLine(greeting)
End Sub
End Module
その後、次のようにコマンド ラインから C# ソース コードをコンパイルできます。
csc Example1.cs
Visual Basic コンパイラのコマンドは非常によく似ています。
vbc Example1.vb
メイン アセンブリにリソースが埋め込まれていないため、 /resource
スイッチを使用してコンパイルする必要はありません。
言語がロシア語以外のシステムから例を実行すると、次の出力が表示されます。
Bon jour!
提案されたパッケージの代替案
時間または予算の制約により、アプリケーションがサポートするすべてのサブカルチャに対して一連のリソースを作成できなくなる可能性があります。 代わりに、関連するすべてのサブカルチャで使用できる親カルチャ用の単一のサテライト アセンブリを作成できます。 たとえば、リージョン固有の英語リソースを要求するユーザーによって取得される 1 つの英語サテライト アセンブリ (en) と、リージョン固有のドイツ語リソースを要求するユーザー用の単一のドイツサテライト アセンブリ (de) を提供できます。 たとえば、ドイツ (de-DE)、オーストリア (de-AT)、スイス (de-CH) で話されているドイツ語の要求は、ドイツのサテライト アセンブリ (de) にフォールバックします。 既定のリソースは最終的なフォールバックであるため、アプリケーションの大部分のユーザーから要求されるリソースである必要があるため、これらのリソースは慎重に選択してください。 この方法では、カルチャに固有ではないリソースをデプロイしますが、アプリケーションのローカライズ コストを大幅に削減できます。
こちらも参照ください
.NET