blob: 6cfdf92b659102c041718fbf07e19e33c5d59a48 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="copyright" content="Copyright (c) 2007, 2016 EclipseSource. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page."/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Internationalization</title>
<link rel="stylesheet" href="../../../PRODUCT_PLUGIN/book.css" type="text/css"/>
</head>
<body>
<h1>Internationalization in RAP</h1>
<p>
Internationalization (i18n) is the process of adapting applications to the user's
language and region, including things like number formats, date and time, etc.
The Java class library has support for internationalization, most notably by
<em>locales</em> and <em>resource bundles</em>.
RAP applications can use these features just like other applications,
but since they are accessed by multiple users simultaneously, they must be designed to
work with user-specific locales instead of a single, system-wide locale.
</p>
<h2>Getting and Setting the Locale</h2>
<p>
In RAP, every UISession has its own locale that can be obtained using the method
<em><a href="../reference/api/org/eclipse/rap/rwt/service/UISession.html#getLocale--">getLocale</a></em>.
By default, this locale is based on the user's preferred locale provided by the client.
If the client does not provide a locale, the system-wide default locale is taken as a fallback.
The default locale can be set by adding the system property <code>user.language</code>
to the launch configuration.
The UISession locale can also be changed programmatically using
<em><a href="../reference/api/org/eclipse/rap/rwt/service/UISession.html#setLocale-java.util.Locale-">setLocale</a></em>,
for example when the user selects a preferred locale in the application's UI.
</p>
<p>
Note: The static methods <em>RWT.getLocale()</em> and <em>RWT.setLocale()</em>
are shortcuts for <em>RWT.getUISession().getLocale()</em> and
<em>RWT.getUISession().getLocale(...)</em>, respectively.
</p>
<p>
In addition to this, a client provides the user's preferred locales in the
<em><a href="../reference/api/org/eclipse/rap/rwt/client/service/ClientInfo.html">ClientInfo</a></em>
service.
This information is based on the list of locales passed in the
HTTP header <code>Accept-Language</code>, which usually reflects the user's language preferences
in the Web browser.
Alternative RAP clients may provide a different ClientInfo implementation.
</p>
<h2>Localization</h2>
<p>
Localization is the process of translating an internationalizable application
for a certain language and region.
The locale-specific strings are usually kept in a Java properties files, accessed
by a <em>ResourceBundle</em>.
Translated versions of these property files must have a suffix that indicates
their language, optionally also the country and a variant (for the details, please refer to
<a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Locale.html">Locale</a> and
<a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>.
For example, to create a German translation for a resource property file named
<code>MyResources.properties</code>, you would create a copy of the file and name it
<code>MyResources_de.properties</code>.
Then you would translate the strings in this file and put it into the same package as the
original file.
The translated files and other localized resources can go into a separate .jar file or,
if your application uses OSGi, in a fragment bundle.
</p>
<p>
Be aware that the property files are expected to be in ISO-8859-1 (Latin 1) encoding.
If the translated properties files contain accented characters that are not included
in the Latin-1 encoding, they have to be represented by <en>Unicode Escapes</en>.
Property files in other encodings can be converted using the <code>native2ascii</code>
utility, that is shipped with the Java SDK.
</p>
<p>
<strong>Note:</strong> The ResourceBundle fallback mechanism can sometimes lead to confusion.
You could expect that the system falls back to the default properties file if no translated
properties file can be found that matches the user's locale. That's not the case.
If a translation is not found for the locale in question, the ResourceBundle lookup will
first try the <em>default</em> locale, i.e. <em>Locale.getDefault()</em>.
For example, if your VM is set to German and there is a <code>MyResources_de.properties</code>
file, the translation will fallback to this file instead of the default
<code>MyResources.properties</code>.
If you want to have English as your fallback, you have to set your VM to English.
</p>
<h2 id="messages">Localizing RAP Messages</h2>
<p>
In case of session timeout, a network error, and other kinds of exception,
the web client will display a message box.
In an internationalized application these messages should be translated as well.
The default texts reside in the properties file
<em>org/eclipse/rap/rwt/internal/RWTMessages.properties</em>
in the bundle <em>org.eclise.rap.rwt</em>.
To localize the application, include the translated versions (<em>RWTMessages_xx.properties</em>)
in the deployed application, e.g. in an OSGi fragment bundle.
At the moment, we don't provide any translated versions, so you'll have to
create them on your own.
</p>
<h2>Internationalization in JFace</h2>
<p>
The texts for JFace dialog buttons are traditionally set directly to one of the constants
in <code>IDialogConstants</code>.
This method is not suitable for multiple users because the strings contained in these constants
are translated only once.
For multi-user applications, <code>IDialogLabelKeys</code> also provides <em>keys</em> that can
be resolved to localized strings dynamically using <code>JFaceResources.getString( key )</code>.
In a RAP application, label texts should be obtained as in this example:
</p>
<pre class="lang-java">
protected void createButtonsForButtonBar( Composite parent ) {
createButton( parent,
IDialogConstants.OK_ID,
JFaceResources.getString( IDialogLabelKeys.OK_LABEL_KEY ),
true );
createButton( parent,
IDialogConstants.CANCEL_ID,
JFaceResources.getString( IDialogLabelKeys.CANCEL_LABEL_KEY ),
false );
}
</pre>
<h2>Internationalization in RCP</h2>
<p>
RCP established its own internationalization mechanism that is explained in
<a href="#ref1">[1]</a>.
This approach is based on resource bundle <em>accessor classes</em> that keep translated
strings in static fields, which is not suitable for a multi-user system.
To solve this problem, the RAP project has developed a method to adjust existing RCP
applications for use in multi-user environments with minimal modifications.
</p>
<p>
Here's an example snippet of RCP code that reads a localized string from a static field of an
accessor class (commonly named “Messages”).
</p>
<pre class="lang-java">
label.setText( Messages.ExampleView_Message );
</pre>
<p>
For multiple users, we need different translations.
Therefore we suggest to use instance fields instead of static fields and to create a different
instance of the class for every language.
This allows for re-using the existing code with only a minimal change,
which is to insert a <em>get()</em> method that returns an instance of
the resource bundle accessor class for the current UISession locale:
</p>
<pre class="lang-java">
label.setText( Messages<strong>.get()</strong>.ExampleView_Message );
</pre>
<p>
To allow for this pattern, the static fields in the <code>Messages</code> class must be changed
to instance fields.
Moreover, the <em>get()</em> method must be added to this class.
This method must return an instance of the class with all fields translated to the current
UISession locale.
The RAP framework provides a helper class RWT.NLS to do this.
Here's an example of a modified accessor class:
</p>
<pre class="lang-java">
public class Messages {
private static final String BUNDLE_NAME = "org.example.views.messages"; //$NON-NLS-1$
public String ExampleView_Title;
public String ExampleView_Message;
public static Messages get() {
Class clazz = Messages.class;
return ( Messages )RWT.NLS.getISO8859_1Encoded( BUNDLE_NAME, clazz );
}
private Messages() {
// prevent instantiation
}
}
</pre>
<p>
Note that in contrast to RCP, the class does not extend
<code>org.eclipse.osgi.util.NLS</code>.
The constant <code>BUNDLE_NAME</code> contains the name (without extension) of
the properties file that contains the mapping from keys to localized strings.
In the example above, a properties file <code>messages.properties</code> is expected in
the package <code>org/example/views</code>.
This property file must contain the default strings for every key:
</p>
<pre>
ExampleView_Title = Example
ExampleView_Message = Hello World
</pre>
<p>
Note: to simplify the translation to non-Latin languages, the RAP NLS utility also accepts
UTF-8 encoded property files.
</p>
<h2>Internationalization of Plug-ins (plugin.xml)</h2>
<p>
Plug-in manifest files (<code>plugin.xml</code>) may also contain translatable strings,
e.g. view names or menu labels.
Therefore, a plugin.xml may contain placeholder strings that are prefixed with a
<code>%</code> sign.
These placeholder keys are then resolved in a properties file, which is by convention named
<code>plugin.properties</code> and resides in the root directory of the plug-in.
Here's an example of a view extension that contains a placeholder for the name attribute:
</p>
<pre class="lang-xml">
&lt;extension
point="org.eclipse.ui.views"&gt;
&lt;view
id="org.example.views.exampleView"
class="org.example.views.ExampleView"
name="<strong>%exampleView_name</strong>"&gt;
&lt;/view&gt;
&lt;/extension&gt;
</pre>
<p>
The bundle would include a file <code>plugin.properties</code> that contains the translatable
text for this placeholder in a line like the following:
</p>
<pre>
exampleView_name = Example
</pre>
<p>
To make this work, the OSGi manifest (<code>MANIFEST.MF</code>) must contain a
<em>Bundle-Localization</em> header that points to the name of the properties file
(without extension):
</p>
<pre>
Bundle-Localization: plugin
</pre>
<p>
In a multi-user environment, the Equinox extension registry must be set to multi-locale mode
to be able to serve strings in multiple locales simultaneously. This is done by setting the
system property <code>eclipse.registry.MultiLanguage</code> to <code>true</code> or by setting
the framework property <code>registryMultiLanguage</code>.
</p>
<p>
If you're <a href="deployment.html">deploying your application as a WAR</a>,
make sure to include the framework property in the <code>web.xml</code> like
shown below:
</p>
<pre class="lang-xml">
&lt;init-param&gt;
&lt;param-name&gt;commandline&lt;/param-name&gt;
&lt;param-value&gt;-registryMultiLanguage&lt;/param-value&gt;
&lt;/init-param&gt;
</pre>
<h2>Tool Support</h2>
<p>
The Java tools in the Eclipse IDE provide a tool to easily extract strings into message bundles,
the <em>Externalize Strings</em> wizard (<em>Source &gt; Externalize String…</em>).
This wizard has an option to “use Eclipse's string externalization mechanism” (the mechanism
that is described in [1]), which is enabled by default for Plug-in Projects.
As explained above, this mechanism is not suitable for multi-user applications.
</p>
<h2>References</h2>
<ul>
<li><a name="ref1" href="http://www.eclipse.org/articles/Article-Internationalization/how2I18n.html">1. How to Internationalize your Eclipse Plug-In (Article on Eclipse.org)</a></li>
</ul>
</body>
</html>