Saturday, December 20, 2008

i18n for Javascript

The WSO2 Carbon platform contains two UI technologies. Plain old JSPs and Javascript (DHTML/Ajax, the rich client stuff). When it comes to i18n JSPs are taken care of. In Javascript however, i18n seems a daunting task. Various Javascript libraries such as GWT, Dojo and even YUI have tried to address the issue in their own way. But when I did an evaluation last week of those, I wasn't really happy about the unnecessary complexity of their code and the additional QA overhead they will add.

So I wrote my own i18n implementation for Javascript, which will be used by all Javascript embedded components in the Carbon platform. The implementation uses both JSP and Javascript code to balance out processing overheads between the browser and server.

Server side processing is done with a JSP tag library, which reads a given Resource bundle and populates a JSON Object with the key-value pairs found within. The JSP authors can opt to either use one single Resource Bundle for all their i18n values or have a separate bundle for Javascript (JSResources.properties for instance). I recommend the latter because it will reduce the memory footprint of your i18n JSON Object.

This Tag library is named jsi18n (Apache Licensed). To include it in one's JSP, all they have to do is add the following code after including the it in their project. The library requires two parameters to be set. The mandatory 'request' parameter, which passes the ServletRequest and the 'resourceBundle' parameter which tells the library where it can find your i18n Resource Bundle in the classpath .

<carbon:jsi18n resourceBundle="org.wso2.carbon.server.admin.ui.i18n.JSResources" request="<%=request%>"/>

When the page is generated, it will contain a JSON object named jsi18n with key-value mappings found in your Resource Bundle. The tag library changes the values depending on the Browsers locale set by a user. If you view the source of a generated page after this tag library is invoked, you will see the following Javascript code embedded in it. The code below comes straight from a page in WSO2 Carbon, so the key-value pairs are specific to that page.

<script type = "text/javascript" >
var tmpPairs = '{"dialog.cancel":"Cancel","dialog.ok":"OK","graceful.shutdown.verify":"Do you really want to gracefully shutdown the server?","graceful.shutdown.error":"An error occurred while gracefully shutting down the server","graceful.shutdown.in.progress.message":"Server is being gracefully shutdown. This Management Console will no longer be accessible","restart.in.progress.message":"Server is being restarted. This Management Console will not be accessible for a few minutes.","shutdown.verification":"Do you really want to shutdown the server?","shutdown.error":"Error occurred while shutting down the server","graceful.restart.in.progress.message":"Server is being gracefully restarted. This Management Console will not be accessible for a few minutes.","graceful.restart.verification":"Do you really want to gracefully restart the server?","graceful.restart.error":"Error occurred while gracefully restarting the server","restart.verification":"Do you really want to restart the server?","restart.error":"Error occurred while restarting the server","shutdown.in.progress.message":"Server is being shutdown. This Management Console will no longer be accessible"}';

var jsi18n = YAHOO.lang.JSON.parse(tmpPairs);
</script>


Once the page is loaded, all Javascript code will have access to the jsi18n variable (the JSON object) in the above code. Therefore, to make one's Javascript messages i18ned, instead of writing

alert("Do you really want to gracefully shutdown the server?");

an author can use

alert(jsi18n["graceful.shutdown.verify"]);

in his code.

Depending on the Browser locale and the availability of a matching language Resource Bundle, the text of the above alert will change.