Internationalization

This document describes how to create a system service and setup a Nexaweb Java application to
display text and messages in multiple languages.

Overview

The process of internationalizing an application to display text and messages in multiple languages requires the following major steps:

  • Create a system service to allow the application language to be selectable.
  • Create property files with key value pairs as resource bundles.
  • Register the system service.
  • Set the value of component text attributes with resolution syntax corresponding to the keys
    defined in property files

Creating a System Service

The following is an example of a system service container for internationalizaton:

 

package com.nexaweb.i18n.utils;
import java.util.Locale;
import java.util.ResourceBundle;
import com.nexaweb.client.ClientSession;
import com.nexaweb.client.macro.Macro;
import com.nexaweb.client.mco.AbstractMco;
import com.nexaweb.client.mco.Container;
import com.nexaweb.session.ClientInfo;
import com.nexaweb.xml.ParserException;

public class I18nServiceRegistrar extends AbstractMco {
	private Locale locale;
	private ResourceBundle resBundle;

}

 

The following section creates an instance of the service class, itself, and registers it in the SystemContainer. It also sets the locale to the default locale of the client.

public void registerI18nService() {
	I18nServiceRegistrar i18nSysService = new I18nServiceRegistrar();
	Container sysContainer = getSession().getSystemContainer();
	ClientSession clientSession = getSession();
	ClientInfo clientInfo = clientSession.getClientInfo();
	Locale locale = clientInfo.getLocale();
	i18nSysService.setLocale(locale);
	sysContainer.put("i18nService", i18nSysService); 
}

The following section sets the service locale based on the language and country. It then repaints
the screen based on the new language by calling the macro repaintScreen,
defined in the XAL file.

The language parameter specifies the newly selected language.
The country parameter specifies the newly selected country.

 

public void setLocale(String language, String country) {
	Locale locale = new Locale(language, country);
	Container sysContainer = getSession().getSystemContainer();
	I18nServiceRegistrar i18nSysService = (I18nServiceRegistrar)
	sysContainer.get("i18nService");
	i18nSysService.setLocale(locale);
	sysContainer.put("i18nService", i18nSysService);

	Macro repaintScreenMacro = getSession().getMacroContainer().getMacro("repaintScreen");
	try {
		repaintScreenMacro.execute();
	} catch (ParserException e) {
		// TODO Auto-generated catch block 
		e.printStackTrace();
		System.out.println("Macro parse exception occurred");
	}
}

 

The following section loads the resource bundle for the supplied locale.
The locale parameter specifies the locale.

public void setLocale(Locale locale) { 
	this.locale = locale; 
	System.out.println("Locale: " + this.locale.toString()); 
	resBundle = ResourceBundle.getBundle("CETS", this.locale);
}

The following section returns the value from the resource bundle for the supplied key. The key parameter lookups the translation from the resource bundle and returns the value corresponding to the input key.

public String getValue(String key) { 
	String value = resBundle.getString(key); 
	if (value == null) { 
		value = ""; 
	} 
	return value; 
}

Creating Property Files

Create separate property files for each locale the application supports as your resource bundles.

Each property file contains key value pairs. The key corresponds to a resolution syntax parameter used in the UI file to specify the text attribute of some component. The value specifies locale-specific text to display in that component.

To create property files, follow these steps:

  • Create a text file with a .properties extension named: basename_language-code_location-code for each locale the application supports. For example, create a properties file for US, English named: MYAPP_en_US.properties.
  • Inside the file, specify key-value pairs for each text attribute in the UI that the application displays as follows:
KeyValue

Specify a key that corresponds to the parameter used in the UI file as the resolution sytnax.

Specify the text to appear in the language that this property file supports.

For languages requiring the use of special characters, use JAVA's native2ascii.exe to convert the text to unicode values.

 For example, create key-value pair entries in the English-US properties file similar to the following:

WELCOME_TEXT=Welcome to CETS
USERID_TEXT=User Id
PASSWORD_TEXT=Password
CLEAR_TEXT=Clear
SUBMIT_TEXT=Submit
  • Create properties files for other languages including the same keys and the language-specific values.
  • Place the properites file in the project\WebContent\WEB-INF\client\classes directory.

UI File

You must include in the UI file a call to the MCO that registers the system service similar
to the following:

<mco:mco xmlns:mco="http://openxal.org/core/mco" 
	id="i18nServiceRegistrar" src="com.nexaweb.i18n.utils.I18nServiceRegistrar" 
	onLoad="mco:i18nServiceRegistrar.registerI18nService()"/> 
<mco:mco xmlns:mco="http://openxal.org/core/mco" 
	id="sampleMco" src="com.nexaweb.i18nsample.mco.SampleMco" onLoad="mco:sampleMco.init()"/>

In addition, you must add syntax resolution to the text attribute of any component for which you want
the text to display multiple languages, similar to the following:

<label height="20px" 
	text="'{i18nService.getValue(''WELCOME_TEXT'')'}" 
	width="200px" x="350px" y="30px" borderColor="#000000" borderWidth="1px"/> 
<label height="20px" 
	text="'{i18nService.getValue(''USERID_TEXT'')'}" width="200px" x="120px" y="110px"/> 
<textField id="userId" height="25px" 
	text="TextField" width="200px" x="320px" y="110px"/> 
<label height="20px" 
	text="'{i18nService.getValue(''PASSWORD_TEXT'')'}" width="200px" x="120px" y="150px"/> 
<textField id="password" height="25px" 
	text="TextField" width="200px" x="320px" y="150px"/> 
<button height="25px" 
	text="'{i18nService.getValue(''CLEAR_TEXT'')'}" width="100px" x="320px" y="220px" 
	onCommand="mco:sampleMco.clear()"/> 
<button height="25px" 
	text="'{i18nService.getValue(''SUBMIT_TEXT'')'}" width="100px" x="430px" y="220px"/>

Note: Since the above code is within a Macro, both the single quote and braces need to be escaped with a single quote.

The following shows the complete UI file for an application that supports multiple languages and 
works with the system service, MCO and properties files shown above:

<xal xmlns="http://openxal.org/ui/java">
	<mco:mco xmlns:mco=http://openxal.org/core/mco id="i18nServiceRegistrar" src="com.nexaweb.i18n.utils.I18nServiceRegistrar" 
		onLoad="mco:i18nServiceRegistrar.registerI18nService()"/>
	<mco:mco xmlns:mco="http://openxal.org/core/mco" id="sampleMco"
		src="com.nexaweb.i18nsample.mco.SampleMco"
		onLoad="mco:sampleMco.init()"/>
	<macro:macro xmlns:macro=http://openxal.org/core/macro 
		name="repaintScreen">
		<xm:modifications xmlns:xm="http://openxal.org/core/xmodify">
			<xm:replace-children select="id(''presentationSpace'')">
				<freePane xmlns="http://openxal.org/ui/java" width="1024px" height="768px">
					<label height="20px"
						text="'{i18nService.getValue(''WELCOME_TEXT'')'}" 
						width="200px" x="350px" y="30px"
						borderColor="#000000" borderWidth="1px"/>
					<label height="20px"
						text="'{i18nService.getValue(''USERID_TEXT'')'}"
						width="200px" x="120px" y="110px"/> 
					<textField id="userId" height="25px" text="TextField"
						width="200px" x="320px" y="110px"/>
					<label height="20px"
						text="'{i18nService.getValue(''PASSWORD_TEXT'')'}"
						width="200px" x="120px" y="150px"/>
					<textField id="password" height="25px" text="TextField"
						width="200px" x="320px" y="150px"/>
					<button height="25px" 
						text="'{i18nService.getValue(''CLEAR_TEXT'')'}"
						width="100px" x="320px" y="220px"
						onCommand="mco:sampleMco.clear()"/>
					<button height="25px"
						text="'{i18nService.getValue(''SUBMIT_TEXT'')'}"
						width="100px" x="430px" y="220px"/>
				</freePane>
			</xm:replace-children>
		</xm:modifications>
	</macro:macro>
	<rootPane>
		<borderPane> 
			<horizontalFlowPane borderPosition="north" x="0px" y="0px" 
				width="988px" height="40px" alignment="center">
				<radioButton height="25px" text="US" width="100px"
					onSelect="mco:i18nServiceRegistrar.setLocale('en','US')" 
					group="country" selected="true"/>
				<radioButton height="25px" text="Canada" width="100px"
					borderPosition="west"
					onSelect="mco:i18nServiceRegistrar.setLocale('fr','CA')"
					group="country"/>
				<radioButton height="25px" text="Mexico" width="100px"
					borderPosition="center"
					onSelect="mco:i18nServiceRegistrar.setLocale('sp','MX')"
					group="country"/>
			</horizontalFlowPane>
			<freePane id="presentationSpace" height="300px" width="300px"
				borderPosition="center" 
				onCreate="macro:repaintScreen"/>
		</borderPane>
	</rootPane>
</xal>