我要实现这样一个功能,就是按一个按键在两种语言(比如中文和英文)之间切换。
注:我用的是ASP.NET Beta 2。参考文章列在最后。
参考第一篇文章,"Implicit Localization Expressions"一节。一个页面(Page)的本地化内容是在FrameworkInitlize()中创建所有的控件时决定的。比如
button1.Text = ((string)
base.GetLocalResourceObject("LinkButtonResource1.Text"));
所以要在FrameworkInitlize()之前设置好你所需要的页面的文化(Culture).
第二篇文章"Page Lifecycle"一节列出了页面的生命周期(Lifecycle)涉及的方法。下面列出了从页面的构造函数(Constructor)开始与我的问题相关的一些方法。
Constructor
Construct
TestDeviceFilter
AddParsedSubObject
DeterminePostBackMode
OnPreInit
LoadPersonalizationData
InitializeThemes
OnInit
在第三篇文章"The Page Lifecycle"的开头写道:
Once the HTTP page handler class is fully identified, the ASP.NET run
time calls the handler's ProcessRequest method to process the request.
... (it) begins by calling the method FrameworkInitialize, which builds
the controls tree for the page. The method is a protected and virtual
member of the TemplateControl class - the class from which Page itself
derives. Any dynamically generated handler for an .aspx resource
overrides FrameworkInitialize. In this method, the whole control tree
for the page is built.
Next, ProcessRequest makes the page transit various phases:
initialization, loading of view state information and postback data,
loading of the page's user code and execution of postback server-side
events. After that, the page enters in rendering mode: the updated view
state is collected; the HTML code is generated and then sent to the
output console. Finally, the page is unloaded and the request is
considered completely served.
从这里,我推断FrameworkInitlize()至少是在OnPreInit()之前被调用的。但是仍然看不出来FrameworkInitlize的准确位置。
绕过上面所说的这些。有两种方法可以实现上述的要求。
方法一。在某页面的InitializeCulture方法中设置你所需要的文化。比如
{
protected override void InitializeCulture()
{
string cul = Session["UICulture"];
if (!String.IsNullOrEmpty(cul))
{
Thread.CurrentThread.CurrentUICulture =
new CultureInfo(cul);
}
}
}
但这是针对某一个页面的。要应用到整个网站,就要多一点儿麻烦。要把这个InitializeCulture方法写在一个System.Web.UI.Page的子类中,然后让所有页面的类继承于这个子类而不是直接继承System.Web.UI.Page。
方法二。在PreRequestHandlerExecute中设置你所需要的文化。参见HttpApplication类的在线帮助:
An application executes events that are handled by modules or user code that is
defined in the Global.asax file in the following sequence:
1. BeginRequest
2. AuthenticateRequest
3. PostAuthenticateRequest
4. AuthorizeRequest
5. PostAuthorizeRequest
6. ResolveRequestCache
An event handler (a page corresponding to the request URL) is created at this point.
7. PostResolveRequestCache
8. PostMapRequestHandler
9. AcquireRequestState
10. PostAcquireRequestState
11. PreRequestHandlerExecute
The event handler is executed.
12. PostRequestHandlerExecute
13. ...
我试过 BeginRequest, 但是不行。我想原因是因为Page.Request在此之后才被创建或赋值,所以在BeginRequest中设置的文化会被覆盖了。直到 10. PostAcquireRequestState,才被准备好,只有在此之后我们才可以设置所需要的文化。
11和12之间的
"The event handler is executed."就应该是整个页面的生命周期的处理了。方法一使用InitializeCulture就是在这里。
这样就能够达到最初的目的了。但是还有一个小问题。按键的事件处理函数只会在设置了线程的文化之后才会被执行(不论是用PreRequestHandlerExecute,抑或InitializeCulture)。
结果就是在页面的HTML传到浏览器时,所要设的文化与线程的文化不一样。而在其他的事件发生时,由于所要设的文化没有改变,就会和线程的文化一样。这样程序的行为就不一致了,容易使用户产生混淆。有一个不太完善的结局方法,就是在按键的事件处理函数最后加上下面这句,这样用户就能立刻看到改变了的语言了。
缺憾是由于当前页面要重新生成,原先的状态(比如用户已经输入的东西)就不会保留了。
另外还有一个与此相关的问题,就是如何本地化sitemap(网页导航?)。请参考下面这篇文章。
ASP.NET 2.0: 在使用web.sitemap时,如何本地化网页导航(sitemap)
很抱歉,有许多术语不知道准确的中文是什么,希望大家不吝赐教。
参考文章:
- ASP.NET 2.0 Localization Features: A Fresh Approach to Localizing Web Applications
- ASP.NET 2.0 Internals
- The ASP.NET Page Object Model