0

We load our translations from our database. To retrieve the bundles we have a custom java.util.ResourceBundle.Control.

To translate our e4 RCP application, I already created a TranslationService, which I add to the root context using an addon. That was no problem (only that I had to copy 95% of BundleTranslationProvider because I did not see any other way).

Now I want to use the new Message Extension (coming with Eclipse Luna) to translate the rest. As far as I can see from the sources of the default MessageFactoryServiceImpl, there does not seem to be an easy way to inject my ResourceBundle.Control there either.

In the linked blog series, the use case of getting the resource bundles from a database is described, but solved by using class based resource bundles. This is no option, because I can't implement a class for every resource bundle and every locale. The reason for loading the resource bundles from the database is to be able to deploy translations into new languages without redeploying the application.

Is the only way to achive this by creating my own IMessageFactoryService by copying 99% of the default MessageFactoryServiceImpl, just to pass our Control into the calls to ResourceBundleHelper?

Tobias Schulte
  • 3,765
  • 1
  • 29
  • 33

2 Answers2

1

AFAIK ResourceBundle.Control is used to load ResourceBundles. In the new Message Extension we use a custom ResourceBundle.Control to enable the loading of ResourceBundles in the OSGi context, and it is configurable via annotations.

AFAICS exchanging the ResourceBundle.Control will break any other use case supported by the new Message Extension.

The question is, why do you use a custom ResourceBundle.Control instead of creating a class based ResourceBundle? I haven't tried it yet, but maybe it is possible to create only the base ResourceBundle (without Locale information) and determine the Locale in another way than using getLocale().

But without knowing what you are doing in your custom ResourceBundle.Control, I don't know what to answer and what to suggest. Of course we could open the API for that, but as I said before, then every other plugin that makes use of the default implementation will fail.

Maybe you can give some hints on what you are doing exactly and I can show you a way to achieve your goal in another way.

Dirk Fauth
  • 4,128
  • 2
  • 13
  • 23
  • Our Control does load the resourcebundle from a server. Additionally it supports UTF-8 resourcebundles. If it is possible to use our Control in a class-based resource bundle, and if it is sufficient to create a base resource bundle class and determine the locale in another way, I can live with this. I already plan to generate the message class from the resourcebundle, and I could add generation of the bundle class. So it would not add any additional development-time overhead. I will try this. – Tobias Schulte Feb 14 '14 at 16:02
  • As far as I understand, using class based rb will not work for the app model. – Tobias Schulte Feb 15 '14 at 09:59
  • 1
    You can not simply use a class based resource bundle for the app model. Because the default TranslationService is the BundleTranslationProvider which is only working with properties file based resource bundles, that can be configured via MANIFEST.MF. But you could create a new TranslationService that is operating on a class based resource bundle and register that. – Dirk Fauth Feb 15 '14 at 12:14
  • But for this again I have to copy 95% of the default implementation, if I want to get the bundle from the contribution uri to get the bundle name out of the manifest. – Tobias Schulte Feb 15 '14 at 13:05
  • What code needs to be copied? There is the ResourceBundleHelper with static helper methods you can use. But if you want to introduce a generic way of specifying a class based resourcebundle in the MANIFEST for the application model, then yes. I thought of a static way for your specific use case. For a generic way in the platform, feel free to create an enhancement ticket to add support for class based resourcebundles for the application model. – Dirk Fauth Feb 15 '14 at 14:01
  • I played around a bit to use a class based ResourceBundle for translating the application model. You can find it here: https://github.com/fipro78/e4classbasedtranslation This is of course only a simple example, but it should show the idea. I still don't have an idea for the Control. – Dirk Fauth Feb 15 '14 at 21:57
1

After some investigation on this, I found a way that you are able to support your use case without modifying or copying code a lot.

You need to exchange the BundleLocalization to load the ResourceBundle your way. In your case by using your custom ResourceBundle.Control. By doing this you override that the platform is looking for the ResourceBundle specified by the MANIFEST.

At the moment you will also have to implement a custom TranslationService that uses your BundleLocalization. The existing BundleTranslationProvider does not take the BundleLocalization out of the context. And you will need to copy a lot of code there, because getBundle() is private. I will discuss possible modifications with the developers.

You can find an example here: https://github.com/fipro78/e4classbasedtranslation

Hope that helps you to solve your specific requirement.

Dirk Fauth
  • 4,128
  • 2
  • 13
  • 23
  • Ah, I was not aware that the BundleTranslationProvider is exported. I thought because it is in an internal package it was private. Is it save to extend that class? But too bad, the method getBundle is private, so I still have to copy it. – Tobias Schulte Feb 17 '14 at 07:56
  • There seems to be some duplicated code in ResourceBundleHelper and BundleTranslationProvider for retrieving the Bundle from the contributionUri. – Tobias Schulte Feb 17 '14 at 08:12
  • Works like a charm. Thank you very much. I did not use a LifecycleManager but an addon to set my BundleLocalisation and TranslationService into the IEclipseContext though. Do you see any problem with this? https://gist.github.com/tschulte/9003397 – Tobias Schulte Feb 17 '14 at 09:19
  • 1
    For the duplicated code, this is because the BundleTranslationProvider existed before the ResourceBundleHelper and initially the ResourceBundleHelper only existed in e4.tools, so it was not possible to merge that in some way. Regarding on how you set the service, AFAIK there shouldn't be problems. Form the lifecycle perspective model addons are processed within @ProcessAdditions, which is still before the renderers are called. So it should be fine to use an addon instead of a lifecycle handler. – Dirk Fauth Feb 17 '14 at 10:00
  • 1
    To keep this up-to-date: there are some modifications that will be released with Luna M6 1. The ResourceBundleProvider service is introduced to abstract out the BundleLocalization. With this you should not change the BundleLocalization implementation but the ResourceBundleProvider implementation. This is because you shouldn't exchange OSGi services. 2. Some API changes that enable extending TranslationService and for the use case of a custom ResourceBundle.Control making it not necessary to register a custom TranslationService anyway. The example on GitHub is already updated for Luna M6 – Dirk Fauth Feb 20 '14 at 08:03