收录日期:2019/10/18 22:05:10 时间:2009-11-11 00:13:16 标签:asp.net-mvc,localization,routes

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.

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

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.

Here is a blog where described very simple and very powerful way of storing localization in URL using routing mechanism. http://adamyan.blogspot.com/2010/07/addition-to-aspnet-mvc-localization.html

The core is to add new parameter to all routes of specified type

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

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

    foreach (Route r in routes)
    {
        if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
        {
            r.RouteHandler = new MultiCultureMvcRouteHandler();
            r.Url = "{culture}/" + r.Url;
           //Adding default culture 
           if (r.Defaults == null)
           {
               r.Defaults = new RouteValueDictionary();
           }
           r.Defaults.Add("culture", Culture.ru.ToString());

           //Adding constraint for culture param
           if (r.Constraints == null)
           {
               r.Constraints = new RouteValueDictionary();
           }
           r.Constraints.Add("culture", new CultureConstraint(Culture.en.ToString(), 
Culture.ru.ToString()));
        }
   }

}

and the switching controller action

public ActionResult ChangeCulture(Culture lang, string returnUrl)
{
     if (returnUrl.Length >= 3)
     {
         returnUrl = returnUrl.Substring(3);
     }
     return Redirect("/" + lang.ToString() + returnUrl);
}