воскресенье, 3 апреля 2011 г.

Introdaction into “Localize messages in the initialization and update wizard” project

My post is devoted to “Localize messages in the initialization and update wizard” project. I think there are a few things I would like to discuss: 

As I’ve already understood, we need to use already existed java messages.properties files to provide access to localized messages directly from the velocity templates. There are few ways to accomplish it. 

1) First, and as I think, not the best way, is to use velocity MultiViewTool (or just even IncludeTool). Yes, it provides careless life for programmer, but only for programmer. In my opinion, the main drawback of this approach is that we must keep separate template file for each supported language. Usage it “tool” from a template would be something like the following: 

 #parse( $include.find('header.vm', 'en') ) 
 #include( $include.find('installmethod.vm', 'en') ). 

Using of this approach will complicate adding new functionality (e.g. addig new supported language will require creating one more copy of all templates). 

2) Second, and much better way is to use velocity ResourceTool. It's the access point from Velocity templates to standard mechanisms for java support i18n and i10n with ResourceBundles. For using it we only need to configure velocity toolbox. After configuring it we will gave an opportunity to access to our messages from bundles in this way: 

$locale.continue                       ->  Continue 
$locale.install.method              ->  Advanced 
$locale.install.method              ->  Simple 

But it has one drawback. This tool loads bundles ONLY from class path. And it’s UNACCEPTABLE, ‘cause our messages.properties files are located in /WEB-INF directory, which, unfortunately, IS NOT INCLUDED INTO THE CLASSPATH (but /WEB-INF/classes and /WEB-INF/lib included)))). 

3) The third approaches is MessageSourceResourceBundles (and similar) from spring framework, but, unfortunately, it also loads resource bundles from class path. Nevertheless in can be rewritten in the desired manner (like MutableResourceBundleMessageSource from core project), but it's not the best approach in this case to using spring. 
Such behavior (loading resource's bundles extremely from classpath) can be explained that either velocity ResourceTool and spring MessageSourceResourceBundles uses the same mechanism of loading resources – implementation of java.lang.ClassLoader which loads classes and resources directly from java class path. 

4) So, there is only one acceptable way to provide localization support for initial and update wizards (in case of OpenMRS directories location, of course). This is writing appropriate resource bundles loader and tool for managing these bundles. Yes, it’s a hack, but very graceful hack. We won’t change directory location in OpenMRS war file (suchlike in case of classpath-based resource loaders) or add new template files, or just even create separate spring application context. Nothing that we do not have to do. We just simply need to create two own classes (first, that will be responsible for loading and caching resource files from specified location (either from classpath or file system), and another class, which will be responsible for getting messages from these bundles by key). And usage it approach from velocity template would be something like the following 

$l10n.get("locale.continue", $basename, $locale), 

where, l10n – object that represents appropriate resource tool, "locale.continue" – message key, $basename – something like “messages” string object, and $locale – object that represents current locale (e.g, “en_GB” or es). 

Also, it approach very flexible, cause we simply can change resource bundles access object for new one, or use new similar approach to access it bundles. Moreover, in this case we will only inject our custom message localization tool into InitializationFilter or UpdateFilter classes with the fewest changes in theirs code. 

With best wishes, Taras Chorny.