Merging Localized Resource Files

Modified on 2009/12/15 20:47 by Stephen Walther — Categorized as: Uncategorized

Complex and global web applications frequently require localized JavaScript and CSS. There are many ways to perform that task. Microsoft Ajax Minifier provides support for merging RESX string resource files directly into your code at build time.

Let’s start off with an example. Let’s say you have a RESX file names “strings.resx” in your project that contains two localizable strings. The first one is called “Greeting” and contains a string that will be written to the DOM using a document.write call. The second one is called “Praise” and is used as the text of an alert box:


To “compile” this RESX file into your JavaScript source code, you supply the path to the RESX file and a global object name in the command line of ajaxmin via the –RES option:

-RES:global   path

The global portion is a valid JavaScript identifier that your code expects to be defined containing all the globalized strings in the resource file. It should not be an identifier that is actually defined within your source; Microsoft Ajax Minifier will take care of integrating the virtual object into your code. The path portion is the path to the RESX file. For instance, if your code expects the strings.resx file to be using a global resource object named “Strings,” you would specify this on the command line of ajaxmin:

-RES:Strings strings.resx

Code your JavaScript source exactly as if that Strings object exists. For instance, your source code file (foo.js) might be something like:

document.write("<h1>" + Strings.Greeting + "</h1>");

So when we minify foo.js specifying the strings.resx file as the resources using the command line:

ajaxmin foo.js –RES:Strings strings.resx

The resulting code will be:


So what happened here? The steps Microsoft Ajax Minifier goes through to merge resources are as follows:
  1. Open the resource file and create a virtual global variable named “Strings” (taken from the command line options) with the properties Message and Praise.
  2. Process the input source code. Whenever a reference to a property on the global “Strings” object is encountered, the entire property reference is replaced with the string literal from the resource file. If there is no property on the virtual object (and therefore, no corresponding string in the RESX file) to match what is in the JS sources, an empty string is substituted.
  3. Final-pass string literal concatenation combines the expression inside the document.write call to a single string literal.

If I then localized strings.resx into Chinese and create a RESX file named “strings-zh.resx”:

I would compile it against the same sources in the same manner:

ajaxmin foo.js –RES:Strings strings-zh.resx

But the resulting code would contain the localized strings. In this example, I saved the output to a file using the ANSI encoding, so the Unicode Chinese characters are properly escaped for the encoding scheme:


If the –ECHO option is used on the command line as well (copy un-minified input straight to output), then instead of replacing the property references with the literals, the actual Strings object is inserted at the head of the output, resulting in:

var Strings={Greeting:"Hello!",Praise:"Excellent!"};

This can be useful for debugging, but should not be used for production code. The reason is that the Strings object generated in this way will include all strings in the RESX file. When the properties used are replaced with literals, only those strings within the RESX file that are actually used will get into your resulting JavaScript code. This allows your project to maintain a single RESX for all your script localization needs without having to flood your JS files with unused strings.

For CSS, the scenario is a little different. The command-line switch is the same, although the “global” value of the –RES switch is not used. What you do is place a specially-formatted comment in your CSS right before the property whose value you wish to replace with a localized string. The format of this comment is: /*id*/, where “id” is the name of the string in the RESX file. When a comment like this is encountered, the string with the given name is looked up in the RESX file, and its value replaces the value of the next property encountered.

Let’s look at an example. Say your RESX file contains a string named “BodyFontFamily” so you can change the font of the body element depending on your market’s localization. The CSS property you would write would specify a default value, and be prefaced with the appropriately-formatted comment:

font-family: Arial;

/*[BodyColor]*/ color: black; }

If your RESX file looks like this:


Then the resulting CSS when using the –RES option would be:

body{font-family:Segoe UI;color:#009}

If the RESX file does not contain a string with the name specified in the comment, the next property value is left as-is and not replaced.