JavaData & JavaHow to Create a Multilingual JasperReport

How to Create a Multilingual JasperReport

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Almost all modern software that renders text, such as a browser or text editor, supports Unicode fonts encoded with the UTF-8 or UTF-16 encoding mechanism. A Java reporting library such as JasperReport is no exception and provides APIs to load external Unicode fonts representing cultural scripting symbols. This feature can be leveraged to create report schemed with the combination of one or more language scripts. There are databases such as PostgreSQL which support the UTF-8 encoding scheme to persist records in languages other than English as well. However, the construction of words in various cultural languages is very different and often quite complex. For example, creating a report using Indic Unicode fonts that is culturally and linguistically correct and that also rendering them appropriately in a report viewer is still a challenging task. The article explores the idea and shows how to fetch Unicode characters persisted in a database and subsequently create a multilingual report with the help of the JasperReport library in Java.

Problems with India Unicode

Working with Indian languages is the most problematic one. Indian languages, such as Hindi, Devanagiri, Gujrati, Marathi, Bengali/Bangla, and so forth use a collation of Unicode symbols to create a syntactically correct word or collated consonant. Collation refers to two or more Unicode characters merged into a single meaningful symbol according to the context. Representing the exact collation and rendering them appropriately in a viewer requires something more than just the ability of rendering by the software product and Unicode font’s ability of encoding cultural characters symbols. Alphabetic ordering of English is pretty straightforward because letters come one after another with very little variation (as subscripts, superscripts, and so on). Unfortunately, the ordering of Indic language is way more complicated than that. Observe how Unicode character U+0997 is collated with U+09C1 to form a single character symbol in Bengali/Bangla.

Multi1
Figure 1: Combining Unicode characters to form a ligated character

Similarly, the Devanagari ‘Ka’ (U+0915) combined with ‘Chandra bindu’ (U+0901)

Multi2
Figure 2: Combining Devanagari ‘Ka’ with ‘Chandra bindu’

or, in the Tamil language Nya (U+0B9E) and virama (U+0BCD)

Multi3
Figure 3: Combining Tamil’s Nya and virama (U+0BCD)

The situation with other Indian languages is similar. Creating a single code point order within Unicode encoding is not sufficient and feasible even for the script of a single language. Using glyphs for such cases is no solution, either. So, in a way the Unicode encoding scheme is helpless in providing a solution. The only hope remains in the text viewer software that may be able to understand the sequence of characters and render them appropriately. Several techniques of rendering are proposed; some are implemented successfully but a comprehensive, uniform standard is yet to be established. Refer to Improvements requested for Unicode Indic properties for further information.

Creating a Database and Filling a Table with Unicode Records

Here, we shall use PostgreSQL as the database and pgAdmin III as the interface to create the database table.

  1. Give a name of the database in the Properties tab and make sure that the Encoding is set as UTF8 in the Definition tab while creating New Databases…. Click OKto create the database.

    Multi4
    Figure 4: pgAdmin III interface for PostgreSQL database

  2. Now, expand the newly created database from the Object browser, right-click Tables, and select New Tables…from the pop up menu. Create table columns and constraints according to the following SQL statements.
CREATE TABLE survey
(
   id integer NOT NULL,
   country_name character varying,
   population character varying,
   area character varying,
   CONSTRAINT id PRIMARY KEY (id)
);
  1. Right-click the table just created and select View data –> View All Rows. Enter the data as follows in Edit Data window and save the records.

    Multi5
    Figure 5: Edit data window in the pgAdmin III interface for PostgreSQL database

Now, here is the catch. Typing data in Bengali/Bangla as shown above requires a software tool that alters the keyboard layout from Bengali/Bangla to English and vice versa. Here, I have used the Avro keyboard layout. This is an excellent tool for typing in Bengali/Bangla. This can be freely downloaded from OmicronLab. For other Indian languages, there must be a similar tool available; please find them with a Google search.

  1. We are done with the database.

Creating a Multilingual Report

Before you begin. make sure you have the following requirements:

1. Create a jar of the Font File

Open JasperStudio. From the Window menu, select Preference. Expand Jasper Studio from the left pane. Click Font and then click the Add button at the right.

Multi6
Figure 6: Jasper Studio interface

Give a family name of the font, and then browse for the font, as shown in Figure 6. Make sure that the PDF Encoding is set to Identity-H (Unicode with horizontal writing) and check Embed this font in PDF document. Finish.

Note that new font is added to the font list. Now, click the Export button and give a name of the font jar file to be created and Save.

Note: For convenience, consider saving the Unicode font file in the Windows font directory, if it is not already there.

2. Creating the Report Layout in JasperStudio

Create a Jasper Report from File –> New –> Jasper Report and choose a blank A4 report template. A JRXML file will be created. A JRXML file is nothing but an XML file that uses JasperReport tags. So, any XML editor—or simply a plain text editor—can be used to write the following code. Type/Copy & Paste the code from Listing 1 create the report structure.

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.1.1.final -->
<!-- using JasperReports Library version 6.1.1 -->
<!-- 2015-09-11T14:21:37 -->

<jasperReport 
   xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi_schemaLocation="http://jasperreports.sourceforge.net/jasperreports
   http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
   name=" report_template" pageWidth="595"
   pageHeight="842" whenNoDataType="AllSectionsNoDetail"
   columnWidth="535" leftMargin="20"
   rightMargin="20" topMargin="20" bottomMargin="20"
   uuid="d4a1d5eb-82dd-412f-a620-202e4bdf9dba">

<property name="template.engine" value="tabular_template"/>
<property name="com.jaspersoft.studio.data.defaultdataadapter"
  value="NEW_DATAADAPTER.xml"/>
<property name="com.jaspersoft.studio.data.sql.tables"
   value=""/>

<style name="Table"/>
<style name="Table_TH"
   mode="Transparent"
   backcolor="#FFFFFF"/>
<style ame="Table_CH"
   mode="Transparent"
   forecolor="#B89F7D"
   backcolor="#70A9C6"/>
<style name="Table_TD"
   mode="Transparent"
   backcolor="#FFFFFF"/>
<subDataset name="tableDataset"
      uuid="a868e547-a18b-4cb0-a6b7-18862291b4ca">
   <property name="com.jaspersoft.studio.data.
       defaultdataadapter"
      value="NEW_DATAADAPTER.xml"/>
   <queryString>
      <![CDATA[SELECT public.survey.id,
         public.survey.area,
         public.survey.population,
         public.survey.country_name
         FROM public.survey]]>
   </queryString>
   <field name="id" class="java.lang.Integer"/>
   <field name="area" class="java.lang.String"/>
   <field name="population" class="java.lang.String"/>
   <field name="country_name" class="java.lang.String"/>
</subDataset>
<queryString>
   <![CDATA[]]>
</queryString>
<title>
   <band height="72">
      <frame>
         <reportElement mode="Opaque" x="-20" y="-20"
            width="595" height="92" backcolor="#006699"
            uuid="6321f5e3-86eb-444f-acc1-8daaaa0d6c60"/>
         <staticText>
            <reportElement x="20" y="20" width="330" height="43"
               forecolor="#FFFFFF"
               uuid="9e48917a-7b59-4ffd-baad-725f45563194"/>
            <textElement>
               <font size="34" isBold="true"/>
            </textElement>
            <text><![CDATA[SURVEY REPORT]]></text>
         </staticText>
         <staticText>
            <reportElement x="300" y="70" width="275"
               height="20" forecolor="#FFFFFF"
               uuid="0a399baa-bad3-4b1a-9fe3-bb1c563e6a27"/>
            <textElement textAlignment="Right">
               <font fontName="Vrinda" size="14"
                  pdfEncoding="Identity-H"/>
            </textElement>
            <text><![CDATA[দেশ, জনসংখ্যা, এলাকা (বর্গ মাইল)]]></text>
         </staticText>
      </frame>
   </band>
</title>

<pageHeader>
   <band height="13"/>
</pageHeader>
<pageFooter>
   <band height="17">
      <textField>
         <reportElement mode="Opaque" x="0" y="4"
            width="515" height="13" backcolor="#E6E6E6"
            uuid="fed27553-a6c4-4a8a-9056-2f6f2589a3e5"/>
         <textElement textAlignment="Right"/>
         <textFieldExpression><![CDATA["Page "+$V{PAGE_NUMBER}+
            " of"]]></textFieldExpression>
      </textField>
      <textField evaluationTime="Report">
         <reportElement mode="Opaque" x="515" y="4" width="40"
            height="13" backcolor="#E6E6E6"
            uuid="9f5ad531-d413-49c9-874b-8b99e8150fa6"/>
         <textFieldExpression><![CDATA[" " +
            $V{PAGE_NUMBER}]]></textFieldExpression>
      </textField>
      <textField pattern="EEEEE dd MMMMM yyyy">
         <reportElement x="0" y="4" width="100" height="13"
         uuid="fc593335-5cbf-4caf-97b3-ff897c676bde"/>
         <textFieldExpression>
            <![CDATA[new java.util.Date()]]>
         </textFieldExpression>
      </textField>
   </band>
</pageFooter>
<summary>
   <band height="200" splitType="Stretch">
      <property name="local_mesure_unitheight" value="pixel"/>
      <componentElement>
         <reportElement x="60" y="0" width="390" height="200"
            uuid="c8c02560-b300-428d-8a76-a56c9a46a0b9"/>
         <jr:table xmlns_jr="http://jasperreports.sourceforge.net/
               jasperreports/components" xsi_schemaLocation=
               "http://jasperreports.sourceforge.net/jasperreports/components
               http://jasperreports.sourceforge.net/xsd/components.xsd">
            <datasetRun subDataset="tableDataset"
                  uuid="2efa4800-70f1-4aa4-bfdd-e658714298d6">
               <connectionExpression>
                  <![CDATA[$P{REPORT_CONNECTION}]]>
               </connectionExpression>
            </datasetRun>
            <jr:column width="90" uuid="3e384dfe-7e97-4095-afb4-21d79d290ac9">
               <jr:columnHeader style="Table_CH" height="30">
                     <staticText>
                     <reportElement mode="Transparent" x="0" y="0" width="90"
                        height="30" forecolor="#006699" backcolor="#E6E6E6"
                        uuid="5040eaf1-0bb5-4bc7-a078-f239645ebc12"/>
                     <textElement textAlignment="Left">
                        <font size="14" isBold="true"/>
                     </textElement>
                     <text><![CDATA[Serial]]></text>
                  </staticText>
               </jr:columnHeader>
               <jr:detailCell style="Table_TD" height="30">
                  <textField>
                     <reportElement key="" x="0" y="0"
                        width="90" height="30"
                        uuid="31fce5e8-f148-46a0-a3f3-f39d8df0a9a1"/>
                     <box leftPadding="2"/>
                     <textElement textAlignment="Left">
                        <font fontName="Vrinda" size="14"
                           pdfEncoding="Identity-H"/>
                     </textElement>
                     <textFieldExpression>
                        <![CDATA[$F{id}]]>
                     </textFieldExpression>
                  </textField>
               </jr:detailCell>
            </jr:column>
            <jr:column width="90"
                  uuid="08284b54-906a-4fc4-b0ef-02489b35551e">
               <jr:columnHeader style="Table_CH" height="30">
                  <staticText>
                     <reportElement mode="Transparent" x="0" y="0"
                        width="90" height="30" forecolor="#006699"
                        backcolor="#E6E6E6"
                        uuid="c1593795-1655-45e7-b280-06cef71592df"/>
                     <textElement textAlignment="Left">
                        <font fontName="Vrinda" size="14"
                          isBold="true" pdfEncoding="Identity-H"/>
                     </textElement>
                     <text><![CDATA[Area]]></text>
                  </staticText>
               </jr:columnHeader>
               <jr:detailCell style="Table_TD" height="30">
                  <textField>
                     <reportElement key="" x="0" y="0" width="90"
                        height="30"
                        uuid="6a7968d2-a383-44b0-89ed-95991ef5d2cc"/>
                     <box leftPadding="2"/>
                     <textElement textAlignment="Left">
                        <font fontName="Vrinda" size="14"
                           pdfEncoding="Identity-H"/>
                     </textElement>
                     <textFieldExpression>
                        <![CDATA[$F{area}]]>
                     </textFieldExpression>
                  </textField>
               </jr:detailCell>
            </jr:column>
            <jr:column width="90"
                  uuid="66a666b4-abcf-4880-9535-d6b9e62fd9b6">
               <jr:columnHeader style="Table_CH" height="30">
                  <staticText>
                     <reportElement mode="Transparent" x="0" y="0"
                        width="90" height="30" forecolor="#006699"
                        backcolor="#E6E6E6"
                        uuid="4cb528be-0c12-43e2-aa16-20b36362d49a"/>
                     <textElement textAlignment="Left">
                        <font size="14" isBold="true"/>
                     </textElement>
                     <text><![CDATA[Population]]></text>
                  </staticText>
               </jr:columnHeader>
               <jr:detailCell style="Table_TD" height="30">
                     <textField>
                     <reportElement key="" x="0" y="0" width="90"
                        height="30"
                        uuid="8321a6d9-cc80-46d9-bd49-2eb5afe1043a"/>
                     <box leftPadding="2"/>
                     <textElement textAlignment="Left">
                        <font fontName="Vrinda" size="14"
                           pdfEncoding="Identity-H"/>
                     </textElement>
                     <textFieldExpression>
                        <![CDATA[$F{population}]]>
                     </textFieldExpression>
                  </textField>
               </jr:detailCell>
            </jr:column>
            <jr:column width="90"
                  uuid="0f7e7c3e-7b14-4bd1-ac6e-a941e7e74f2c">
               <jr:columnHeader style="Table_CH" height="30">
                  <staticText>
                     <reportElement mode="Transparent" x="0" y="0"
                        width="90" height="30" forecolor="#006699"
                        backcolor="#E6E6E6"
                        uuid="3c609b59-57cc-451c-9d07-a80a216cf9e1"/>
                     <textElement textAlignment="Left">
                        <font size="14" isBold="true"/>
                        </textElement>
                     <text><![CDATA[Country]]></text>
                  </staticText>
               </jr:columnHeader>
               <jr:detailCell style="Table_TD" height="30">
                  <textField>
                     <reportElement key="" x="0" y="0" width="90"
                        height="30"
                        uuid="3d2bf3b0-16b2-4d0b-8ed0-b06d39b1ab71"/>
                     <box leftPadding="2"/>
                     <textElement textAlignment="Left">
                        <font fontName="Vrinda" size="14"
                           pdfEncoding="Identity-H"/>
                     </textElement>
                     <textFieldExpression>
                        <![CDATA[$F{country_name}]]>
                     </textFieldExpression>
                  </textField>
               </jr:detailCell>
            </jr:column>
            </jr:table>
         </componentElement>
      </band>
   </summary>
</jasperReport>

Listing 1: report_template.jrxml

3. Programming the Report

Open Eclipse and then create a Java Project file. Include the following jar files in the Build Path of the project.

  • PostgreSQL JDBC jar
  • Vrinda jar we have created from Jasper Studio (since I have used the Vrinda font)
  • All the jars from /dist and /lib directories of the unzipped Jasperreports-6.1.0-project

Create a Java file named ReportInBangla in a package under src. Type/Copy & Paste in the code from Listing 2.

package org.mano;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.view.JasperViewer;

public class ReportInBangla {

   private final String jrxmlFileName =
      "C:/workspace/MLReport/report_template.jrxml";
   private final String sourceFile =
      "C:/workspace/MLReport/report_template.jasper";
   private final String pdfFile =
      "C:/workspace/MLReport/report_template.pdf";
   private final String htmlFile =
      "C:/workspace/MLReport/report_template.html";

   private String printFile = null;

   public static void main(String[] args) {
      ReportInBangla rb = new ReportInBangla();
      rb.compileJRXMLFile();
      rb.showReportInJasperViewer();
   rb.printReportToFile();
}

   public void compileJRXMLFile() {
      System.out.println("Compiling Report Design ...");
      try {
         JasperCompileManager.compileReportToFile(jrxmlFileName);
         System.out.println("Done compiling!!! ...");
      } catch (JRException e) {
         System.out.println("Compilation Error: " +
            e.getMessage());
      }
   }

   public void showReportInJasperViewer() {
      Connection con = null;
      try {
         Class.forName("org.postgresql.Driver");
         con = DriverManager.getConnection(
            "jdbc:postgresql://localhost:5432/MultiLigualDatabase",
            "postgres", "kamikaze");

         JasperPrint jp = JasperFillManager.fillReport(sourceFile,
            new HashMap<>(), con);
         JasperViewer.viewReport(jp);
      } catch (JRException | ClassNotFoundException |
            SQLException ex) {
         ex.printStackTrace();
      } finally {
         if (con != null)
            try {
               con.close();
            } catch (SQLException e) {
               e.printStackTrace();
            }
      }

   }

   public void printReportToFile() {
      Connection con = null;
      try {
         Class.forName("org.postgresql.Driver");
         con = DriverManager.getConnection(
            "jdbc:postgresql://localhost:5432/MultiLigualDatabase",
               "postgres", "kamikaze");
         printFile = JasperFillManager.fillReportToFile(sourceFile,
            new HashMap<>(), con);
         if (printFile != null) {
            JasperExportManager.exportReportToPdfFile(printFile,
               pdfFile);
            JasperExportManager.exportReportToHtmlFile(printFile,
                  htmlFile);
               System.out.println("done printing...!!");
         }
      } catch (JRException | ClassNotFoundException |
            SQLException ex) {
         ex.printStackTrace();
      }finally {
         if (con != null)
            try {
               con.close();
            } catch (SQLException e) {
               e.printStackTrace();
         }
      }
   }
}

Listing 2: ReportInBangla.java

Multi7
Figure 7: Report output in JasperViewer

Multi8
Figure 8: Report output in a PDF file

Multi9
Figure 9: Report output in an HTML file

Conclusion

Observe that the report output in the PDF file and JasperViewer is not rendered properly. However, the report output in browser for HTML file is exact and appropriate. This is a clear indication of the text parsing problem from the point of view of PDF file creation or PDF reader input distortion of Unicode characters. However, redirecting output to a printer also has no distortion. This is the story of almost all languages that require/use collation. The only solution seems to be redirecting the output as an HTML file or to the printer, as of now.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories