在ASP.NET 2.0 中提供多語言轉換和多樣式主題轉換功能,兩種實作形式比較類似,所以放在一起說明一下。
1. Language switcher 多語言轉換在Quick Start Tutorial 中,介紹如何儲存和應用使用者選擇的語言。通常是用一個DropDownList展示支援的語言,供使用者選擇,通常放在masterpage 裡面,將使用者選擇的語言儲存起來這裡用了ASP.NET 2.0的Profile,當然也可以存在cookie session 或querystring裡。在頁面中重寫InitializeCulture 方法,使用使用者先前選擇的語言。因為設定語言的操作(這裡是SelectedIndexChanged事件)發生在InitializeCulture 時間後面,所以在設定作業完成後為了使的當前頁面也馬上生效,需要做個重轉向,以從新加載本頁面,觸發InitializeCulture 事件。下面使quickstart中的部分程式碼,注意紅色部分。因為有的頁面位址後面可能還存在queystring,所以個人覺得紅色程式碼部分最好用Response.Redirect(Request.Url.PathAndQuery);來代替。
protected void DropDownLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
string SelectedLanguage = DropDownLanguage.SelectedValue.ToString();
//Save selected user language in profile
Profile.SetPropertyValue("PreferredCulture", SelectedLanguage);
//Force re-initialization of the page to fire InitializeCulture()
Response.Redirect(Request.Url.LocalPath);
}
protected override void InitializeCulture()
{
// override virtual method InitializeCulture() to check if profile contains a user language setting
string UserCulture = Profile.GetPropertyValue("PreferredCulture").ToString();
if ( UserCulture != "")
{
// there is a user language setting in the profile: switch to it
Thread.CurrentThread.CurrentUICulture = new CultureInfo(UserCulture);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(UserCulture);
}
}
為了減少程式碼的重複,一般會自訂一個customer base page類,使它繼承Page類,然後在自訂的頁基類中重新InitializeCulture方法。最後把你的每個頁面繼承自你的自訂頁面基底類別。這樣你就不需要每個頁面都重寫InitializeCulture方法了。
但上面這個方法還是不是很爽,因為每個新增一個頁面都要去修改後置程式碼,來繼承自訂頁基底類別。
我們注意到,InitializeCulture方法中實際上只是修改了目前執行緒的Culture和UICulture。那麼可不可以在一個全域的事件中,例如Application的某個事件,來修改這兩個屬性呢?我很早以前這麼試過,在Application的BeginRequest事件觸發時來實作InitializeCulture 的細節,類似下面程式碼:
void Application_BeginRequest(object sender, EventArgs e)
{
string lang = string.Empty;//default to the invariant culture
lang = Profile.PreferredCulture;
if (string.IsNullOrEmpty(lang))
{
lang = string.Empty;
}
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
}
注意紅色部分應用其他方式取代,因為在beginrequest觸發階段,profile物件還沒有被asp.net建立。可以用cookies取代。
我記得當時這麼做後,語言設定後並不起作用,當時認為在全域事件中處理,可能到後來還是會被覆蓋掉,所以可能不行。所以當時還是用了InitializeCulture法。今天在asp.net論壇看到有人如此實現了,
void Application_BeginRequest(Object sender, EventArgs e){
string lang = string.Empty;//default to the invariant culture
HttpCookie cookie = Request.Cookies["DropDownName"];
if (cookie != null && cookie.Value != null)
lang = Request.Form[cookie.Value];
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
}
所以我覺得當時可能哪裡沒有設定好,於是又試了一次,原來是頁面頭指令<%@ Page UICulture="auto" Culture="auto" %>的原因,如果在頁面中設定了UICulture和Culture後,它們就會覆蓋掉在全域中的設定。去掉之後,全域設定起作用了。看來頁面中的culture的設定會覆蓋全域的設置,而頁面中InitializeCulture方法(確切地說是一切支援該方法的控制項)的設定會覆蓋頁面的設定。其實在Page類別中InitializeCulture方法的預設實作是空的,因此再將頁頭指令UICulture="auto" Culture="auto" 去掉後,Global中的設定就運作了。
另外,如果很想使用Profile(像我一樣)來儲存使用者的選擇,那就不能在beginrequest階段來處理了,我是在PreRequestHandlerExecute事件觸發時處理:
void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
string lang = string.Empty;//default to the invariant culture
lang = Profile.PreferredCulture;
if (string.IsNullOrEmpty(lang))
{
lang = string.Empty;
}
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
}
這時候Profile已經被建立了,所以可以使用了。
2. 多樣式主題轉換Theme switcher
這篇文章講了Theme的切換,覺得形式上和語言的切換很類似。他使用了HttpModule,我覺得直接放在Global.asax檔案裡對應的事件處理髮放下就可以了,說到底都是一樣的。他的儲存採用了cookie,我還覺得用Profile好,既然提供了就用唄,Profile應該是有快取的吧,所以效能應該不是問題。
出處:厚積而勃發BLOG