ASP.NET Core 全球化和當地語系化

Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya 提供

透過多語系網站,網站便能觸及更廣大的受眾。 ASP.NET Core 提供服務與中介軟體,可將網站當地語系化成不同的語言與文化特性。

詞彙

  • 全球化 (G11N):讓應用程式支援不同語言和區域的程序。 縮寫來自第一個和最後一個字母,以及這些字母之間的字母數目。
  • 當地語系化 (L10N):針對特定語言和區域自訂全球化應用程式的流程。
  • 國際化 (I18N):全球化和當地語系化這兩部分。
  • 文化:一種語言和 (選擇性的) 區域。
  • 中性文化特性:具有指定的語言但不限地區的文化特性 (例如,「en」、「es」)。
  • 特定文化特性:具有指定語言和區域的文化特性 (例如,「en-US」、「en-GB」、「es-CL」)。
  • 父文化特性:包含特定文化特性的中性文化特性 (例如,「en」是「en-US」和「en-GB」的父文化特性)。
  • 地區設定:地區設定與文化特性相同。

語言和國家/地區字碼

文化特性名稱的 RFC 4646 格式為 <language code>-<country/region code>,其中 <language code> 會識別語言,而 <country/region code> 會識別子文化特性。 例如,es-CL 是指西班牙文 (智利),en-US 是指英文 (美國),而 en-AU 是指英文 (澳大利亞)。 RFC 4646 是 ISO 639 (兩個小寫字母,為與某個語言建立關聯的文化特性代碼) 及 ISO 3166 (兩個大寫字母,為與某個國家或地區建立關聯的子文化特性代碼) 的組合。 如需詳細資訊,請參閱System.Globalization.CultureInfo

將應用程式當地語系化的工作

全球化和當地語系化應用程式牽涉到下列工作:

檢視或下載範例程式碼 \(英文\) (如何下載)

其他資源

Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya 提供

透過多語系網站,網站便能觸及更廣大的受眾。 ASP.NET Core 提供服務與中介軟體,可將網站當地語系化成不同的語言與文化特性。

詞彙

  • 全球化 (G11N):讓應用程式支援不同語言和區域的程序。 縮寫來自第一個和最後一個字母,以及這些字母之間的字母數目。
  • 當地語系化 (L10N):針對特定語言和區域自訂全球化應用程式的流程。
  • 國際化 (I18N):全球化和當地語系化這兩部分。
  • 文化:一種語言和 (選擇性的) 區域。
  • 中性文化特性:具有指定的語言但不限地區的文化特性 (例如,「en」、「es」)。
  • 特定文化特性:具有指定語言和區域的文化特性 (例如,「en-US」、「en-GB」、「es-CL」)。
  • 父文化特性:包含特定文化特性的中性文化特性 (例如,「en」是「en-US」和「en-GB」的父文化特性)。
  • 地區設定:地區設定與文化特性相同。

語言和國家/地區字碼

文化特性名稱的 RFC 4646 格式為 <language code>-<country/region code>,其中 <language code> 會識別語言,而 <country/region code> 會識別子文化特性。 例如,es-CL 是指西班牙文 (智利),en-US 是指英文 (美國),而 en-AU 是指英文 (澳大利亞)。 RFC 4646 是 ISO 639 (兩個小寫字母,為與某個語言建立關聯的文化特性代碼) 及 ISO 3166 (兩個大寫字母,為與某個國家或地區建立關聯的子文化特性代碼) 的組合。 如需詳細資訊,請參閱System.Globalization.CultureInfo

將應用程式當地語系化的工作

全球化和當地語系化應用程式牽涉到下列工作:

檢視或下載範例程式碼 \(英文\) (如何下載)

其他資源

Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya 提供

透過多語系網站,網站便能觸及更廣大的受眾。 ASP.NET Core 提供服務與中介軟體,可將網站當地語系化成不同的語言與文化特性。

國際化涉及 System.Globalization當地語系化。 全球化是指設計出可支援不同文化特性之應用程式的程序。 透過全球化,您可新增支援與特定地區相關之已定義語言指令碼的輸入、顯示及輸出作業。

當地語系化是指針對全球化應用程式進行調整的程序,且您已順應特定文化特性/地區設定對這些全球化應用程式進行可當地語系化處理。 如需詳細資訊,請參閱本文件結尾處的全球化和當地語系化詞彙

應用程式當地語系化包含下列作業:

  1. 讓應用程式的內容可當地語系化
  2. 針對您支援的語言和文化特性提供當地語系化資源
  3. 實作可依據每項要求選取語言/文化特性的策略

檢視或下載範例程式碼 \(英文\) (如何下載)

讓應用程式的內容可當地語系化

IStringLocalizerIStringLocalizer<T> 的設計用意是,提高開發當地語系化應用程式時的生產力。 IStringLocalizer 會使用 ResourceManagerResourceReader,在執行階段提供特定文化特性的資源。 這個介面具有的索引子和 IEnumerable 可傳回當地語系化字串。 IStringLocalizer 不需要您將預設語言字串儲存在資源檔中。 您不必在開發初期建立資源檔,即可開發以當地語系化為目標的應用程式。 下列程式碼會示範如何包裝 "About Title" 字串以進行當地語系化。

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

在上述程式碼中,IStringLocalizer<T> 實作是來自相依性插入。 如果找不到 "About Title" 的當地語系化值,即會傳回索引子的索引鍵,也就是 "About Title" 字串。 您可以保留應用程式中的預設語言常值字串,並將其包裝在當地語系化工具中,以便專注於開發應用程式。 您不用先建立預設資源檔,即可使用預設語言來開發應用程式,並針對當地語系化步驟進行應用程式的準備。 或者,您可以使用傳統方法,並提供索引鍵以擷取預設語言字串。 對許多開發人員來說,新的工作流程 (單純包裝字串常值而不使用預設語言的 .resx 檔案) 可以降低當地語系化應用程式的額外負荷。 其他開發人員則偏好傳統的工作流程,因為這種方法更便於使用較長的字串常值,且更易於更新當地語系化的字串。

若是包含 HTML 的資源,請使用 IHtmlLocalizer<T> 實作。 IHtmlLocalizer 會對資源字串中經過格式化的引數進行 HTML 編碼,但不會對資源字串本身進行 HTML 編碼。 在下列醒目提示的範例中,只有 name 參數的值經過 HTML 編碼。

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers
{
    public class BookController : Controller
    {
        private readonly IHtmlLocalizer<BookController> _localizer;

        public BookController(IHtmlLocalizer<BookController> localizer)
        {
            _localizer = localizer;
        }

        public IActionResult Hello(string name)
        {
            ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

            return View();
        }

注意

一般而言,只會將文字當地語系化,而不是 HTML。

您可以在最底層的相依性插入中,將 IStringLocalizerFactory 移出:

{
    public class TestController : Controller
    {
        private readonly IStringLocalizer _localizer;
        private readonly IStringLocalizer _localizer2;

        public TestController(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(type);
            _localizer2 = factory.Create("SharedResource", assemblyName.Name);
        }       

        public IActionResult About()
        {
            ViewData["Message"] = _localizer["Your application description page."] 
                + " loc 2: " + _localizer2["Your application description page."];

上述程式碼會示範這兩個 Factory Create 方法。

您可以依據控制器或區域來分割當地語系化的字串,也可以只用一個容器。 在範例應用程式中,會針對共用資源使用名為 SharedResource 的虛擬類別。

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

有些開發人員會使用 Startup 類別來包含全域或共用字串。 下列範例會使用 InfoControllerSharedResource 當地語系化工具:

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

檢視當地語系化

IViewLocalizer 服務可提供檢視的當地語系化字串。 ViewLocalizer 類別會實作這個介面,並透過檢視檔案路徑來找出資源的位置。 下列程式碼示範如何使用 IViewLocalizer 的預設實作:

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

IViewLocalizer 的預設實作會依據檢視的檔案名稱來找出資源檔。 其中並沒有任何選項可以使用全域共用的資源檔。 ViewLocalizer 會使用 IHtmlLocalizer 來實作當地語系化工具,因此 Razor 不會對當地語系化的字串進行 HTML 編碼。 您可以參數化資源字串,IViewLocalizer 即會對參數 (而不是資源字串) 進行 HTML 編碼。 請考慮下列 Razor 標記:

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

法文資源檔可能包含下列內容:

Key
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

轉譯的檢視內容可能包含來自資源檔的 HTML 標記。

注意

一般而言,只會將文字當地語系化,而不是 HTML。

若要在檢視中使用共用的資源檔,請插入 IHtmlLocalizer<T>

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

DataAnnotations 當地語系化

DataAnnotations 錯誤訊息會使用 IStringLocalizer<T> 來當地語系化。 使用 ResourcesPath = "Resources" 選項時,RegisterViewModel 中的錯誤訊息會儲存在下列路徑之一:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

無驗證屬性已當地語系化。

針對多個類別使用同一個資源字串

下列程式碼會示範如何針對含有多個類別的驗證屬性使用同一個資源字串:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

在先前的程式碼中,SharedResource 是與儲存驗證訊息的 resx 對應的類別。 使用這個方法時,DataAnnotations 只會使用 SharedResource,而不是每個類別的資源。

針對您支援的語言和文化特性提供當地語系化資源

SupportedCultures 和 SupportedUICultures

ASP.NET Core 可讓您指定 SupportedCulturesSupportedUICultures 這兩個文化特性值。 SupportedCultures 物件的 CultureInfo 可決定文化特性相依函式的結果,例如日期、時間、數字及貨幣格式。 SupportedCultures 也可決定文字排列順序、大小寫慣例和字串比較。 如需伺服器如何取得文化特性的詳細資訊,請參閱 CultureInfo.CurrentCultureCultureInfo.CurrentUICultureSupportedUICultures 可決定 ResourceManager 要查閱哪些翻譯的字串 (來自 .resx 檔案)。 ResourceManager 會查閱 CurrentUICulture 所決定的文化特性特有字串。 .NET 中的每個執行緒都有 CurrentCultureCurrentUICulture 物件。 此架構會在轉譯文化特性相依函式時檢查這些值。 如果目前對話的文化特性設定為 en-US (英文、北美洲),DateTime.Now.ToLongDateString() 則會顯示 Thursday, February 18, 2016;但如果將 CurrentCulture 設定為 es-ES (西班牙文、西班牙),則輸出為 jueves, 18 de febrero de 2016

資源檔

資源檔是一種實用的機制,可讓您將可當地語系化的字串與代碼區隔開來。 非預設語言的翻譯字串會在 .resx 資源檔中隔離。 例如,您可以建立名為 Welcome.es.resx 的西班牙文資源檔,以包含翻譯的字串。 "es" 是西班牙文的語言代碼。 若要在 Visual Studio 中建立這個資源檔:

  1. 在 [方案總管] 中,以滑鼠右鍵按一下要包含資源檔的資料夾 > [新增]> [新增項目]

    巢狀特色選單:方案總管會開啟 [資源] 的特色選單,接著針對 [新增] 開啟第二個特色選單,並反白顯示 [新增項目] 命令。

  2. 在 [Search installed templates] (搜尋已安裝的範本) 方塊中,輸入「資源」,並命名檔案。

    [新增項目] 對話方塊

  3. 在 [名稱] 資料行中輸入索引鍵值 (原生字串),並在 [值] 資料行中輸入已翻譯的字串。

    Welcome.es.resx 檔案 (西班牙文的「歡迎使用」資源檔),其中 [名稱] 資料行的文字為 Hello,而 [值] 資料行的文字為 Hola (Hello 的西班牙文)

    Visual Studio 會顯示 Welcome.es.resx 檔案。

    方案總管,其中顯示「歡迎使用」的西班牙文 (es) 資源檔

資源檔命名

資源的命名方式是以其類別的完整類型名稱去掉組件名稱而得。 例如,假設專案中的法文資源是 LocalizationWebsite.Web.Startup 類別、主要組件為 LocalizationWebsite.Web.dll,就會命名為 Startup.fr.resxLocalizationWebsite.Web.Controllers.HomeController 類別的資源會命名為 Controllers.HomeController.fr.resx。 如果目標類別的命名空間和組件名稱不相同,則需要使用完整類型名稱。 比方說,範例專案中 ExtraNamespace.Tools 類型的資源會命名為 ExtraNamespace.Tools.fr.resx

在範例專案中,ConfigureServices 方法會將 ResourcesPath 設為 "Resources",因此首頁控制器的法文資源檔專案相對路徑即為 Resources/Controllers.HomeController.fr.resx。 或者,您可以使用資料夾來收集資源檔。 若為首頁控制器,路徑會是 Resources/Controllers/HomeController.fr.resx。 如果您不使用 ResourcesPath 選項,.resx 檔案即會放置在專案的基底目錄中。 HomeController 的資源檔會命名為 Controllers.HomeController.fr.resx。 您可依據自己的資源檔收集方式,來選擇要使用點或路徑的命名慣例。

資源名稱 點或路徑命名
Resources/Controllers.HomeController.fr.resx
Resources/Controllers/HomeController.fr.resx 路徑

在 Razor 檢視中使用 @inject IViewLocalizer 的資源檔會遵循類似的模式。 您可以使用點命名或路徑命名方式,來命名檢視的資源檔。 Razor 檢視的資源檔會模仿其相關聯檢視檔案的路徑。 假設我們將 ResourcesPath 設為 "Resources",與 Views/Home/About.cshtml 檢視建立關聯的法文資源檔可為下列其一:

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

如果您不使用 ResourcesPath 選項,則檢視的 .resx 檔案會與檢視位於相同資料夾中。

RootNamespaceAttribute

RootNamespaceAttribute 屬性會在組件的根命名空間與組件名稱不同時,提供組件的根命名空間。

警告

若專案名稱不是有效的 .NET 識別碼,就會發生這種情況。 例如,my-project-name.csproj 會使用根命名空間 my_project_name 和組件名稱 my-project-name,因而導致此錯誤。

如果組件的根命名空間與組件名稱不同:

  • 根據預設,當地語系化無法運作。
  • 在組件中搜尋資源的方式造成當地語系化失敗。 RootNamespace 是建置時間值,無法用於執行處理序。

如果 RootNamespaceAssemblyName 不同,請將下列內容納入 AssemblyInfo.cs (參數值取代為實際值):

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

上述程式碼可成功解析 resx 檔案。

文化特性後援行為

搜尋資源時,當地語系化會使用「文化特性後援」。 從所要求的文化特性開始,如果找不到,就會還原成該文化特性的父文化特性。 另外,CultureInfo.Parent 屬性代表父文化特性。 這通常 (但並非一定) 表示從 ISO 中移除國家意符 (Signifier)。 例如,墨西哥的西班牙文方言是 "es-MX"。 它具有父系 "es" — 西班牙文不是任何國家/地區的特定項目。

假設您的網站收到使用文化特性 "fr-CA" 之 "Welcome" 資源的要求。 當地語系化系統會依照順序尋找下列資源,並選取第一個相符項目:

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (如果 NeutralResourcesLanguage 是 "fr-CA")

舉例來說,如果您移除 ".fr" 文化特性指示項,並將文化特性設定為法文,則系統會讀取預設資源檔,並將字串當地語系化。 當沒有任何項目符合您要求的文化特性時,資源管理員即會指定預設資源或後援資源。 如果您只想在要求的文化特性缺少資源時傳回索引鍵,就不能使用預設資源檔。

使用 Visual Studio 產生資源檔

如果您在 Visual Studio 中建立資源檔,但檔案名稱中不含文化特性 (例如 Welcome.resx),則 Visual Studio 會針對每個字串的屬性建立 C# 類別。 但這通常不是您使用 ASP.NET Core 的初衷。 一般來說,您不會有預設的 .resx 資源檔 (不含文化特性名稱的 .resx 檔案)。 因此,建議您建立含有文化特性名稱的 .resx 檔案 (例如 Welcome.fr.resx)。 當您建立含有文化特性名稱的 .resx 檔案時,Visual Studio 就不會產生類別檔案。

新增其他文化特性

每種語言和文化特性的組合 (非預設語言) 都需要唯一的資源檔。 若要建立不同文化特性和地區設定的資源檔,您可以建立新的資源檔並將 ISO 語言代碼作為檔名的一部分 (例如 en-usfr-caen-gb)。 您應將 ISO 代碼置於檔案名稱和 .resx 副檔名之間,例如 Welcome.es-MX.resx (西班牙文/墨西哥)。

實作可依據每項要求選取語言/文化特性的策略

設定當地語系化

您可以在 Startup.ConfigureServices 方法中設定當地語系化:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization 可將當地語系化服務新增至服務容器。 上方的程式碼也會將資源路徑設為 "Resources"。

  • AddViewLocalization 可支援當地語系化的檢視檔案。 在此範例中,檢視的當地語系化會以檢視檔案的後置詞為依據。 例如 Index.fr.cshtml 檔案中的「fr」。

  • AddDataAnnotationsLocalization 可支援透過 IStringLocalizer 抽象概念而來的當地語系化 DataAnnotations 驗證訊息。

當地語系化中介軟體

您可以在當地語系化中介軟體中,設定要求目前的文化特性。 已在 Startup.Configure 方法中啟用當地語系化中介軟體。 您必須在可能檢查要求文化特性的任何中介軟體之前,設定當地語系化中介軟體 (例如 app.UseMvcWithDefaultRoute())。 如果使用 RouteDataRequestCultureProvider,則當地語系化中介軟體必須出現在路由中介軟體之後。 如需中介軟體順序的詳細資訊,請參閱 ASP.NET Core 中介軟體

var supportedCultures = new[] { "en-US", "fr" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

如果您想要查看翻譯為英文以外語言的程式碼註解,請在此 GitHub 討論問題中告訴我們。

UseRequestLocalization 會初始化 RequestLocalizationOptions 物件。 在每次要求時,系統會列舉 RequestLocalizationOptions 中的 RequestCultureProvider 清單,並使用能成功判斷要求的文化特性的第一個提供者。 預設的提供者是來自 RequestLocalizationOptions 類別:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

預設清單會由針對性高到低來排列。 在本文稍後,我們會說明如何變更順序,甚至新增自訂的文化特性提供者。 如果沒有任何提供者可以判斷要求的文化特性,即會使用 DefaultRequestCulture

QueryStringRequestCultureProvider

某些應用程式會使用查詢字串來設定 CultureInfo。 若是使用 cookie 或 Accept-Language 標頭方法的應用程式,您可以將查詢字串新增至 URL 以偵錯和測試程式碼。 系統預設會將 QueryStringRequestCultureProvider 登錄為 RequestCultureProvider 清單中的第一個當地語系化提供者。 您應傳遞查詢字串參數 cultureui-culture。 下列範例會設定西班牙文/墨西哥的特定文化特性 (語言和地區):

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

如果您只傳入兩者其一 (cultureui-culture),查詢字串提供者就會使用您傳入的項目來設定這兩個值。 例如,若只設定文化特性,即會同時設定 CultureUICulture

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

生產環境應用程式通常會提供一個機制,來設定 ASP.NET Core 文化特性 cookie 的文化特性。 使用 MakeCookieValue 方法來建立 cookie。

CookieRequestCultureProviderDefaultCookieName 會傳回預設 cookie 名稱,以用來追蹤使用者的慣用文化特性資訊。 預設 cookie 名稱為 .AspNetCore.Culture

cookie 格式為 c=%LANGCODE%|uic=%LANGCODE%,其中 cCulture,而 uicUICulture,例如:

c=en-UK|uic=en-US

如果您只指定文化特性資訊和 UI 文化特性其一,系統就會將您所指定的文化特性用於文化特性資訊和 UI 文化特性。

Accept-Language HTTP 標頭

您可在大多數的瀏覽器中設定 Accept-Language 標頭,其最初的設計目的是用來指定使用者的語言。 這項設定可指出瀏覽器已設好要傳送哪些項目,或已從基礎作業系統繼承哪些項目。 透過瀏覽器要求的 Accept-Language HTTP 標頭來偵測使用者的慣用語言,並非萬無一失 (請參閱 Setting language preferences in a browser (在瀏覽器中設定語言喜好設定)。 生產環境應用程式應該包含可讓使用者自訂文化特性的選擇方式。

在 IE 中設定 Accept-Language HTTP 標頭

  1. 從齒輪圖示,點選 [網際網路選項]

  2. 點選 [語言]

    網際網路選項

  3. 點選 [設定語言喜好設定]

  4. 點選 [新增語言]

  5. 新增語言。

  6. 點選語言,然後點選 [上移]

使用自訂提供者

假設您想要讓客戶將他們的語言和文化特性儲存在您的資料庫中。 您可以撰寫提供者,以供使用者查詢這些值。 下列程式碼會示範如何新增自訂提供者:

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return await Task.FromResult(new ProviderCultureResult("en"));
    }));
});

使用 RequestLocalizationOptions 新增或移除當地語系化提供者。

變更要求文化特性提供者順序

RequestLocalizationOptions 有三個預設要求文化特性提供者:QueryStringRequestCultureProviderCookieRequestCultureProviderAcceptLanguageHeaderRequestCultureProvider。 如下所示,使用 [RequestLocalizationOptions.RequestCultureProviders] (xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.RequestCultureProviders) 屬性來變更這些提供者的順序:

    app.UseRequestLocalization(options =>
    {
        var questStringCultureProvider = options.RequestCultureProviders[0];    
        options.RequestCultureProviders.RemoveAt(0);
        options.RequestCultureProviders.Insert(1, questStringCultureProvider);
    });

在上述範例中,會切換 QueryStringRequestCultureProviderCookieRequestCultureProvider 的順序,因此 RequestLocalizationMiddleware 會先從 cookie 尋找文化特性,然後是查詢字串。

如先前所述,透過 AddInitialRequestCultureProvider 新增自訂提供者,以將順序設定為 0,因此此提供者的優先順序會高於其他提供者。

以程式設計方式來設定文化特性

GitHub 上的這個範例 Localization.StarterWeb 專案包含可設定 Culture 的 UI。 Views/Shared/_SelectLanguagePartial.cshtml 檔案可讓您從支援的文化特性清單中選取文化特性:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

Views/Shared/_SelectLanguagePartial.cshtml 檔案會新增至 footer 版面配置檔案的 區段,以便將其供所有檢視使用:

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

SetLanguage 方法會設定文化特性的 cookie。

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

您無法將 _SelectLanguagePartial.cshtml 插入此專案的範例程式碼。 GitHub 上的 Localization.StarterWeb 專案,其中的程式碼會部分透過相依性插入容器將 RequestLocalizationOptions 流向 Razor。

模型繫結會路由資料和查詢字串

請參閱模型繫結路由資料和查詢字串的全球化行為

全球化和當地語系化詞彙

在進行應用程式的當地語系化程序時,您也需要具備現代軟體開發中常用的相關字元集基本知識,並了解與它們建立關聯的問題。 雖然所有電腦都會將文字儲存為數字 (程式碼),但不同系統會使用不同數字來儲存相同的文字。 當地語系化是指針對特定文化特性/地區設定,轉譯應用程式使用者介面 (UI) 的程序。

可當地語系化是確認全球化應用程式已準備好進行當地語系化的中繼程序。

文化特性名稱的 RFC 4646 格式是 <languagecode2>-<country/regioncode2>,其中 <languagecode2> 是語言代碼,而 <country/regioncode2> 是子文化特性代碼。 例如,es-CL 是指西班牙文 (智利),en-US 是指英文 (美國),而 en-AU 是指英文 (澳大利亞)。 RFC 4646 是 ISO 639 (兩個小寫字母,為與某個語言建立關聯的文化特性代碼) 及 ISO 3166 (兩個大寫字母,為與某個國家或地區建立關聯的子文化特性代碼) 的組合。 如需詳細資訊,請參閱System.Globalization.CultureInfo

國際化通常縮寫為 "I18N"。 這個縮寫是採用該詞彙的第一個和最後一個字母,以及這兩個字母間的字母數組成,因此 18 代表第一個字母 "I" 及最後 "N" 中間的字母數。 同樣的原則也適用於全球化 (G11N) 與當地語系化 (L10N) 的縮寫。

詞彙:

  • 全球化 (G11N):讓應用程式支援不同語言和區域的程序。
  • 當地語系化 (L10N):針對特定語言和區域,自訂應用程式的程序。
  • 國際化 (I18N):包含全球化和當地語系化這兩部分的描述。
  • 文化特性:它是一種語言和/或地區。
  • 中性文化特性:具有指定的語言但不限地區的文化特性 (例如 "en"、"es")。
  • 特定文化特性:具有指定的語言和地區的文化特性 (例如 "en-US"、"en-GB"、"es-CL")。
  • 父文化特性:包含特定文化特性的中性文化特性 (例如,"en" 是 "en-US" 和 "en-GB" 的父文化特性)。
  • 地區設定:地區設定與文化特性相同。

注意

您可能無法在小數欄位中輸入小數逗號。 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。 請參閱此 GitHub 問題 4076 \(英文\),以取得加入十進位逗號的指示。

注意

在 ASP.NET Core 3.0 Web 應用程式之前,如果不支援要求的文化特性,則為每個要求寫入一種 LogLevel.Warning 記錄類型。 每個要求記錄一個 LogLevel.Warning 記錄,可以產生具有備援資訊的大型記錄檔。 ASP.NET 3.0 中此行為已有所變更。 RequestLocalizationMiddleware 會寫入 LogLevel.Debug 類型的記錄,以減少生產記錄的大小。

其他資源