Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [e4-dev] Set up of my translation scene


Hi Tom,
Nice write-up. It might make sense to create a set of Wiki pages based on your post  so that design can be updated as it evolves.

The most important part is the design goal. The 3.x approach is highly optimized for the "simple" case, but does not support more complicated scenarios. To me, it feels like the proposed new design would support well the advanced use cases, but at the expense of performance/scalability/usability of the simple case. (Simple case being: having one language that does not change).

So, I'd add the following two goals:
- it should be possible to describe the basic part of "the new NLS" to a plug-in developer in under two paragraphs;
- it should scale well enough to not to be a memory or CPU hog for large size applications

Sincerely,
Oleg Besedin



From: Tom Schindl <tom.schindl@xxxxxxxxxxxxxxx>
To: E4 Project developer mailing list <e4-dev@xxxxxxxxxxx>
Date: 12/16/2010 12:33 PM
Subject: [e4-dev] Set up of my translation scene
Sent by: e4-dev-bounces@xxxxxxxxxxx





Hi,

*Disclaimer: This is a very lengthy mail*

These are the topics I'll discuss in this mail:
a) CORE TRANSLATION FRAMEWORK
b) TRANSLATIONS IN OUR MODEL
c) LANGUAGE CONTEXT / LANGUAGE SWITCHING
d) MODEL CONTRIBUTION TRACKING
e) TRANSLATION IN UI-CODE

On the first sight the system might look complex but in reality it isn't
really. The most important thing is a) the rest builts upon this
foundation and d) has to be done anyways for other stuff like bundle
uninstalls and e) must not be a framework part but it makes translations
fit better in an Eclipse 4.0 world where we defined "Singletons and
Statics are evil"


In the bug following bugs Oleg and I are discussing translations and
things those are related to.

* 306576: Root defect
* 331260: Defines a generic translation infrastructure
* 331010: Model Contribution Tracking

To better understand my arguing I'd like to setup my requirements to NLS
support the Eclipse 4.0 Application Platform.

My main driving points who are influenceing the design:
* I need to get away from only supporting .properties-Files as a
 resource for translations
* I need to switch the locale of a running application without
 restarting
* I see translations of UI-Artifacts as a pure decoration process which
 is an important fact because it removes the need to do all
 translations at application startup

So here's my design-ideas:

CORE TRANSLATION FRAMEWORK:
---------------------------
At the core of the whole system which a extensible service

interface ITranslationService {
 public String translate(String providerId, String key, String
                         language);
}

and

interface ITranslationProvider {
 public String translate(String key, String language);
}

As you might have guessed already the ITranslationService delegates
translations to an ITranslationProvider which means lookup is now
flexible and not only bound to .properties.

By default there's are by default translation providers available for
all BundleLocalization. So in case you want to translate a key "mykey"
from bundle "com.my.personal.bundle" you'll call it like this:

---------------------------8<---------------------------
@Inject
private ITranslationService translation;
translation.translate("com.my.personal.bundle","mykey");
---------------------------8<---------------------------


TRANSLATIONS IN OUR MODEL
-------------------------
In our model attributes we are marking values we need to translate
similar to how we do it in todays plugin.xml by prefixing it with %
which means a Part with a translated name would look like this (I'm
using the XMI-Notation but please keep in mind in the end what is
important is the memory representation of the model).

---------------------------8<---------------------------
<children xsi:type="basic:Part"
         xmi:id="_SeXUDO8EEd6FC9cDb6iV7g"
         elementId="ContactsView"
         contributionURI="platform:/plugin/..."
         label="%contactlist.label"
         iconURI="platform:/plugin/..."
         tooltip="%contactlist.tooltip"/>
---------------------------8<---------------------------

At the very moment the renderer is now creating the UI-Widgets because
of whatever reason it will look up the translation of the
"contactlist.label" and "contactlist.tooltip" using the ITranslationService.

This means the renderer is call the ITranslationService like this
(assuming the Part was contributed by the contacts.demo bundle - take a
look at MODEL CONTRIBUTION TRACKING):

---------------------------8<---------------------------
@Inject
private ITranslationService ts;

@Inject
private IWorkbenchLocaleService ls;

public void render(MPart p) {
 CTabItem item = ...
 item.setText(ts.translate(p.getContributor(),p.getLabel(),getLang()));
}

private String getLang() {
 // See WORKBENCH LANGUAGE CONTEXT
 return ls.getLocale();
}
---------------------------8<---------------------------

This means the default translation strategy is to do the translations
using the BundleLocalization-Service for the lookup but if someone don't
want the translations to come from .properties and e.g. has installed a
ITranslationProvider under the key "mytranslationprovider" one can put
overrule this default by putting the information into the model in the
following way:

---------------------------8<---------------------------
<children xsi:type="basic:Part"
         xmi:id="_SeXUDO8EEd6FC9cDb6iV7g"
         elementId="ContactsView"
         contributionURI="platform:/plugin/..."
         label="%mytranslationprovider#contactlist.label"
         iconURI="platform:/plugin/..."
         tooltip="%mytranslationprovider#contactlist.tooltip"/>
---------------------------8<---------------------------


LANGUAGE CONTEXT / LANGUAGE SWITCHING:
--------------------------------------
In my opinion there has to be a lanuage context which I think is best
suited for our UI stuff to be at workbench level.

We'll provide a service named like this at the workbench level

---------------------------8<---------------------------
interface IWorkbenchLocaleService {
 public void setLocale(String locale);
 public String getLocale();
}
---------------------------8<---------------------------

If the locale is switched by the user we are delivering an event through
our EventBroker and so our render engine can react upon it.


MODEL CONTRIBUTION TRACKING:
----------------------------
And at this very moment 331010 comes into play because the current
information in the model is not enough to look up the translation
because it needs to know from which model element the translation came from.

To answer this we need remember where elements can come from:
a) From the root e4xmi
b) From a fragment e4xmi
c) From a processor e4xmi
d) Totally programmatic (e.g. Addons, Handlers, ...)

a, b, c are quite easy to solve because for a & b we are the ones who
load them and merge them into the model so we can adjust the
contributor, c is quite easy because we know exactly that we are now
launching an processor and can run and track added elements.

The really hard part is d) because those things can happen at any time
and we are not in charge of them.

There are 2 solutions and i think both are needed here:

a) The compat layer should has to use the Standard EMF-Factories and
  reflect the contribution information from the corresponding
  IConfigurationElements

b) All other code will go through custom factory implementations which
  is bundle aware

  public class BundleawareBasicFactory implements MBasicFactory {
    private Bundle b;

    public void createPart() {
       MPart p = MBasicFactory.INSTANCE.createPart();
       // remember the contributor
    }
  }


TRANSLATION IN UI-CODE:
-----------------------
The current solution is to use NLS and static fields like this:

---------------------------8<---------------------------
public class MyMessages {
 public static String myMessage;

 static {
   NLS.initialize(....);
 }
}

Label l ....
l.setText(MyMessages.myMessage);
---------------------------8<---------------------------

which is nice and small but because the informations are stored in
static fields there can be only one language available make this not
useable in multi instance environments and we'll do something we always
said is Eclipse 4.0 will not do it emphasizes the usage of STATICS.

In contrast to the current solution my proposal looks like this:

public class MyMessages {
 public String myMessage;
}

and will be consumed in our UI code like this:

---------------------------8<---------------------------
@Inject
@Translation
private MyMessages myMessage;

Label l ....
l.setText();
---------------------------8<---------------------------

The default lookup of translations is equal to the one of NLS but there
are major differences:
a) No singletons anymore hence multiple locales can be supported in one
  OSGI-Env

b) In case of a language switch through IWorkbenchLocaleService a new
  MyMessages instance can be injected

c) We can plug ourselves into the ITranslationService by annotating the
  MyMessages class like this:

  @Messages(providerid="mytranslationprovider")
  public class MyMessages {
    public String myMessage;
  }

If you managed to follow me until here I hope you found this background
information useful.

Tom

--
B e s t S o l u t i o n . a t                        EDV Systemhaus GmbH
------------------------------------------------------------------------
tom schindl                                        geschaeftsfuehrer/CEO
------------------------------------------------------------------------
eduard-bodem-gasse 5/1    A-6020 innsbruck      phone    ++43 512 935834
_______________________________________________
e4-dev mailing list
e4-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/e4-dev



Back to the top