Change culture based on a link MVC4

Cosmin picture Cosmin · Feb 27, 2013 · Viewed 9.5k times · Source

I have a curiosity related to culture change in MVC. I tried in 2 ways, but apparently I was wrong somewhere.

In my Web.config I have :

 <globalization uiCulture="auto" culture="auto" />

This is how I tried to change the thread culture :

 <li>@Html.ActionLink("Eng", "ChangeCulture", "Home", new { lang="en-US"}, new { @class = "languageSelectorEnglish" })</li>

First method

I have the following controller :

    public void ChangeCulture(string lang)
    {
        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(lang);
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang);

        Response.Cookies.Remove("Language");
        var langCookie = new HttpCookie("Language");
        langCookie["Language"] = lang;
        langCookie.Value = lang;
        langCookie.Expires = System.DateTime.Now.AddDays(21);
        Response.Cookies.Add(langCookie);

        Response.Redirect(Request.UrlReferrer.ToString());
    }

Second method

    public ActionResult ChangeCulture(string lang)
    {
        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(lang);
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang);

        // Split the url to url + query string
        var fullUrl= Request.UrlReferrer.ToString();
        var questionMarkIndex = fullUrl.IndexOf('?');
        string queryString = null;
        string url = fullUrl;
        if (questionMarkIndex != -1) // There is a QueryString
        {
            url = fullUrl.Substring(0, questionMarkIndex);
            queryString = fullUrl.Substring(questionMarkIndex + 1);
        }

        // Arranges
        var request = new HttpRequest(null, url, queryString);
        var response = new HttpResponse(new StringWriter());
        var httpContext = new HttpContext(request, response);

        var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

        // Extract the data    
        var values = routeData.Values;
        var controllerName = values["controller"];
        var actionName = values["action"];
        var areaName = values["area"];

        return RedirectToAction(actionName.ToString());
    }

Where am I wrong ? Thank you.

Answer

Cosmin picture Cosmin · Feb 27, 2013

It's seems I need to override the culture for my resource strings and not the thread. So my final method is this :

    public void ChangeCulture(string lang)
    {
         Resources.Resources.Culture = new CultureInfo(lang);

         Response.Redirect(Request.UrlReferrer.ToString());
    }

Hope this helps.

UPDATE :

The code above is not good when your application is used by multiple users, because it sets same culture for every user, no matter what browser they are using.

The good way to do it is to make a method which sets a cookie in your browser :

    public void ChangeCulture(string lang)
    {
        Response.Cookies.Remove("Language");

        HttpCookie languageCookie = System.Web.HttpContext.Current.Request.Cookies["Language"];

        if (languageCookie == null) languageCookie = new HttpCookie("Language");

        languageCookie.Value = lang;

        languageCookie.Expires = DateTime.Now.AddDays(10);

        Response.SetCookie(languageCookie);

        Response.Redirect(Request.UrlReferrer.ToString());
    }

After this ( the tricky way ) you need to make every controller to inherit from one BaseController. It is tricky because you need to override Initialize.

protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {


        HttpCookie languageCookie = System.Web.HttpContext.Current.Request.Cookies["Language"];
        if (languageCookie != null)
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo(languageCookie.Value);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(languageCookie.Value);
        }
        else
        {
        //other code here
        }


        base.Initialize(requestContext);
    }