Home Tutorials Training Consulting Products Books Company Donate Contact us

vogella commercial offerings

Training Events

Eclipse internationalization and localization. This article describes how to prepare your Eclipse RCP and Eclipse plug-ins for translation.

1. Internationalization and localization

1.1. Translation of a Java applications

The process of preparing an application for being translated into several languages is called internationalization. This term is typically abbreviated to i18n.

The process of translating the application is called localization and is abbreviated to l10n.

Java applications are typically translated via property files. Such a file contains key/values. The key can be used in your application and is substituted at runtime with the corresponding value. The following listing demonstrates an example content of such a file.

#Properties file

Based on the language of the user, the Java runtime searches for the corresponding resource bundle using language identifiers. If a certain language identifier is not provided, the Java runtime will fall back to the next general resource bundle.

For example:

  • messages.properties: default language file, if nothing else is available

  • messages_de.properties: used for German

  • messages_en.properties: default for English

  • messages_en_US.properties: US English file

  • messages_en_UK.properties: British English file

The Eclipse platform provides functionality to support translations based on properties files but also allows the usage of alternative approaches.

Resource bundles in Java are always LATIN-1 (ISO 8859-1) encoded. This is defined by the Java specification.

1.2. Relevant files for translation in Eclipse applications

The following table lists the file relevant for localization.

Table 1. Translation relevant files for Eclipse plug-ins
Entity Description

application model (Application.e4xmi and model fragment files)

Describes the application model in Eclipse RCP.


Primarily important for Eclipse 3.x based plug-ins.

Source Code

The source code contains text, e.g., labels which must be translated.

1.3. Where to store the translations?

Plug-ins can contain their translations. If a translation should be used by several plug-ins, it is good practice to have one central plug-in which contains the translations. This plug-in contains at least the main language and potentially more.

It is also possible to provide translation files via fragment projects. Fragment projects extend their host plug-in at runtime. This approach allows that different languages are maintained in separate plug-ins. This is sometimes easier to handle for the translation team. This approach also allows configuring the included languages via the product configuration file.

1.4. Setting the language in the launch configuration

By default, Eclipse uses the language configured in the operating system of the user.

For testing, you can set the language via the launch configuration. On the Arguments tab use the runtime parameter -nl for this purpose, e.g. -nl en.

1.5. Translation service

Eclipse uses a translation service via the TranslationService interface. The default implementation of this class is the BundleTranslationProvider which uses property files as input for the translations. You can provide a custom service which uses a different source, e.g., a database to get the translations.

This service is stored in the application context. You can replace it there, e.g., via a life cycle hook or via a model-addon which modifies the application context once the application startup is completed.

By storing it in the IEclipseContext context hierarchy, you can have different translation services for different local contexts. For example, you can use different translation services for different windows.

1.6. OSGi resource bundles

For the translation of the plugin.xml and application model files the Eclipse runtime uses by default OSGi resource bundles. These are property files in a specified location. OSGi expects at least one resource bundle in this location.

OSGI-INF/l10n/bundle is the default location and file prefix which the Eclipse translation service is using. Via the Bundle-Localization attribute in the manifest file, you can specify an alternative location for the bundle resources. The usage of this attribute is demonstrated in the following listing.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: I18n
Bundle-SymbolicName: de.vogella.rcp.i18n; singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: de.vogella.rcp.i18n.Activator
Require-Bundle: org.eclipse.ui,
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-Localization: OSGI-INF/anotherlocation/bundle

Alternative languages are defined via additional property files. The filename of these files can include a language and optional a country variant as described in Translation of a Java applications. For example, bundle_en.properties or bundle_en_UK.properties.

1.7. Translating the application model

The translation key can be specified in your application model via the %key reference. This usage is demonstrated via the following screenshot of the model data for a part.

How to use external strings in the workbench model

Currently the application model tooling includes rudimentary support for extracting Strings. Press the right mouse button on an empty space in the application model editor and select Externalize Strings.

This action extracts all Strings from the application model. If you want to replace only a set of relevant Strings, you have to do this manually.

1.8. Translating plugin.xml

Similar to the usage of keys in the application model, you can use the key prefixed with % in the plugin.xml file. The Eclipse tooling supports extracting existing String values from the plugin.xml file. Select your plugin.xml file, right-click on it and select Plug-in Tools  Externalize Strings.

Eclipse PDE Wizard for externizing plugin.xml

Via PDE Tools  Internationalize you can also directly create one or several fragments for the result of the internationalization.

1.9. Potential problems with translations

You must include your property files in the build.properties file. If not, your translations will be missing in the exported product.

If the translations are not displayed in the application, select Clear Configuration in your launch configuration. OSGi sometimes caches text information.

2. Eclipse 4 internationalization

2.1. Translation with POJOs

To define your translations you simply define a Java object with several public fields of type String.

public class Messages {
    public String labelSummary;
    public String labelDescription;
    public String labelDone;
    public String labelDueDate;
    public String labelWithPlaceholder = {0} says {1}

The fields of such a Java object are initialized when an instance is injected via the @Translation annotation. The org.eclipse.e4.core.services plug-in contains the annotations which are used for translations.

Messages messages;

// more code

To find the property files for the key/value pairs, if searches for property files in the following order.

  • Check for a @Message annotation in the Messages class. The optional @Message annotation can be used to define the location of the resource bundle. It allows also to define how and if translations should be cached by the Eclipse platform. See the Javadoc of the @Message annotation for more information on this topic.

  • Check if a property file with a corresponding name is available relatively to the Messages class.

  • Check if a property file is configured via the OSGi-ResourceBundle header in the MANIFEST.MF file.

  • Check the OSGI-INF/l10n folder

It is possible to initialize fields via the @PostConstruct method in a message object as demonstrated in the following snippet.

public class Messages {
    public String labelWithPlaceholder1 = {0} says {1}
    public String labelWithPlaceholder2 = {0} says {1}

    // initialize the first message

    public void format() {
        labelWithPlaceholder2 =
                    format(labelWithPlaceholder2, "Test", "this is fun.");

@PostConstruct does not support parameter injection in the context of a message object.

2.2. Dynamic language switch

The currently active locale, e.g., "de" or "en", is represented by an object of type Locale. The Eclipse runtime supports a dynamic switch of this locale at runtime.

The type of the TranslationService.LOCALE key was changed from String to Locale in Eclipse 4.4.2.

To support a dynamic locale switch the application must be able to react on changes in the messages. This requires that the widgets are declared as public fields and that a method exists which updates them. This is called the Eclipse Translation Pattern.

public class TranslationExamplePart {
    private Label myLabel;

    public void postConstruct(Composite parent, @Translation Messages messages) {
        // create the UI
        myLabel = new Label(parent, SWT.NONE);
        // as @PostConstruct is executed after field injection, we need to
        // call translate here manually to fill the UI initially

    // the method that will perform the dynamic locale changes
    public void translate(@Translation Messages messages) {
        if (myLabel != null && !myLabel.isDisposed())

To change the active locale at runtime use the ILocaleChangeService service. This is demonstrated by the following class which could be used as part of a tool control.

public class SwitchLanguageToolControl.java {

    Button button;

    ILocaleChangeService lcs;

    public createPartControls(Composite parent) {

        final Text input = new Text(parent, SWT.BORDER);

        input.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent event) {
                if (event.keyCode == SWT.CR
                        || event.keyCode == SWT.KEYPAD_CR) {

        button = new Button(parent, SWT.PUSH);
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {

    public void translate(@Translation Messages messages) {
        // button localization via Eclipse Translation Pattern

To get notified you can use dependency injection.

private void getNotified(
    @Named(TranslationService.LOCALE) Locale s) {
    System.out.println("Injected via context: " + s);

private void getNotified(
    @UIEventTopic(ILocaleChangeService.LOCALE_CHANGE) Locale s) {
    System.out.println("Injected via event broker: " + s);

2.3. Using the BaseMessageRegistry to track language changes

Instead of implementing a method to receive the Message object on locale change in a part, like @Inject public void translate(@Translation Messages messages), a BaseMessageRegistry can be implemented.

The BaseMessageRegistry<M> contains methods to register controls, which are supposed to be translated. So basically the BaseMessageRegistry<M> will be informed about new Message objects and applies the new values to its registered controls.

The BaseMessageRegistry<M> itself gets the Message object injected.

package com.vogella.tasks.ui.i18n;

import javax.inject.Inject;

import org.eclipse.e4.core.di.annotations.Creatable;
import org.eclipse.e4.core.services.nls.BaseMessageRegistry;
import org.eclipse.e4.core.services.nls.Translation;

public class MessagesRegistry extends BaseMessageRegistry<Messages> {

    public void updateMessages(@Translation Messages messages) {
        // Update the Messages for the BaseMessageRegistry by DI

Because the MessagesRegistry class is annoted with @Creatable, it is instanciated by the framework and can directly be injected into the postConstruct method.

package com.vogella.tasks.ui.parts;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.e4.core.services.nls.MessageConsumer;
import org.eclipse.e4.core.services.nls.MessageFunction;
import org.eclipse.e4.core.services.nls.Translation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

import com.vogella.tasks.ui.i18n.Messages;
import com.vogella.tasks.ui.i18n.MessagesRegistry;

public class MessagesRegistryExamplePartWithoutJava8 {
    private Label myLabel;

    public void postConstruct(Composite parent, MessagesRegistry messagesRegistry) {
        // create the UI
        myLabel = new Label(parent, SWT.NONE);
        // Let the MessagesRegistry apply the correct label
        messagesRegistry.register(new MessageConsumer() {

            public void accept(String value) {
        }, new MessageFunction<Messages>() {

            public String apply(Messages m) {
                return m.labelSummary;

By using Java 8 registering controls looks better and is even shorter.

package com.vogella.tasks.ui.parts;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.e4.core.services.nls.MessageConsumer;
import org.eclipse.e4.core.services.nls.MessageFunction;
import org.eclipse.e4.core.services.nls.Translation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

import com.vogella.tasks.ui.i18n.Messages;
import com.vogella.tasks.ui.i18n.MessagesRegistry;

public class MessagesRegistryExamplePartWithJava8 {

    public void postConstruct(Composite parent, MessagesRegistry messagesRegistry) {
        // create the UI
        Label myLabel = new Label(parent, SWT.NONE);
        // Let the MessagesRegistry apply the correct label
        messagesRegistry.register(myLabel::setText, m -> m.labelSummary);

3. Source code translation with NLS support

3.1. Translating your source code with the NLS approach

This part of the description is included for completeness. It describes the NLS approach for translation. This approach still works but the Eclipse translation mechanism provides more flexibility, e.g., dynamic switching of languages, less memory consumption and a translation service which can be exchanged. This superior approach is described in Translation with POJOs.

It is possible to translate the Java source with two different approaches, based on Strings and based on constants. The approach based on constants is more reliable and should be preferred. To enable this support you need to configure the org.eclipse.core.runtime plug-in as dependency in your related plug-in.

To translate Strings in the source code, select the file you want to translate and select Source  Externalize Strings.

Externalizing strings in source files dialog

Please note that the Use Eclipse’s string externalization mechanism option is only visible if you have the org.eclipse.core.runtime plug-in configured as a dependency in your plug-in.

Externizing strings in source files dialog

In this wizard you can select which Strings should be translated, which should be skipped and which should be marked as not translatable.

If you select that a String should not be translated, Eclipse marks the occurrence with a $NON-NLS comment in the source code.

As the result a Messages class is generated which serves as an access point for the properties file.

package test;

import org.eclipse.osgi.util.NLS;

public class Messages extends NLS {
    private static final String BUNDLE_NAME
        = "test.messages"; //$NON-NLS-1$
    public static String View_0;
    public static String View_1;
    static {
        // initialize resource bundle
        NLS.initializeMessages(BUNDLE_NAME, Messages.class);

    private Messages() {

In this example the Messages class uses a constant called BUNDLE_NAME to point to the message*.properties file in the test package. * is a placeholder for your locale, e.g., _de,_en, etc.


In your code you access the translations via the Message class.


You can also use placeholders in the messages and evaluate them with the NLS.bind() method.

MyMessage = {0} says {1}
// NLS bind will call the toString method on obj
NLS.bind(Message.MyMessage, obj, obj);

If translations should be used over several plug-ins to ensure consistency, it is good practice to create separate plug-ins or fragments for the translations. All plug-ins which want to use the translations define a dependency to the corresponding plug-in.

Additional languages are typically contributed via Eclipse fragment projects to this message plug-in.

3.2. Translating SWT and JFace code

The SWT and JFace plug-ins include their resource translation files. You can change these default texts and their translations because resource bundles have an override support built in.

If you supply a different file of the SWT or JFace translation bundles in a fragment or plug-in (such as SWTMessage_de.properties), then the bundle matching the current local is used.

To change the text supplied by SWT and JFace do the following:

  • Create two fragments projects, which will hold the translations. One with org.eclipse.jface and one with org.eclipse.swt as Host-Plug-in.

  • Create the org.eclipse.jface and org.eclipse.swt.internal packages in the corresponding fragments.

  • Copy the org/eclipse/jface/message.properties file from the org.eclipse.jface plug-in and the org/eclipse/swt/internal/SWTMessage.properties file from the SWT plug-in to the corresponding packages in your project. See the appendix for the links to their location in the Eclipse Git repository.

  • Provide the files with your desired language extensions, e.g. message_de.properties.

  • Edit the files to contain your text properties.

The original message.properties in JFace or SWTMessage.properties in SWT cannot be overridden by a fragment. Therefore, you can only provide additional *.properties files for a certain locale like message_de.properties.

You can translate selected properties of the original message.properties file.

Package structure of the JFace fragment

4. Tutorial: Translate plugin.xml

Create a new Eclipse RCP application "de.vogella.rcp.i18n" based on the "RCP application with a view" template. Check the contributions to the "org.eclipse.ui.views" extension point in your plugin.xml file and validate that the name of the View is hard coded to "View".

Right-click on the plugin.xml file and select PDE Tools  Externalize Strings. Accept the default and press ok.

This will create the file bundle.properties and replace the hard-coded string in plugin.xml with a "%key" placeholder, e.g. %View.


Copy bundle.properties to "bundle_fr.properties" and "bundle_en.properties" Change the text in the property views for the view.

Start you application in the different languages and valid that the translation is correctly used.

View = Lars Test

5. Eclipse i18n resources

6. vogella training and consulting support

Copyright © 2012-2019 vogella GmbH. Free use of the software examples is granted under the terms of the Eclipse Public License 2.0. This tutorial is published under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany license.