.NET Localization, Part 1: Resource Managers
by Satya Komatineni10/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.
- What packages to include for working with
ResourceManagerand related classes. - How to instantiate a resource manager class.
- How to use a resource manager to read resource strings.
- A combined code example.
- Satellite assemblies and the IDE.
- Creating resources for multiple languages.
- Setting the locales to test your resource retrieval.
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 |
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
Page1RBaseNameof the resource file that you have asked your IDE to create under the project ofSKLocalizationSample
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

