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.
3 Answers 3
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.
Comments
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
1 Comment
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.ActionLinkand/orUrl.Actionextension methods).
See this answer for further details and code samples.
- Code sample for multi-language Html.ActionLink extension
- Code sample for multi-language Url.Action extension
(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.
Comments
Explore related questions
See similar questions with these tags.
MapMvcAttributeRoutesand make a similar method that registers a localized route for eachRouteattribute (be sure to call your custom method beforeMapMvcAttributeRoutesto put the routes into the RouteTable in the right order).MapMvcAttributeRoutes()is called to create a copy of routes, then first route is of typeRouteCollectionRoutewhich can't be casted toRoute. And even if I ignore that, these added localized routes are not working.