How to store culture in the URL instead of a cookie?
There can be different reasons why you want the culture to be part of your website url (such as search engine indexing). Anyway. First let's fist define the culture to be part of our routes. Edit RouteConfig.cs like below:
1
2
3
4
5
6
7
8
9
| public static void RegisterRoutes(RouteCollection routes){ routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{culture}/{controller}/{action}/{id}", defaults: new {culture = CultureHelper.GetDefaultCulture(), controller = "Home", action = "Index", id = UrlParameter.Optional } );} |
Notice the we used the default culture in case it is missing. Now modify the base controller:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state){ string cultureName = RouteData.Values["culture"] as string; // Attempt to read the culture cookie from Request if (cultureName == null) cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ? Request.UserLanguages[0] : null; // obtain it from HTTP header AcceptLanguages // Validate culture name cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe if (RouteData.Values["culture"] as string != cultureName) { // Force a valid culture in the URL RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too // Redirect user Response.RedirectToRoute(RouteData.Values); } // Modify current thread's cultures Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName); Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; return base.BeginExecuteCore(callback, state);} |
The final step is to modify the SetCulture action in HomeController.cs
1
2
3
4
5
6
7
8
9
| public ActionResult SetCulture(string culture){ // Validate input culture = CultureHelper.GetImplementedCulture(culture); RouteData.Values["culture"] = culture; // set culture return RedirectToAction("Index");} |
NOTE: To force the default culture appear in the URL, simply set the default value for culture in RouteConfig.cs to string.Empty
Summary
Building a multilingual web application is not an easy task. but it's worth it especially for web applications targeting users from all over the world, something which many sites do. It is true that globalization is not the first priority in site development process, however, it should be well planned early in the stage of development so it can be easily implemented in the future. Luckily, ASP.NET supports globalization and there are plenty of .NET classes that are handy. We have seen how to create an ASP.NET MVC application that supports 3 different languages, including a right-to-left one, which requires a different UI layout. Anyway, here is a summary of how to globalize a site in ASP.NET MVC:
- Add a base controller from which all controllers inherit. This controller will intercept the view names returned and will adjust them depending on the current culture set.
- Add a helper class that stores the list of culture names that the site will support.
- Create resource files that contain translation of all string messages. (e.g. Resources.resx, Resources.es.resx, Resources.ar.resx, etc )
- Update views to use localized text.
- Localize javascript files.
I hope this helps!
Any questions or comments are welcome!
Any questions or comments are welcome!
Thank you for this tutorial. I have impemented it in my web application and it is work fine. But I faced the problem that application always started with default culture defined in CultureHelper class. And did not use browser language settings. I solved it by modifying this code "if (cultureName == null)" in BeginExecuteCore to "if (cultureName == null) || cultureName == string.Empty".
ReplyDelete