Usually, web applications should be available in multiple languages other than English. In this blogpost, I am going to walk over creating a sample application that will be localized in French and Dutch. Usually, the preferred language is picked from the user's browser settings. To make it a little tougher, we will allow the user to switch languages at runtime. To enable runtime switching of languages, we will add three link buttons in the master page.


<div style="background-color: #cccccc;float:right;">
    <asp:LinkButton ID="btnEn" runat="server" Text="en" CommandArgument="en" OnCommand="SetCulture"></asp:LinkButton> | 
    <asp:LinkButton ID="btnFr" runat="server" Text="fr" CommandArgument="fr" OnCommand="SetCulture"></asp:LinkButton> | 
    <asp:LinkButton ID="btnNl" runat="server" Text="nl" CommandArgument="nl" OnCommand="SetCulture"></asp:LinkButton> 
</div>

Localization is providing a placeholder for text in multiple languages. The text comes from a resource file. Asp.Net provides multiple ways of doing localization: implicit and explicit. In Default.aspx, we enable implicit localization. We allow the text within a label with ID lblImplicit to come from resource files. The code for the label has a meta:resourcekey="" attribute attached to it:


<h2>
    Culture Demo - Implicit Localization
</h2>
<p>
    <asp:Label ID="lblImplicit" runat="server" meta:resourcekey="lblImplicit" Text="Implicit Localization"></asp:Label>
</p>

In implicit localization, the text comes from a resource file defined under App_LocalResources folder. The resource file has the convention of .aspx..resx. The default resource file for default.aspx is default.aspx.resx. The resource file for french is default.aspx.fr.resx. Create resource files for each supported language. Within the resource file, use the .Text to define the text for the label. The french resource file looks like:

We can set explicit localization for About.aspx (just to try it out). Explicit localization looks for resource files under App_GlobalResources. In this folder, resource files are not organized by aspx page names. You can create a default resource file of Messages.resx. In the About.aspx, we can create a label to use Message1 from Messages.resx as follows:


<h2>
    Culture Demo - Explicit Localization
</h2>
<p>
    <asp:Label ID="lblExplicit" Text="<%$ Resources: Messages, Message1 %>" runat="server"></asp:Label>
</p>

In the above label, the text is available within a tag. It has a Resources: keyword. Both the Resource file name as well as the Key name is provided (delimited with a comma). The french resource file for Messages will look like Messages.fr.resx. The dutch resource file, Messages.nl.resx looks like:

 

Now, we are ready to write some code to make all of this work. When we are clicking the link button in the master page, the SetCulture event handler is called. All we do in the below code is set the Session["Culture"] variable to the selected language. Also, the page is redirected to. This will ensure that the selected culture will set in the reload.


protected void SetCulture(object sender, CommandEventArgs e)
{
    Session["Culture"] = e.CommandArgument.ToString();
    Response.Redirect(Request.RawUrl);
}

Every page has a method - InitializeCulture(). This method is triggered in the Page lifecycle ahead of all events including Page_PreInit(). This is one reason that the page is reloaded again. In InitializeCulture(), we pick the language setting from the Session variable. Then, we set the UICulture for the current thread. This will ensure that the right resource files are picked for the current request.


protected override void InitializeCulture()
{
    // When the user comes to the page for the first time
    if (Session["Culture"] == null)
    {
        Session["Culture"] = "en";
        Session["OldCulture"] = "en";
    }

    // Set the UI Culture here

    System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo((string)Session["Culture"]);
    UICulture = (string)Session["Culture"];
    base.InitializeCulture();

}

Finally, there is some code to enable / disable the link buttons in the Page_load of the master page:


protected void Page_Load(object sender, EventArgs e)
{
          
    string culture = (string)Session["Culture"];
    string oldCulture = (string)Session["OldCulture"];

    // Disable the button in current culture
    // This is required if user goes to some other page
    // Page is populated with controls.
    LinkButton newBtn = FindControl("btn" + culture) as LinkButton;
    if (newBtn != null)
        newBtn.Enabled = false;

    // if old culture is different
    // This happens when the user clicks on any of the link buttons
    if (culture != oldCulture)
    {
        // disable the button for the current culture
              

        // enable the old button and reset oldculture  
        LinkButton oldBtn = FindControl("btn" + oldCulture) as LinkButton;
        if (oldBtn != null)
            oldBtn.Enabled = true;
        Session["OldCulture"] = culture;
    }
}

One last thing to note, I have used a baseclass for Page - CultureDemo.MainPage. This class overrides the InitializeCulture method. All pages in the CultureDemo application derive from CultureDemo.MainPage instead of System.Web.UI.Page. This ensures that all page and all requests have the right language setting. The complete application is available in the zip file: CultureDemo