views:

697

answers:

3

Hi,

i'd like to create localized URL's for my site. They should obviously point to the same controller actions, but I want the first routevalues to -always- be the location/language specification. Is this possible?

http://www.website.com/en/us/controller/action

http://www.website.com/en/gb/controller/action

I understand it can be done by defining {language} and {location} in every route, but i'm looking for a slick, non-hacky solution.

+3  A: 

You can create a route that has the culture built into it like this...

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

    routes.MapRoute(
        "Default",                                              // Route name
        "{culture}/{controller}/{action}/{id}",                           // URL with parameters
        new { culture="en-US", controller = "Home", action = "Index", id = "" }  // Parameter defaults
    );

}

You can get the culture by adding a culture parameter to all your actions like this...

public ActionResult Index(string culture)
{
    ViewData["Message"] = "Welcome to ASP.NET MVC! (" + culture + ")";

    return View();
}

You can also probably parse the URL in the Application_BeginRequest method in Global.asax and set the threads culture there (code sample below shows how to set the culture, the parsing I leave to you).

If you do this you will probably not be able to use the RedirectToAction and HTML.ActionLink type of methods since those don't know anything about cultures. Of course you could always write your own.

The downside to using the url to store the culture is that if you miss a link somewhere on your website or the user leaves the website and then comes back, you could lose the users culture and they will have to set it again (not the end of the world, but annoying. Possibly a good side of using the url to store the culture is that Google will index all the different languages.

If you are more concerned about user experience or ease of development over Google indexing different cultures (really depends on what kind of site you are building), I would suggest storing the culture in a cookie or session state.

Check out How to localize ASP .Net MVC application?. The accepted answer points to a blog post that shows how you can localize an ASP.Net application.

If you store the culture the user selects in a cookie, session state, or query parameter and then set the threads culture in the BeginRequest method in the Global.asax file. Then localization is done using the standard Microsoft localization assemblies.

The following code will allow you to change the culture at any time by simply adding culture=?? to the query string (MyPage?culture=es-MX). It will then be added to a cookie so that you don't need to add it to the end of every link in your system.

protected void Application_BeginRequest()
{
    var culture = Request["culture"];
    if (culture == null) culture = "en-US";
    var ci = CultureInfo.GetCultureInfo(culture);

    Thread.CurrentThread.CurrentCulture = ci;
    Thread.CurrentThread.CurrentUICulture = ci;

    var cookie = new HttpCookie("culture", ci.Name);
    Response.Cookies.Add(cookie);
}
Brian
He is asking for a way to add the culture and language in all the routes.
Eduardo Molteni
I understood that. What I suggested was a way to do it without adding it to the routes. Adding it to the routes needlessly complicates the application.
Brian
If there were an answer to my question, could you specify what would be complication the situation?
Ropstah
I updated my answer with information about how to modify the route to allow for culture in the url.
Brian
I was hoping for a route-inheritance kind of solution to be possible. Thank you for your clear answer, looking at my requirements the most notable benefit of storing culture in the URL (google indexing) is probably not the most required one. Would the creation of seperate route files for each language (or obviously prefixing every route with a culture routevalue) be the only solution to use 'cultured-urls' and keep ActionLink.RouteUrl functionality?
Ropstah
You could probably set up "route inheritance" easily enough. Just add the route I mentioned before the default MVC route and either remove the defaults or use a regular expression to determine if the culture route should be used. If you don't, the default controller would never get hit.There might be a way to automatically get the MVC ActionLink methods to put the culture into the url. Html.ActionLink does allow you to specify route values. I have not tried this before so I am not sure if this would work for you or not.
Brian
+1  A: 

Output caching relies on URL variations. Consider this when designing your localization strategy. If you are planning on using output caching, embed the localization token somewhere within the URL.

Allan McLemore
Good point, thanks!
Ropstah
+1  A: 

This seems to be a much better aproach: http://microsoft.realdolmenblogs.com/post/Translating-routes-(ASPNET-MVC-and-Webforms).aspx

BrunoSalvino