ASP.NET Core 全球化和當地語系化Globalization and localization in ASP.NET Core

Rick AndersonDamien BowdenBart CalixtoNadeem AfanaHisham Bin Ateya 提供By Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana, and Hisham Bin Ateya

使用 ASP.NET Core 建立多語系網站時,可讓更廣大的群眾使用您的網站。Creating a multilingual website with ASP.NET Core will allow your site to reach a wider audience. ASP.NET Core 提供服務與中介軟體,可將網站當地語系化成不同的語言與文化特性。ASP.NET Core provides services and middleware for localizing into different languages and cultures.

國際化包含全球化當地語系化這兩部分。Internationalization involves Globalization and Localization. 全球化是指設計出可支援不同文化特性之應用程式的程序。Globalization is the process of designing apps that support different cultures. 透過全球化,您可新增支援與特定地區相關之已定義語言指令碼的輸入、顯示及輸出作業。Globalization adds support for input, display, and output of a defined set of language scripts that relate to specific geographic areas.

當地語系化是指針對全球化應用程式進行調整的程序,且您已順應特定文化特性/地區設定對這些全球化應用程式進行可當地語系化處理。Localization is the process of adapting a globalized app, which you have already processed for localizability, to a particular culture/locale. 如需詳細資訊,請參閱本文件結尾處的全球化和當地語系化詞彙For more information see Globalization and localization terms near the end of this document.

應用程式當地語系化包含下列作業:App localization involves the following:

  1. 讓應用程式的內容可當地語系化Make the app's content localizable

  2. 針對您支援的語言和文化特性提供當地語系化資源Provide localized resources for the languages and cultures you support

  3. 實作可依據每項要求選取語言/文化特性的策略Implement a strategy to select the language/culture for each request

檢視或下載範例程式碼 (英文) (如何下載)View or download sample code (how to download)

讓應用程式的內容可當地語系化Make the app's content localizable

ASP.NET Core 中導入了 IStringLocalizerIStringLocalizer<T>,其設計用意是提高開發當地語系化應用程式時的生產力。Introduced in ASP.NET Core, IStringLocalizer and IStringLocalizer<T> were architected to improve productivity when developing localized apps. IStringLocalizer 會使用 ResourceManagerResourceReader,於執行階段時提供文化特性特有的資源。IStringLocalizer uses the ResourceManager and ResourceReader to provide culture-specific resources at run time. 這個簡單介面具有的索引子和 IEnumerable 可傳回當地語系化字串。The simple interface has an indexer and an IEnumerable for returning localized strings. IStringLocalizer 不需要您將預設語言字串儲存在資源檔中。IStringLocalizer doesn't require you to store the default language strings in a resource file. 您不必在開發初期建立資源檔,即可開發以當地語系化為目標的應用程式。You can develop an app targeted for localization and not need to create resource files early in development. 下列程式碼會示範如何包裝 "About Title" 字串以進行當地語系化。The code below shows how to wrap the string "About Title" for localization.

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> 實作是來自相依性插入In the code above, the IStringLocalizer<T> implementation comes from Dependency Injection. 如果找不到 "About Title" 的當地語系化值,即會傳回索引子的索引鍵,也就是 "About Title" 字串。If the localized value of "About Title" isn't found, then the indexer key is returned, that is, the string "About Title". 您可以保留應用程式中的預設語言常值字串,並將其包裝在當地語系化工具中,以便專注於開發應用程式。You can leave the default language literal strings in the app and wrap them in the localizer, so that you can focus on developing the app. 您不用先建立預設資源檔,即可使用預設語言來開發應用程式,並針對當地語系化步驟進行應用程式的準備。You develop your app with your default language and prepare it for the localization step without first creating a default resource file. 或者,您可以使用傳統方法,並提供索引鍵以擷取預設語言字串。Alternatively, you can use the traditional approach and provide a key to retrieve the default language string. 對許多開發人員來說,新的工作流程 (單純包裝字串常值而不使用預設語言的 .resx 檔案) 可以降低當地語系化應用程式的額外負荷。For many developers the new workflow of not having a default language .resx file and simply wrapping the string literals can reduce the overhead of localizing an app. 其他開發人員則偏好傳統的工作流程,因為這種方法更便於使用較長的字串常值,且更易於更新當地語系化的字串。Other developers will prefer the traditional work flow as it can make it easier to work with longer string literals and make it easier to update localized strings.

若是包含 HTML 的資源,請使用 IHtmlLocalizer<T> 實作。Use the IHtmlLocalizer<T> implementation for resources that contain HTML. IHtmlLocalizer 會對資源字串中經過格式化的引數進行 HTML 編碼,但不會對資源字串本身進行 HTML 編碼。IHtmlLocalizer HTML encodes arguments that are formatted in the resource string, but doesn't HTML encode the resource string itself. 在下列醒目提示的範例中,只有 name 參數的值經過 HTML 編碼。In the sample highlighted below, only the value of name parameter is HTML encoded.

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。Note: You generally want to only localize text and not HTML.

您可以在最底層的相依性插入中,將 IStringLocalizerFactory 移出:At the lowest level, you can get IStringLocalizerFactory out of Dependency Injection:

{
    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 方法。The code above demonstrates each of the two factory create methods.

您可以依據控制器或區域來分割當地語系化的字串,也可以只用一個容器。You can partition your localized strings by controller, area, or have just one container. 在範例應用程式中,會針對共用資源使用名為 SharedResource 的虛擬類別。In the sample app, a dummy class named SharedResource is used for shared resources.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

有些開發人員會使用 Startup 類別來包含全域或共用字串。Some developers use the Startup class to contain global or shared strings. 下列範例會使用 InfoControllerSharedResource 當地語系化工具:In the sample below, the InfoController and the SharedResource localizers are used:

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;
    }

檢視當地語系化View localization

IViewLocalizer 服務可提供檢視的當地語系化字串。The IViewLocalizer service provides localized strings for a view. ViewLocalizer 類別會實作這個介面,並透過檢視檔案路徑來找出資源的位置。The ViewLocalizer class implements this interface and finds the resource location from the view file path. 下列程式碼示範如何使用 IViewLocalizer 的預設實作:The following code shows how to use the default implementation of 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 的預設實作會依據檢視的檔案名稱來找出資源檔。The default implementation of IViewLocalizer finds the resource file based on the view's file name. 其中並沒有任何選項可以使用全域共用的資源檔。There's no option to use a global shared resource file. ViewLocalizer 會使用 IHtmlLocalizer 來實作當地語系化工具,因此 Razor 不會對當地語系化的字串進行 HTML 編碼。ViewLocalizer implements the localizer using IHtmlLocalizer, so Razor doesn't HTML encode the localized string. 您可以參數化資源字串,IViewLocalizer 即會對參數 (而不是資源字串) 進行 HTML 編碼。You can parameterize resource strings and IViewLocalizer will HTML encode the parameters, but not the resource string. 請考慮下列 Razor 標記:Consider the following Razor markup:

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

法文資源檔可能包含下列內容:A French resource file could contain the following:

KeyKey Value
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

轉譯的檢視內容可能包含來自資源檔的 HTML 標記。The rendered view would contain the HTML markup from the resource file.

注意: 一般來說,您只想將文字當地語系化,而不是 HTML。Note: You generally want to only localize text and not HTML.

若要在檢視中使用共用的資源檔,請插入 IHtmlLocalizer<T>To use a shared resource file in a view, inject 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 localization

DataAnnotations 錯誤訊息會使用 IStringLocalizer<T> 來當地語系化。DataAnnotations error messages are localized with IStringLocalizer<T>. 使用 ResourcesPath = "Resources" 選項時,RegisterViewModel 中的錯誤訊息會儲存在下列路徑之一:Using the option ResourcesPath = "Resources", the error messages in RegisterViewModel can be stored in either of the following paths:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resxResources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resxResources/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; }
}

在 ASP.NET Core MVC 1.1.0 和更高版本中,系統會將非驗證屬性當地語系化。In ASP.NET Core MVC 1.1.0 and higher, non-validation attributes are localized. ASP.NET Core MVC 1.0 不會查閱非驗證屬性的當地語系化字串。ASP.NET Core MVC 1.0 does not look up localized strings for non-validation attributes.

針對多個類別使用同一個資源字串Using one resource string for multiple classes

下列程式碼會示範如何針對含有多個類別的驗證屬性使用同一個資源字串:The following code shows how to use one resource string for validation attributes with multiple classes:

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

在先前的程式碼中,SharedResource 是與儲存驗證訊息的 resx 對應的類別。In the preceding code, SharedResource is the class corresponding to the resx where your validation messages are stored. 使用這個方法時,DataAnnotations 只會使用 SharedResource,而不是每個類別的資源。With this approach, DataAnnotations will only use SharedResource, rather than the resource for each class.

針對您支援的語言和文化特性提供當地語系化資源Provide localized resources for the languages and cultures you support

SupportedCultures 和 SupportedUICulturesSupportedCultures and SupportedUICultures

ASP.NET Core 可讓您指定 SupportedCulturesSupportedUICultures 這兩個文化特性值。ASP.NET Core allows you to specify two culture values, SupportedCultures and SupportedUICultures. SupportedCulturesCultureInfo 物件可決定文化特性相依函式的結果,例如日期、時間、數字及貨幣格式。The CultureInfo object for SupportedCultures determines the results of culture-dependent functions, such as date, time, number, and currency formatting. SupportedCultures 也可決定文字排列順序、大小寫慣例和字串比較。SupportedCultures also determines the sorting order of text, casing conventions, and string comparisons. 如需伺服器如何取得文化特性的詳細資訊,請參閱 CultureInfo.CurrentCultureSee CultureInfo.CurrentCulture for more info on how the server gets the Culture. SupportedUICultures 可決定 ResourceManager 要查閱哪些翻譯的字串 (來自 .resx 檔案)。The SupportedUICultures determines which translates strings (from .resx files) are looked up by the ResourceManager. ResourceManager 僅會查閱 CurrentUICulture 所決定之文化特性特有的字串。The ResourceManager simply looks up culture-specific strings that's determined by CurrentUICulture. .NET 中的每個執行緒都有 CurrentCultureCurrentUICulture 物件。Every thread in .NET has CurrentCulture and CurrentUICulture objects. ASP.NET Core 會在轉譯文化特性相依函式時檢查這些值。ASP.NET Core inspects these values when rendering culture-dependent functions. 比方說,如果目前執行緒的文化特性設定為 "en-US" (英文 - 美國),DateTime.Now.ToLongDateString() 會顯示 "Thursday, February 18, 2016",但如果 CurrentCulture 設定為 "es-ES" (西班牙文 - 西班牙),則輸出會是 "jueves, 18 de febrero de 2016"。For example, if the current thread's culture is set to "en-US" (English, United States), DateTime.Now.ToLongDateString() displays "Thursday, February 18, 2016", but if CurrentCulture is set to "es-ES" (Spanish, Spain) the output will be "jueves, 18 de febrero de 2016".

資源檔Resource files

資源檔是一種實用的機制,可讓您將可當地語系化的字串與代碼區隔開來。A resource file is a useful mechanism for separating localizable strings from code. 您可以將非預設語言的翻譯字串作為隔離的 .resx 資源檔。Translated strings for the non-default language are isolated .resx resource files. 例如,您可以建立名為 Welcome.es.resx 的西班牙文資源檔,以包含翻譯的字串。For example, you might want to create Spanish resource file named Welcome.es.resx containing translated strings. "es" 是西班牙文的語言代碼。"es" is the language code for Spanish. 若要在 Visual Studio 中建立這個資源檔:To create this resource file in Visual Studio:

  1. 在方案總管 中,以滑鼠右鍵按一下要放置資源檔的資料夾 > [新增] > [新增項目] 。In Solution Explorer, right click on the folder which will contain the resource file > Add > New Item.

    巢狀快顯功能表:在 [方案總管] 中,會開啟 [資源] 的快顯功能表。

  2. 在 [Search installed templates] (搜尋已安裝的範本) 方塊中,輸入「資源」,並命名檔案。In the Search installed templates box, enter "resource" and name the file.

    [新增項目] 對話方塊

  3. 在 [名稱] 資料行中輸入索引鍵值 (原生字串),並在 [值] 資料行中輸入已翻譯的字串。Enter the key value (native string) in the Name column and the translated string in the Value column.

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

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

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

資源檔命名Resource file naming

資源的命名方式是以其類別的完整類型名稱去掉組件名稱而得。Resources are named for the full type name of their class minus the assembly name. 例如,假設專案中的法文資源是 LocalizationWebsite.Web.Startup 類別、主要組件為 LocalizationWebsite.Web.dll,就會命名為 Startup.fr.resxFor example, a French resource in a project whose main assembly is LocalizationWebsite.Web.dll for the class LocalizationWebsite.Web.Startup would be named Startup.fr.resx. 若是 LocalizationWebsite.Web.Controllers.HomeController 類別的資源,則應命名為 Controllers.HomeController.fr.resxA resource for the class LocalizationWebsite.Web.Controllers.HomeController would be named Controllers.HomeController.fr.resx. 如果目標類別的命名空間和組件名稱不相同,則需要使用完整類型名稱。If your targeted class's namespace isn't the same as the assembly name you will need the full type name. 比方說,範例專案中 ExtraNamespace.Tools 類型的資源會命名為 ExtraNamespace.Tools.fr.resxFor example, in the sample project a resource for the type ExtraNamespace.Tools would be named ExtraNamespace.Tools.fr.resx.

在範例專案中,ConfigureServices 方法會將 ResourcesPath 設為 "Resources",因此首頁控制器的法文資源檔專案相對路徑即為 Resources/Controllers.HomeController.fr.resxIn the sample project, the ConfigureServices method sets the ResourcesPath to "Resources", so the project relative path for the home controller's French resource file is Resources/Controllers.HomeController.fr.resx. 或者,您可以使用資料夾來收集資源檔。Alternatively, you can use folders to organize resource files. 若是首頁控制器,路徑就是 Resources/Controllers/HomeController.fr.resxFor the home controller, the path would be Resources/Controllers/HomeController.fr.resx. 如果您不使用 ResourcesPath 選項, .resx 檔案即會放置在專案的基底目錄中。If you don't use the ResourcesPath option, the .resx file would go in the project base directory. HomeController 的資源檔會命名為 Controllers.HomeController.fr.resxThe resource file for HomeController would be named Controllers.HomeController.fr.resx. 您可依據自己的資源檔收集方式,來選擇要使用點或路徑的命名慣例。The choice of using the dot or path naming convention depends on how you want to organize your resource files.

資源名稱Resource name 點或路徑命名Dot or path naming
Resources/Controllers.HomeController.fr.resxResources/Controllers.HomeController.fr.resx Dot
Resources/Controllers/HomeController.fr.resxResources/Controllers/HomeController.fr.resx 路徑Path

如果資源檔是使用 Razor 檢視中的 @inject IViewLocalizer,亦遵循類似的模式。Resource files using @inject IViewLocalizer in Razor views follow a similar pattern. 您可以使用點命名或路徑命名方式,來命名檢視的資源檔。The resource file for a view can be named using either dot naming or path naming. Razor 檢視的資源檔會模仿其相關聯檢視檔案的路徑。Razor view resource files mimic the path of their associated view file. 假設我們將 ResourcesPath 設為 "Resources",與 Views/Home/About.cshtml 檢視建立關聯的法文資源檔可為下列其一:Assuming we set the ResourcesPath to "Resources", the French resource file associated with the Views/Home/About.cshtml view could be either of the following:

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

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

如果您不使用 ResourcesPath 選項,則檢視的 .resx 檔案會與檢視位於相同資料夾中。If you don't use the ResourcesPath option, the .resx file for a view would be located in the same folder as the view.

RootNamespaceAttributeRootNamespaceAttribute

RootNamespace 屬性會在組件的根命名空間與組件名稱不同時,提供組件的根命名空間。The RootNamespace attribute provides the root namespace of an assembly when the root namespace of an assembly is different than the assembly name.

如果組件的根命名空間與組件名稱不同:If the root namespace of an assembly is different than the assembly name:

  • 根據預設,當地語系化無法運作。Localization does not work by default.
  • 在組件中搜尋資源的方式造成當地語系化失敗。Localization fails due to the way resources are searched for within the assembly. RootNamespace 是建置時間值,無法用於執行處理序。RootNamespace is a build-time value which is not available to the executing process.

如果 RootNamespaceAssemblyName 不同,請將下列內容納入 AssemblyInfo.cs (參數值取代為實際值):If the RootNamespace is different from the AssemblyName, include the following in AssemblyInfo.cs (with parameter values replaced with the actual values):

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

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

上述程式碼可成功解析 resx 檔案。The preceding code enables the successful resolution of resx files.

文化特性後援行為Culture fallback behavior

搜尋資源時,當地語系化會使用「文化特性後援」。When searching for a resource, localization engages in "culture fallback". 從所要求的文化特性開始,如果找不到,就會還原成該文化特性的父文化特性。Starting from the requested culture, if not found, it reverts to the parent culture of that culture. 另外,CultureInfo.Parent 屬性代表父文化特性。As an aside, the CultureInfo.Parent property represents the parent culture. 這通常 (但並非一定) 表示從 ISO 中移除國家意符 (Signifier)。This usually (but not always) means removing the national signifier from the ISO. 例如,墨西哥的西班牙文方言是 "es-MX"。For example, the dialect of Spanish spoken in Mexico is "es-MX". 它具有父系 "es" — 西班牙文不是任何國家/地區的特定項目。It has the parent "es"—Spanish non-specific to any country.

假設您的網站收到使用文化特性 "fr-CA" 之 "Welcome" 資源的要求。Imagine your site receives a request for a "Welcome" resource using culture "fr-CA". 當地語系化系統會依照順序尋找下列資源,並選取第一個相符項目:The localization system looks for the following resources, in order, and selects the first match:

  • Welcome.fr-CA.resxWelcome.fr-CA.resx
  • Welcome.fr.resxWelcome.fr.resx
  • Welcome.resx (如果 NeutralResourcesLanguage 是 "fr-CA")Welcome.resx (if the NeutralResourcesLanguage is "fr-CA")

舉例來說,如果您移除 ".fr" 文化特性指示項,並將文化特性設定為法文,則系統會讀取預設資源檔,並將字串當地語系化。As an example, if you remove the ".fr" culture designator and you have the culture set to French, the default resource file is read and strings are localized. 當沒有任何項目符合您要求的文化特性時,資源管理員即會指定預設資源或後援資源。The Resource manager designates a default or fallback resource for when nothing meets your requested culture. 如果您只想在要求的文化特性缺少資源時傳回索引鍵,就不能使用預設資源檔。If you want to just return the key when missing a resource for the requested culture you must not have a default resource file.

使用 Visual Studio 產生資源檔Generate resource files with Visual Studio

如果您在 Visual Studio 中建立資源檔,但檔案名稱中不含文化特性 (例如 Welcome.resx),則 Visual Studio 會針對每個字串的屬性建立 C# 類別。If you create a resource file in Visual Studio without a culture in the file name (for example, Welcome.resx), Visual Studio will create a C# class with a property for each string. 但這通常不是您使用 ASP.NET Core 的初衷。That's usually not what you want with ASP.NET Core. 一般來說,您不會有預設的 .resx 資源檔 (不含文化特性名稱的 .resx 檔案)。You typically don't have a default .resx resource file (a .resx file without the culture name). 因此,建議您建立含有文化特性名稱的 .resx 檔案 (例如 Welcome.fr.resx)。We suggest you create the .resx file with a culture name (for example Welcome.fr.resx). 當您建立含有文化特性名稱的 .resx 檔案時,Visual Studio 就不會產生類別檔案。When you create a .resx file with a culture name, Visual Studio won't generate the class file. 我們認為大多數開發人員不需建立預設的語言資源檔。We anticipate that many developers won't create a default language resource file.

新增其他文化特性Add other cultures

每種語言和文化特性的組合 (非預設語言) 都需要唯一的資源檔。Each language and culture combination (other than the default language) requires a unique resource file. 若要建立不同文化特性和地區設定的資源檔,您可以建立新的資源檔並將 ISO 語言代碼作為檔名的一部分 (例如 en-usfr-caen-gb)。You create resource files for different cultures and locales by creating new resource files in which the ISO language codes are part of the file name (for example, en-us, fr-ca, and en-gb). 您應將 ISO 代碼置於檔案名稱和 .resx 副檔名之間,例如 Welcome.es-MX.resx (西班牙文/墨西哥)。These ISO codes are placed between the file name and the .resx file extension, as in Welcome.es-MX.resx (Spanish/Mexico).

實作可依據每項要求選取語言/文化特性的策略Implement a strategy to select the language/culture for each request

設定當地語系化Configure localization

您可以在 Startup.ConfigureServices 方法中設定當地語系化:Localization is configured in the Startup.ConfigureServices method:

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

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization 可將當地語系化服務新增至服務容器。AddLocalization Adds the localization services to the services container. 上方的程式碼也會將資源路徑設為 "Resources"。The code above also sets the resources path to "Resources".

  • AddViewLocalization 可支援當地語系化的檢視檔案。AddViewLocalization Adds support for localized view files. 在此範例中,檢視的當地語系化會以檢視檔案的後置詞為依據。In this sample view localization is based on the view file suffix. 例如 Index.fr.cshtml 檔案中的 "fr"。For example "fr" in the Index.fr.cshtml file.

  • AddDataAnnotationsLocalization 可支援透過 IStringLocalizer 抽象概念而來的當地語系化 DataAnnotations 驗證訊息。AddDataAnnotationsLocalization Adds support for localized DataAnnotations validation messages through IStringLocalizer abstractions.

當地語系化中介軟體Localization middleware

您可以在當地語系化中介軟體中,設定要求目前的文化特性。The current culture on a request is set in the localization Middleware. 已在 Startup.Configure 方法中啟用當地語系化中介軟體。The localization middleware is enabled in the Startup.Configure method. 您必須在可能檢查要求文化特性的任何中介軟體之前,設定當地語系化中介軟體 (例如 app.UseMvcWithDefaultRoute())。The localization middleware must be configured before any middleware which might check the request culture (for example, app.UseMvcWithDefaultRoute()).

var supportedCultures = new[]
{
    new CultureInfo("en-US"),
    new CultureInfo("fr"),
};

app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture("en-US"),
    // Formatting numbers, dates, etc.
    SupportedCultures = supportedCultures,
    // UI strings that we have localized.
    SupportedUICultures = supportedCultures
});

app.UseStaticFiles();
// To configure external authentication, 
// see: http://go.microsoft.com/fwlink/?LinkID=532715
app.UseAuthentication();
app.UseMvcWithDefaultRoute();

UseRequestLocalization 會初始化 RequestLocalizationOptions 物件。UseRequestLocalization initializes a RequestLocalizationOptions object. 在每次要求時,系統會列舉 RequestLocalizationOptions 中的 RequestCultureProvider 清單,並使用能成功判斷要求的文化特性的第一個提供者。On every request the list of RequestCultureProvider in the RequestLocalizationOptions is enumerated and the first provider that can successfully determine the request culture is used. 預設的提供者是來自 RequestLocalizationOptions 類別:The default providers come from the RequestLocalizationOptions class:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

預設清單會由針對性高到低來排列。The default list goes from most specific to least specific. 在本文稍後,我們會說明如何變更順序,甚至新增自訂的文化特性提供者。Later in the article we'll see how you can change the order and even add a custom culture provider. 如果沒有任何提供者可以判斷要求的文化特性,即會使用 DefaultRequestCultureIf none of the providers can determine the request culture, the DefaultRequestCulture is used.

QueryStringRequestCultureProviderQueryStringRequestCultureProvider

有些應用程式會使用查詢字串來設定文化特性和 UI 文化特性Some apps will use a query string to set the culture and UI culture. 若是使用 Cookie 或 Accept-Language 標頭方法的應用程式,您可以將查詢字串新增至 URL 以偵錯和測試程式碼。For apps that use the cookie or Accept-Language header approach, adding a query string to the URL is useful for debugging and testing code. 系統預設會將 QueryStringRequestCultureProvider 登錄為 RequestCultureProvider 清單中的第一個當地語系化提供者。By default, the QueryStringRequestCultureProvider is registered as the first localization provider in the RequestCultureProvider list. 您應傳遞查詢字串參數 cultureui-cultureYou pass the query string parameters culture and ui-culture. 下列範例會設定西班牙文/墨西哥的特定文化特性 (語言和地區):The following example sets the specific culture (language and region) to Spanish/Mexico:

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

如果您只傳入兩者其一 (cultureui-culture),查詢字串提供者就會使用您傳入的項目來設定這兩個值。If you only pass in one of the two (culture or ui-culture), the query string provider will set both values using the one you passed in. 例如,若只設定文化特性,即會同時設定 CultureUICultureFor example, setting just the culture will set both the Culture and the UICulture:

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

CookieRequestCultureProviderCookieRequestCultureProvider

生產環境應用程式通常會提供一個機制,來設定 ASP.NET Core 文化特性 Cookie 的文化特性。Production apps will often provide a mechanism to set the culture with the ASP.NET Core culture cookie. 若要建立 Cookie,請使用 MakeCookieValue 方法。Use the MakeCookieValue method to create a cookie.

CookieRequestCultureProvider DefaultCookieName 會傳回預設 Cookie 名稱,以用來追蹤使用者的慣用文化特性資訊。The CookieRequestCultureProvider DefaultCookieName returns the default cookie name used to track the user's preferred culture information. 預設 Cookie 名稱為 .AspNetCore.CultureThe default cookie name is .AspNetCore.Culture.

Cookie 格式為 c=%LANGCODE%|uic=%LANGCODE%,其中 cCultureuicUICulture,例如:The cookie format is c=%LANGCODE%|uic=%LANGCODE%, where c is Culture and uic is UICulture, for example:

c=en-UK|uic=en-US

如果您只指定文化特性資訊和 UI 文化特性其一,系統就會將您所指定的文化特性用於文化特性資訊和 UI 文化特性。If you only specify one of culture info and UI culture, the specified culture will be used for both culture info and UI culture.

Accept-Language HTTP 標頭The Accept-Language HTTP header

您可在大多數的瀏覽器中設定 Accept-Language 標頭,其最初的設計目的是用來指定使用者的語言。The Accept-Language header is settable in most browsers and was originally intended to specify the user's language. 這項設定可指出瀏覽器已設好要傳送哪些項目,或已從基礎作業系統繼承哪些項目。This setting indicates what the browser has been set to send or has inherited from the underlying operating system. 透過瀏覽器要求的 Accept-Language HTTP 標頭來偵測使用者的慣用語言,並非萬無一失 (請參閱 Setting language preferences in a browser (在瀏覽器中設定語言喜好設定)。The Accept-Language HTTP header from a browser request isn't an infallible way to detect the user's preferred language (see Setting language preferences in a browser). 生產環境應用程式應該包含可讓使用者自訂文化特性的選擇方式。A production app should include a way for a user to customize their choice of culture.

在 IE 中設定 Accept-Language HTTP 標頭Set the Accept-Language HTTP header in IE

  1. 從齒輪圖示,點選 [網際網路選項] 。From the gear icon, tap Internet Options.

  2. 點選 [語言] 。Tap Languages.

    網際網路選項

  3. 點選 [設定語言喜好設定] 。Tap Set Language Preferences.

  4. 點選 [新增語言] 。Tap Add a language.

  5. 新增語言。Add the language.

  6. 點選語言,然後點選 [上移] 。Tap the language, then tap Move Up.

使用自訂提供者Use a custom provider

假設您想要讓客戶將他們的語言和文化特性儲存在您的資料庫中。Suppose you want to let your customers store their language and culture in your databases. 您可以撰寫提供者,以供使用者查詢這些值。You could write a provider to look up these values for the user. 下列程式碼會示範如何新增自訂提供者:The following code shows how to add a custom provider:

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.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return new ProviderCultureResult("en");
    }));
});

使用 RequestLocalizationOptions 新增或移除當地語系化提供者。Use RequestLocalizationOptions to add or remove localization providers.

以程式設計方式來設定文化特性Set the culture programmatically

GitHub 上的這個範例 Localization.StarterWeb 專案包含可設定 Culture 的 UI。This sample Localization.StarterWeb project on GitHub contains UI to set the Culture. Views/Shared/_SelectLanguagePartial.cshtml 檔可讓您從支援的文化特性清單中選取文化特性:The Views/Shared/_SelectLanguagePartial.cshtml file allows you to select the culture from the list of supported cultures:

@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 區段,以供所有檢視使用:The Views/Shared/_SelectLanguagePartial.cshtml file is added to the footer section of the layout file so it will be available to all views:

<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。The SetLanguage method sets the culture 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 插入這個專案的範例程式碼。You can't plug in the _SelectLanguagePartial.cshtml to sample code for this project. GitHub 上的範例 Localization.StarterWeb 專案,其中的程式碼會部分透過相依性插入容器將 RequestLocalizationOptions 流向 Razor。The Localization.StarterWeb project on GitHub has code to flow the RequestLocalizationOptions to a Razor partial through the Dependency Injection container.

全球化和當地語系化詞彙Globalization and localization terms

在進行應用程式的當地語系化程序時,您也需要具備現代軟體開發中常用的相關字元集基本知識,並了解與它們建立關聯的問題。The process of localizing your app also requires a basic understanding of relevant character sets commonly used in modern software development and an understanding of the issues associated with them. 雖然所有電腦都會將文字儲存為數字 (程式碼),但不同系統會使用不同數字來儲存相同的文字。Although all computers store text as numbers (codes), different systems store the same text using different numbers. 當地語系化是指針對特定文化特性/地區設定,轉譯應用程式使用者介面 (UI) 的程序。The localization process refers to translating the app user interface (UI) for a specific culture/locale.

可當地語系化是確認全球化應用程式已準備好進行當地語系化的中繼程序。Localizability is an intermediate process for verifying that a globalized app is ready for localization.

文化特性名稱的 RFC 4646 格式是 <languagecode2>-<country/regioncode2>,其中 <languagecode2> 是語言代碼,而 <country/regioncode2> 是子文化特性代碼。The RFC 4646 format for the culture name is <languagecode2>-<country/regioncode2>, where <languagecode2> is the language code and <country/regioncode2> is the subculture code. 例如,es-CL 是指西班牙文 (智利),en-US 是指英文 (美國),而 en-AU 是指英文 (澳大利亞)。For example, es-CL for Spanish (Chile), en-US for English (United States), and en-AU for English (Australia). RFC 4646 是 ISO 639 (兩個小寫字母,為與某個語言建立關聯的文化特性代碼) 及 ISO 3166 (兩個大寫字母,為與某個國家或地區建立關聯的子文化特性代碼) 的組合。RFC 4646 is a combination of an ISO 639 two-letter lowercase culture code associated with a language and an ISO 3166 two-letter uppercase subculture code associated with a country or region. 請參閱 Language Culture Name (語言的文化特性名稱)。See Language Culture Name.

國際化通常縮寫為 "I18N"。Internationalization is often abbreviated to "I18N". 這個縮寫是採用該詞彙的第一個和最後一個字母,以及這兩個字母間的字母數組成,因此 18 代表第一個字母 "I" 及最後 "N" 中間的字母數。The abbreviation takes the first and last letters and the number of letters between them, so 18 stands for the number of letters between the first "I" and the last "N". 同樣的原則也適用於全球化 (G11N) 與當地語系化 (L10N) 的縮寫。The same applies to Globalization (G11N), and Localization (L10N).

詞彙:Terms:

  • 全球化 (G11N):讓應用程式支援不同語言和區域的程序。Globalization (G11N): The process of making an app support different languages and regions.
  • 當地語系化 (L10N):針對特定語言和區域自訂應用程式的程序。Localization (L10N): The process of customizing an app for a given language and region.
  • 國際化 (I18N):描述全球化和當地語系化。Internationalization (I18N): Describes both globalization and localization.
  • 文化特性:它是一種語言和選擇性的區域。Culture: It's a language and, optionally, a region.
  • 中性文化特性:具有指定的語言但不限地區的文化特性。Neutral culture: A culture that has a specified language, but not a region. (例如 "en"、"es")。(for example "en", "es")
  • 特定文化特性:具有指定的語言與區域的文化特性。Specific culture: A culture that has a specified language and region. (例如 "en-US"、"en-GB"、"es-CL")。(for example "en-US", "en-GB", "es-CL")
  • 父文化特性:包含特定文化特性的中性文化特性。Parent culture: The neutral culture that contains a specific culture. (例如,"en" 是 "en-US" 和 "en-GB" 的父文化特性)。(for example, "en" is the parent culture of "en-US" and "en-GB")
  • 地區設定:地區設定與文化特性相同。Locale: A locale is the same as a culture.

注意

您可能無法在小數欄位中輸入小數逗號。You may not be able to enter decimal commas in decimal fields. 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。To support jQuery validation for non-English locales that use a comma (",") for a decimal point, and non US-English date formats, you must take steps to globalize your app. 這個 GitHub 問題 4076 有加入小數逗號的指示。This GitHub issue 4076 for instructions on adding decimal comma.

其他資源Additional resources