In my previous post I described the way of localization using session, but in real-world applications it's definitely not the best way of localization. Now I'll describe very simple and very powerful way of storing it in URL using routing mechanism.
Also this way of localization will not require OutputCache tricks described in previous post
The goal of this post is to show how to get URL like this/{culture}/{Controller}/{Action}... in your application like /ru/Home/About.
Custom Route Handlers
First of all we'll need to extend standard MvcRouteHandler class. One classMultiCultureMvcRouteHandler for routes that will use culture in params andSingleCultureMvcRouteHandler class (will be used as a marker, no implementation changes)
In the overridden GetHttpHandler before calling it's base implementation we just get "culture" param from RouteData collection, create CultureInfo object and set it to current thread current culture. So here is a place where we set culture and will not useApplication_AcquireRequestState method in Global.asax
As I mention this class will be used only for marking some routes for case if you'll need some routes to be culture independent.
Now lets go to Global.asax file where we have route registering methodRegisterRoutes(). Right after last route mapping add foreach statement code snippet like in the following example.
OK, lets go through this code... So for each route we first of all check whether its handler type is SingleCultureMvcRouteHandler or not... So if not we change RouteHandler property of the current route to MultiCulture one, add prefix to Url, add default culture and finally add constraint for culture param checking.
And enum of cultures
Simple culture switching mechanism
For changing culture we'll need following simple action which I placed in AccountController
and partial view with languages links - CultureSwitchControl.ascx
Single culture case
Finally, if we need some single culture route all we need to do is to set RouteHandlerproperty to SingleCultureMvcRouteHandler like this
So, that's it :) Localization without using Session, without problems with OutputCache(will be explained in my next post) and with use of routing.
Here is the link of source code(project created in VS2010)
Also this way of localization will not require OutputCache tricks described in previous post
The goal of this post is to show how to get URL like this/{culture}/{Controller}/{Action}... in your application like /ru/Home/About.
Custom Route Handlers
First of all we'll need to extend standard MvcRouteHandler class. One classMultiCultureMvcRouteHandler for routes that will use culture in params andSingleCultureMvcRouteHandler class (will be used as a marker, no implementation changes)
public class MultiCultureMvcRouteHandler : MvcRouteHandler { protected override IHttpHandler GetHttpHandler(RequestContext requestContext) { var culture = requestContext.RouteData.Values["culture"].ToString(); var ci = new CultureInfo(culture); Thread.CurrentThread.CurrentUICulture = ci; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name); return base.GetHttpHandler(requestContext); } }
In the overridden GetHttpHandler before calling it's base implementation we just get "culture" param from RouteData collection, create CultureInfo object and set it to current thread current culture. So here is a place where we set culture and will not useApplication_AcquireRequestState method in Global.asax
public class SingleCultureMvcRouteHandler : MvcRouteHandler {}
As I mention this class will be used only for marking some routes for case if you'll need some routes to be culture independent.
Registering routes
Now lets go to Global.asax file where we have route registering methodRegisterRoutes(). Right after last route mapping add foreach statement code snippet like in the following example.
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())); } } }
OK, lets go through this code... So for each route we first of all check whether its handler type is SingleCultureMvcRouteHandler or not... So if not we change RouteHandler property of the current route to MultiCulture one, add prefix to Url, add default culture and finally add constraint for culture param checking.
public class CultureConstraint : IRouteConstraint { private string[] _values; public CultureConstraint(params string[] values) { this._values = values; } public bool Match(HttpContextBase httpContext,Route route,string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { // Get the value called "parameterName" from the // RouteValueDictionary called "value" string value = values[parameterName].ToString(); // Return true is the list of allowed values contains // this value. return _values.Contains(value); } }
And enum of cultures
public enum Culture { ru = 1, en = 2 }
Simple culture switching mechanism
For changing culture we'll need following simple action which I placed in AccountController
public ActionResult ChangeCulture(Culture lang, string returnUrl) { if (returnUrl.Length >= 3) { returnUrl = returnUrl.Substring(3); } return Redirect("/" + lang.ToString() + returnUrl); }
and partial view with languages links - CultureSwitchControl.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <%= Html.ActionLink("eng", "ChangeCulture", "Account", new { lang = (int)MvcLocalization.Helpers.Culture.en, returnUrl = this.Request.RawUrl }, new { @class = "culture-link" })%> <%= Html.ActionLink("рус", "ChangeCulture", "Account", new { lang = (int)MvcLocalization.Helpers.Culture.ru, returnUrl = this.Request.RawUrl }, new { @class = "culture-link" })%>
Single culture case
Finally, if we need some single culture route all we need to do is to set RouteHandlerproperty to SingleCultureMvcRouteHandler like this
routes.MapRoute( "AboutRoute", "About", new { controller = "Home", action = "About"} ).RouteHandler = new SingleCultureMvcRouteHandler();
So, that's it :) Localization without using Session, without problems with OutputCache(will be explained in my next post) and with use of routing.
Here is the link of source code(project created in VS2010)
Комментариев нет:
Отправить комментарий