Wednesday, September 21, 2011

BIRT: Using Resource Bundles

A question that has recently been posted on the BIRT Exchange has got me revisiting an old problem with BIRT, localization. BIRT has a localization mechanism built in, but this only works for labels with the UI. You can also use Javascript and the report context to access messages. But I wanted to look at another way to accomplish this same task? It would stand to reason that since BIRT is running inside OSGi, and OSGi is just a fancy layer on top of Java, that we should have access to the localization features in Java, right? That would be correct.

I prefer to use Java Event Handlers for this. It is possible using Javascript event handlers, but that is a bit of a pain. So, in the following example, I will show a simple Java Report Event Adapter that will load up a Resource Bundle based on the Locale passed in from BIRT, and initialize a HashMap that can be used in BIRT to retrieve those values.

The first thing I do is create a separate Java project, and extend the ReportEventAdapter class. I then created a initialize event, although this would work in the beforeFactory event as well. All you need to do is use the same coding you would use in Java to load the ResourceBundle, and retrieve your keys and values. Using the reportContext passed in, you can load the Locale, and set a global variable that can be used in the report design to retrieve those values. The Java code is below.

package com.digiassn.blogspot.birt.event.handlers;

import java.util.HashMap;
import java.util.ResourceBundle;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.ScriptException;
import org.eclipse.birt.report.engine.api.script.eventadapter.ReportEventAdapter;

public class ResourceReportEventAdapter extends ReportEventAdapter {
private static String LABEL_KEY = "myLabel";
private static String RESOURCE_NAME = "myResource";

@Override
public void initialize(IReportContext reportContext) throws ScriptException {
super.initialize(reportContext);

ResourceBundle resourceBundle = ResourceBundle.getBundle(RESOURCE_NAME, reportContext.getLocale());

String stringValue = resourceBundle.getString(LABEL_KEY);

HashMap<String, String> resourceValues = new HashMap<String, String>();
resourceValues.put(LABEL_KEY, stringValue);

reportContext.setGlobalVariable("resources", resourceValues);
}

}



The next piece of the puzzle is where to put the .properties files. You should put them into the projects /src folder. If you put them under a package, you would reflect that in the getBundle call above. I just kept mine at the root.



So now, how do you leverage this in a report? Create a new report project. Right-mouse click in the Navigator, and go to Properties. Select Report Design/Classpath. Click on the Add Projects button, and select the Java project with your Event Adapter.



In my example report, I dropped a Dynamic Text Element in, and used the following expression:

var resourceMap = reportContext.getGlobalVariable("resources");

resourceMap.get("myLabel");

And that’s it. Its read for preview. I can now localize this however I choose. If I wanted to, in my data set, I could have an additional column with the key to retrieve, and just retrieve it from my map. This allows for external localization.

Be sure to check the BIRT Internationalization FAQ at http://wiki.eclipse.org/BIRT/FAQ/Internationalization. You can use a standard reportContext.getMessage call in a similar manner.

2 comments:

Anonymous said...

you can also directly use the spring resourceBundle into your script like that :

Packages.java.util.ResourceBundle.getBundle("messages", reportContext.getLocale())
.getString("my_message")

summ3r said...

If you use resource bundles in your localization projects you may find useful this online software localization tool: https://poeditor.com/