多國語系 - 使用資源檔(Resource)來呈現靜態文字
前言
在處理多國語系網站之靜態文字資料時,可使用資源檔對應出各語系所需顯示的內容。本篇文章將示範如何建立資源檔,了解如何在程式中設定及獲得語系資訊,最後在頁面上呈現正確語系文字。
建立資源檔
首先需要建立各語系資源檔,筆者習慣將資源檔獨立為一個類別庫專案,方便網站上線後若需調整文字時,可以直接抽換該資源檔專案dll,而無須重啟網站服務。資料夾對應約略如下,以方便辨識為目的。
以Layout為例,建立該預設語系(en-US)資源檔如下
再建立Layout 日語(ja-JP)語系資源檔如下
建議使用ResXManager工具來管理資源檔,可以清楚地列出各資源檔及語系文字對應關係。如果不熟悉ResXManager的朋友可參考多國語系 - 使用ResXManager管理資源檔文章,有簡易的重點功能說明。
設定語系資料
首先建立網站建置的語系列舉(Enum)類別,以利後續使用
public enum LanguageEnum
{
[Description("en-US")]
English = 1,
[Description("ja-JP")]
Japanese = 2
}
再來建立CultureHelper來協助處理相關事項;主要就是要檢核網站支援的語系(GetImplementedCulture),若用戶語系尚未被網站建置時,套用預設語系(GetDefaultCulture)英文來呈現頁面。
public static class CultureHelper
{
/// <summary>
/// 取得合法語系名稱(尚未實作則給予預設值)
/// </summary>
/// <param name="name">語系名稱 (e.g. en-US)</param>
public static string GetImplementedCulture(string name)
{
// give a default culture just in case
string cultureName = GetDefaultCulture();
// check if it's implemented
if (EnumHelper.TryGetValueFromDescription<LanguageEnum>(name))
cultureName = name;
return cultureName;
}
/// <summary>
/// 取得預設 語系名稱
/// </summary>
/// <returns></returns>
public static string GetDefaultCulture()
{
return LanguageEnum.English.GetDescription();
}
/// <summary>
/// 取得目前 語系
/// </summary>
/// <returns></returns>
public static LanguageEnum GetCurrentLanguage()
{
var currentCulture = Thread.CurrentThread.CurrentCulture.Name;
// get implemented culture name
currentCulture = GetImplementedCulture(currentCulture);
// get language by implemented culture name
return EnumHelper.GetValueFromDescription<LanguageEnum>(currentCulture);
}
}
另附上CultureHelper中所使用到的Enum擴充功能及EnumHelper方法
public static class EnumExtension
{
/// <summary>
/// 取得Enum的描述標籤內容
/// </summary>
/// <returns></returns>
public static string GetDescription(this Enum self)
{
FieldInfo fi = self.GetType().GetField(self.ToString());
DescriptionAttribute[] attributes = null;
if (fi != null)
{
attributes =
(DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
return attributes[0].Description;
}
return self.ToString();
}
}
public class EnumHelper
{
/// <summary>
/// 透過標籤描述內容反射出Enum數值
/// </summary>
/// <typeparam name="T">Enum類別</typeparam>
/// <param name="description">Enum描述標籤</param>
/// <returns>Enum數值</returns>
public static T GetValueFromDescription<T>(string description)
{
var type = typeof(T);
if (!type.IsEnum) throw new InvalidOperationException();
foreach (var field in type.GetFields())
{
var attribute = Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attribute != null)
{
if (attribute.Description == description)
return (T)field.GetValue(null);
}
else
{
if (field.Name == description)
return (T)field.GetValue(null);
}
}
throw new ArgumentException("Not found.", "description");
}
/// <summary>
/// 是否能透過標籤描述內容反射出Enum數值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="description"></param>
/// <returns></returns>
public static bool TryGetValueFromDescription<T>(string description)
{
bool isOkToGetValueFromDescription = true;
try
{
GetValueFromDescription<T>(description);
}
catch (Exception)
{ isOkToGetValueFromDescription = false; }
return isOkToGetValueFromDescription;
}
}
此時就可以設定使用者的偏好語系於Cookie中,提供後續網站語系識別的依據。以下在HomeController中建立一個 SetCulture Action 來處理這段事務。
public ActionResult SetCulture(string culture, string returnUrl)
{
// Validate input
culture = CultureHelper.GetImplementedCulture(culture);
// Save culture in a cookie
HttpCookie cookie = Request.Cookies["_culture"];
if (cookie != null)
{
// update cookie value
cookie.Value = culture;
}
else
{
// create cookie value
cookie = new HttpCookie("_culture");
cookie.Value = culture;
cookie.Expires = DateTime.Now.AddYears(1);
}
Response.Cookies.Add(cookie);
return Redirect(returnUrl);
}
取得語系資料
剛剛我們將語系資訊放置在Cookie中,因此在伺服端接收到Request時就可以查看該Cookie資訊,並且依據該資訊來設定調整目前的CurrentCulture及CurrentUICulture。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
HttpCookie cultureCookie = Request.Cookies["_culture"];
if (cultureCookie != null)
{
// get culture name
var cultureInfoName = CultureHelper.GetImplementedCulture(cultureCookie.Value);
// set culture
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo(cultureInfoName);
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo(cultureInfoName);
}
}
}
使用資源檔
在View中使用資源檔的方式很簡單。首先參考剛建立的Resource專案,然後利用Razor語法來輸出資源檔內的文字資料。以下是 Views/Shared/_layout.cshtml 中利用資源檔來顯示聯絡方式Title文字的示意代碼。
對應的顯示畫面如下 (預設en-US語系)
切換語系實作測試
建立2個ActionLink來切換語系
點選日本語 - 正確顯示日文Title
點選English - 正確顯示英文Title
參考資訊
http://afana.me/post/aspnet-mvc-internationalization.aspx
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !