共用方式為


.NET 中的當地語系化

在地化是將應用程式的資源轉譯為應用程式所支援之每個文化的在地化版本的過程。 只有在完成 當地語系化能力檢閱 步驟之後,您才能繼續進行當地語系化步驟,以確認全球化應用程式已準備好進行當地語系化。

準備好進行本地化的應用程式會分成兩個概念區塊:包含所有使用者介面元素的區塊,以及包含可執行程式碼的區塊。 使用者介面區塊只包含可本地化的使用者介面元素,例如字串、錯誤訊息、對話框、功能表、內嵌物件資源等等,以取得中性文化特性。 程式代碼區塊只包含所有支持的文化使用的應用程式代碼。 Common Language Runtime 支援衛星組件資源模型,以分隔應用程式的可執行程式代碼與其資源。 如需實作此模型的詳細資訊,請參閱 .NET 中的資源

針對應用程式的每個在地化版本,新增附屬元件,其中包含翻譯為目標文化特性的適當語言的在地化使用者介面區塊。 所有文化特性的程式代碼區塊都應該維持不變。 使用者介面區塊的當地語系化版本與程式碼區塊的組合會產生應用程式的當地語系化版本。

在本文中,您將瞭解如何使用 IStringLocalizer<T>IStringLocalizerFactory 實作。 本文中的所有範例原始程式碼都依賴 Microsoft.Extensions.LocalizationMicrosoft.Extensions.Hosting NuGet 套件。 如需主機托管的詳細資訊,請參閱 .NET 泛型主機

資源檔

隔離可當地語系化字串的主要機制是使用 資源檔。 資源檔是擴展名為 .resx 的 XML 檔案。 資源檔會在執行取用的應用程式之前翻譯,換句話說,它們代表待用的翻譯內容。 資源檔案名稱最常包含地區設定識別碼,並採用下列格式:

<FullTypeName><.Locale>.resx

地點:

  • <FullTypeName>表示特定型別的可當地語系化資源。
  • 選擇性 <.Locale> 表示資源文件內容的地區設定。

指定地區設定

地區設定應該至少定義語言,但它也可以定義文化(地區語言),甚至是國家或地區。 這些區段通常以 - 字元分隔。 根據文化具體的增加,會套用「文化回退」規則,其中優先選擇最佳匹配。 地區設定應該對應至已知的語言標籤。 如需詳細資訊,請參閱CultureInfo.Name

文化備援方案

假設您的本地化應用程式支援各種塞爾維亞地區設定,且其 MessageService具有下列資源檔:

檔案 地區語言 國碼 (地區碼)
MessageService.sr-Cyrl-RS.resx (西里爾字母,塞爾維亞) RS
MessageService.sr-Cyrl.resx 西里爾
MessageService.sr-Latn-BA.resx (拉丁,波士尼亞與赫塞哥維納) 文学士
MessageService.sr-Latn-ME.resx (拉丁,黑山)
MessageService.sr-Latn-RS.resx (拉丁,塞爾維亞) RS
MessageService.sr-Latn.resx 拉丁語
MessageService.sr.resx 拉丁語
MessageService.resx

語言的預設區域語言。

當您的應用程式以 CultureInfo.CurrentCulture 設定為本地化文化特性 "sr-Cyrl-RS" 執行時,會依下列順序嘗試解析檔案:

  1. MessageService.sr-Cyrl-RS.resx
  2. MessageService.sr-Cyrl.resx
  3. MessageService.sr.resx
  4. MessageService.resx

不過,如果應用程式執行時,將 CultureInfo.CurrentCulture 設定為 "sr-Latn-BA" 的文化特性,則會依下列順序嘗試解析檔案:

  1. MessageService.sr-Latn-BA.resx
  2. MessageService.sr-Latn.resx
  3. MessageService.sr.resx
  4. MessageService.resx

當沒有任何對應的相符專案時,「文化特性後援」規則會忽略地區設定,這表示如果找不到相符專案,則會選取資源文件編號 4。 如果文化特性設定為 "fr-FR",當地語系化最終會落到 MessageService.resx 檔案,這可能會造成問題。 如需詳細資訊,請參閱 資源後援程式

資源查閱

作為查找例程的一部分,資源文件會自動解析。 如果您的項目檔名稱與專案的根命名空間不同,元件名稱可能會不同。 這可以防止資源查閱在其他情況下成功。 若要解決此不相符的問題,請使用 RootNamespaceAttribute 來提供當地語系化服務的提示。 當提供時,它會在資源查找過程中使用。

此範例專案名為 example.csproj,它會建立 example.dllexample.exe,不過會 Localization.Example 使用 命名空間。 assembly套用層級屬性以更正此不符:

[assembly: RootNamespace("Localization.Example")]

註冊本地化服務

若要註冊當地語系化服務,請在 AddLocalization 服務設定期間呼叫其中一個擴充方法。 這會開啟下列型態的相依性插入 (DI) :

設定當地語系化選項

AddLocalization(IServiceCollection, Action<LocalizationOptions>) 重載接受一個類型為 setupActionAction<LocalizationOptions> 參數。 這可讓您設定當地語系化選項。

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddLocalization(options =>
{
    options.ResourcesPath = "Resources";
});

// Omitted for brevity.

資源檔可以存在於專案中的任何地方,但有一些已證明成功的做法。 通常而言,人們會選擇阻力最小的路徑。 上述 C# 程式代碼:

這會導致當地語系化服務在 資源 檔的資源目錄中尋找。

使用 IStringLocalizer<T>IStringLocalizerFactory

註冊(可選擇性進行配置)本地化服務之後,您可以搭配 DI 使用下列類型:

若要建立能夠傳回本地化字串的訊息服務,請考慮下列事項 MessageService

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;

namespace Localization.Example;

public sealed class MessageService(IStringLocalizer<MessageService> localizer)
{
    [return: NotNullIfNotNull(nameof(localizer))]
    public string? GetGreetingMessage()
    {
        LocalizedString localizedString = localizer["GreetingMessage"];

        return localizedString;
    }
}

在上述 C# 程式碼中:

  • 欄位已宣告IStringLocalizer<MessageService> localizer
  • 主要建構函式定義IStringLocalizer<MessageService> 參數,並將其作為localizer 參數來使用。
  • GetGreetingMessage 方法會呼叫 IStringLocalizer.Item[String],並將 "GreetingMessage" 作為參數傳遞。

IStringLocalizer也支持參數化字串資源,請考慮下列事項ParameterizedMessageService

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;

namespace Localization.Example;

public class ParameterizedMessageService(IStringLocalizerFactory factory)
{
    private readonly IStringLocalizer _localizer =
        factory.Create(typeof(ParameterizedMessageService));

    [return: NotNullIfNotNull(nameof(_localizer))]
    public string? GetFormattedMessage(DateTime dateTime, double dinnerPrice)
    {
        LocalizedString localizedString = _localizer["DinnerPriceFormat", dateTime, dinnerPrice];

        return localizedString;
    }
}

在上述 C# 程式碼中:

  • 欄位已宣告IStringLocalizer _localizer
  • 主要建構函式會採用IStringLocalizerFactory參數,用來從IStringLocalizer類型建立 ParameterizedMessageService ,並將它指派給 _localizer 字段。
  • 方法 GetFormattedMessage 會調用 IStringLocalizer.Item[String, Object[]],並傳遞 "DinnerPriceFormat"dateTime 物件及 dinnerPrice 作為參數。

這很重要

IStringLocalizerFactory 不需要。 相反地,建議取用服務需要IStringLocalizer<T>

兩個IStringLocalizer.Item[]索引器都會回傳LocalizedString,它們具有隱含轉換string?

把所有東西放在一起

若要使用這兩個訊息服務以及當地語系化和資源檔來示範應用程式,請考慮下列 Program.cs 檔案:

using System.Globalization;
using Localization.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using static System.Console;
using static System.Text.Encoding;

[assembly: RootNamespace("Localization.Example")]

OutputEncoding = Unicode;

if (args is [var cultureName])
{
    CultureInfo.CurrentCulture =
        CultureInfo.CurrentUICulture =
            CultureInfo.GetCultureInfo(cultureName);
}

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddLocalization();
builder.Services.AddTransient<MessageService>();
builder.Services.AddTransient<ParameterizedMessageService>();
builder.Logging.SetMinimumLevel(LogLevel.Warning);

using IHost host = builder.Build();

IServiceProvider services = host.Services;

ILogger logger =
    services.GetRequiredService<ILoggerFactory>()
        .CreateLogger("Localization.Example");

MessageService messageService =
    services.GetRequiredService<MessageService>();
logger.LogWarning(
    "{Msg}",
    messageService.GetGreetingMessage());

ParameterizedMessageService parameterizedMessageService =
    services.GetRequiredService<ParameterizedMessageService>();
logger.LogWarning(
    "{Msg}",
    parameterizedMessageService.GetFormattedMessage(
        DateTime.Today.AddDays(-3), 37.63));

await host.RunAsync();

在上述 C# 程式碼中:

*MessageService每個類別都會定義一組 .resx 檔案,每個檔案都有單一項目。 以下是從 MessageService 開始的資源文件範例內容

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Hi friends, the ".NET" developer community is excited to see you here!</value>
  </data>
</root>

MessageService.sr-Cyrl-RS.resx

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!</value>
  </data>
</root>

MessageService.sr-Latn.resx

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!</value>
  </data>
</root>

以下是資源文件的範例內容 ParameterizedMessageService ,從 ParameterizedMessageService.resx 開始:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>On {0:D} my dinner cost {1:C}.</value>
  </data>
</root>

ParameterizedMessageService.sr-Cyrl-RS.resx

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>У {0:D} моја вечера је коштала {1:C}.</value>
  </data>
</root>

ParameterizedMessageService.sr-Latn.resx

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>U {0:D} moja večera je koštala {1:C}.</value>
  </data>
</root>

小提示

為了簡潔起見,會刻意省略所有資源檔 XML 批注、架構和 <resheader> 元素。

範例運行

下列範例執行結果顯示針對目標地區的各種當地語系化結果。

請考慮 "sr-Latn"

dotnet run --project .\example\example.csproj sr-Latn

warn: Localization.Example[0]
      Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!
warn: Localization.Example[0]
      U utorak, 03. avgust 2021. moja večera je koštala 37,63 ¤.

省略 .NET CLI 的參數以執行 專案時,會使用預設的系統文化,此案例 "en-US"中的語言文化為:

dotnet run --project .\example\example.csproj

warn: Localization.Example[0]
      Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
      On Tuesday, August 3, 2021 my dinner cost $37.63.

傳遞 "sr-Cryl-RS"時,找到正確的對應資源檔,並套用當地語系化:

dotnet run --project .\example\example.csproj sr-Cryl-RS

warn: Localization.Example[0]
      Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!
warn: Localization.Example[0]
      У уторак, 03. август 2021. моја вечера је коштала 38 RSD.

範例應用程式不提供 "fr-CA" 的資源檔,但在使用該文化特性呼叫時,將使用非本地化的資源檔。

警告

由於找到文化,但未找到正確的資源檔,因此套用格式時,您會得到部分的當地化結果。

dotnet run --project .\example\example.csproj fr-CA

warn: Localization.Example[0]
     Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
     On mardi 3 août 2021 my dinner cost 37,63 $.

另請參閱