.NET Localization, Part 3: Localizing Text
Pages: 1, 2
Developer Utilities to Retrieve Localized Keys
So far, we have shown how to create the keys and their values in a scalable
manner. This section will cover how to retrieve these keys and place them on
dialog boxes and Web pages. .NET provides a class called ResourceManager to
assist with the retrieval of these keys with a well-defined, fall back process.
A fall back process is a process by which .NET will look for a resource key in a
language-dependent file first and if not found, it will look in the default
resource file. It will also uses a hiearchical process to search the files;
thereby, the localization process is gradual.
Let me present a couple of options to access these keys starting with the native .NET way and proceeding to demonstrate a few utilities for the same purpose.
Option 1: Direct Resource Manager
The first option is the option of directly using the resource manager classes
available in .NET. In this option, you need to know the resource filename in which
you are interested. In other words, you need to know the key of the resource
and also the module in which the key is defined. As you can see, some of the
effort we have put into our CommonKeys has already paid off. We were able to say
CommonKeys.SAVE to identify the key in a discoverable, non-error-prone manner,
but also able to specify the module name in a uniform anonymous manner:
CommonKeys.root.
You can retrieve the keys by explicitly constructing the resource manager yourself:
Using System.resources;
Using SKLocalizationSample.resources.keys;
ResourceManager rm = new ResourceManager(your-resource-filename,your-assembly);
rm.getString(CommonKeys.FILE);
Option 2: Utility Function
The second option uses a utility called ResourceUtility that we are going to
design in the following section. Let us consider here its usage, so that we can
contrast it with Option 1 and see if it is worth the effort. One thing to notice
is that we no longer need to instantiate resource managers, one for each module,
ourselves. This is controlled by the static utility function. As we might embed
static strings on a moment's notice in our programs, this one-line approach is very
very welcome. We are still mentioning the module name and the key name,
nevertheless. Let us see if we can improve on this one more step.
String value = ResourceUtility.getString(CommonKeys.SAVE, CommonKeys.root);
Option 3: A Utility Function Where the Module Name is Implied
We are able to just say the key name in the utility function. This is possible because we have used a convention where the key name includes the module name as a prefix. So inside of the utility function, we will infer the module name from the key, and accordingly retrieve the keys. This function may be slightly inefficient. Usually, this should be the least of your performance considerations. If it does, you can collapse the resource files into a single resource file at deployment time, or use another, similar method to optimize this out.
String value = ResourceUtility.getString(CommonKeys.SAVE);
Sample Code For the Above Function
Would it not be nice to cover how this function works? It is quite straightforward, so the complete code for this function is presented here. The code has enough comments to make it clear:
public class ResourceUtility
{
public ResourceUtility(){}
// Define a hashtable to hold resource managers one for each module
static Hashtable resourceManagers = new Hashtable();
// Given a key and a modulename return its value
public static string getString(string key, string modname)
{
// See if the reource manager already exists
ResourceManager rm = (ResourceManager)resourceManagers[modname];
if (rm != null)
{
// ResourceManager not found,
// create the resource manager and add it to the hashtable
// the following ideally be run inside of synchronous block
rm = new ResourceManager("SKLocalizationSample.resources.files."
+ modName
+ "Resources",
Assembly.GetExecutingAssembly());
// Notice how in the above line, the name of the passed in module
// is converted into a resource filename
resourceManagers.Add(modname,rm);
}
// when the resource manager is available just return the value for the key
return rm.GetString(key);
}
//***********************************************
//Option2, implying the module from the key
//************************************************
public static string getString(string key)
{
// get the module name from the string
char[] sep = {'.'};
string[] modKeyPair = key.Split(sep);
string mod = modKeyPair[0];
return getString(key,mod);
}
}
The only tricky part is where we are figuring out the resource file name from the module name.
For example, if the module name is:
Commmon
Then the resource filename to be passed to the resource manager is:
MyAppProject.resources.files.CommonResources.resources
Developer Access to Localized Resources to Update Them
You have access to your module-specific resource file in the following directory:
\myproject\resources\files\your-module.resx
You can update this file either through its XML or through an IDE-based editor.
Transcribers' Access to Localized Resources
Temporarily, if you want to localize any of your modules' resources, simply copy the existing resource file using the IDE into the same directory. Then rename it to the new language extension, and update the keys to reflect that language.
For ex:
\resources\files\CommonResources.resx
\resources\files\CommonResources.en-gb.resx // British version of the file
The Visual Studio IDE will automatically generate the satellite assemblies in the bin directory.
This process may not be practical for each of the files. In that case, we will collect all of the resource files and generate these language-dependent file outside of the framework and create satellite assemblies manually.
Refer to the article on the same site titled "Creating Satellite Assemblies" for converting these external resource files into satellite assemblies.
Recommended Conventions to Use These Utilities
Let us start with a module called MyMod and a key within that module called
MYKEY:
1. Create a file called
\project\resources\keys\MyMod.cs
public static string root = "MyMod";
public static string MYKEY = root + ".MYKEY";
Notice the conventions used for root and the key MYKEY.
2. Create a resource file as follows (pay attention to the name of the file):
\project\resources\files\MyModResources.res
Key: MyMod.MYKEY
Value: Any language specific value
Note: Naming the key along with the module name should allow for better management of resources.
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 ONDotnet.com

