What is the best place to set the Culture/UI Culture in an ASP.net MVC app
Currently I have a CultureController class which looks like this:
public class CultureController : Controller
{
public ActionResult SetSpanishCulture()
{
HttpContext.Session["culture"] = "es-ES";
return RedirectToAction("Index", "Home");
}
public ActionResult SetFrenchCulture()
{
HttpContext.Session["culture"] = "fr-FR";
return RedirectToAction("Index", "Home");
}
}
and a hyperlink for each language on the homepage with a link such as this:
<li><%= Html.ActionLink("French", "SetFrenchCulture", "Culture")%></li>
<li><%= Html.ActionLink("Spanish", "SetSpanishCulture", "Culture")%></li>
which works fine but I am thinking there is a more appropriate way to do this.
I am reading the Culture using the following ActionFilter http://www.iansuttle.com/blog/post/ASPNET-MVC-Action-Filter-for-Localized-Sites.aspx. I am a bit of an MVC noob so am not confident I am setting this in the correct place. I don't want to do it at the web.config level, it has to be based on a user's choice. I also don't want to check their http-headers to get the culture from their browser settings.
Edit:
Just to be clear - I am not trying to decide whether to use session or not. I am happy with that bit. What I am trying to work out is if it is best to do this in a Culture controller that has an action method for each Culture to be set, or is there is a better place in the MVC pipeline to do this?
I know this is an old question, but if you really would like to have this working with your ModelBinder (in respect to
DefaultModelBinder.ResourceClassKey = "MyResource";
as well as the resources indicated in the data annotations of the viewmodel classes), the controller or even anActionFilter
is too late to set the culture.The culture could be set in
Application_AcquireRequestState
, for example:EDIT
Actually there is a better way using a custom routehandler which sets the culture according to the url, perfectly described by Alex Adamyan on his blog.
All there is to do is to override the
GetHttpHandler
method and set the culture there.What is the best place is your question. The best place is inside the Controller.Initialize method. MSDN writes that it is called after the constructor and before the action method. In contrary of overriding OnActionExecuting, placing your code in the Initialize method allow you to benefit of having all custom data annotation and attribute on your classes and on your properties to be localized.
For example, my localization logic come from an class that is injected to my custom controller. I have access to this object since Initialize is called after the constructor. I can do the Thread's culture assignation and not having every error message displayed correctly.
Even if your logic is not inside a class like the example I provided, you have access to the RequestContext which allow you to have the URL and HttpContext and the RouteData which you can do basically any parsing possible.
1: Create a custom attribute and override method like this:
2: In App_Start, find FilterConfig.cs, add this attribute. (this works for WHOLE application)
That's it !
If you want to define culture for each controller/action in stead of whole application, you can use this attribute like this:
Or:
Being as it is a setting that is stored per-user, the session is an appropriate place to store the informtion.
I would change your controller to take the culture string as a parameter, rather than having a different action method for each potential culture. Adding a link to the page is easy, and you shouldn't need to write the same code repeatedly any time a new culture is required.
I would do it in the Initialize event of the controller like this...
I'm using this localization method and added a route parameter that sets the culture and language whenever a user visits example.com/xx-xx/
Example:
I have a filter that does the actual culture/language setting:
To activate the Internationalization attribute, simply add it to your class:
Now whenever a visitor goes to http://example.com/de-DE/Home/Index the German site is displayed.
I hope this answers points you in the right direction.
I also made a small MVC 5 example project which you can find here
Just go to http://{yourhost}:{port}/en-us/home/index to see the current date in English (US), or change it to http://{yourhost}:{port}/de-de/home/index for German etcetera.