To offer a website in multiple languages using ASP.Net we simply need to add some resource.resx files to our project and voilà. Based on the language of the browser, IIS will match the localization resource. However, what if we want to give the choice to the user?
The goal
One pattern often used to achieve this, is to split the resource based on the URL.
Ex:
http://www.DomainName.com/EN/About for the English path
http://www.DomainName.com/FR/About for the French path
The needs
We will need something to grab the desired language from the URL and set it as the current language.
The Solution
First, let's add a new route. Asp.Net uses routing to parse the URL and to extract information from it, while keeping the displayed URL more user friendly. The default route is {controller}/{action}/{id}. So without a new route, our language will be treated as a Controller name; but that’s no good.
The route we want is {lang}/{controller}/{action}/{id}. We could just replace the default, but then what would happen to "normal" calls?
The best thing to do is to add our localized route first and keep the default second. The way the routing works, it will use the first route that matches. Since we will use the two-letter code for chosen language, lets add the first part {lang}, which must be two characters long to be considered valid. You can see this in the code where I define a constraint using the following Regex: "^[a-zA-Z]{2}$".
Now that we have the language, we must change the user interface culture of the current thread. I decided to use an Attribute, making it easy to use. Under the Filter folder add a new class which inherits from ActionFilterAttribute. This method will check if "lang" is available from RouteData. If lang is present it will change the currentUICulture of the current thread. If "lang" is not part of the URL, then it will set it to the default.
We could put the [Localization] attribute on all controller classes, but a best practice is to create a BaseController class and use it there.
Voilà, you can now change the language of the entire website by changing the URL.
Bonus: Use it everywhere
To use it in the view and the controller it's easy; just add the namespace and just type Resources.NameOfYourResourceString.
To use it in the validation and the generated code from the model, we could use something like this:
This way, in the view, the code will still stay clean and simple.
@Html.LabelFor(model.UserName)
I hope this post helps you in your development efforts. Any comments, suggestions and/or questions are welcome.
~Frank