4

I'm creating a MVC5 web site that should support multiple languages. The structure of the app is complex so I'm using Attribute Routing only. RouteConfig.cs is very simple:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapMvcAttributeRoutes();
}

I want to keep language information in URL by adding language identifier after site name. For English, which is default language, URL should remain "clean". Here are an example:

http://test.com/foo/1/bar/2
http://test.com/de/foo/1/bar/2

My first attempt was to use two RoutePrefix attributes for each controller:

[RoutePrefix("foo")]
[RoutePrefix("{lang}/foo")]

But MVC doesn't allow to use more than one RoutePrefix attribute for a controller.

So now I'm not using RoutePrefix attributes at all, and specify full route for each controller action:

[Route("foo/{a}/bar/{b}")]
[Route("{lang}/foo/{a}/bar/{b}")]

Is there any better way to handle lang route? Ideally I would like to specify in one place only, not for every controller.

PS. I'm setting current thread culture by parsing language route in custom filter.

Aleksandr Ivanov
  • 2,778
  • 5
  • 27
  • 35
  • 1
    Have a look at [this answer](http://stackoverflow.com/questions/32764989/asp-net-mvc-5-culture-in-route-and-url#32839796). For attribute routing, read the comments. – NightOwl888 Mar 07 '16 at 11:39
  • So your suggestion is just to add two routes for each action? Or I missed something? – Aleksandr Ivanov Mar 07 '16 at 20:17
  • You could 1) add 2 routes per action 2) use conventional routing or 3) analyze the source for `MapMvcAttributeRoutes` and make a similar method that registers a localized route for each `Route` attribute (be sure to call your custom method before `MapMvcAttributeRoutes` to put the routes into the RouteTable in the right order). – NightOwl888 Mar 07 '16 at 20:45
  • I updated my [other answer](http://stackoverflow.com/questions/32764989/asp-net-mvc-5-culture-in-route-and-url#32839796) with an example of the 3rd option. – NightOwl888 Mar 07 '16 at 21:41
  • Have you tried to execute your code for attribute routing? When method `MapMvcAttributeRoutes()` is called to create a copy of routes, then first route is of type `RouteCollectionRoute` which can't be casted to `Route`. And even if I ignore that, these added localized routes are not working. – Aleksandr Ivanov Mar 09 '16 at 21:54
  • Sorry, I didn't execute it. I have updated the example with a version of `MapLocalizedMvcAttributeRoutes` that works. Unfortunately, due to the types Microsoft used being internal there is little choice but to use Reflection to get it to work. Fortunately, this is something that happens once per application startup/recycle, so the performance hit of using Reflection won't be very noticeable. – NightOwl888 Mar 10 '16 at 15:55

3 Answers3

2

I found the easiest solution (at least for ASP.NET MVC 5.2) is to use a default value for the optional parameter.

For example, if English is your default language, you can use a single attribute on the Controller:

[RoutePrefix("{lang=en}/foo")]

or a single attribute on the Action:

[Route("{lang=en}/foo/bar")]

Note that optional URI parameters (e.g. {lang?}) don't work if they are at the start of the URL.

dionoid
  • 500
  • 4
  • 9
0

If all else fails then I suggest you keep your default routes as is and store the language in a query parameter

For English, your default language, URL will remain "clean" as you intended.

http://test.com/foo/1/bar/2

But for other languages you include lang as query parameter

http://test.com/foo/1/bar/2?lang=De-DE

Then in your custom filter, check if the query parameter is present. If it is then change culture to match. Otherwise use default language.

Also: You should use 5 character encoding and not 2 char globalization ISO code. De-DE and not DE or fr-FR and not FR

Nkosi
  • 235,767
  • 35
  • 427
  • 472
0

You basically need three things:

  • A multi-language aware route to handle incoming URLs (if you're using MVC5 or above you could also go for Attribute-based routing instead, but I still prefer to use a global rule to handle this).
  • A LocalizationAttribute to handle these kinds of multi-language requests.
  • An helper method to generate these URLs within your application (Html.ActionLink and/or Url.Action extension methods).

See this answer for further details and code samples.

(both are written in C# - affiliation disclaimer: I made those samples)

For additional info and further samples you can also read this blog post I wrote on this topic.

http://www.ryadel.com/en/html-actionlink-extension-method-written-c-handle-multi-language-routes-asp-net-mvc/

Darkseal
  • 9,205
  • 8
  • 78
  • 111