onsdag 13 maj 2009

Top domain based web localization support

There are a couple of different ways on how to deal with web site localization. In some cases you simply want to display text and images in a given languages either by sniffing the user’s browser language setting or letting users select a language of choice. Other times you may want to have a top domain locked into a specific language. This post will discuss one method of supporting the latter.

Imagine you’re a web developer being assigned the task of creating an e-commerce web application that should support the following requirements:

  • One single application instance should allow users browse the site and retrieve the web pages translated to their language.
  • The application should emit the content in the language corresponding to the top domain, such as
    • .com –> English pages
    • .se –> Swedish pages
    • .de –> German pages
    • and so on…
  • Visiting a particular top domain of the e-commerce site you should only have that domains corresponding language displayed, i.e. selecting a different language in the event of a Select language option you should be seeing the selected language’s top domain reflected in the URI. Either you’re browsing Swedish stuff, or you’re browsing American stuff.
  • In this e-commerce site, web content like products should contain language specific prices, descriptions and the like and it should be a breeze for you, the web developer, determining how to gather product data corresponding to the users language – or rather, top domain choice.

One way of fulfilling the requirements listed is by making use of the IHttpModule interface. One great aspect of the IHttpModule interface is that it allows you to hook up with events such as BeginRequest and perform whatever you need to before the page and subsequent requests and events happen. Not too seldom I’ve used http modules to gather and set some members frequently needed by many pages and controls in order to avoid having to run the same calls from every single page and/or control. Doing this one time at the beginning and keep the result readily available for later often comes handy.

So, let’s see how we solve the issue at hand, namely create a web application supporting the requirements listed above by using the IHttpModule interface. Below is an example implementation snippet of a http module that sets the threads culture members in addition to a static CultureInfo object that we can use from any page within the web application.

public static CultureInfo Culture { get; set; }

public void Init(HttpApplication context)
{
// Hook up the BeginRequest event.
context.BeginRequest += new EventHandler(this.context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context
= ((HttpApplication)sender).Context;
string fileExtension = VirtualPathUtility.GetExtension(context.Request.FilePath).ToLower();

// We only want to run this once for each .aspx page being loaded.
if (fileExtension.Equals(".aspx"))
{
string topDomain;
try
{
// Determine the hosts top domain
topDomain = context.Request.Url.Host.Substring(context.Request.Url.Host.LastIndexOf('.'),
context.Request.Url.Host.Length);
}
catch (Exception)
{
// We do this for 2 reasons.
// 1) Make sure we can fall back on a language should it happen so we have better
// host header support than actual localization material
// 2) Under localhost development we need to be able to set a default language,
// and also be able to change between them for test, debug and other.
topDomain = "se";
}
// Switch through some supported top domains and set Culture member to the corresponding language.
// Note! default sets Culture to Swedish. This could as well be configurable through an AppSetting
// rather than hardcoded here.
switch (topDomain)
{
case "se":
Culture
= new System.Globalization.CultureInfo("sv-SE");
break;
case "com":
Culture
= new System.Globalization.CultureInfo("en-US");
break;
case "de":
Culture
= new System.Globalization.CultureInfo("de-DE");
break;
default:
Culture
= new System.Globalization.CultureInfo("sv-SE");
break;
}

// Set the culture properties for both UICulture and Culture
System.Threading.Thread.CurrentThread.CurrentUICulture = Culture;
System.Threading.Thread.CurrentThread.CurrentCulture
= Culture;
}
}



As you may have noticed there is certainly room for improvements to this code but I hope it illustrates the purpose. This particular implementation will fall back on Swedish if you’d visit the site using a host like http://www.yourdomainname.fi/.


Having set the Culture member we can now use it in .aspx pages and .ascx user controls like below:

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
gvProducts.DataSource
= DAL.GetProducts(InstanceModule.Culture.Name, dataFilePath);
gvProducts.DataBind();
}
}

Pretty nice!

In order to not become an overly wordy post I created a tiny sample application using the http module implementation above so you can play around and see how it works. Change the line topDomain = "com"; to topDomain = "se"; in the catch statement above and notice how the Swedish products are picked up instead of the English ones. The thourough observer may also notice there is no .resx file specific for Swedish but due to the fallback mechanism built into the framework we’ll still get Swedish cause the default .resx contains Swedish.


Download code

About time entering cyber space!

Reading this? Welcome to my blog!

Although having spent half my life around computing I never really got hooked on the latest and greatest social computing technologies and forums like blogging, Facebook, Twitter, Live spaces and other. I guess I considered myself busy enough on other things but producing text for blog posts, posting status updates like being stuck in traffic jam, mowing the lawn or other no one would ever care reading anyway.

- Or would they? No clue. Better test this out or be stuck in uncertainty forever.

For now I’ll use this place to share some stuff I hope might be of interest to others that may run into similar issues as I’ve done myself. I think it’s fair to say I’ve gotten (or should have gotten) a fairly good understanding of a few areas such as:

  • Software globalization and localization
  • Web development using primarily Microsoft technologies
  • Database development
  • .Net Framework developing using C#
  • And other random software related areas

So, them postings ain’t gonna post themselves. Better get going! Stay tuned for the first one. Think it’ll be something related to software localization from a web development perspective.

Välkommen! (Welcome!)