惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog
D
Docker
J
Java Code Geeks
腾讯CDC
Blog — PlanetScale
Blog — PlanetScale
G
Google Developers Blog
M
MIT News - Artificial intelligence
L
LangChain Blog
T
The Blog of Author Tim Ferriss
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
博客园 - Franky
GbyAI
GbyAI
Hugging Face - Blog
Hugging Face - Blog
aimingoo的专栏
aimingoo的专栏
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
N
Netflix TechBlog - Medium
B
Blog RSS Feed
Y
Y Combinator Blog
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News

博客园 - 想想

通过 ASP.NET 4.0、Visual Studio 2010 和 IIS7 实现的搜索引擎优化 WidgetIfYr.com:将代码转化为Widget TheUniformProject:1件衣服365种穿法 使用SandCastle和HTML Help 2.0集成XML代码注释到VS2005和VS2008 iCalendar 中文VS2008安装MVC框架后,不显示相关模板 无法在证书存储区中找到清单签名证书 HttpModule实现简单权限限制访问 什么是数据持久性? 向google,baidu,yahoo,msn,sogou等搜索引擎提交网站 什么是 ASP.NET? (悼念四川地震死难者)使整个网页变黑白色(灰色)的特效代码 window.open 参数 详细说明 Response.Redirect 打开新窗口的方法 如果有一些引用存在于标记中,则不会重命名这些引用,要继续吗 如何用VS2005制作Web安装程序 ASP.NET弹出日历 在IIS 6.0环境下运行ASP.NET 1.1 CSS色谱表
模板页全球化
想想 · 2009-11-10 · via 博客园 - 想想

Introduction

This article explains a page independent way of performing Master Page globalization. Implementation details and complete code snippets are included.

Background

The difficult thing about doing Master Page globalization is that the MasterPage class does not have the InitializeCulture method for us to override. This is significant because the InitializeCulture method is called very early in the page life cycle, and thus is able to affect the initialization of the controls. None of the methods of the MasterPage class can do this. (The best we could do with MasterPage is OnInit, which is not early enough.)

To get around this problem, we have three choices:

  1. Override the InitializeCulture method in the pages that use the master page.
  2. Set the culture in one of the MasterPage's event handlers and reload the master page to recreate the controls.
  3. Set the culture in Global.asax. Global.asax is the first thing called upon page request, and thus provides us with a way to affect control creation.

Because the culture of the current thread resets to default on page redirect and other events, the culture setting process has to take place per request. For this reason, the second solution mentioned above is not acceptable for performance and user experience reasons.

Many articles and forum posts talk about how to implement the first solution. Instead of having InitializeCulture in each page, a more elegant way is to have a base page that handles the culture setting and is inherited by all the pages in the website/web application.

In this article, I would like to talk about the third solution, which allows developers to simply drop a master page to the website/application and make the culture switch work. Implementation details are explained in the following sections.

Setting the Culture in Global.asax

The first task we have here is setting the culture in Global.asax. Cookies are used here because session objects are not accessible in the context when BeginRequest executes.

Global.asax:

Collapse Copy Code

protected void Application_BeginRequest(object sender, EventArgs e)
{
     HttpCookie cookie = Request.Cookies["CultureInfo"];

     if (cookie != null && cookie.Value != null)
     {
         Thread.CurrentThread.CurrentUICulture = new CultureInfo(cookie.Value);
         Thread.CurrentThread.CurrentCulture = new CultureInfo(cookie.Value);
     }
    else
    {
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-CA");
        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-CA");
    } 
}

The code reads the stored culture information from the cookie and uses it, if it's not null, to set the current thread culture.

Use a Drop Down List to Change the Culture

The next task is to add the drop down list to the master page.

.Master:

Collapse Copy Code

<asp:DropDownList ID="ddlLanguage" runat="server" 
       OnSelectedIndexChanged="ddlLanguage_SelectedIndexChanged"
       AutoPostBack="true">
    <asp:ListItem Text="<%$ Resources:Resource, users_English %>" Value="en-CA" />
    <asp:ListItem Text="<%$ Resources:Resource, users_French %>" Value="fr-CA" />
</asp:DropDownList>

Then, we implement the drop down list event handler that stores the selected culture value in the cookie.

.Master.cs:

Collapse Copy Code

protected void ddlLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
    
    HttpCookie cookie = new HttpCookie("CultureInfo");
    cookie.Value = ddlLanguage.SelectedValue;
    Response.Cookies.Add(cookie);

    
    
    Thread.CurrentThread.CurrentCulture = 
                  new CultureInfo(ddlLanguage.SelectedValue);
    Thread.CurrentThread.CurrentUICulture = 
                  new CultureInfo(ddlLanguage.SelectedValue);
    Server.Transfer(Request.Path);
}

As stated in the comments above, setting the culture and performing a reload forces the thread culture to change immediately.

Display the Current Culture in the Drop Down List

Finally, we would like the drop down list to have the current culture as the selected value.

.Master.cs:

Collapse Copy Code

protected void Page_Load(object sender, EventArgs e)
{
    
    
    if (!Page.IsPostBack)
    {
        ddlLanguage.SelectedValue = Thread.CurrentThread.CurrentCulture.Name;
    }
}

Note that it only happens for non-postback events. If we do it for postback events as well, the user selection will be overridden before it reaches the event handler. Another way of getting around this problem is by polling the selected value of the drop down list in Global.asax.

Complete Code Snippets

Global.asax:

Collapse Copy Code

protected void Application_BeginRequest(object sender, EventArgs e)
{
     HttpCookie cookie = Request.Cookies["CultureInfo"];

     if (cookie != null && cookie.Value != null)
     {
         Thread.CurrentThread.CurrentUICulture = new CultureInfo(cookie.Value);
         Thread.CurrentThread.CurrentCulture = new CultureInfo(cookie.Value);
     }
    else
    {
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-CA");
        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-CA");
    }

}

.Master.cs:

Collapse Copy Code

protected void Page_Load(object sender, EventArgs e)
{ 
    
    
    if (!Page.IsPostBack)
	{
        ddlLanguage.SelectedValue = Thread.CurrentThread.CurrentCulture.Name;
    }
}

protected void ddlLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
    
    HttpCookie cookie = new HttpCookie("CultureInfo");
    cookie.Value = ddlLanguage.SelectedValue;
    Response.Cookies.Add(cookie);

    
    
    Thread.CurrentThread.CurrentCulture = new CultureInfo(ddlLanguage.SelectedValue);
    Thread.CurrentThread.CurrentUICulture = new CultureInfo(ddlLanguage.SelectedValue);
    Server.Transfer(Request.Path);
}

.Master:

Collapse Copy Code

<asp:DropDownList ID="ddlLanguage" runat="server" 
           OnSelectedIndexChanged="ddlLanguage_SelectedIndexChanged"
           AutoPostBack="true">
    <asp:ListItem Text="<%$ Resources:Resource, users_English %>" Value="en-CA" />
    <asp:ListItem Text="<%$ Resources:Resource, users_French %>" Value="fr-CA" /> 
</asp:DropDownList>