AddThis Social Bookmark Button

Print

.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