Search code examples
c#asp.net-mvcrazorasp.net-mvc-routingmultilingual

How to handle multiple language in MVC application?


I've set up my application so that the contents are read from different RESX files, according to the pattern that the router recognizes. Every page is accessible in a certain language depending on the first part of the URL.

routes.MapRoute(
  name: "Localization",
  url: "{lang}/{controller}/{action}/{id}", ...
);

When I'm testing with no specification, I get to the English version of my Lingo.REXS and when I put in se, I get to the Swedish version, i.e. Lingo.se.RESX. Everything's fine this far.

However, I'm not sure how to let the user control the setting of the language. I don't want it to be automatic nor assumed based on the browser's settings, geo-data etc. I basically want three flags (img controls) that somehow magically set that user (or at least that browser session) to be routable with the prefix corresponding to the language of the flag clicked.

So, we have /se/Home/About and /ge/Home/About. The user clicks on the German flag - how do we route them to the latter? And if they click on the Swedish flag - how do we route them to the former?

I've verified with this blog but it doesn't address the actual issue with how to route into a certain language depending on the clicked flag image. I've also found this blog but I simply don't understand how they do it. I see a bunch of calls to a DB so I suspect that it's not based on RESX files (and my understanding is that it's the proper way to go), although there's also some reference to @TestResource.

Right now I'm confused and uncertain. Any suggestions or clarifications?


Solution

  • There is a somewhat non-intuitive feature of MVC that makes this really easy. MVC automatically reuses any route values from the request. So all of your URLs will automatically "inherit" the culture - there is no need to specify it explicitly in ActionLink.

    The one exception is during language selection. But you can take advantage of this same routing behavior to build a common header or footer in your _Layout.cshtml. Whatever route values the current page has will be inherited - all you need to do is specify controller, action, and culture.

    @{ 
        var routeValues = this.ViewContext.RouteData.Values;
        var controller = routeValues["controller"] as string;
        var action = routeValues["action"] as string;
    }
    <ul>
        <li>@Html.ActionLink("Swedish", @action, @controller, new { lang = "se" }, new { rel = "alternate", hreflang = "se" })</li>
        <li>@Html.ActionLink("English", @action, @controller, new { lang = "en" }, new { rel = "alternate", hreflang = "en" })</li>
    </ul>
    

    As mentioned previously, all other links on the page will automatically be passed a culture from the current context, so they will automatically stay within the same culture. There is no reason to pass the culture explicitly in those cases.

    @ActionLink("About", "About", "Home")
    

    With the above link, if the current URL is /Home/Contact, the link that is generated will be /Home/About. If the current URL is /en/Home/Contact, the link will be generated as /en/Home/About.

    Reference: ASP.NET MVC 5 culture in route and url