The String Resource Tool

Do you use the ResourceManager to pull strings from embedded resource files (.resx)?  This technique is a good way to store string values for localization or centralization of common strings.  Here is a code snippet:

ResourceManager rm = new ResourceManager(“ResourceTest.strings”, Assembly.GetExecutingAssembly());
Console.WriteLine(rm.GetString(“accountNotFoundMsg”));

The two lines above assume that there is a strings.resx file in the project that has a named string of “accountNotFoundMsg”.  When the second line runs the resource manager extracts the value of the accountNotFoundMsg from the embedded resource and writes it to the console.  Pretty simple stuff.  Maybe this string is used throughout your application and to be consistent with the wording in all places you’ve added it to the resx file.  Then where ever you need to use the string you can add the above lines and get it out, or create a helper method to retrieve the value for you.  In any event you have to request the string by it’s key name, which is a string.  Let’s say you use this message in 50 places in your application.  Just how many of those could you accidentally mistype?  Remember, it has to be the exact spelling, including the same casing to work.  If you mistype the key then you aren’t going to get a compile error, or even a runtime exception….all you get is a blank string from the resource manager.  This can lead to blank labels or text deep in your application that may be hard to spot.

What if you could have a compile time check to ensure that your string resources are properly referenced?  What if there was a tool that you could use to even have dynamic strings pulled from a resource file?  Well, there is.  It’s call the String Resource Tool and is available from the pattern & practices community for Enterprise Library (you’ll need a Microsoft Passport account and be a member of the community to download it, but membership is free).  This tool allows you to add a new type of project item to your projects called a .strings file.  This file is nothing more than a list of string keys and their values (much like the resx file, but not in XML).  Each time you save the strings file the String Resource Tool compiles the strings into two files (a class file, which provides a wrapper around the resourcemanager and exposes the specific strings in the file, and a resx file which actually contains the strings. 

Let’s say we create a strings file called AppStrings.strings and add the following line to it:

AccountNotFoundMsg = The account you requested does not exist.

When we save the strings file a resx file will be created that contains the key and message, and a class file with a property named AccountNotFoundMsg will be created automatically.  Then in our application code we would have the following line if we wanted to write the message to the console:

Console.WriteLine(AppStrings.AccountNotFoundMsg);

This string is now a property on a type within the application and is checked at compile time for existence.  You’ll know immediately on compile if you have accidentally misspelled a string resource.  You’ll know if someone removes a string resource that you were using since the next time the application is compiled it will show up. Compile time checking reduces mistyping mistakes and decreases bugs in string localization.

Now, what if we wanted to be a little more specific on the account message.  What if we anted to say:

The account you requested (AccountID: 1234) does not exist.

In using just the resource manager we would have (assuming the stored string looked like The account you requested (AccountID: {0}) does not exist.):

ResourceManager rm = new ResourceManager(“ResourceTest.strings”, Assembly.GetExecutingAssembly());
Console.WriteLine(string.format(rm.GetString(“accountNotFoundMsg”), accountID.ToString()));

Now, with the string resource tool we could add a line to the AppStrings.strings file that looks like this:

AccountNotFoundMsg(accountID) = The account you requested (AccountID: {0}) does not exist.

After we save the strings file the String Resource tool creates a function called AccountNotFoundMsg in the generated class file and then we can call it in our code as follows:

Console.WriteLine(AccountNotFoundMsg(accountID.ToString()))

Again, the string usage here is simply calling a method on a type in the application that was automatically generated by the String Resource Tool.

The String Resource Tool also handles culture specific strings for globalization.

This is a pretty neat tool and can save you a LOT of time.  Check it out!  The included readme file in the download explains how to get started.

NOTE: If you are going to use the String Resource Tool in Visual Basic.Net then you need to take some extra steps after the installation of the tool.  This does require a Registry change, so as always, you change the registry at your own risk and don’t blame me for anything that may happen as a result.  Thanks to davidmo on the pattern & practices Community site for sharing this work around.  If you don’t take these steps then the String Resource Tool will not show up as an option for new project items in VB.Net projects.

  1. Copy the following folders to the destination indicated (replace {VS.NetInstallFolder} with the location of where VS.Net 2003 is installed on your machine, usually C:\Program Files\Microsoft Visual Studio .NET 2003 by default.):
    • {VS.NetInstallFolder}\VC#\CSharpProjectItems\LocalProjectItems\Resources copied to {VS.NetInstallFolder}\Vb7\VBProjectItems\Local Project Items\Resources
    • {VS.NetInstallFolder}\VC#\CSharpProjectItems\WebProjectItems\Resources copied to {VS.NetInstallFolder}\Vb7\VBProjectItems\Web Project Items\Resources
    • {VS.NetInstallFolder}\VC#\VC#Wizards\StringResourceTool copied to {VS.NetInstallFolder}\Vb7\VBWizards\StringResourceTool
  2. The next step is to register the generator with Visual Studio so that when you save the file it will auto generate the class and resx file. 
    • Go to the following Registry Key: HKey_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.1\Generators
    • Locate the GUID for C# projects in the subkeys.  You’ll see a subkey called StringResourceTool.  Export that key.
    • Locate the GUID for the VB projects in the Generators subkey.  If you need to figure out the key then take a look under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.1\InstalledProducts\Visual Basic.NET key at the value for the package key.  This will be the GUID that you’ll need to find under the Generators key above. 
    • Edit the exported registry key for the StringResourceTool and modify the keyname at the top of the file to be the VB.Net package GUID instead.
      Double-click on the .reg file and import the keys. 
    • You can also manually add these keys if you want instead of exporting/importing the reg file.  I just found it easier to do it with the file.