ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


.NET Localization, Part 1: Resource Managers

by Satya Komatineni
10/01/2002

ASP.NET uses a class called System.Resources.ResourceManager for localizing text. This is similar to the resource bundle support under the Java platform. The documentation for the ResourceManager class is a little spotty. There are a few noteworthy points to make about the interaction of Visual Studio IDE and the resource files. This short article will cover these issues and should serve as a quick reference guide if you are looking to use the ResourceManager class. This article will cover the following topics:

How to Create a Resource File Using Visual Studio

A resource manager is used to retrieve language-dependent strings from resource files. So the first thing to do is to create a resource file. You can do this simply with the IDE. Create a resource file using the Add New Item option either on a project or on a folder within that project. For the item type, pick Assembly Resource File. You can add a resource file to your project either at the root level of your project or at the subfolder level (module level). This action will create a file with a .resx extension. If you were working with a page called Page1, you may want to name this resource file Page1R.resx or Page1Resoruce.resx.

Related Reading

Programming ASP .NET
By Jesse Liberty, Dan Hurwitz

Once you have created the resource file, you have the option of editing this using the name/value pairs presented to you by the IDE editor, or you can switch to the XML version and edit the XML directly. The XML section that you plan to edit will look something like this:


     <data name="MyKey1">
          <value>MyValue1
     </data>
     <data name="MyKey2">
          <value>MyValue2
     </data>

The goal of the exercise is to look for the above keys (MyKey1 and MyKey2) in a language-independent manner. To do this, we need to obtain a resource manager.

Required Packages

To work with a resource manager, you will most likely need the following two packages:


using System.Resources;
using System.Reflection;

The reflection package is necessary because you need access to an assembly to instantiate a resource manager.

How to Instantiate a Resource Manager

Here is the code for instantiating a resource manager:


ResourceManager rm = new ResourceManager(
     "YourWebProject.Page1R",
	 Assembly.GetExecutingAssembly());
SKLocalizationSample:
your Web project name
Page1R
BaseName of the resource file that you have asked your IDE to create under the project of SKLocalizationSample

This is a bit tricky. When you created the resource file, you called it Page1R.resx in the root directory of your project. Then how come your first argument to the ResourceManager (points to a basename of the resource file) is YourWebProject.Page1R?

We can see a couple of things here. The extension .resx is dropped. Your project name is prepended. When the IDE builds your project, it creates a resource file internally with this new name, based on the name you have specified.

The second argument points to the assembly where these resources are available. There are multiple ways you can derive this assembly object. One of the ways is shown in this example.

Using the Resource Manager to Retrieve Resources

Assuming you have a label called "Label1" in your Web form, you can set its text as follows:


Label1.Text = rm.GetString("MyKey1");

Where rm is the resource manager that you have instantiated earlier, and MyKey1 is the language-dependent keyname. Note that the keys are case-sensitive.

Now let's take a look at the combined code example:


using System.Resources;
using System.Reflection;
...
     ResourceManager rm =
          new ResourceManager(
               "SKLocalizationSample.Page1R"
               ,Assembly.GetExecutingAssembly());
     Label1.Text = rm.GetString("English");

Multiple Resource Files in Multiple Submodule Directories

In the above example, we have shown accessing a resource file in the root directory of the project. What if you have multiple resource files in multiple sub-module directories? It is worth considering an example for a complete picture of resource file path specification.

The following shows the directory structure:


     YourWebProject
          Page1R.resx
          \module1\mod1res.resx

In this example, a resource file called mod1res.resx is created in a subdirectory of module1.

Here is some sample code for accessing resources under a subdirectory.


resourcemanager rm1 = new resourcemanager(
     "sklocalizationsample.module1.mod1res",     
     assembly.getexecutingassembly());
mod1languagelabel.text=rm1.GetString("mod1-language");

See here how the resource file path is being mentioned for creating the resource manager class? Not only are we dropping the .resx extension and prepending with the project name, but also, our seperators are periods instead of backslashes.

Creating Resources For Multiple Languages

We have seen how we can access string resources from multiple resource files spread across multiple directories. It is time to look at how to retrieve string resources from resource files that can span multiple languages. To do this, consider the following directory structure and the files in that directory structure. We essentially copy a resource file into the same directory and rename it to the language-dependent extension. One can repeat this process for each language.

So now our directory structure looks like this:


     YourWebProject
          Page1R.resx
          Page1R.en-gb.resx
          \module1\mod1res.resx
                 \mod1res.en-gb.resx

For a resource file called Page1R.resx we have created Page1R.en-gb.resx, and for a resource file called module1\mod1res.resx we have created module1\mod1res.en-gb.resx, where en-gb is the locale.

Now the resource manager will automatically search for the right file when your locale setting matches the language spec. If it cannot find the language-specific resource file, it will use the default resource file.

When the project is built with these language-specific resource files, the IDE creates the satellite assemblies for these language-dependent files. To see this satellite assembly creation, use Project -> ShowAllFiles to see the bin directory. Under bin, you will see subdirectories that are dedicated to each language.


wwroot\SKlocalizationSample\bin    
\en-jb\SKLocalizationSampleResources.dll
\en-RU\SKLocalizationSampleResources.dll
..etc

Setting Up the Locales

The resource manager retrieves language-dependent keys, but how does the resource manager know what language to look for? The resource manager uses the UICulture variable that is available on the current thread. This variable has to be set to point the resource manager to the intended language resource file.

Here is an example. This section of the code can be executed in your Global.asax.cs file. This will essentially intercept every page process and sets its locale to the desired locale. I believe you can do this in your web.config as well; those details are not provided here.


using System.Globalization;
using System.Threading;

protected void Application_BeginRequest(
       Object sender, 
       EventArgs e)
     {
      CultureInfo ci = new CultureInfo("en-gb");
      Thread.CurrentThread.CurrentCulture = ci;
      Thread.CurrentThread.CurrentUICulture = ci;
     }

It is important to set the CurrentUICulture, as it is this setting -- not CurrentCulture -- at which the resource manager looks. This distinction allows for your Web site to display all strings in an appropriate language while leaving the rest of the Web site (dates, numbers, currency, units, etc.) in a predetermined setting. This could be valuable for a multistep localization process, where in the first step you will convert all of your text for multiple languages, and in the second step you will attempt the rest of the localization process.

Satya Komatineni is the CTO at Indent, Inc. and the author of Aspire, an open source web development RAD tool for J2EE/XML.


Return to .NET DevCenter

Copyright © 2009 O'Reilly Media, Inc.