一、 加入全球化信息
在我的網站中,在創建資源文件並加入一些本地化數據後,我首先開始使用 顯式本地化來設置控件(例如,在我的網站中的標簽)的文本,以便它們可以從 資源文件中得到它們的值。既然存在四種語言;所以,除一個完全可依賴的資源 文件之外(沒有本地化命名),我創建了四個資源文件。
注意,這些資源文件都以本地化標記作為它們的中間名稱,因此,我需要把 UICulture設置為與該本地化相同的名字以便ASP.NET存取這些資源文件。
但是,問題是:我該怎樣在PostBack事件中動態地改變文化呢?幸好, ASP.NET在Page類中提供了一種可重載的方法: InitializeCulture()。這個方 法在頁面生命周期(在生成任何控件之前)中執行得很早,並且在此,我們能夠設 置當前線程的UICulture和Culture。
由於這個方法位於Page類中,並且我不想針對每一個web頁面都重復相同的代 碼,所以我創建了一個BasePage類,我的應用程序中的所有的aspx頁面都派生自 這個BasePage類。但是現在,我又面臨另一個問題。下面,讓我進行解釋:
回到UI設計:我使用了一個MasterPage和一個Header用戶控件(在一個 ContentPlaceHolder內)。我把一個缺省的頁面與該MasterPage相關聯。整個站 點必須動態地實現本地化。因此,在頂部,有一個下拉框,用戶可以從中選擇一 種語言/文化。在BasePage的InitilializeCulture方法中,我必須取得用戶從下 拉框選擇的項的值;但是,因為它還沒有被初始化,所以,我還不能存取任何控 件的值。答案是:使用表單集合(從響應對象內)。下面是實現代碼:
///<SUMMARY>
///從通用的頁面頭部的下拉框列表中選擇的語言名。
///我們需要使用這個名字,因為我們還沒有任何其它控件屬性-現在控件本 身還沒有被初始化。
///因此,我們使用"嵌套的"下拉框列表名,從中我們可以從Request.Form[] 集合中得到該下拉框列表的值。
/// </SUMMARY>
public const string LanguageDropDownID = "ctl00$cphHeader$Header1 $ddlLanguage";
/// <SUMMARY>
///在一個回寄表單中的PostBack事件目標域的名字。你可以使用
///它來確定是哪個控件觸發了PostBack:
/// Request.Form[PostBackEventTarget] .
/// </SUMMARY>
public const string PostBackEventTarget = "__EVENTTARGET";
請注意,在此,我是如何使用"parentControl:ChildControl"方法從表單集 合中存取控件的。通過使用這一約定,你可以存取任何ASP.NET生成的嵌套控件 。借助於表單集合中選擇的值,我可以通過一個switch case語句來進行文化設 置:
/// <SUMMARY>
///重載InitializeCulture方法來設置在當前線程中用戶選擇的選項
///。注意,這個方法在Page生命周期的早期調用
///,並且目前我們不存在任何控件
///,因此必須使用Form集合.
/// </SUMMARY>
protected override void InitializeCulture()
{
///<remarks><REMARKS>
///檢查是否PostBack發生.不能使用在此方法中使用IsPostBack
///,因為這個屬性還沒有設置。
///</remarks>
if (Request[PostBackEventTarget] != null) {
string controlID = Request[PostBackEventTarget];
if (controlID.Equals(LanguageDropDownID)) {
string selectedValue = Request.Form[Request [PostBackEventTarget]].ToString();
switch (selectedValue)
{
case "0": SetCulture("hi-IN", "hi-IN");
break;
case "1": SetCulture("en-US", "en-US");
break;
case "2": SetCulture("en-GB", "en-GB");
break;
case "3": SetCulture("fr-FR", "fr-FR");
break;
default: break;
}
}
}
///<remarks>
///從會話中取得文件,如果控制給導航到同一程序中的一個新頁面。
///</remarks>
if (Session["MyUICulture"] != null && Session ["MyCulture"] != null)
{
Thread.CurrentThread.CurrentUICulture = (CultureInfo)Session ["MyUICulture"];
Thread.CurrentThread.CurrentCulture = (CultureInfo)Session ["MyCulture"];
}
base.InitializeCulture();
}
/// <Summary>
///使用參數設置當前的UICulture和CurrentCulture
/// </Summary>
/// <PARAM name="name"></PARAM>
/// <PARAM name="locale"></PARAM>
protected void SetCulture(string name, string locale) {
Thread.CurrentThread.CurrentUICulture = new CultureInfo (name);
Thread.CurrentThread.CurrentCulture = new CultureInfo (locale);
///<remarks>
///由用戶把當前線程的文化集保存在會話中
///,以便它能夠在當前應用程序中跨頁面應用。
///</remarks>
Session["MyUICulture"] = Thread.CurrentThread.CurrentUICulture;
Session["MyCulture"] = Thread.CurrentThread.CurrentCulture;
}
因此,用戶在他/她選擇的語言中會看到此內容。我們需要把該文件選擇保存 到一個會話或一個Cookie變量中,因為如果用戶移動到同一應用程序中的其它一 些頁面,那麼,當新的頁面類一開始被實例化時,該線程的文化信息將會丟失 (HTTP是無狀態的!)。注意,在用戶的會話到期時,如果你不想丟失當前線程的 文化信息,那麼你可以使用Cookies。
一旦我們從web應用程序中提取了所有的內容並且基於用戶選擇和使用 Resources.TestWebSite.XXXPropertyName設置好了Culture和UICulture,那麼 ,我們就已經為我們的全球化框架作好了准備。現在,剩下的唯一事情是把資源 特定的數據添加到相應的資源文件中。針對每一種文件類型,我們需要有一個單 獨的(和適當命名的)資源文件。這個過程稱為本地化。在我的web.config文件中 ,我使用了下列屬性:
<globalization responseEncoding"=utf-8" requestEncoding="utf -8" fileEncoding="utf-8" />
注意,這裡使用了編碼屬性-utf-8(8位Unicode轉換格式),因為它是可變長 度字符編碼;並且,除了它是ASCII兼容的之外,還能夠代表例如Greek,Arabic 等語言。有關UTF-8編碼的更多信息,請參考下面這個鏈接:
http://en.wikipedia.org/wiki/UTF-8
另外,特別值得注意的是,盡管我們能夠在發布服務器上擁有原始XML形式的 資源文件(這樣,用戶可以方便地編輯它們而不必重新編譯整個站點),但是,如 果我們對資源文件作出任何修改的話,應用程序將重新開始運行。這有可能妨礙 此發布的應用程序的性能。