ASP.NET 實作多國語言的應用程式 [使用Resources檔]

前些天老闆詢問了如果要在現有或新的專案應用程式內加入多國語系功能大概會怎麼實作,筆者的部落格上從有類似的文章。今天想來稍微小試一下身手,用自己的想法來實作一個簡單的 ASP.NET 多國語言範例程式。

前些天老闆詢問了如果要在現有或新的專案應用程式內加入多國語系功能大概會怎麼實作,筆者的部落格上從有類似的文章。今天想來稍微小試一下身手,用自己的想法來實作一個簡單的 ASP.NET 多國語言範例程式。

整體構思:

1. 希望使用 Resources 檔案存放個語系的文字

而且獨立於另外的 Assembly 中,且希望透過抽換 Assembly 的方式即可任意切換世界各國不同的語系。

2. 透過自行定義的 LABEL 控制項來顯示多語系文字,

因此只有使用自定義的 LABEL 控制項才會具有多語系文字的顯示,不會與其他原生的 WebControls 相衝突。

3. 主要的網頁上希望使用一個下拉選單來改變頁面上的多語系控制項。

且希望不要受到不同語言的瀏覽器設定的影響。接著我們就開始來進行實作。首先第一步,

 

一、建立 Resources 的 Library 專案,並加入兩個 Resources 檔案

image

ChineseResource.resx 的內容如下

image

EnglishResource.resx 的內容如下

image

而為了將 Resources 的內容開放出來,在加入一個 ResMultiLang.cs 類別

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Reflection;
   5:  using System.Text;
   6:  using System.Threading.Tasks;
   7:  
   8:  namespace LanguageResources
   9:  {
  10:      public class ResMultiLang
  11:      {
  12:          public static string GetMiltiStringByID(string ID, UseLanguage Language)
  13:          {
  14:              string result = "";
  15:              switch(Language)
  16:              {
  17:                  case UseLanguage.UseChineseTraditional:
  18:                      result = ChineseResource.ResourceManager.GetString(ID);
  19:                      break;
  20:                  case UseLanguage.UseUA:
  21:                      result = EnglishResource.ResourceManager.GetString(ID);
  22:                      break;
  23:              }
  24:              return result;
  25:          }
  26:      }
  27:  
  28:      public enum UseLanguage
  29:      {
  30:          None,
  31:          UseChineseTraditional,
  32:          UseUA
  33:      }
  34:  }

上面程式非常的簡單,只是一照 ID 與 UseLanguage 類型,從不同的 Resources 中取得字串而已。

 

二、建立 MultiLabel 類別庫專案

也就前面第 2 點所提到的,希望透過自定義控制項才具備此功能。程式碼如下,只是加入 UseLanguage 屬性 與 LanguageStringID 屬性,UseLanguage 屬性主要將 UseLanguage 存放於 ViewState 中,而 LanguageStringID 則是要存取 Resources 檔要使用哪一個 StringID 。當然這個專案必須參考上面 LanguageResources 專案。

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.Threading.Tasks;
   7:  using System.Web;
   8:  using System.Web.UI;
   9:  using System.Web.UI.WebControls;
  10:  using LanguageResources;
  11:  
  12:  namespace MultiLabel
  13:  {
  14:      [MultiLanguageAttributes()]
  15:      [DefaultProperty("Text")]
  16:      [ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
  17:      public class MLabel : Label
  18:      {
  19:          /// <summary>
  20:          /// 要使用的語系
  21:          /// </summary>
  22:          [Bindable(true)]
  23:          [Category("Behavior")]
  24:          [Description("要使用的語系")]
  25:          [DefaultValue(UseLanguage.None)]
  26:          [Localizable(true)]
  27:          public UseLanguage Language
  28:          {
  29:              get
  30:              {
  31:                  if (ViewState["Language"] != null)
  32:                  {
  33:                      UseLanguage u = (UseLanguage)ViewState["Language"];
  34:                      return u;
  35:                  }
  36:                  ViewState["Language"] = UseLanguage.None;
  37:                  return UseLanguage.None;
  38:              }
  39:              set 
  40:              { 
  41:                  ViewState["Language"] = value;
  42:                  SetTextLanguage();
  43:              }
  44:          }
  45:  
  46:          /// <summary>
  47:          /// 指定來源 Resources 檔案的 Resources StringID
  48:          /// </summary>
  49:          [Category("Behavior")]
  50:          [Description("指定來源 Resources 檔案的 Resources StringID")]
  51:          public string LanguageStringID
  52:          {
  53:              get
  54:              {
  55:                  if (ViewState["LanguageStringID"] == null)
  56:                  {
  57:                      ViewState["LanguageStringID"] = "(無)";
  58:                  }
  59:                  return ViewState["LanguageStringID"].ToString();
  60:              }
  61:              set { ViewState["LanguageStringID"] = value; }
  62:          }
  63:          /// <summary>
  64:          /// 將字串內容指定給控制項的 Text 屬性.
  65:          /// </summary>
  66:          void SetTextLanguage()
  67:          {
  68:              Text = ResMultiLang.GetMiltiStringByID(LanguageStringID, Language);
  69:          }
  70:  
  71:          public MLabel()
  72:          {
  73:              
  74:          }
  75:      }
  76:  }

如上程式,各位應該會發現,程式在 SetTextLanguage() 便會呼叫 LanguageResources 專案的 ResMultiLang 類別的 GetMultiStringByID() 方法實際指定字串給自身的 Text 屬性。

 

三、建立 WebMultiLanguageApp1 的 Web 的應用程式專案,並加入一個 MultiLanguage1.aspx 頁面

image

這邊我們直接來看畫面好了。在我們將 MultiLabel 編譯完成,也參考到 WebMultiLanguageApp1 網頁應用程式專案後,Visual Studio 11 會很貼心將您透過專案參考進來的 Assembly 中是否有 System.Web.UI 底下的 WebControls 或 HtmlControls 類型的 UI 控制項,如果有,它會自動建立一個 [AssemblyName + Components] 的頁籤,並將該 UI 控制項列出。因此您只要直接拖曳至畫面中即可。如下圖為筆者完成的畫面:

image

如上畫面中,筆者已經預先拖曳了一個 DropDownList 控制項,透過變更 DropDownList 以改變畫面上所有控制項顯示的語系字串。這在之前我們要先設定我們加入的 LanguageStringID 屬性為 "CountryName" ,因為我們前面在 Resources 檔案中的 StringID 即是宣告為 CountryName,如下:

image

當然筆者目前只先測試 DropDownList 下方的 MLabel 控制項是否可以透過 DropDownList 改變其內容。而要做到這樣,我們得寫一些些程式碼,我們得搜尋 Page 上所有屬於自定義的控制項,這筆者又再 MultiLabel 專案內定義了 MultiLanguageAttributes 的標籤,以便我們再搜尋頁面所有的控制項時,只要找有打上 MultiLanguageAttributes 這個標籤的控制項即可。筆者將這段作業,另外新增一個 BaseForm.cs 並放置在 BaseForm 之中,以便讓每一個需要的頁面繼承下來使用。筆者就直接列出整個 BaseForm 的程式內容供參考,如下:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Reflection;
   5:  using System.Web;
   6:  using System.Web.UI;
   7:  using System.Web.UI.WebControls;
   8:  using LanguageResources;
   9:  using MultiLabel;
  10:  
  11:  namespace WebMultiLanguageApp1
  12:  {
  13:      public class BaseForm: System.Web.UI.Page
  14:      {
  15:          /// <summary>
  16:          /// 在 Page 裡執行找尋特定 ID 的控制項
  17:          /// </summary>
  18:          /// <typeparam name="T"></typeparam>
  19:          /// <param name="id"></param>
  20:          /// <returns></returns>
  21:          public T FindControl<T>(string id) where T : Control
  22:          {
  23:              return FindControl<T>(Page, id);
  24:          }
  25:  
  26:          public static T FindControl<T>(Control C, string id) where T : Control
  27:          {
  28:              T t = default(T);
  29:              int CtlCount = C.Controls.Count;
  30:  
  31:              if (CtlCount > 0)
  32:              {
  33:                  for (int i = 0; i < CtlCount; i++)
  34:                  {
  35:                      Control currentControl = C.Controls[i];
  36:                      if (currentControl is T)
  37:                      {
  38:                          t = C.Controls[i] as T;
  39:                          if (string.Compare(id, t.ID, true) == 0) 
  40:                              break;
  41:                          else 
  42:                              t = null;
  43:                      }
  44:                      else
  45:                      {
  46:                          t = FindControl<T>(currentControl, id);
  47:                          if (t != null) 
  48:                              break;
  49:                      }
  50:                  }
  51:              }
  52:              return t;
  53:          }
  54:  
  55:          void SetAllMControls()
  56:          {
  57:              foreach (Control c in Page.Controls)
  58:              {
  59:                  if (c.HasControls())
  60:                      SetAllMControls(c);
  61:              }
  62:          }
  63:  
  64:          private void SetAllMControls(Control c)
  65:          {
  66:              foreach (Control cc in c.Controls)
  67:              {
  68:                  if (cc is MLabel)
  69:                  {
  70:                      IEnumerable<CustomAttributeData> refAddr = cc.GetType().CustomAttributes;
  71:                      var o = from query in refAddr.AsQueryable()
  72:                                  where query.AttributeType==typeof(MultiLanguageAttributes)
  73:                                  select query;
  74:  
  75:                      if (o.Count() > 0)
  76:                      {
  77:                          object select = FindControl<DropDownList>("DropDownList1");
  78:                          if (select != null)
  79:                          {
  80:                              switch ((select as DropDownList).SelectedValue)
  81:                              {
  82:                                  case "UseChineseTraditional":
  83:                                      (cc as MLabel).Language = UseLanguage.UseChineseTraditional;
  84:                                      break;
  85:                                  case "UseEnglish":
  86:                                      (cc as MLabel).Language = UseLanguage.UseUA;
  87:                                      break;
  88:                              }
  89:                              
  90:                          }
  91:                      }
  92:                  }
  93:                  if (cc.HasControls())
  94:                      SetAllMControls(cc);
  95:              }
  96:          }
  97:  
  98:          protected override void OnLoad(EventArgs e)
  99:          {
 100:              base.OnLoad(e);
 101:              SetAllMControls();
 102:          }
 103:      }
 104:  }

程式執行時,我們只要點選 DropDownList ,如下:

image

這時我們切換到下 DropDownList 點選 UseEnglish

image

我們可以看到,下方的 MLabel 馬上變成了英文的 Taiwan 了

image

 

範例程式下載 (本範例使用 Visual Studio 11 Beta)

WebMultiLanguageApp1.zip

 

結語:

本範例只是大概的示意了多語系的ASP.NET應用程式該大概如何實作,當然這個範例其實還不完整,比如在 BaseForm 寫死了許多東西,如 "UseChineseTraditional"、也還未考慮CultureInfo 的問題等等。還有許多改進的空間,未來有機會筆者再分享給各位~^__^


 

簽名:

學習是一趟奇妙的旅程

這當中,有辛苦、有心酸、也有成果。有時也會有瓶頸。要能夠繼續勇往直前就必須保有一顆最熱誠的心。

軟體開發之路(FB 社團)https://www.facebook.com/groups/361804473860062/

Gelis 程式設計訓練營(粉絲團)https://www.facebook.com/gelis.dev.learning/


 

如果文章對您有用,幫我點一下讚,或是點一下『我要推薦,這會讓我更有動力的為各位讀者撰寫下一篇文章。

非常謝謝各位的支持與愛護,小弟在此位各位說聲謝謝!!! ^_^