Terence Parr
parrt at cs.usfca.edu
WARNING: this example uses a pre-release version of StringTemplate 2.3, which allows the $strings.page1_title$ references used in this example. 2.3 should be out in February 2006. I include a link to a pre-release version at the bottom of this article.
StringTemplate provides a simple and effective method for localizing web pages. The goal is to alter a page based upon the locale; that is, page strings or other content must change depending on a locale. This article not only illustrates how to make a pages change text depending on locale, it shows how the same site may easily have two different skins (site "looks").
This technique works well in practice for real sites. Schoolloop.com is a case in point. Click on the link that says "en espanol" to flip the site into Spanish mode. The exam same templates are used; all strings are pulled from a serious of resource bundles. There is no duplication of pages to change the strings.
First let's look at multiple skins in order to show how templates are loaded for this example. Multiple site looks are organized into their own directories. A StringTemplateGroup object rooted at that directory will load templates directly from there. In my example, I made two skins, blue and red. Here is how the group is loaded:
String skin="blue";
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// get a template group rooted at appropriate skin
String absoluteSkinRootDirectoryName = cl.getResource(skin).getFile();
StringTemplateGroup templates =
new StringTemplateGroup("test", absoluteSkinRootDirectoryName);
Then, when you ask for an instance of a page, it pulls from whichever
directory skin is set to:
StringTemplate page1ST = templates.getInstanceOf("page1");
Here is page 1 in the blue skin:
<html> <title>$strings.page1_title$</title> <body> <font color=blue> <p>$strings.intro$ <p>$strings.page1_content$ </font> </body> <html>and here is page 2:
<html> <title>$strings.page2_title$</title> <body> <font color=blue> <p>$strings.page2_content$ </font> </body> <html>For the red, here is page 1:
<html> <title>$strings.page1_title$</title> <body> <font color=red> <h1>$strings.page1_title$</h1> <p>$strings.intro$ <hr> <p>$strings.page1_content$ </font> </body> <html>and page 2:
<html> <title>$strings.page2_title$</title> <body> <font color=red> <h1>$strings.page2_title$</h1> <hr> <p>$strings.page2_content$ </font> </body> <html>The thing to note is that there is no text, just formatting in these page templates. Those strings from the strings attribute are used for all text that could change per locale.
intro=Welcome to my test page for internationalization with StringTemplate page1_title=Page 1 testing I18N page2_title=Page 2 testing I18N page1_content=This is page 1's simple page content page2_content=This is page 2's simple page contentand here is my fr.strings file:
intro=Bienvenue a mon page de test pour internationalization avec StringTemplate page1_title=Page 1 test de I18N page2_title=Page 2 test de I18N page1_content=Le content du page 1 page2_content=Le content du page 2To load these per the current locale is pretty easy:
// use Locale to get 2 letter country code for this computer
Locale locale = Locale.getDefault();
String defaultLanguage = locale.getLanguage();
// allow them to override language from argument on command line
String language = defaultLanguage;
if ( args.length>0 ) {
language = args[0];
}
// load strings from a properties files like en.strings
URL stringsFile = cl.getResource(language+".strings");
if ( stringsFile==null ) {
System.err.println("can't find strings for language: "+language);
return;
}
Properties strings = new Properties();
InputStream is = stringsFile.openStream();
strings.load(is);
The strings properties object is just a Hashtable so
you can directly pass to StringTemplate templates as an attribute:
StringTemplate page1ST = templates.getInstanceOf("page1");
page1ST.setAttribute("strings", strings);
To generate the page, just say:
System.out.println(page1ST);The output will be (for the en locale):
<html> <title>Page 1 testing I18N</title> <body> <font color=blue> <p>Welcome to my test page for internationalization with StringTemplate <p>This is page 1's simple page content </font> </body> <html>If I change the locale to fr then without changes templates, the following is generated:
<html> <title>Page 1 test de I18N</title> <body> <font color=blue> <p>Bienvenue a mon page de test pour internationalization avec StringTemplate <p>Le content du page 1 </font> </body> <html>Not sure "content" translates to French as "content" (heh, doesn't that mean "happy"?).
You can compile this example like this:
javac -classpath .:antlr-2.7.6.jar:stringtemplate-2.3b5.jar Test.java java -classpath .:antlr-2.7.6.jar:stringtemplate-2.3b5.jar Test