A couple of weeks ago I posted about internationalization with ASP.NET Web Forms. In this post, I’m going to look at how ASP.NET MVC handles internationalization. The good news is that you can localize in a broadly similar way and it’s still nice and easy. The bad news is that MVC does less for you and makes you jump through a few hoops to get it working.
What’s the same?
Resource files, for one thing.
You don’t use App_LocalResources, and Visual Studio doesn’t generate the keys in the resource file for you.
Let’s create the same basic page that we did with Web Forms – a contact form for sending an email. Here is the controller method, passing an Email model through to a strongly typed view Contact.cshtml:
And here is part of the View generated by Visual Studio 2012:
We want the labels to display appropriate text depending on the user’s language settings. In Web Forms, we can get the tools to generate a resource file with keys for relevant text. Here, we have to do it ourselves – and the resource files live with the views. I right-clicked on the Home folder and selected Add | Resources Files…
I called the first file Contact.resx. (The lack of a language specifier makes it the default). Then I went through and added the keys and values I wanted in English. Next, I copied it to create Contact.fr.resx and amended the values to my best guess at the French words I needed. (If someone speaks three languages, they are multi-lingual. If they speak two, they are bi-lingual. If they speak one… they are English. I am very English).
Here is the default file:
Here is the French version:
And here is the structure in Solution Explorer. Notice that the files are in the same folder as the views, NOT in App_LocalResources.
The next step is to tell our View to use the resources. I set the Custom Tool Namespace to Resources.Local to keep it nice and simple:
Then I used the second argument on LabelFor to specify the text, and passed in the relevant key from the resource file:
So everything should work now, right? We’ve created the resource files, pointed the views at them and it should all just work… Let’s run it and see:
Oops. It turns out the default protection level on the file is internal, which doesn’t work. You can use the dropdown at the top of the resource file to change it to public:
And here’s what you get in the Properties window – PublicRexXFileCodeGenerator rather than the default ResXFileCodeGenerator:
Now when we run it with English settings we get:
And when we pretend to be French, we get:
So, overall, it’s very similar to Web Forms, but just different enough to require a little extra work. You can also take an alternative approach and create separate views for each language. For me that’s a step too far, especially as I am likely to have mobile and standard views, and given that you can have device specific views as well, the complication soon increases exponentially. [Back in the 1990s, I worked on a project with 9 different versions of every page (IE, Netscape, Accessible IE, Accessible Netscape, Welsh IE, Welsh Netscape, Accessible Welsh… I can’t go on; the memory is just too painful) and I avoid view proliferation at all costs.]
There is, of course, more to internationalization than resource files. There’s programmatic control – letting your end user choose their language – and localizing strings that come from model classes, such as data annotation validation messages. So I may well return to internationalization again in a future blog post…
For other related information, check out this course from Learning Tree: