Change culture based on a link MVC4

2019-02-06 10:40发布

问题:

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.

回答1:

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);
    }


回答2:

Remove the line in your web.config:

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

Setting these to auto will default the language to the user's language set on the browser. This is overriding your Thread setting.