Setting Culture For ASP.NET Page Request

.NET makes it easy to work with different locales by using the System.Globalization.CultureInfo class.  In a web application you can take advantage of culture specific behaviors such as date and currency formats by setting the executing thread’s culture properties.  Doing this allows your application properly format a decimal when you call you use formatting like “{0:C}” for currency, see Numeric Formatting Strings.

Problem:  Need to store user’s preferred culture and set the culture on page request so that the application take advantage of user’s setting.

Solution:  There are are a number of ways to store the culture.  I like to have options so, I the following three areas: url query string, cookies, and user language (from browser).  You can also use session, database, sub domain (i.e. en.mysite.com for english), but I find these three to be to be the lightest weight and work well.

1.   Create a HttpModule to step into the request pipeline and set the thread’s culture.  Below shows the module I use.  Notice the order of precedence for getting language.  I first check cookie, then query string, and final browser language.  The key to getting the application to use the correct culture is the lines where we set Thread.CurrentThread culture properties.  Finally I store whatever value I find back in a cookie for the next time.

using System.Globalization;
using System.Web;
using System.Threading;

namespace MyAssembly {
public class LocalizationModule : IHttpModule
{
private static readonly string LANGUAGE_CULTURE_PARAM = "lang";
private static readonly CultureInfo DEFAULT_CULTURE = new CultureInfo("en");

public void Dispose() { }

public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new System.EventHandler(context_PreRequestHandlerExecute);
}

void context_PreRequestHandlerExecute(object sender, System.EventArgs e)
{
HttpRequest request = HttpContext.Current.Request;
HttpCookie cookie = request.Cookies[LANGUAGE_CULTURE_PARAM];
string lang = null;
CultureInfo ci;

if (cookie != null) // check cookie first
lang = request.Cookies[LANGUAGE_CULTURE_PARAM].Value;
else if (request.QueryString[LANGUAGE_CULTURE_PARAM] != null) // chceck query string second
lang = request.QueryString[LANGUAGE_CULTURE_PARAM];
else if (request.UserLanguages.Length > 0) // check browser language third
lang = request.UserLanguages[0];

// don't do this if you are using sub cultures like en-GB
lang = lang == null ? DEFAULT_CULTURE.Name : lang.Split('-')[0];

try
{
ci = new CultureInfo(lang);
}
catch
{
ci = DEFAULT_CULTURE;
}
// set thread's culture properties
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
// store cookie value for user's preference
if (cookie == null)
{
cookie = new HttpCookie(LANGUAGE_CULTURE_PARAM, ci.TwoLetterISOLanguageName);
HttpContext.Current.Response.AppendCookie(cookie);
}
else
cookie.Value = lang;

cookie.Path = "/";
}
}}


2.  The last task is to register the module in the web.config file.  Below shows the configuration under the system.web section of the configuration file.

<system.web>
...
<httpModules>
<add name="LocalizationModule" type="MyAssembly.LocalizationModule, MyAssembly" />
</httpModules>
...
</system.web>

No comments: