應用程式依賴 .NET Framework Resource Manager,由ResourceManager類別表示,來擷取在地化資源。 Resource Manager 假設使用中樞和輪輻模型來封裝和部署資源。 中樞是主要元件,其中包含不可本地化的可執行程序代碼,以及單一文化特性的資源,稱為中性或預設文化特性。 應用程式的預設文化特性是備援文化特性;如果找不到本地化的資源,將使用預設文化的資源。 每個分支連線到一個包含單一文化特性資源的衛星元件,但不包含任何程式碼。
此模型有幾個優點:
- 部署應用程式之後,您可以累加新增新文化特性的資源。 因為後續的文化特性特定資源開發可能需要大量的時間,這可讓您先發行主要應用程式,並在稍後提供特定文化特性的資源。
- 您可以更新和變更應用程式的附屬元件,而不需重新編譯應用程式。
- 應用程式只需要載入包含指定文化所需資源的附屬元件。 這可大幅減少系統資源的使用。
不過,此模型也有缺點:
- 您必須管理多個資源集。
- 測試應用程式的初始成本會增加,因為您必須測試數個組態。 請注意,從長遠來看,使用數顆衛星測試一個核心應用程式比測試及維護數個平行國際版本更容易且成本更低。
資源命名慣例
當您封裝應用程式的資源時,您必須使用 Common Language Runtime 預期的資源命名慣例來命名它們。 運行時間會依其文化名稱來識別資源。 每個文化特性都有唯一的名稱,這通常是與語言相關聯的兩個字母、小寫文化特性名稱的組合,而且如果需要,則為與國家或地區相關聯的兩個字母、大寫子文化特性名稱。 子文化名稱遵循文化特性名稱,並以虛線 (-) 分隔。 範例包括在日本使用的日文 ja-JP、美國使用的英文 en-US、德國使用的德文 de-DE,或奧地利使用的德文 de-AT。 請查看 Windows 支援的語言/區域名稱清單中的「語言標籤」列。 文化名稱遵循 BCP 47 定義的標準。
備註
兩個字母的語言代碼有一些例外情況,例如 zh-Hans 中文(簡體中文)。
資源後援流程
封裝和部署資源的中樞和輪輻模型會使用後援程式來找出適當的資源。 如果應用程式要求當地語系化資源但該資源無法使用,Common Language Runtime 會在文化特性階層中搜尋最符合使用者應用程式要求的適當備援資源,僅在萬不得已時才拋出例外狀況。 在階層的每個層級,如果找到合適的資源,執行階段就會使用它。 如果找不到資源,搜尋會繼續在下一個層級。
若要改善查閱效能,請將 NeutralResourcesLanguageAttribute 屬性套用至您的主要元件,並傳遞適用於主要元件的中性語言名稱。
.NET Framework 資源回退流程
.NET Framework 資源後援程式包含下列步驟:
小提示
<您可以使用 relativeBindForResources> 組態專案來優化資源回退過程,以及執行階段探查資源組件的過程。 如需詳細資訊,請參閱 優化資源後援程式。
運行時間會先檢查 全域程式集 緩存中是否有符合應用程式所要求文化特性的元件。
全域程式集緩存可以儲存許多應用程式共用的資源元件。 這可讓您不必在您所建立之每個應用程式的目錄結構中包含特定資源集。 如果執行期間找到元件的參考,它會搜尋元件中所需的資源。 如果它在元件中找到條目,則會使用所要求的資源。 如果找不到項目,則會繼續搜尋。
運行時間接著會檢查目前執行中元件的目錄,以取得符合所要求文化特性的子目錄。 如果找到子目錄,它會在該子目錄中搜尋符合所要求文化特性的有效附屬組件。 運行時間接著會搜尋衛星組件中所要求的資源。 如果它找到元件中的資源,則會使用它。 如果找不到資源,會繼續搜尋。
執行階段接下來會查詢 Windows Installer,以判斷是否要按需安裝衛星組件。 如果是,它會處理安裝、載入元件,然後搜尋它或要求的資源。 如果它找到元件中的資源,則會使用它。 如果找不到資源,會繼續搜尋。
執行階段引發 AppDomain.AssemblyResolve 事件,以指出無法找到衛星組件。 如果您選擇處理事件,事件處理程式可以傳回附屬元件的參考,該附屬元件的資源將用於查閱。 否則,事件處理程式會傳
null回 ,並繼續搜尋。執行階段接下來會再次搜尋全域組件快取,這次尋找的是所要求文化特性的父組件。 如果父元件存在於全域程式集緩存中,運行時間會搜尋要求的元件。
父文化定義為適當的後備文化。 將父代視為備援候選,因為提供任何資源比擲回例外狀況更好。 此程式也可讓您重複使用資源。 只有在子文化特性不需要將要求的資源進行當地化時,才應在父層級包含特定資源。 例如,如果您提供
en(中性英文)的衛星元件、en-GB(英式英文)和en-US(美式英文)的衛星元件,en衛星將包含通用術語,而en-GB和en-US衛星可以只覆蓋那些不同的詞彙。運行時間接著會檢查目前執行元件的目錄,以查看它是否包含父目錄。 如果父目錄存在,執行階段會在該目錄中搜尋是否有符合父文化特性的有效衛星組件。 如果找到元件,運行時間會在元件中搜尋要求的資源。 如果找到資源,則會使用它。 如果找不到資源,會繼續搜尋。
執行階段接下來會查詢 Windows Installer,以確定是否要按需要安裝父附屬程式集。 如果是,它會處理安裝、載入元件,然後搜尋它或要求的資源。 如果它找到元件中的資源,則會使用它。 如果找不到資源,會繼續搜尋。
執行階段會引發 AppDomain.AssemblyResolve 的事件,以指出找不到適當的備援資源。 如果您選擇處理事件,事件處理程式可以傳回附屬元件的參考,該附屬元件的資源將用於查閱。 否則,事件處理程式會傳
null回 ,並繼續搜尋。執行階段接下來會像前三個步驟一樣,搜尋父元件,遍歷許多潛在的層級。 每個文化都只有一個由CultureInfo.Parent屬性定義的父文化,但該父文化可能會有自己的父文化。 當某個文化的Parent屬性回傳CultureInfo.InvariantCulture時,其父文化的搜尋就會停止。至於資源的回退機制,無變異的文化不被視為父文化或能擁有資源的文化。
如果原本指定的文化特性和所有父系都已搜尋,而且仍然找不到資源,則會使用預設 (後援) 文化特性的資源。 通常,主要應用程式組件中會包含預設文化特性的資源。 不過,您可以為 Satellite 屬性的 Location 屬性指定NeutralResourcesLanguageAttribute值,以表示資源的最終後援位置是衛星組件,而不是主要組件。
備註
默認資源是唯一可使用主要元件編譯的資源。 除非您使用 NeutralResourcesLanguageAttribute 屬性指定衛星組件,否則它是最終的後備選項(最後的父級)。 因此,建議您一律在主要元件中包含一組默認資源。 這樣有助於防止擲回例外狀況。 藉由包含預設資源檔案,您提供所有資源的後援,並確保至少有一個資源可用於使用者,即使它不具文化特性。
最後,如果執行階段找不到預設(後援)文化特性的資源,則會擲回 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>
人造衛星模組的優化探測器是需要自行選擇加入的功能。 也就是說,除非 元素,而且其<屬性設定>為 ,否則運行時間會遵循記載的步驟。 如果是這種情況,衛星組件的探查程式會修改如以下所示:
執行時使用父代碼組件的位置來尋找衛星組件。 如果父元件安裝在全域組件快取中,執行階段會探查快取,但不會在應用程式的目錄中探查。 如果父組件安裝在應用程式目錄中,執行階段會探測應用程式目錄,但不會在全域組件快取中探測。
運行時間不會查詢 Windows Installer 以進行衛星組件的隨需安裝。
如果特定資源元件的探查失敗,運行時間不會引發 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 所要求的資源檔。 在資源檔內,它會搜尋所要求的資源名稱。 如果找不到任一個,就會將資源視為找不到。
運行時間接下來會在不同的潛在階層中搜尋父文化組件,並在每個階段重複步驟一和二。
母文化被定義為適當的備用文化。 將父代視為備援候選,因為提供任何資源比擲回例外狀況更好。 此程式也可讓您重複使用資源。 只有在子文化特性不需要將要求的資源進行當地化時,才應在父層級包含特定資源。 例如,如果您提供衛星元件(
en中性英文)、en-GB(英國口語的英文),以及en-US(在美國說出的英文),en則衛星包含通用術語,而en-GB和en-US衛星只提供不同詞彙的覆寫。每個文化都只有一個由CultureInfo.Parent屬性定義的父文化,但該父文化可能會有自己的父文化。 當文化的Parent屬性傳回CultureInfo.InvariantCulture時,父文化的搜尋會停止。 針對資源回退,不變文化不會被視為父文化或具有資源的文化。
如果原本指定的文化特性和所有父系都已搜尋,而且仍然找不到資源,則會使用預設 (後援) 文化特性的資源。 通常,主要應用程式組件中會包含預設文化特性的資源。 不過,您可以為 屬性指定 值SatelliteLocation,指出資源的最終後援位置是附屬元件,而不是主要元件。
備註
默認資源是唯一可使用主要元件編譯的資源。 除非您使用 NeutralResourcesLanguageAttribute 屬性指定衛星組件,否則它是最終的後備選項(最後的父級)。 因此,建議您一律在主要元件中包含一組默認資源。 這樣有助於防止擲回例外狀況。 藉由包含預設資源檔,您可以為所有資源提供備援,並確保使用者始終至少有一個資源存在,即使它不具文化特性。
最後,如果執行階段找不到預設(後援)文化特性所需的資源檔,將擲回 MissingManifestResourceException 或 MissingSatelliteAssemblyException 的例外狀況,表示資源無法找到。 如果找到資源檔案,但要求的資源不存在,則要求會傳
null回 。
最終備援衛星元件
您可以選擇性地從主要元件移除資源,並指定執行階段應從對應特定文化特性的附屬元件載入最終備援資源。 若要控制後援程式,您可以使用 建 NeutralResourcesLanguageAttribute(String, UltimateResourceFallbackLocation) 構函式並提供 參數的值 UltimateResourceFallbackLocation ,指定 Resource Manager 應該從主要元件或附屬元件擷取後援資源。
下列 .NET Framework 範例會使用 NeutralResourcesLanguageAttribute 屬性,將應用程式的後援資源儲存在法文 (fr) 語言的附屬元件中。 此範例有兩個以文字為基礎的資源檔,可定義名為 Greeting的單一字串資源。 第一個 resources.fr.txt,包含法文語言資源。
Greeting=Bon jour!
第二個資源ru.txt包含俄文語言資源。
Greeting=Добрый день
這兩個檔案會從命令行執行 資源檔產生器 (resgen.exe) ,編譯成 .resources 檔案。 針對法文語言資源,此命令為:
resgen.exe resources.fr.txt
針對俄文語言資源,此命令為:
resgen.exe resources.ru.txt
.resources 檔案會通過在命令行中執行 Assembly Linker (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 的檔案中。 它包含 NeutralResourcesLanguageAttribute 屬性,指出預設應用程式資源位於fr子目錄中。 它會具現化 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!
建議的封裝替代方案
時間或預算限制可能會讓您無法為應用程式支援的每個子文化特性建立一組資源。 相反地,您可以為主文化建立一個單一的衛星組件,供所有相關子文化使用。 例如,您可以提供單一英文附屬元件(en),供要求區域特定英文資源的使用者所擷取,併為要求區域特定德文資源的使用者提供單一德文附屬元件(de)。 例如,德國(de-DE)、奧地利(de-AT)和瑞士(de-CH)的語言請求將回退至德語衛星程序集(de)。 默認資源是最終的後援,因此應該是大部分應用程式使用者將會要求的資源,因此請謹慎選擇這些資源。 這種方法會部署文化特性較低的資源,但可以大幅降低應用程式的當地語系化成本。