jasper_reports NG

Albert Cervera i Areny Aug 7, 2009

Right after the release of the first release candidate of Koo, we've commited a bunch of exciting changes in the jasper_reports module. Those changes can be classified in two separate areas: performance and localization.


In the performance area, we've created a java process (which is started automatically when the first report is executed) that allows avoiding the overhead of starting up the Java Virtual Machine each time a report has to be printed. The other performance improvement affects only those reports using the XML interface, which can benefit from up to 10% speedup thanks to the use of CSV files instead of XML. It is totally compatible and doesn't change anything when the user creates new reports.


If performance improvements are good news, the localization part of this post is my favorite one. Now it's possible to use translatable fields such as product name, country name, etc. In any language you want.

By default, the XML interface will create translatable fields in the same language of the user that is executing the report, but if when the field is added in iReport, you set it to type 'java.lang.Object' instead of 'java.lang.String' you can use the following syntax in the report:

$F{product_name}.get( "ca_ES" )

Even more, if the report is an invoice, for example, it will have a relation to the partner. In this case you can use:

$F{product_name}.get( $F{partner_language} )

If the translation is not available for that language, the default one will be used.

But we didn't stop localization improvements here and decided to enhance JasperReports localization features.

Put simply, jasper reports translation mechanism sucks. You're supposed to use a java bundle (.properties file) per language and use $R{key} in the expressions everywhere and obviously doesn't support features available in any modern translation system such as parameters and plural forms.

How does our mechanism work for the report designer? Pretty simple, anywhere you need to translate something you can use:

tr("This is the text I want to translate")
tr("{0} out of {1} think this translation system is great!", $F{positive},$F{total})
or you can use plural forms:
trn("One person", "{0} people", $F{people})

In fact, almost all functions in java gettext are implemented. But that wasn't enough, and for all of them we implemented one with configurable locale. So you can use:

tr( new Locale("ca", "ES"), "This text will be translated into Catalan even if the default report locale is in german!") )

Once we got this working we needed a way to extract those texts and we've made it incredibly simple. There are a couple of scripts in the jasper_reports/java directory:

jrxml2pot: Which extracts the texts from the report into a .pot file, easily translatable with any standard tool or even launchpad!
po2properties: Which converts the translated po file into a .properties file.

We should end up with the following files in our report directory:


If a translation isn't available the original text will be printed.

All this is very easy to do, and most importantly, it can be integrated in your modules and translated using launchpad! The drawback of this mechanism is that, due to lack of infrastructure in JasperReports to do this kind of stuff, we had to reimplement the GroovyCompiler and I18nGroovyCompiler was born. This basically means that:

  • You must use groovy as language in your report. That's not much of a problem, as it's possibly the best choice anyway.
  • You can't do a preview of the report inside iReport. This is a more annoying problem. It isn't hard to solve, but let's leave it to most enthusiastic java programmers that read the planet and see if somebody volunteers for that ;-)

Update: Recent tests have shown that some reports take less than half of the time they used with XML backend, so depending on the report performance gains are really important.