Eclipse Internationalization Part 3/4 – Migration by Dirk Fauth

In my last blog post I explained the new message extension added to the E4 tools by Tom Schindl and me. It is similar to the Eclipse localization mechanism based on OSGi NLS, but gets rid of the downsides of that solution. While the introduction to the new message extension was quite long, this blog post will be rather short. It explains how to migrate from the existing localization based on the OSGi NLS mechanism to the new message extension in a few steps.

As the new message extension currently also lacks in tooling support, like for example the Externalize Strings wizard in Eclipse, this post might also be helpful in creating the necessary files with the existing tooling. This is possible because the Eclipse String externalization mechanism and the new message extension solution are similar. Therefore it is possible to use the existing wizard and migrate to the new solution in a few steps. Hopefully soon there is a wizard for the new message extension so these steps are not necessary anymore.

Let’s start creating a part that contains some labels which are static Strings. The code would look like this:

public class MyPart {

	@PostConstruct
	public void createControls(Composite parent) {
		Label myFirstLabel = new Label(parent, SWT.NONE);
		myFirstLabel.setText("My first label");

		Label mySecondLabel = new Label(parent, SWT.NONE);
		mySecondLabel.setText(
			MessageFormat.format({0} says {1}, "Dirk", "Cool"));
	}
}

Using the Eclipse Externalize Strings wizard as explained in this tutorial, you will get a Messages class that looks similar to the following:

public class Messages extends NLS {

	private static final String BUNDLE_NAME = 
		"com.beone.e4.translation.parts.messages"; //$NON-NLS-1$

	public static String myFirstLabel;
	public static String mySecondLabel;

	static {
		// initialize resource bundle
		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
		//bind values to the placeholders
		NLS.bind(Messages.mySecondLabel, "Dirk", "Cool"); //$NON-NLS-1$ //$NON-NLS-2$
	}

	private Messages() {
	}
}

The part will be changed to use the class variables instead of static Strings, e.g. Messages.myFirstLabel.

Of course you need to get rid of the prefix in the wizard and move the MessageFormat stuff to the Messages class by adding the NLS.bind() call manually. I just added the NLS.bind() to explain the migration path for that scenario too.

Migrate the Messages class

To migrate from the OSGi NLS Messages class to the new message extension Messages class, the following steps are necessary:

  1. Get rid of the class hierarchy. There is no need to extend NLS anymore.
  2. Remove the private constructor.
  3. Change from class to member variables (remove the static for the fields).
  4. Remove the BUNDLE_NAME constant as it is not needed anymore.
  5. Change the static init block to a method annotated with @PostConstruct. This is only necessary in case you initialize parameterized translations in the static init block.
  6. Add the @Message annotation if it is necessary for you to specify a different location or caching behavior. Otherwise it is optional.

After these steps your Messages class should look like this:

@Message
public class Messages {

	public String myFirstLabel;
	public String mySecondLabel;

	@PostConstruct
	public void postConstruct() {
		mySecondLabel = MessageFormat.format(
			mySecondLabel, "Dirk", "Cool"); //$NON-NLS-1$ //$NON-NLS-2$
	}
}

Migrate the Messages using part

After the Messages class is modified for the new message extension, you need to change your Messages using class too. This is rather simple, as you just need to change from static access to instance access. The necessary steps are:

  1. Add an instance variable of type Messages (or whatever your messages class is named) and annotate it with @Inject and @Translation, so the container will create and inject the instance based on the current set locale.
  2. Change the static access to instance access, which is easy by using search and replace functionality of Eclipse

The part we created before will then look like this:

public class MyPart {

	@Inject
	@Translation
	public Messages messages;

	@PostConstruct
	public void createControls(Composite parent) {
		Label myFirstLabel = new Label(parent, SWT.NONE);
		myFirstLabel.setText(messages.myFirstLabel);

		Label mySecondLabel = new Label(parent, SWT.NONE);
		mySecondLabel.setText(messages.mySecondLabel);
	}
}

Links:

This entry was posted in Dirk Fauth, Eclipse, OSGi. Bookmark the permalink.