.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N181220201
出刊日期: 2018/12/12
全球化(Globalization)是設計應用程式支援不同文化特性的程序。當地語系化(Localization)則是針對應用程式資源做本土化設計的過程,例如讓應用程式使用者介面上的文字,以特定文化的語系來做顯示。ASP.NET Core新增IStringLocalizer與IStringLocalizer<T>介面以開發當地語系化應用程式。為了讓開發方便,開發專案的早期,不需要使用資源檔來儲存特定文化特性要顯示的文字或圖片。
本文將介紹如何利用類別庫類型的專案來儲存資源檔,並在ASP.NET Core MVC應用程式之中使用資源檔設計當地語系化網站應用程式。
設計類別庫儲存資源檔案
我們先來建立類別庫專案以儲存資源檔。從Visual Studio開發工具「File」-「New」-「Project」項目,在「New Project」對話盒中,選取左方「Installed」清單-「Templates」-「Visual C#」程式語言,從「.NET Standard」分類中,選取「Class Library(.NET Standard) 」。請參考下圖所示,適當設定專案名稱,以及設定專案存放路徑,按下「OK」鍵。

圖 1:建立「Class Library(.NET Standard) 」類別庫專案。
預設類別庫專案中包含一個「Class1.cs」檔案,在檔案中定義一個「SharedMessageResource」類別,此類別主要是為資源檔案設定一個對應的類別,以便透過類別來存取資源檔案。
using System;
namespace MyLibrary
{
public class SharedMessageResource
{
}
}
建立「Resources」資料夾。從Visual Studio 2017開發工具 -「Solution Explorer」視窗 – 類別庫專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「Resources」,目前畫面看起來如下圖所示:

圖 2:建立「Resources」資料夾。
建立美國語系資源檔案
本文將建立兩個共用資源檔來存放應用程式共用訊息,並提供美國與台灣語系。共用資源檔案檔名要對應到前文建立的類別名稱「SharedMessageResource」。再來共用資源檔案的命名要以文化特性結尾。美國語系文化特性代號為「en-US」;而台灣則是「zh-TW」。沒有以文化特性結尾的資源檔案,則代表預設資源檔,這是選擇性的檔案,不是必要的,通常視為備用(fallback)文化特性。
從「Solution Explorer」視窗 -「你的專案」-「Resources」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」項目。在「Add New Item」對話盒,選取「Visual C# Items」-「General」分類下的「Resource File」項目,然後在下方將「Name:」設定為「SharedMessageResource.en-US.resx」最後按下「Add」按鈕,請參考下圖所示:

圖 3:建立美國語系共用資源檔。
編輯「SharedMessageResource.en-US.resx」資源檔案,新增以下資料,注意視窗上方「Access Modifier」的設定為「No code generation」,目前資源檔的畫面看起來如下圖所示:

圖 4:編輯美國語系共用資源檔。
在「Solution Explorer」視窗,選取「SharedMessageResource.en-US.resx」檔案,按「CTRL+C」複製檔案,再選取「Resources」資料夾,按「CTRL+V」貼到資料夾,並將檔案名字改為「SharedMessageResource.zh-TW.resx」。編輯資源檔案,將「SayHi」與「SayBye」對應的Value換成以下資料,請參考下圖所示:

圖 5:編輯台灣語系共用資源檔。
完成後,目前類別庫專案中的檔案結構看起來如下圖所示:

圖 6:類別庫專案中的檔案結構。
選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。
建立ASP.NET Core Web Application
下一步讓我們在方案中加入一個ASP.NET Core Web Application。從Visual Studio開發工具「File」-「Add」-「New Project」項目,在「New Project」對話盒中,選取左方「Installed」清單-「Templates」-「Visual C#」程式語言,從「.NET Core」分類中,選取「ASP.NET Core Web Application」。請參考下圖所示,適當設定專案名稱,以及專案存放路徑,按下「OK」鍵。

圖 7:建立ASP.NET Core Web Application。
在「New ASP.NET Core Web Application」對話盒中,確認左上方的清單選取「.NET Core」,右上方的清單ASP.NET Core版本為「ASP.NET Core 2.1」,選取下方的「Web Application ( Model – View – Controller) 」樣版專案,清除勾選下方的「Enable Docker Support」核取方塊,確定右方的「Authentication」項目設定為「No Authentication」,然後按下「OK」按鈕建立專案,請參考下圖所示:

圖 8:建立「Web Application ( Model – View – Controller) 」樣版專案。
從「Solution Explorer」視窗 -「你的ASP.NET Core MVC Web Application專案」-資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Reference」項目。在「Reference Manager」對話盒中,選取左方「Projects」-「Solution」,然後勾選右方的「MyLibrary」類別庫專案,請參考下圖所示:

圖 9:加入「MyLibrary」類別庫專案參考。
修改「Home Controller」類別程式碼如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MyWebApplication.Models;
using Microsoft.Extensions.Localization;
using MyLibrary;
using Microsoft.AspNetCore.Localization;
namespace MyWebApplication.Controllers
{
public class HomeController : Controller
{
private readonly IStringLocalizer<SharedMessageResource> _localizer;
public HomeController( IStringLocalizer<SharedMessageResource> localizer )
{
_localizer = localizer;
}
public IActionResult Index( )
{
IRequestCultureFeature rcf = HttpContext.Features.Get<IRequestCultureFeature>();
ViewBag.provider = rcf?.Provider?.GetType().Name;
ViewBag.msg1 = _localizer["SayHi"];
ViewBag.msg2 = _localizer["SayBye"];
return View();
}
[ResponseCache( Duration = 0, Location = ResponseCacheLocation.None, NoStore = true )]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
先引用以下命名空間:
using Microsoft.Extensions.Localization;
using MyLibrary;
using Microsoft.AspNetCore.Localization;
在「Home Controller」類別階層宣告一個唯讀變數,型別為「IStringLocalizer< SharedMessageResource>」:
private readonly IStringLocalizer<SharedMessageResource> _localizer;
在「Home Controller」類別加入一個建構函式,以建構函式注入方式,傳入「IStringLocalizer< SharedMessageResource >」型別的localizer物件,並將傳入的「localizer」指定給「_localizer」變數:
public HomeController( IStringLocalizer<SharedMessageResource> localizer )
{
_localizer = localizer;
}
修改「Home Controller」類別「Index」方法中的程式碼,然後在「Index」方法,加入以下程式碼,取出資源檔案中儲存的當地語系化字串:
public IActionResult Index()
{
IRequestCultureFeature rcf = HttpContext.Features.Get<IRequestCultureFeature>();
ViewBag.provider = rcf?.Provider?.GetType().Name;
ViewBag.msg1 = _localizer["SayHi"];
ViewBag.msg2 = _localizer["SayBye"];
return View();
}
此外,我們使用HttpContext.Features.Get<IRequestCultureFeature>( )方法取得IRequestCultureFeature,來取得目前程式套用的是哪一個當地語系化提供者(default providers)。預設ASP.NET Core提供預設當地語系化提供者(default providers)包含以下三種:
· QueryStringRequestCultureProvider
· CookieRequestCultureProvider
· AcceptLanguageHeaderRequestCultureProvider
套用的順序根據表列清單由上至下優先權由高到低,順序可以客製化調整,若找不到適當的提供者,則會採用預設文化特性(DefaultRequestCulture)。
建立「Index」檢視
下一步驟,建立「Index」檢視。將游標停留在控制器程式設計畫面「Index」方法之中,按滑鼠右鍵,從快捷選單選取「Add View」。在「Add View」對話盒中,設定:
· View name:「Index」。
· Template:「Empty (without model)」。
· Model class:不設定。
· 清除勾選所有核取方塊。
然後按下「Add」按鈕。Visual Studio 2017便會在「Views\Home」資料夾下,新增一個「Index.cshtml」檔案,請參考下圖所示:

圖 10:建立「Index」檢視。
修改Index檢視的內容。從「Solution Explorer」視窗專案名稱下,雙擊「Views\Home\Index.cshtml」檔案,開啟設計畫面,在<body>下<div>標籤中,新增以下標籤,顯示當地語系化字串:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
Provider : @ViewBag.provider
<br />
@ViewBag.msg1
<br />
@ViewBag.msg2
</body>
</html>
啟用當地語系化
修改「Startup」類別,在「ConfigureServices」方法加入以下程式碼,叫用「AddLocalization」方法,加入當地語系化服務,傳入「LocalizationOptions」物件當參數以設定「ResourcesPath」,指定資源檔案所在的資料夾為「Resources」:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace MyWebApplication
{
public class Startup
{
public Startup( IConfiguration configuration )
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices( IServiceCollection services )
{
services.AddLocalization( options => options.ResourcesPath = "Resources" );
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion( CompatibilityVersion.Version_2_1 );
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler( "/Home/Error" );
app.UseHsts();
}
var supportedCultures = new[] {
new CultureInfo( "en-US" ),
new CultureInfo( "zh-TW" )
};
app.UseRequestLocalization( new RequestLocalizationOptions
{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
修改「Configure」方法,叫用「UseRequestLocalization」方法來使用服務,並利用「RequestLocalizationOptions」物件,設定支援美國(en-US)與台灣(zh-TW)兩種文化特性。
選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。在Visual Studio開發工具,按CTRL+F5執行網站首頁(請注意:上列的埠號可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下網址(URL)
https://localhost:44329/home/Index
根據瀏覽器語言喜號設定的不同,你的執行結果可能會有不同。以筆者的測試環境而言,作業系統是英文版,使用Chrome瀏覽器測試,語言喜好設定最喜好語言設為「English (United States)」,請參考下圖所示:

圖 11:Chrome瀏覽器測試,語言喜好設定。
目前執行結果如下圖所示,套用「AcceptLanguageHeaderRequestCultureProvider」,並顯示出美國語系資源檔中的文字:

圖 12:執行結果。
由於「QueryStringRequestCultureProvider 」優先權高於「AcceptLanguageHeaderRequestCultureProvider」,修改瀏覽器網址測試,使用查詢字串指定文化特性是美國:
https://localhost:44329/?culture=en-US
執行的結果如下圖所示:

圖 13:使用查詢字串指定文化特性測試。
修改瀏覽器網址測試,使用查詢字串指定文化特性是台灣:
https://localhost:44329/?culture=zh-tw
執行的結果如下圖所示:

圖 14:使用查詢字串指定文化特性測試。
修改瀏覽器網址測試,使用查詢字串指定文化特性是目前應用程式不支援的日本:
https://localhost:44329/?culture=ja-jp
執行的結果如下圖所示,可能會與您的環境DefaultRequestCulture設定不同而結果不同。因為查詢字串指定不支援的日本文化特性「ja-JP」,因此這次是套用「AcceptLanguageHeaderRequestCultureProvider」:

圖 15:使用查詢字串指定文化特性測試。
文化特性備用(Culture fallback)
資源檔案名稱沒有後綴文化特性稱之為預設資源檔案,以提供文化特性備用(Culture fallback)功能。我們來測試一下它的用法。先刪除「MyLibrary」專案中的「SharedMessageResource.en-US.resx」檔案,然後加入一個新的資源檔案,命名為「SharedMessageResource.resx」。編輯其中的內容如下圖所示:

圖 16:預設資源檔案。
目前專案中的檔案結構看起來如下圖所示:

圖 17:類別庫檔案結構。
修改瀏覽器網址測試,根據瀏覽器語言喜好設定的不同,你的執行結果可能會有不同。以筆者的測試環境而言,作業系統是英文版,使用Chrome瀏覽器測試,語言喜好設定最喜好語言設為「English (United States)」,請參考下圖所示:
https://localhost:44329/home/index
執行結果如下,套用「AcceptLanguageHeaderRequestCultureProvider」,並顯示出預設資源檔中的文字,請參考下圖所示:

圖 18:預設資源檔套用測試。
修改瀏覽器網址測試,使用查詢字串指定文化特性是美國:
https://localhost:44329/?culture=en-US
執行的結果如下圖所示,顯示出預設資源檔中的文字:

圖 19:預設資源檔套用測試。
使用查詢字串指定文化特性是目前應用程式不支援的日本文化特性:
https://localhost:44329/?culture=ja-jp
執行的結果如下圖所示,顯示出預設資源檔中的文字,請參考下圖所示:

圖 20:預設資源檔套用測試。
修改瀏覽器網址測試,使用查詢字串指定文化特性是台灣:
https://localhost:44329/?culture=zh-tw
執行的結果,請參考下圖所示:

圖 21:預設資源檔套用測試。