1. 程式人生 > >深入研究.NET Core的本地化機制

深入研究.NET Core的本地化機制

ASP.NET Core中提供了一些本地化服務和中介軟體,可將網站本地化為不同的語言文化。

ASP.NET Core中我們可以使用Microsoft.AspNetCore.Localization庫來實現本地化。

在.NET Core 2.0以上版本, Microsoft.AspNetCore.Localization已經包含在了Microsoft.AspNetCore.All中,所以我們並不需要手動引入其他的類庫。

建立一個MVC網站

為了測試ASP.NET Core的本地化,我們首先在Visual Studio 2017中建立一個MVC專案LocalizationSample。

配置Startup類

ASP.NET Core中,如果希望啟動本地化,首先需要在Startup類的ConfigureServices方法中使用services.AddLocalization新增本地化服務。

public void ConfigureServices(IServiceCollection services)
{
    services.AddLocalization(o =>
    {
        o.ResourcesPath = "Resources";
    });
    
    services.AddMvc();
}

在這個方法中,我們指定了資料夾Resources作為存放翻譯檔案的目錄。

注: 如果不指定存放翻譯檔案的目錄, ASP.NET Core會預設從網站根目錄下讀取。

然後我們需要在Configure方法中新增本地化中介軟體。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles();

    IList<CultureInfo> supportedCultures = new List<CultureInfo>
    {
        new CultureInfo("en-US"),
        new CultureInfo("zh-CN"),
    };
    app.UseRequestLocalization(new RequestLocalizationOptions
    {
        DefaultRequestCulture = new RequestCulture("en-US"),
        SupportedCultures = supportedCultures,
        SupportedUICultures = supportedCultures
    });

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}
  • app.UseRequestLocalization必須放置app.UseMvc之前
  • DefaultRequestCulture引數指定了預設的語言文化,即使用者不指定任何文化時的預設語言文化
  • SupportedCulturesSupportedUICultures是指定當前應用支援的所有語言文化

注: SupportedCultures指定的是數字和日期格式, SupportedUICultures指定的翻譯檔案

新增資原始檔

下面我們嘗試新增一個資原始檔

  1. 首先我們建立一個Resources資料夾,這就是我們在前面Startup類中配置的目錄名。
  2. 然後我們在Resource資料夾中新增一個資原始檔,並命名為Controllers.HomeController.zh-CN.resx。
  3. 在這個資原始檔中,新增一個欄位Hello, 並設定其值為“你好”。

在Controller中獲取本地化字串

現在我們開啟預設生成的HomeController, 清空裡面所有的action, 並新增一個新的action, 程式碼如下:

public class HomeController : Controller
{
    public HomeController()
    {
       
    }

    public IActionResult Hello()
    {
        return Content("Hello");
    }
}

啟動專案之後訪問/Home/Hello, 結果如下

下面我們修改HomeController的程式碼, 來引入本地化字串訪問器

public class HomeController : Controller
{
    private readonly IStringLocalizer<HomeController> _localizer;

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

    public IActionResult Hello()
    {
        return Content(_localizer["Hello"]);
    }
}

程式碼解釋

  • IStringLocalizer是一個本地化字串訪問器的泛型介面,這裡我們通過依賴注入的方式在HomeController的建構函式中將其注入
  • 我們可以通過IStringLocalizer的屬性訪問器獲取到對應欄位在不同語言下的文字。

最終效果

現在我們啟動程式, 重新訪問/Home/Hello, 結果如下

你會發現結果沒有變化,這是因為預設我們設定的語言文化是en-US, 但是我們之前沒有新增en-US的資原始檔,所以程式就直接將訪問的欄位名輸出了。

現在我們修改URL, 訪問/Home/Hello?ui-culture=zh-CN, 結果如下

我們期望的“你好”被正確輸出了,這說明ASP.NET Core預設支援在Url中以culture引數的形式設定當前網站使用的語言文化。

資原始檔命名

為什麼我們之前添加了一個名為Controllers.HomeController.zh-CN.resx的資原始檔,本地化字串訪問器IStringLocalizer就能定位到這個檔案並讀取其中的欄位屬性呢?

這是由ASP.NET Core資原始檔的命名約定決定的。

ASP.NET Core資原始檔的名稱由2部分組成:

  • 去掉程式集名稱的完整類名
  • 語言文化名稱

以前面的例子為例:
我們建立了一個本地化字串訪問器介面,它的泛型型別是HomeController, 其完整類名是LocalizationSample.Controllers.HomeController, 當前程式集的名稱是LocalizationSample, 所以去掉程式集名稱之後,剩餘部分是Controllers.HomeController。當我們設定culture引數是zh-CN時, ASP.NET Core查詢的資原始檔名是Controllers.HomeController.zh-CN.resx, 這正是我們前面新增的中文語言文化資原始檔名。

如果你不喜歡這種方式,ASP.NET Core還提供了另外一種資原始檔的組織方式

你可以Resources目錄下建立以下目錄結構

  • Resources
    • Controllers
      • HomeController.zh-CN.resx

本地化字串訪問器也能自動定位到這個檔案。

預設的語言文化提供器

ASP.NET Core的本地化中介軟體預設支援3種語言文化提供器

  • URL中的查詢字串
  • Cookie
  • 請求頭

URL中的查詢字串

ASP.NET Core會從URL中的culture引數中獲取當前應用使用的語言文化,這就是前面例子中,“你好”能正確輸出的原因

除了指定ui-culture引數,你還可以使用culture引數指定當前格式化時間,數字等所使用的語言文化。

?culture=zh-CN&ui-culture=zh-CN

?culture=zh-CN

?ui-culture=zh-CN

Tips: 當只指定culture或ui-culture引數時,ASP.NET Core會自動將culture和ui-culture設定成一樣的。即?culture=zh-CN等同於?culture=zh-CN&ui-culture=zh-CN

ASP.NET Core中還支援使用Cookie的方式設定當前應用使用的語言文化。預設使用的Cookie名稱是.AspNetCore.Culture。

.AspNetCore.Culture的值格式如下

c=zh-CN|uic=zh-CN

c=zh-CN

uic=zh-CN

其中c表示culture, uic表示ui-culture。

下面我們使用Chrome的開發者工具, 為當前網頁新增語言文化Cookie

然後我們訪問/Home/Hello, "你好"也被正確的輸出了

這說明ASP.NET Core從Cookie中讀取到了語言文化配置

請求頭

除了URL查詢字串和Cookie, ASP.NET Core還支援在請求頭中指定語言文化。請求頭中語言文化欄位名稱是 Accept-Language。

這裡我們使用Postman來測試一下,我們設定Accept-Language為zh-CN, zh;q=0.9, 結果如下

如何在View中使用本地化

除了Controller, 我們更多的是在View中使用本地化。
如果希望在View中使用本地化,首先需要在Startup類的ConfigureServices方法中啟用View本地化。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
}

這裡LanguageViewLocationExpanderFormat支援2種方式,這個和前面Controller的本地化檔名稱約定類似

  • Suffix, 例/Resources/Home/Hello.zh-CN.resx
  • Path, 例/Resources/Home/zh-CN/Hello.resx

下面我們修改HomeController的程式碼,Hello方法將返回一個View

HomeController

public IActionResult Hello()
{
    //return Content(_localizer["Hello"]);
    return View();
}

Hello.cshtml


@{
    ViewData["Title"] = "Hello";
}

<h2>Good Bye</h2>

然後我們建立如下圖的目錄結構, 並建立資原始檔Hello.zh-CN.resx, 並新增GoodBye欄位,其值為"再見"

使用ViewLocalizer

ViewLocalizer類可以幫助我們在Razor檢視中使用本地化文字。現在我們來修改Hello.cshtml, 在檔案新增本地化引用,並注入一個ViewLocalizer物件

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer
@{
    ViewData["Title"] = "Hello";
}

<h2>@Localizer["GoodBye"]</h2>

這裡我們使用ViewLocalizer讀取了本地化文字,它的用法和IStringLocalier一樣,都是通過屬性訪問器訪問對應欄位的本地化文字。

最終效果

現在我們執行程式並訪問/Home/Hello, 結果如下

然後我們繼續訪問/Home/Hello?ui-culture=zh-CN, 結果如下

本地化字串讀取成功