Yesterday I set out to add multi-language support to an ASP.net MVC application and had a bit more difficulty than I had anticipated. The standard suggestions seemed to be "just do it like ASP.net webforms does it." While having a literal point to a resource with a special tag DOES work in mvc (as displayed here for a resource named Title), why not take the opportunity to clean things up a bit and make them more flexible?
<asp:Literal ID="title" runat="server" Text="<%$ Resources:Title%>" />
First, some background.
There are two primary settings in .net relevant to localization: CurrentCulture and CurrentUICulture. For an excellent explanation of what each does read this blog entry. To summarize (and oversimplify), the CurrentCulture controls the formatted output of ToString() calls for dates and numbers while the CurrentUICulture is used to determine which alternative caption resource text to fetch at runtime.
There are 2 types of resources available to you with ASP.net, global and local. Global resources are not tied to any user interface while local resources correspond to a UI element, most commonly an ASPX page.
K Scott Allen has a good post about ASP.net MVC localization here but the tidbits of knowledge he dropped didn't get me to a clean solution. He does demonstrate that for simple projects the App_GlobalResources folder can be used and how to have the ASP.net runtime automatically associate CurrentUICulture
Lets meet the need for a global resource using a tip from Mr. Allen:
Add a new resource file to your project; I throw my global resources under Content but you can put it into any normal folder that you like.
- Add a resource string for testing purposes. (The Name property is actually the key.)
- Now be sure to set the scope to be public in the dropdown provided at the top of the resource editor window.
- Go to the properties window settings for the file and set the custom tool namespace to be the same as your default namespace for your ASP.net mvc solution.
You can now reference your global resources from controllers or from your views like so. (Here I'm referencing a resource by the key GlobalResourceTest located in a resource file named GlobalResources in the namespace MVCExperiment and putting the value into a ViewData field.)
ViewData["Message"] = MVCExperiment.GlobalResources.GlobalResourceTest;

That takes care of global resources, but local resources are likely going to be a more common need. To do those elegantly (and to avoid the Literal type syntax at the top) I gleaned a bit of knowledge and extension code from this blog entry by Matt Hawley. Essentially you just need to add a special App_LocalResources folder in the appropriate location for your view to find its resources. Go grab his resource extensions - you'll need them in a minute.
Once you've created resource files that the resource manager can find as depicted here you can now reference keys in an associated local resource file like so from within your views:
<%=Html.Resource("Title") %>
In your web.config file add the following entry under configuration/system.web to have the asp.net runtime associate the visitor's preferred ui culture to your available ui culture:
<globalization uiCulture="auto" culture="auto"/>
If you ever need to set the culture or ui culture explicitly you can do so as well with a line or two of code (say if you allow your user to see things in an alternative language explicitly by dropdown selection of language preference).
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("es-MX");
Tags: