0

I created the current solution some time ago with the help of a tutorial. At the time it looked like a best solution. I created the solution by adding Application event Listener AcquireRequestState into global.asax. Here I than checked , through simple condition, if there is a Session running. If there was one, I adjusted according to it. (see code below)

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    HttpContext context = HttpContext.Current;
    if (context != null && context.Session != null && Session[sessionNameCulture] != null)
    {
        string culture = Session[sessionNameCulture].ToString();
        try
        {
            culture = culture.ToLower();
            Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); ;
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture); ;
        }
        catch (Exception ex)
        {
            ErrorHandler.HandleError("Culture info setup failure.", ex);
        }
    }

}

Back to my question. I need to, when there is no existing Session, to set culture according to the settings of the browser. Unfortunately, the event is being called approx. three times and during one of the calls:

if(Session[sessionNameCulture] == null)

It ends up with exception. I found an alternative solution, which would consist of moving the logic into BaseController, where I could catch the Page_load event or use something like this.

Before I start redoing the whole project, I would like to make sure there isn’t a way to solve this through catching Application events. I have in mind something like:

protected void Application_AcquireRequestState(object sender, EventArgs e) {
    HttpContext context = HttpContext.Current; if(Session[sessionNameCulture] == null)
           Session[SessionNameCulture] = new System.Globalization.CultureInfo(Request.UserLanguages[0]);

    if (context != null && context.Session != null && Session[sessionNameCulture] != null)
    {
     ...    }

Also, it might be a problem that this is supposed to work for a not logged in user.

P.Milan
  • 73
  • 1
  • 14

1 Answers1

1

For cross-cutting concerns such as localization, you should generally avoid using the old ASP.NET event model.

You should also avoid using base classes for controllers, because that will tightly bind your controllers to the base class, and make it difficult to deal with if the shared base class needs an injected service to run some business logic or access the database.

Since MVC 3 there are now filters that can (and should) be used to implement cross-cutting concerns. You can implement each piece of logic in its own filter (which adhere to the Single Responsibility Principle), inject dependencies, and even make the filter conditional by using custom attributes.

Specifically for localization, see this example that uses routing rather than session state to track the culture, and a filter to set the culture of the current thread based on the routing.

Related: Think twice about using session state

Setting Language Based on Browser

The official way to get the settings from the user's browser is to use Request.UserLanguages.

Example:

// Get Browser languages.
var defaultCulture = "en-us";
var userLanguages = Request.UserLanguages;
CultureInfo ci;
if (userLanguages.Count() > 0)
{
    try
    {
        ci = new CultureInfo(userLanguages[0]);
    }
    catch(CultureNotFoundException)
    {
         ci = new CultureInfo(defaultCulture);
    }
}
else
{
    ci = new CultureInfo(defaultCulture);
}
// Here CultureInfo should already be set to either user's prefereable language
// or to defaultCulture if user transmitted invalid culture ID

That said I strongly recommend you stay away from this approach. These settings (which come from page headers) could be manipulated by any number of firewalls, and therefore don't necessarily reflect the "user's requested language". They may even contain invalid values (hence the try-catch above).

Also, if your site is Internet facing, your efforts for localization will be entirely wasted as far as SEO is concerned. Google's official recommendations are:

  • if you’re going to localize, make it visible in the search results
  • keep the content for each language on separate URLs
  • Google tries to determine the main languages of each one of your pages. You can help to make language recognition easier if you stick to only one language per page

Odds are that if you switch the page language that is displayed on a single URL by using headers, you are missing out on any traffic coming from search engines in anything but the default language because none of the other languages will be indexed. You may even make it impossible for users to view the site in their language of choice (because some firewall decides that the user languages header should default to a specific language).


True Story

I had my browser's home page set to MSN for several years. However, when I moved to Thailand suddenly the page was displayed in Thai. At that time, I could not read Thai.

Even worse, there was no (obvious) way to select the language from the user interface. When I tried to change the URL to en-us, it redirected me back to the page in Thai language. I hunted for quite some time, but couldn't find a solution to switch the page back to English. While I don't know the specific reason why I couldn't change to English, I do know that some programmer at Microsoft made a bad decision about how to localize MSN.com and it was preventing me from accessing the site.

That was 7 years ago. Since then, my home page has been set to Google. Recently, I tried to use the MSN site, and it still does not have a way to switch it to English.

The point: Always give the user a choice of what language to view. The best way is by putting each language on a different URL.

Community
  • 1
  • 1
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • Sorry, maybe I did not exactly explain the problem. I looking for the solution how to localize website based on a setting of the web browser. – P.Milan Apr 08 '16 at 12:06