Thursday, May 10, 2012

The right way to use resource files for localization and internationalization in an ASP.NET MVC application

Before I switched to ASP.NET MVC as my server-side web application framework I used to define controls in ASPX pages that referred to locally defined resources in the following way:
<asp:Button ID="btnReset" runat="server" meta:resourceKey="btnReset" />
Let's assume that the button is defined in a page Default.aspx. The btnReset resource key defines an entry in the file Default.aspx.resx in the App_LocalResources folder. This folder and the Default.aspx file share the same parent directory. If we look at the source of the .resx file we can find the following XML element, that defines the text of the button:
<data name="btnReset.Text" xml:space="preserve">
    <value>Reset layout</value>
</data>
Recently I needed to localize an MVC application and had already started to add App_GlobalResources and App_LocalResources folders to my Visual Studio 2010 solution. Then I remembered a .NET expert writing that this is not the right way to use resources in ASP.NET MVC. To summarize him, resource files in MVC can be added to any directory (or a separate class library). More important, after compilation the files cannot only be referenced in views but also in unit tests (a big advantage). I decided to follow K. Scott Allen's suggestion and assign the namespace pattern "Resources.Controller.View" to .resx file names, for resources dedicated to specific views. In fact, each resource file has two properties that must be set (in the Visual Studio property window for the file) before the entries in the file can be referenced from a view:
  • The Custom Tool property must be set to 'PublicResXFileCodeGenerator' instead of 'ResXCodeFileGenerator'.
  • The Custom Tool Namespace should be set to something meaningfull. What this is, is up to you. Like I said, I use the pattern "Resources.Controller.View". Thus, I define resources for the 'Index' view that is created by the Home controller in a file named Strings.resx that gets the namespace Resources.Home.Index. Also, there is a file Strings.resx with the custom tool namespace Resources.Home.About, for the 'About' view that is created by the same controller.
The Strings.resx files are located in a Resources folder in the root of the MVC web application. The structure of that folder is:
Resources
  |- Account
    |- Logon
      |- Strings.fr.resx
      |- Strings.resx
    |- Register
      |- Strings.fr.resx
      |- Strings.resx
  |- Home
    |- About
      |- Strings.fr.resx
      |- Strings.resx
    |- Index
      |- Strings.fr.resx
      |- Strings.resx
Another thing that may not be immediately clear is how to refer to the resources from a Razor view (.cshtml) file. Here are the contents of the Index.cshtml file that comes with each new MVC project in Visual Studio:
@{
    ViewBag.Title = @Resources.Home.Index.Strings.Title;
}

<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
Note that the string "Home Page" that is normally assigned to ViewBag.Title has been 'localized' and therefore moved to the Strings.resx file in the Resources > Home > Index directory.

3 comments:

  1. Why not -h2-@Resources.Home.Index.Strings.Title-h2- ? (tags are not allowed so i removed them).

    ReplyDelete
  2. Thank you for writing this article. Probably saved me hours if not days. The folder structure (and namespaces based off of it) is an especially good idea.

    ReplyDelete
  3. Just what I was looking for, very simple and concise. Thank you.

    ReplyDelete