Eclipse Internationalization Part 2/4 – New Message Extension by Dirk Fauth and Tom Schindl

In my last blog post I explained the current available solutions for translating an Eclipse 4 application and what is wrong with them.

In this blog post I will show you a new solution for translating your Eclipse 4 application. This one is created as an OSGi service and gets rid of all the disadvantages of the existing solutions. The main idea and implementation was created by Tom Schindl, while I extended it to the current state, so we are writing this blog post together.

To use the services you need to install the latest E4 tools into your IDE or at least create a target-platform that contains the location to it. You could for example use the p2 update site for the E4 tools provided by vogella to get the latest version. (see here for more information http://www.vogella.com/blog/2013/03/12/eclipse-4-tools-update-sites-available-from-vogella/)

As the constant based solution has several benefits when used in combination with the tooling, e.g. code completion, refactoring and find references, the solution designed by Tom uses a similar approach. The big difference is, that it is not constant but member based. So using that solution is working on an instance of a message class, which means that it can be collected by the garbage collector if it is not referenced anymore and values can be changed at runtime.

Another advantage over the existing mechanisms is a more technical one. The existing translation mechanism in Eclipse is based on Java 1.4 and has some workaround code to deal with a special use case. What most people are not aware of is that the process on resolving a resource bundle is a little bit different than resolving a key out of a loaded resource bundle. Guess you have a loaded resource bundle for the locale de_DE, the search order for a key in that resource bundle looks like this:

  1. bundle_de_DE.properties
  2. bundle_de.properties
  3. bundle.properties

So it is searching from the most specific to the default bundle for that key. If the default bundle is configured to contain the English translations, if you missed to translate a key to German, the English one will be returned.

For resolving a resource bundle the process differs slightly with a huge impact. Guess you are running on a system that has the German locale set as default locale. Your application contains only the German and the default resource bundle files as shown above. What would you expect to get for translation if you set the application locale to fr_FR? Only knowing about the process above, you would expect to get the English translations out of the default resource bundle. But on resolving and loading the resource bundle, the default locale is used as fallback. So the following search order is used to resolve the bundle for fr_FR:

  1. bundle_fr_FR.properties
  2. bundle_fr.properties
  3. bundle_de_DE.properties
  4. bundle_de.properties
  5. bundle.properties

This means you will get the German translations on a German system if you try to localize your application to fr_FR and there are no such resource bundle files in your application.

In Equinox resolving the resource bundle was implemented like resolving keys without taking the default locale as fallback into account. That was reported and fixed a while ago (https://bugs.eclipse.org/bugs/show_bug.cgi?id=330602). A technical switch was introduced that allows to specify the equinox.root.locale as system property. If it is not set it will be treated as en by default. Now if the value for equinox.root.locale is en and the locale with language code en is requested, the default locale is not used as fallback.

Also the loading of resource bundles out of an OSGi bundle is a bit different because of the fragment support and the classloader per bundle. Using the Java 1.4 API dealing with all of these facts was quite difficult and caused the limitation that only properties based resource bundles are supported.

With Java 1.6 the ResourceBundle.Control class was introduced. It allows you to take control on how resource bundles are loaded, how the candidate locales are determined, e.g. using a fallback locale or not, and how the caching of the loaded resource bundles should be handled. The new message extension is based on Java 1.6 and makes use of this ResourceBundle.Control to deal with the described issues above in a more convenient way. Using the Java default mechanism instead of the custom workaround also enables the usage of class based resource bundles. The advantage of using class based resource bundles will be explained in the last blog post in this series.

To use the new message extension you need to add the org.eclipse.e4.tools.services bundle to the required plugins in your MANIFEST.MF. This bundle contains the OSGi services that are necessary for the new message extension and will give you access to two new annotations, @Message and @Translation.

To explain those annotations and their usage we first need to create the Messages class that will contain our translations.

public class Messages {
	public String label_message;
}

Comparing the implementation with the constant based OSGi NLS solution you will notice that

  • Messages is a POJO and does not implement or extend something
  • There are no constants but member variables
  • There is no static initialization block needed anymore

Now that we have the Messages class, we need to configure where to get the translation values that should be put into those member variables. As different developers have different opinions on where to put their resource bundles to, the new message extension supports a quite flexible approach to specify where the resource bundle files can be found. When processing the initialization, the mechanism searches for the resource bundle files in the following order:

  1. Check for a configuration via @Message annotation
    @Message(contributorURI=”...”)
    public class Messages {
    	public String label_message;
    }
  2. Check for resource bundle files with the same base name and in the same package as the Messages class
    NamedMessages
  3. Check for OSGi resource bundles configured in MANIFEST.MF
    If you placed your resource bundle files in OSGI-INF/l10n and named in bundle, there is nothing else you have to do

@Message annotation

The @Message annotation is optional and only necessary if you want to configure the location of the resource bundle files or the caching behaviour. To configure the location of the resource bundle files, you need to set the contributorURI parameter to the annotation. This parameter supports the following location patterns:

  • platform:/[plugin|fragment]/[Bundle-SymbolicName]
    Load the OSGi resource bundle out of the bundle/fragment named [Bundle-SymbolicName]
    For example:
    @Message(contributorURI="platform:/plugin/com.beone.e4.translation.extension")
    will load the OSGi resource bundle that is configured in the MANIFEST.MF of the com.beone.e4.translation.extension plugin
  • platform:/[plugin|fragment]/[Bundle-SymbolicName]/[Path]/[Basename]
    Load the resource bundle specified by [Path] and [Basename] out of the bundle/fragment named [Bundle-SymbolicName].
    For example:
    @Message(contributorURI="platform:/plugin/com.beone.e4.translation/resources/another")
    will load the resource bundle that is located in the folder resources/other in the com.beone.e4.translation plugin.
  • bundleclass://[plugin|fragment]/[Fully-Qualified-Classname]
    Instantiate the class based resourcebundle specified by [Fully-Qualified-Classname] out of the bundle/fragment named [Bundle-SymbolicName]. Note that the class needs to be a subtype of ResourceBundle.
    For example:
    @Message(contributorURI="bundleclass://com.beone.e4.translation/com.beone.e4.translation.resources.MockBundle")
    will load the class based resource bundle MockBundle in package com.beone.e4.translation.resources in the com.beone.e4.translation plugin.

Using the bundleclass contributorURI enables you to use class based resource bundles. What’s possible by implementing them will be explained in a later post.

While the constant based OSGi NLS translation mechanism had no chance to update the translation values at runtime and kept them in memory forever, you can specify the caching behaviour for messages in the new message extension. This is done by the referenceType parameter of the @Message annotation.

If the same translations are requested for injection at several places, for memory efficiency the same instance will be returned. This is achieved by internally caching the created instances as a SoftReference by default. As they are not hard references, once all requestors are garbage collected (e.g. the parts were closed) the message instance can be garbage collected as well. Using SoftReferences as default has the advantage that e.g. if a part is closed and opened again within a very short time, the message instance can be reused instead of being garbage collected and newly created. In case the default behavior does not suite your needs the @Message annotation provides the following caching/garbage collection strategies:

  • NONE: The message instance is not cached. Each requestor gets its own instance.
  • WEAK: The message instance is cached as a weak reference. If every requestor was garbage collected, the message instance is also discarded at the next garbage collection cycle.
  • SOFT: The message instance is cached as a soft reference. If every requestor was garbage collected, the message instance is not immediately discarded with the next garbage collection cycle, but will retain for a while in memory.

The strategy to use can be specified by setting the annotation parameter referenceType. The following for example will set the strategy to ReferenceType.NONE which means that every requestor will get its own instance of the messages class:

@Message(referenceType=ReferenceType.NONE)

@Translation annotation

After the messages class is created and connected to the resource bundle, it can simply be used by injecting the Messages instance with the @Translation annotation:

@Inject
@Translation
private Messages messages;
...
myLabel.setText(messages.label_message);

Compared with the TranslationService that is already available in Eclipse 4, you are injecting your Messages instance without the need to know the contributionURI of the containing bundle or the key of the translation you are requesting.

@PostConstruct annotation

With the latest implementation it is possibility to add methods annotated with @PostConstruct. Following the dependency injection rules, this method will be executed after the Messages instance is created. This allows you to use placeholders like with using the constant based NLS.bind() solution. Guess you have a property that looks like this:

my.label.message = {0} says {1}

You could initialize this property by adding a method annotated with @PostConstruct to your Messages class.

public class Messages {
	public String my_label_message;

	@PostConstruct
	public void format() {
		my_label_message = MessageFormat.format(
			my_label_message, "Dirk", "Cool");
	}
}

Note that the method annotated with @PostConstruct in the Messages class does not support parameters as it doesn’t support dependency injection at that place. This is quite the default behaviour when thinking of @PostConstruct in the JavaEE context. As @PostConstruct in Eclipse 4 generally supports dependency injection, we need to mention that in this special case it is not supported.

A small but personally huge improvement in properties key handling is the handling of the dot as property key separator. Using the constant based solution you need to use a separator that is valid within a Java variable, e.g. the underscore. This is because the dot is not valid as part of a field name and the binding from key to constant is directly without transformation. The new message extension at least supports the dot as key separator within the properties. So the properties can look like you know them from other Java frameworks. Of course you still can’t use it as separator in the fields. But as you can see in the example above, using the dot in the properties file is possible when using the underscore as separator in the Messages field.

Links:

Posted in Dirk Fauth, Eclipse, OSGi | Leave a comment

Removing the shopping and other unwanted lenses from Ubuntu

After playing with Ubuntu 13.04 for a while, I must say I really like it. I only dislike the lenses I don’t need.

But uninstalling them is straightforward.

sudo apt-get autoremove unity-lens-music unity-lens-photos unity-lens-gwibber unity-lens-shopping unity-lens-video

Posted in Other | 2 Comments

Getting the Eclipse New and Noteworthy information

If you are looking for the note and newsworthy notes of the Eclipse platform project you are potentially using Google to search for it.

This is not necessary, you can just clone the repository which contains this information.

git clone git://git.eclipse.org/gitroot/platform/eclipse.platform.news.git

You find the N&N for the platform in the “platform/4.3″ folder.

Posted in Eclipse, Lars Vogel | 4 Comments

Eclipse Internationalization Part 1/4 – Current Situation by Dirk Fauth

If you are developing Eclipse applications and plugins for users around the world, you should prepare them to be translated into several languages. While in other frameworks this process is quite straight forward (think of any webframework you know), in Eclipse you have to deal with several facts. In the upcoming series of blog entries I want to show you the following about internationalization with Eclipse 4:

  1. why the current situation is not satisfying
  2. what is possible (and already available) using OSGi services
  3. how to migrate your current localization code to the new solution
  4. what cool stuff is possible with the new solution you always waited for

If you are not yet familiar on how to internationalize your Eclipse application, you should start with reading this tutorial by Lars Vogel: Eclipse RCP and Plugin Internationalization

To localize an Eclipse 4 application you need to prepare several files:

  • plugin.xml
  • application model (*.e4xmi)
  • source code

Translating plugin.xml / application model

The plugin.xml and the application model are both using OSGi resource bundles for translation. For any label or value that needs to be translated you enter a value that starts with % and corresponds to a key in your resource bundle. The location where to find the resource bundle can be configured in the MANIFEST.MF by setting a value for the Bundle-Localization attribute.

Bundle-Localization: OSGI-INF/l10n/bundle

OSGI-INF/l10n/bundle is the default bundle and doesn’t need to be set explicitly. But you can modify this to point to a different location which we will use in a second.

For the plugin.xml there is no alternative to this. You are limited to using resource bundles based on properties files at the specified location.

The application model instead uses the TranslationService and you are able to change the mechanism that should be used, e.g. translating by using a database or Google translate which was shown by Tom Schindl at several conferences. More on the TranslationService will be showed later in this blog.

Translating the Sources

While you are limited in the way you translate the plugin.xml, there are several ways to translate your application within the source code. Talking about an Eclipse application the following options are available at the moment:

  • String based translation
  • Constant based translation
  • Eclipse 4 TranslationService

Using the Eclipse 4 TranslationService also allows you to modify the way the application model is translated. Using the default TranslationService also limitates you to use the resource bundle at the specified location.

String based translation

Your first option is to translate the source code based on Strings. This is a solution that works for every Java project and does not rely on Eclipse. For convenience you typically create a class that looks like this:

public class Messages {
	private static final String BUNDLE_NAME = 
		"org.eclipse.nebula.widgets.nattable.messages"; //$NON-NLS-1$

	private static final ResourceBundle RESOURCE_BUNDLE = 
		ResourceBundle.getBundle(BUNDLE_NAME);

	private Messages() {
	}

        //use this method to simply retrieve the value for the key
	public static String getString(String key) {
		try {
			return RESOURCE_BUNDLE.getString(key);
		} catch (MissingResourceException e) {
			return '!' + key + '!';
		}
	}

        //use this method to retrieve the value with parameters
	public static String getString(String key, Object[] args) { 
		return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args); 
	}
}

Setting the localized text to a label in your code you would look like this

myLabel.setText(Messages.getString("label_message"));

Using the String based translation has the advantage that you are using plain Java ResourceBundle mechanisms and are able to use all features that are provided by Java. But it also has several disadvantages:

  • You need to know the keys that are available in the resource bundle
  • If a key changes you need to search for the String in your code
  • You need to copy the class for every plugin because of the RESOURCE_BUNDLE constant
  • The resource bundle files need to be in the same classpath as the Messages class. Well, as you are able to use all ResourceBundle capabilities you could also specify a different classloader, but understanding classloading in an OSGi context is something advanced, so typically you end up in having the resource bundle and the Messages class in the same package.

Constant based translation

The constant based solution, which can be found in the org.eclipse.core.runtime plugin, solves most of the mentioned issues for String based translation. Using this approach the Messages class would look like this:

public class Messages extends NLS {
   private static final String BUNDLE_NAME = 
		"org.eclipse.nebula.widgets.nattable.messages"; //$NON-NLS-1$

   public static String label_message;

   static {
       // initialize resource bundle
       NLS.initializeMessages(BUNDLE_NAME, Messages.class);
   }

   private Messages() {}
}

To set the localized text to a label in your code you would write code like this

myLabel.setText(Messages.label_message);

Using this approach you don’t need to know the keys exactly, as you can use code completion to see which translations are available. If a key changes you can use the refactoring mechanism in Eclipse to update your code and you can search for occurrences of used constants in your code. As a constant based resource bundle is tightly coupled to the plugin it belongs to, it is obvious that there need to be one for each plugin. But as the containing code differs because of different constants, this isn’t an issue.

But the constant based solution also has some disadvantages:

  • The resource bundle files need to be in the same classpath as the Messages class. As you are not using the Java ResourceBundle directly, there is no other option to that.
  • The translations are stored in constants. So they can not be removed by the garbage collection and they can’t be changed at runtime.
  • You can not use the “.” as separator for hierarchies in your properties because they are not allowed Java to be part of a constant/member name.

The String based solution aswell as the constant based solution for translating source code share one common disadvantage. Additionally to the OSGi resource bundle for translating the application model and the plugin.xml, you need to create a resource bundle within your source code package structure. This is because the resource bundle is resolved via the same classloader as the Messages class and therefore does not know about the plugin structure. As I personally prefer to manage translations only in one resource bundle rather than splitting them, the only way to solve this is to set the OSGi resource bundle to point into the source package:

Bundle-Localization: src/org/eclipse/nebula/widgets/nattable/messages

But this way you are moving resources into the source tree, and not in the default OSGi container location anymore. IMHO this is also not a good design for managing resources.

Eclipse 4 TranslationService

With using the Eclipse Application Platform you get access to OSGi services. For translation there is the TranslationService whose default implementation is the BundleTranslationProvider. You can inject the TranslationService into your classes and use it for translation like shown here:

@Inject
public TranslationTest(Composite parent, TranslationService service) {
       myLabel = new Label(parent, SWT.NONE);
       myLabel.setText(service.translate(
              "%label_message", "platform:/plugin/translation")); //$NON-NLS-1$ //$NON-NLS-2$
}

Looking at the usage of the TranslationService it looks like an advanced String based solution with the following enhancements:

  • There is no need to copy code for several plugins as it is an OSGi service
  • It uses the OSGi resource bundle rather than resource bundle in the source tree
  • You could exchange it to get the translations from anywhere you want, even a database

So it is really a flexible alternative for translating your source code. But it still has several disadvantages which makes the TranslationService not a good solution in the develoment process:

  • If you are using the default implementation, than you are forced to use the OSGi resource bundles
  • You need to know the keys that are available in the resource bundle
  • If a key changes you need to search for the String in your code
  • Additionally to know the key to use for translation, you need to know the plugin URI where the OSGi resource bundle should be retrieved. Of course you could also point out that this is an advantage because of the flexibility to choose in which bundle the resource bundle should be searched. But usually you don’t mix.

Conclusion

So what is the conclusion of my blog post until now? To perform localization in your source code in Eclipse you have several options. But they all have several disadvantages. While the Eclipse Platform tries to add some convenience for translating over using the plain String based Java solution, those solutions doesn’t feel comfortable in the end.

The question that remains is, why isn’t there a solution that combines the advantages of the shown solutions and avoids the disadvantages to have a clean and straight forward solution. Well, there is such a solution, otherwise my blog post series would be nonsense. And I will show you this solution in my next post. So stay tuned for cool stuff coming!

Links:

Posted in Dirk Fauth, Eclipse, Java, OSGi | Leave a comment

Eclipse Papercut #13 – Improved test template for JUnit 4

For Eclipse 4.3 we fixed the JUnit 4 test templates. See Bug report for details.

In Eclipse 4.3 you can type “test” followed by CTRL+Space and select the first template proposal to get a JUnit test method generated.

Good times a head for the usage of templates in Eclipse 4.3. :-) See also Papercut #12.

Posted in Eclipse, Lars Vogel, Papercut | Leave a comment

Eclipse IDE Book – Finally a paper version and update for Kindle

I finally released the next edition of my Eclipse IDE book. I released two versions for the Kindle already and the last time I promised to deliver an update including handling Git with Eclipse.

kindle_cover

I used this opportunity to rework the complete book. It has grown approx. 300 % in size and contains a detailed introduction into using the Eclipse IDE. I also included lots of tips and tricks in using Eclipse as I learned in countless customer workshops that most developer don’t know the little tricks in Eclipse to work efficiently.

Here are some voices about the book:

A great visual introduction to everything Eclipse — from first installation and initial usage through advanced topics such as unit testing and plugin development. The git coverage alone is worth the price of admission.

Tor Norbye, Software Engineer at Google and Java Posse podcaster

An excellent jump start for beginners who want to learn how to use Eclipse for Java Development. Packed with pro tips from Lars Vogel who taught countless developers in his online and classroom training how to develop with and for Eclipse.

Matthias Sohn, Project Lead Git at Eclipse, Git team lead at SAP AG

For many years, I have consulted Lars’ excellent online Eclipse tutorials. Lars always manages to include the information that I’m looking for in a precise way. This book builds upon those tutorials and provide all the information that Eclipse newbies need to get up and going. Seasoned Eclipse users can find a great reference of tips, tricks and how-tos. Now I make sure that I always keep a copy of this excellent book besides me. Highly recommended.

Alex Ruiz, Software Engineer at Google, Android Development Tools

Here are some links to Amazon for the paper version:

Eclipse IDE on Amazon.com

Eclipse IDE on Amazon Germany

Eclipse IDE in Amazon France

Please note that a Kindle version with a low price is also available and existing Kindle customers will get an update, as I promised to deliver an update including EGit. This will be the last update for the Kindle version, a potential next edition will be released as a new book.

Kindle reader should be able to trigger the update via their Amazon Kindle page, Amazon does NOT automatically distribute updates. The cover of the Kindle version has not yet been updated, Amazon seems to be a bit slow with that.

A really big thanks goes to Holger Vormann, Dirk Fauth, Matthias Sohn for providing intensive feedback on this edition.

Posted in Eclipse, Java, Lars Vogel | Leave a comment

Eclipse Papercut #12 Showing all templates in code completion

I just returned from the JAX conference where I had the pleasure to join a panel discussion about Eclipse. I argued in that panel that the community (including me) need to contribute more to make things easier in Eclipse. This includes improvements in the Java development tools.

On the train ride I decided to try to solve an issue which IMHO makes the usage of the JDT templates much more intuitive.

Currently if you press CTRL+Space twice without a starting letter you end up with an empty list of proposals, which is IMHO not very helpful.

jdt01

If the proposed patch gets accepted all templates will be shown.

jdt02

I really like this change, I hope it will be accepted. See Bug report for details.

[UPDATE] Great! Dani from the JDT team accepted my patch for better template handling. That was fast. Bug report.

Posted in Eclipse, Lars Vogel, Papercut | Leave a comment

Eclipse Papercut #11 Updating Eclipse 4 RCP application with p2

I’m happy to report that with the help of Markus Kuppe we have created a detailed description how to update your Eclipse 4 RCP application with the Eclipse p2 API.

See the Updating Eclipse 4 RCP applications tutorial for details.

I hope this helps.

Posted in Eclipse, Lars Vogel, Papercut | Tagged , , | Leave a comment

Migration of vogella.com to new server complete

Migration of vogella.com to the new server is complete. All looks good and well to me. :-)

If you see issues, please ping me at twitter @vogella.

Posted in vogella | Leave a comment

Using Eclipse Forms in Eclipse 4 RCP

During EclipseCon 2013 several people complained that Eclipse Forms is not available for pure Eclipse 4 RCP applicatoins.

I hope it helps to migrate existing applications that Eclipse Forms has been migrate out of any Eclipse 3.x dependencies. See Bug 369657 – FormsPlugin (Activator) unnecessary extends AbstractUIPlugin.

Please note that you should prefer CSS styling over the usage of Forms for new code. This Bugfix is supposed to help migrating existing code.

Posted in Eclipse, Lars Vogel | Tagged , | Leave a comment