https://wiki.eclipse.org/api.php?action=feedcontributions&user=Nigel.miegel.org&feedformat=atomEclipsepedia - User contributions [en]2024-03-19T08:51:04ZUser contributionsMediaWiki 1.26.4https://wiki.eclipse.org/index.php?title=Orbit/FAQ&diff=88480Orbit/FAQ2008-03-24T19:23:44Z<p>Nigel.miegel.org: /* How do I work with a bundle in Orbit? */</p>
<hr />
<div>== What is Orbit? ==<br />
Orbit is a project designed to be a repository for third party libraries that are approved for use in Eclipse projects. If the incoming libraries are not already bundles then Orbit committers will work to create a bundle that is suitable for use in Eclipse projects.<br />
<br />
== Does Orbit replace or affect the Eclipse Foundation legal process? ==<br />
NO! Orbit holds only libraries that have been approved by the standard legal process. Projects must still follow this process to request permission to use libraries in their releases.<br />
<br />
== If a library is approved for use in "all" projects, do I still have to go through the legal process? ==<br />
As of this writing, all projects must request permission to use '''any''' third party libraries. More generally, this is a question for the legal team. Orbit does not affect the IP policy and legal process. <br />
<br />
== Do projects have to use the Orbit bundles? ==<br />
This is not explicitly required however we do hope that the Release Review process is enhanced to require justification for using a library in your release and not using the corresponding bundle from Orbit. There may well be valid scenarios here the Orbit bundle is not appropriate but projects are strongly urged to share as much as possible.<br />
<br />
== What if I don't want to put the library I need into Orbit? ==<br />
That's fine but you will be foregoing the help and support you would get of the greater Orbit community as well as preventing others from sharing in your efforts. Keep in mind that you may have to justify this approach when it comes time for your release review.<br />
<br />
== Who are the committers in Orbit? ==<br />
The following is the current list of committers and the projects they represent. Note that those with ?? after their names are potential committers.<br />
{| <br />
!Committer || Project <br />
|-<br />
|Bjorn Freeman-Benson || Dash<br />
|-<br />
|Christian W. Damus || [http://www.eclipse.org/modeling Modeling]<br />
|-<br />
|DJ Houghton || Eclipse<br />
|-<br />
|David Williams || WTP<br />
|-<br />
|Grahame Grieve?? || OHF<br />
|-<br />
|Hubert Leung || TPTP<br />
|-<br />
|Jeff McAffer (Project Lead) || Eclipse<br />
|-<br />
|John Graham || DTP<br />
|-<br />
|Martin Oberhuber || [http://www.eclipse.org/dsdp/tm DSDP.TM]<br />
|-<br />
|Pascal Rapicault || Eclipse<br />
|-<br />
|Richard Gronback?? || GMF<br />
|-<br />
|Simon Kaegi || Eclipse<br />
|-<br />
|Tom Watson || Eclipse<br />
|-<br />
|Chris Aniszczyk || Eclipse, ECF<br />
|}<br />
<br />
== How do I become a committer in Orbit? ==<br />
Orbit committers are already committers from other Eclipse projects that have a need for a third party library. These people come to Orbit with an approved library and propose to include it in Orbit. If they are not already a committer in Orbit and their project does not have any committers in Orbit, they can become a committer by agreeing to bundle and maintain the new library. Accordingly, they will then be responsible for the care and feeding of that library and the corresponding bundle. You should make your interest known on the [http://dev.eclipse.org/mailman/listinfo/orbit-dev Orbit mailing list].<br />
<br />
== How do you name bundles containing other people's code? ==<br />
That's a great question! See the documentation and guidelines on [[Bundle Naming]].<br />
<br />
== Which libraries are managed in Orbit? ==<br />
<br />
The complete list of bundles available in a given Orbit build and links to download them can be seen on the individual [http://download.eclipse.org/tools/orbit/downloads/ Orbit download pages]. See also [[Orbit Bundles]].<br />
<br />
== How does Orbit manage multiple versions of the same library?==<br />
Luckily OSGi supports multiple versions of the same bundle installed and running at the same time so this does not present any particular runtime problems. At development time however there is a challenge of project naming. Since the Eclipse convention has been to use the bundle symbolic name as the name of the project, there would be a conflict if two versions of the same project need to be in the workspace at the same time. <br />
<br />
The initial direction here is to use a CVS branch for each version of a library. So, for example, for javax.servlet there is version 2.3 and 2.4 of the library. Correspondingly, there branches named v2_3 and v2_4 are created to hold the related content. HEAD of the javax.servlet project is empty except for a readme.txt file indicating that all work is carried out in branches.<br />
<br />
== How do I add something to Orbit? ==<br />
There are a number of factors and processes to be considered when adding a library to Orbit. Please see [[Adding Bundles to Orbit]].<br />
<br />
== How is source managed/delivered? ==<br />
TBD<br />
<br />
== How do I work with a bundle in Orbit? ==<br />
Since all of the interesting orbit work is done in branches, working with an orbited bundle can be confusing to the first-time user. But just follow these simple steps and you'll have it checked out into your workspace in no time!<br />
# Create a repository connection to the orbit repository. The Orbit repository is located on dev.eclipse.org at \cvsroot\tools.<br />
# Navigate to ''HEAD/org.eclipse.orbit/'''<your_project>''' ''.<br />
# Check your project out into your workspace.<br />
# Note that the project will be empty. (this is ok)<br />
# In the Navigator (or Package Explorer, etc) right-click on the project and choose ''Replace With -> Another Branch or Version...'' and select the branch that you want to work with. (the branch names are the versions)<br />
<br />
== Should we use qualifiers in the bundle version? ==<br />
Yes. We should add a qualifier as the 4th part of a bundle version. e.g. ''3.8.1.qualifier''.<br />
<br />
If we have versions which already have 4 parts to them then we should pad the 4th segment to 2 digits. For instance: ''4.1.0.01_qualifier''.<br />
<br />
<br />
[[Category: Orbit]]<br />
[[Category: FAQ]]</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86578Babel / Runtime Translation Editor2008-03-08T18:34:23Z<p>Nigel.miegel.org: /* Editors and Views */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory. This plug-in is currently available only by checking out the project source from CVS. It can be found at dev.eclipse.org:/cvsroot/technology,org.eclipse.babel/plugins/org.eclipse.babel.runtime.<br />
<br />
2. For a more interesting demo, install at least one language pack. Language packs can be installed from the Babel update site at http://download.eclipse.org/technology/babel/update-site. Then start the target platform with the "-nl" parameter specified in the program arguments. So, for example, to run with Swiss German, start eclipse from the command line using "eclipse.exe -nl de_CH" or from the IDE by including "-nl de_CH" in the program arguments box.<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view), the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. However, none of the parts and dialogs in the IDE or, likely, in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. If you currently use the NLS class to load your messages, then use instead TranslatableNLS. <br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. Note that the bind methods also accept and return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is required because<br />
<UL><br />
<LI>getStateLocation is called to get the location in which the language delta files are maintained.</LI><br />
<LI>The OSGi bundle symbolic name is displayed in the tooltip giving the origins of each text.</LI><br />
<LI>The OSGi bundle symbolic name is used to uniquely identify the message on the Babel server.<LI><br />
</UL><br />
<br />
If you currently use the Java ResourceBundle objects to load your messages then it is recommended that you upgrade to use TranslatableNLS. However, if you want to support the Babel runtime with the minimum of changes, you can use the TranslatableResourceBundle class provided by the Babel runtime. This class is derived from ResourceBundle so can be used in it's place. An instance of this class can be obtained by calling the static get method:<br />
<br />
<code><br />
resourceBundle = TranslatableResourceBundle.get(getBundle(), getClass().getClassLoader(), "com.acme.myApplication.Language");<br />
</code><br />
<br />
This is typically called when the plug-in is started.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
Note that if you use the TranslatableNLS class, you do not need to call the above constructor because the TranslatableText objects are created for you and are the values of the message fields in your derived class.<br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
<code><br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
</code><br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace. You can find these delta files in the plug-in's state directory at ".metadata\.plugins\<Bundle-SymbolicName>\.translations". The delta files contain the differences between the resource bundles embedded in the plug-in or fragment and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
Although the language fragments are built nightly on the Babel server, users may not be downloading these on a regular basis. Non-technical users may not even know about the Babel server or how to install the fragments. If users open the dialog to enter translations then it is desirable for the user to see the latest translations from the server. Therefore the current values should e fetched from the server every time the translation dialog is opened. This work has not been done.<br />
<br />
Another problem to consider is how we handle the installation of a later language pack. Ideally the delta files should modified to be deltas from that later version. This work has not been done, which means there may be older translations left in the delta files that are overriding more recent translations in the language packs.<br />
<br />
<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86577Babel / Runtime Translation Editor2008-03-08T18:27:37Z<p>Nigel.miegel.org: /* The TranslatableNLS Class */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory. This plug-in is currently available only by checking out the project source from CVS. It can be found at dev.eclipse.org:/cvsroot/technology,org.eclipse.babel/plugins/org.eclipse.babel.runtime.<br />
<br />
2. For a more interesting demo, install at least one language pack. Language packs can be installed from the Babel update site at http://download.eclipse.org/technology/babel/update-site. Then start the target platform with the "-nl" parameter specified in the program arguments. So, for example, to run with Swiss German, start eclipse from the command line using "eclipse.exe -nl de_CH" or from the IDE by including "-nl de_CH" in the program arguments box.<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view), the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. However, none of the parts and dialogs in the IDE or, likely, in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. If you currently use the NLS class to load your messages, then use instead TranslatableNLS. <br />
<br />
<br />
If you currently use the Java ResourceBundle objects to load your messages then it is recommended that you upgrade to use TranslatableNLS. However, if you want to support the Babel runtime with the minimum of changes, you can use the TranslatableResourceBundle class provided by the Babel runtime. This class is derived from ResourceBundle so can be used in it's place. An instance of this class can be obtained by calling the static get method:<br />
<br />
<code><br />
resourceBundle = TranslatableResourceBundle.get(getBundle(), getClass().getClassLoader(), "com.acme.myApplication.Language");<br />
</code><br />
<br />
This is typically called when the plug-in is started.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
Note that if you use the TranslatableNLS class, you do not need to call the above constructor because the TranslatableText objects are created for you and are the values of the message fields in your derived class.<br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
<code><br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
</code><br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace. You can find these delta files in the plug-in's state directory at ".metadata\.plugins\<Bundle-SymbolicName>\.translations". The delta files contain the differences between the resource bundles embedded in the plug-in or fragment and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
Although the language fragments are built nightly on the Babel server, users may not be downloading these on a regular basis. Non-technical users may not even know about the Babel server or how to install the fragments. If users open the dialog to enter translations then it is desirable for the user to see the latest translations from the server. Therefore the current values should e fetched from the server every time the translation dialog is opened. This work has not been done.<br />
<br />
Another problem to consider is how we handle the installation of a later language pack. Ideally the delta files should modified to be deltas from that later version. This work has not been done, which means there may be older translations left in the delta files that are overriding more recent translations in the language packs.<br />
<br />
<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86576Babel / Runtime Translation Editor2008-03-08T18:25:56Z<p>Nigel.miegel.org: /* Persistence */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory. This plug-in is currently available only by checking out the project source from CVS. It can be found at dev.eclipse.org:/cvsroot/technology,org.eclipse.babel/plugins/org.eclipse.babel.runtime.<br />
<br />
2. For a more interesting demo, install at least one language pack. Language packs can be installed from the Babel update site at http://download.eclipse.org/technology/babel/update-site. Then start the target platform with the "-nl" parameter specified in the program arguments. So, for example, to run with Swiss German, start eclipse from the command line using "eclipse.exe -nl de_CH" or from the IDE by including "-nl de_CH" in the program arguments box.<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view), the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. However, none of the parts and dialogs in the IDE or, likely, in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. If you currently use the NLS class to load your messages, then use instead TranslatableNLS. <br />
<br />
<br />
If you currently use the Java ResourceBundle objects to load your messages then it is recommended that you upgrade to use TranslatableNLS. However, if you want to support the Babel runtime with the minimum of changes, you can use the TranslatableResourceBundle class provided by the Babel runtime. This class is derived from ResourceBundle so can be used in it's place. An instance of this class can be obtained by calling the static get method:<br />
<br />
<code><br />
resourceBundle = TranslatableResourceBundle.get(getBundle(), getClass().getClassLoader(), "com.acme.myApplication.Language");<br />
</code><br />
<br />
This is typically called when the plug-in is started.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
Note that if you use the TranslatableNLS class, you do not need to call the above constructor because the TranslatableText objects are created for you and are the values of the message fields in your derived class.<br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
<code><br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
</code><br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace. You can find these delta files in the plug-in's state directory at ".metadata\.plugins\<Bundle-SymbolicName>\.translations". The delta files contain the differences between the resource bundles embedded in the plug-in or fragment and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
Although the language fragments are built nightly on the Babel server, users may not be downloading these on a regular basis. Non-technical users may not even know about the Babel server or how to install the fragments. If users open the dialog to enter translations then it is desirable for the user to see the latest translations from the server. Therefore the current values should e fetched from the server every time the translation dialog is opened. This work has not been done.<br />
<br />
Another problem to consider is how we handle the installation of a later language pack. Ideally the delta files should modified to be deltas from that later version. This work has not been done, which means there may be older translations left in the delta files that are overriding more recent translations in the language packs.<br />
<br />
== The TranslatableNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. The bind methods also return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86575Babel / Runtime Translation Editor2008-03-08T18:07:55Z<p>Nigel.miegel.org: /* Editors and Views */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory. This plug-in is currently available only by checking out the project source from CVS. It can be found at dev.eclipse.org:/cvsroot/technology,org.eclipse.babel/plugins/org.eclipse.babel.runtime.<br />
<br />
2. For a more interesting demo, install at least one language pack. Language packs can be installed from the Babel update site at http://download.eclipse.org/technology/babel/update-site. Then start the target platform with the "-nl" parameter specified in the program arguments. So, for example, to run with Swiss German, start eclipse from the command line using "eclipse.exe -nl de_CH" or from the IDE by including "-nl de_CH" in the program arguments box.<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view), the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. However, none of the parts and dialogs in the IDE or, likely, in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. If you currently use the NLS class to load your messages, then use instead TranslatableNLS. <br />
<br />
<br />
If you currently use the Java ResourceBundle objects to load your messages then it is recommended that you upgrade to use TranslatableNLS. However, if you want to support the Babel runtime with the minimum of changes, you can use the TranslatableResourceBundle class provided by the Babel runtime. This class is derived from ResourceBundle so can be used in it's place. An instance of this class can be obtained by calling the static get method:<br />
<br />
<code><br />
resourceBundle = TranslatableResourceBundle.get(getBundle(), getClass().getClassLoader(), "com.acme.myApplication.Language");<br />
</code><br />
<br />
This is typically called when the plug-in is started.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
Note that if you use the TranslatableNLS class, you do not need to call the above constructor because the TranslatableText objects are created for you and are the values of the message fields in your derived class.<br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
<code><br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
</code><br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
An update command should be added that fetches the latest translations from the server and updates the delta files.<br />
<br />
== The TranslatableNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. The bind methods also return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86574Babel / Runtime Translation Editor2008-03-08T17:51:59Z<p>Nigel.miegel.org: /* Getting Started */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory. This plug-in is currently available only by checking out the project source from CVS. It can be found at dev.eclipse.org:/cvsroot/technology,org.eclipse.babel/plugins/org.eclipse.babel.runtime.<br />
<br />
2. For a more interesting demo, install at least one language pack. Language packs can be installed from the Babel update site at http://download.eclipse.org/technology/babel/update-site. Then start the target platform with the "-nl" parameter specified in the program arguments. So, for example, to run with Swiss German, start eclipse from the command line using "eclipse.exe -nl de_CH" or from the IDE by including "-nl de_CH" in the program arguments box.<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view), the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. However, none of the parts and dialogs in the IDE or, likely, in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. Use the TranslatableResourceBundle class provided by the Babel runtime instead of ResourceBundle provided by Java. <br />
<br />
<code><br />
resourceBundle = (TranslatableResourceBundle)ResourceBundle.getBundle("com.acme.myApplication.Language",<br />
new TranslatableResourceControl(getStateLocation()));<br />
TranslatableResourceBundle.register(resourceBundle, getBundle());<br />
</code><br />
<br />
This is typically called when the plug-in is started. Note that the location of the plug-in state is passed. This is where the delta files are stored. The delta files contain the differences between the resource bundles embedded in the plug-in and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
An update command should be added that fetches the latest translations from the server and updates the delta files.<br />
<br />
== The TranslatableNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. The bind methods also return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86334Babel / Runtime Translation Editor2008-03-07T05:29:00Z<p>Nigel.miegel.org: /* Getting Started */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory. This plug-in is currently available only by checking out the project source from CVS. It can be found at dev.eclipse.org:/cvsroot/technology,org.eclipse.babel/plugins/org.eclipse.babel.runtime.<br />
<br />
2. For a more interesting demo, install at least one language pack. Language packs can be installed from the Babel update site at http://download.eclipse.org/technology/babel/update-site. Then start the target platform with the "-nl" parameter specified in the program arguments. So, for example, to run with Swiss German, start eclipse from the command line using "eclipse.exe -nl de_CH" or from the IDE by including "-nl de_CH" in the program arguments box.<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view) and the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. Of course, none of the parts and dialogs in the IDE or in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. Use the TranslatableResourceBundle class provided by the Babel runtime instead of ResourceBundle provided by Java. <br />
<br />
<code><br />
resourceBundle = (TranslatableResourceBundle)ResourceBundle.getBundle("com.acme.myApplication.Language",<br />
new TranslatableResourceControl(getStateLocation()));<br />
TranslatableResourceBundle.register(resourceBundle, getBundle());<br />
</code><br />
<br />
This is typically called when the plug-in is started. Note that the location of the plug-in state is passed. This is where the delta files are stored. The delta files contain the differences between the resource bundles embedded in the plug-in and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
An update command should be added that fetches the latest translations from the server and updates the delta files.<br />
<br />
== The TranslatableNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. The bind methods also return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86321Babel / Runtime Translation Editor2008-03-07T04:22:47Z<p>Nigel.miegel.org: /* Editors and Views */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory.<br />
<br />
2. For a more interesting demo, set the system Locale to a locale that has a country code as well as a language code, and install the language packs for the selected locale. If using Windows XP, go to the 'Advanced' tab of 'Regional and Language Options'', select in 'Language for non-Unicode programs', and re-boot, or just start eclipse with the "-nl" parameter specified. In the following screen shots, we use FR_ca, so to see the same screens, start eclipse using "eclipse.exe -nl fr_CA".<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view) and the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. Of course, none of the parts and dialogs in the IDE or in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. Use the TranslatableResourceBundle class provided by the Babel runtime instead of ResourceBundle provided by Java. <br />
<br />
<code><br />
resourceBundle = (TranslatableResourceBundle)ResourceBundle.getBundle("com.acme.myApplication.Language",<br />
new TranslatableResourceControl(getStateLocation()));<br />
TranslatableResourceBundle.register(resourceBundle, getBundle());<br />
</code><br />
<br />
This is typically called when the plug-in is started. Note that the location of the plug-in state is passed. This is where the delta files are stored. The delta files contain the differences between the resource bundles embedded in the plug-in and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
2. Define a TranslatableSet object in the part.<br />
<br />
<code><br />
private TranslatableSet fTranslatableSet = new TranslatableSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ITranslatableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ITranslatableText implementation is then 'associated' with a control.<br />
<br />
The TranslatableText object can be used to provide an implementation of ITranslatableText where the text comes directly from a resource bundle. The constructor needs the TranslatableResourceBundle and the key:<br />
<br />
<code><br />
ITranslatableText title = new TranslatableText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
This translatable text object is then 'associated' with a control. This is done by creating an object derived from the abstract TranslatableTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
fTranslatableSet.associate(<br />
new TranslatableTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
<br />
The updateControl method is called initially when the TranslatableTextInput object is constructed and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided in the TranslatableSet class that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ITranslatableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ITranslatableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the TranslatableSet object cannot be used. An alternative method is to implement the Layout method in the TranslatableSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
An update command should be added that fetches the latest translations from the server and updates the delta files.<br />
<br />
== The TranslatableNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. The bind methods also return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=86316Babel / Runtime Translation Editor2008-03-07T04:11:06Z<p>Nigel.miegel.org: /* The TranslatableNLS Class */</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory.<br />
<br />
2. For a more interesting demo, set the system Locale to a locale that has a country code as well as a language code, and install the language packs for the selected locale. If using Windows XP, go to the 'Advanced' tab of 'Regional and Language Options'', select in 'Language for non-Unicode programs', and re-boot, or just start eclipse with the "-nl" parameter specified. In the following screen shots, we use FR_ca, so to see the same screens, start eclipse using "eclipse.exe -nl fr_CA".<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view) and the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. Of course, none of the parts and dialogs in the IDE or in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. Use the UpdatableResourceBundle class provided by the Babel runtime instead of ResourceBundle provided by Java. <br />
<br />
<code><br />
resourceBundle = (UpdatableResourceBundle)ResourceBundle.getBundle("com.acme.myApplication.Language",<br />
new UpdatableResourceControl(getStateLocation()));<br />
UpdatableResourceBundle.register(resourceBundle, getBundle());<br />
</code><br />
<br />
This is typically called when the plug-in is started. Note that the location of the plug-in state is passed. This is where the delta files are stored. The delta files contain the differences between the resource bundles embedded in the plug-in and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
2. Define a LanguageSet object in the part.<br />
<br />
<code><br />
private LocalizableTextSet localizableTextCollection = new LocalizableTextSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ILocalizableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ILocalizableText implementation is then 'associated' with a control.<br />
<br />
The LocalizableText object can be used to provide an implementation of ILocalizableText where the text comes directly from a resource bundle. The constructor needs the UpdatableResourceBundle and the key:<br />
<br />
<code><br />
ILocalizableText title = new LocalizedText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
This localizable text object is then 'associated' with a control. This is done by creating an object derived from the abstract LocalizedTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
localizableTextSet.associate(<br />
new LocalizedTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
<br />
The updateControl method is called initially and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ILocalizableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ILocalizableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the LocalizableTextSet object cannot be used. An alternative method is to implement the Layout method in the LocalizableTextSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
An update command should be added that fetches the latest translations from the server and updates the delta files.<br />
<br />
== The TranslatableNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from TranslatableNLS. Change all the messages from String objects to ITranslatableText objects. The bind methods also return ITranslatableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel_/_Runtime_Translation_Editor&diff=84053Babel / Runtime Translation Editor2008-02-23T22:01:41Z<p>Nigel.miegel.org: New page: == Babel Runtime Translation Editor == One of the aims of the Babel project is to make it is easy as possible for end users to contribute translations. == The Babel Runtime Plug-in == ...</p>
<hr />
<div>== Babel Runtime Translation Editor ==<br />
<br />
One of the aims of the Babel project is to make it is easy as possible for end users<br />
to contribute translations. <br />
<br />
== The Babel Runtime Plug-in ==<br />
<br />
The Babel runtime plug-in (org.eclipse.babel.runtime) should be included in an Eclipse RCP application to<br />
allow users of that application to provide translations. Note that this is quite different from the Babel Resource Bundle Editor plug-in. The<br />
The Message Editor plug-in runs in the IDE only, and is used by the developer to aid in producing language files for the program under development.<br />
The runtime plug-in, in comparison, is included in the RCP application (the target configuration), and allows the end-user to provide translations.<br />
While end-users of the Eclipse IDE typically have a good understanding of plug-ins, Java resource bundles, and the localization architecture in general,<br />
end-users of RCP applications typically will have no such understanding. The Babel runtime plug-in therefore is oriented towards allowing the user to<br />
translate what the user sees on the screen at that moment, and hides from the user details such as the key and the plug-in that contributed the message.<br />
<br />
== Getting Started ==<br />
<br />
Because readers will more likely be familiar with the Eclipse IDE than with any other single RCP application, the Eclipse IDE is used as the example target application in these steps. However, these steps can be applied to any RCP application.<br />
<br />
1. Copy org.eclipse.babel.runtime_1.0.0.jar into your Eclipse 3.3 plugins directory.<br />
<br />
2. For a more interesting demo, set the system Locale to a locale that has a country code as well as a language code, and install the language packs for the selected locale. If using Windows XP, go to the 'Advanced' tab of 'Regional and Language Options'', select in 'Language for non-Unicode programs', and re-boot, or just start eclipse with the "-nl" parameter specified. In the following screen shots, we use FR_ca, so to see the same screens, start eclipse using "eclipse.exe -nl fr_CA".<br />
<br />
3. Start up Eclipse.<br />
<br />
The Babel runtime plug-in allows users to translate only to the language to which the system Locale is set. If their locale has both a language and a country code then they can provide both country specific translations and general translations for that language. For example, if the locale is fr_CA then the user can provide both translations specific to french Canadians and general french translations. The reason for restricting the user in this way is to make the UI as simple as possible for non-technical users. The intent is that the user is translating/correcting what the user sees on the screen. There is of course nothing to stop a user from changing the system locale and restarting the platform.<br />
<br />
The plug-in does allow a way for the user to view and translate messages based on the contributing plug-in. However, as end-users are not likely to be aware of a particular message's contributing plug-in, the user can also view messages based on the part (editor or view) and the action bar (menu, toolbar, or status bar), or the dialog.<br />
<br />
Having started the Eclipse IDE, open the "Translate Text..." menu under "Help". Select the "Menu" tab and you should see a list of menu items. This list should match the actual menu. (The only known difference being that items will appear in the list even if they have been excluded from the menu based on disabled activities). A few items may have 'lock' icons, which means the Babel runtime plug-in was not able to obtain sufficient information about the source of the message to allow translation. On any of the other items, you may provide translations by in-place editing. If you are interested, the icons have tooltips that show the source of the message. However, this information has been relegated to the tooltip because end-users have no need for this information and it probably would not mean anything to them.<br />
<br />
Expand the "File" element in the tree and you should see a row for each of the menu items under the "File" menu. Try entering a translation for, say, the "Open" menu. Press OK. Now select the "File" menu and you should see your new translation taking immediate effect. Quit the workbench and re-start. You should see that you new translation is still active. This demonstrates that the plug-in allows the user to provide translations that are both hot-swappable and persistent across sessions.<br />
<br />
The Babel runtime plug-in fully takes care of the menu. It could also fully take care of the toolbar and status bar though this has not been implemented so currently there is no support for providing translations of toolbar and status bar text (other than knowing the contributing plug-in, resource bundle, and key).<br />
<br />
To allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. Of course, none of the parts and dialogs in the IDE or in your RCP application have yet been modified to work with the Babel runtime. You will see a tab in the translation dialog with a title that matches the editor or view part that was active when you opened the dialog. If you select that tab, though, you will see only a message indicating that the part does not support dynamic text translation. However, there is one dialog that has been so modified. The dialog boxes used in Babel itself supports dynamic translation.<br />
<br />
Workbench actions cannot be used while a dialog is open. Translatable dialog boxes therefore have a button in the lower left corner next to the help button. Press that to translate messages in the dialog box. You should then get another dialog box but with a tab titled 'Dialog - Text Translations'. Select that and you will see something like:<br />
<br />
<embed babel-dialogTranslation.jpeg><br />
<br />
Enter your translations in the table. When you press 'OK', you should see the new text in the dialog.<br />
<br />
You will notice one message that has the lock icon to indicate it is not translatable. That is because the message is in fact formatted from other component messages. Expand it and you will see the format string which you can edit and a parameter text which you cannot edit. The top level messages are what the user actually sees in the application. By doing this, instead of showing only the translatable parts, it is easier for the user to see the message that the user wants to translate.<br />
<br />
As mentioned earlier, to allow translation of views, editors, and dialogs, changes must be made to the source code for those parts. We now describe the changes that the developer of a part must make to the code so that end-users can provide translations.<br />
<br />
== Editors and Views ==<br />
<br />
To allow translation of editors and views, the following steps must be taken by the developer.<br />
<br />
1. Use the UpdatableResourceBundle class provided by the Babel runtime instead of ResourceBundle provided by Java. <br />
<br />
<code><br />
resourceBundle = (UpdatableResourceBundle)ResourceBundle.getBundle("com.acme.myApplication.Language",<br />
new UpdatableResourceControl(getStateLocation()));<br />
UpdatableResourceBundle.register(resourceBundle, getBundle());<br />
</code><br />
<br />
This is typically called when the plug-in is started. Note that the location of the plug-in state is passed. This is where the delta files are stored. The delta files contain the differences between the resource bundles embedded in the plug-in and the actual text to be used. The differences being changes either made by the user or obtained from a server running Aptana's software.<br />
<br />
2. Define a LanguageSet object in the part.<br />
<br />
<code><br />
private LocalizableTextSet localizableTextCollection = new LocalizableTextSet();<br />
</code><br />
<br />
3. All text used in the part should be first wrapped in an object that implements the ILocalizableText interface. These objects contain information about the source of the text such as the contributing plug-in, the resource bundle, and the key. The ILocalizableText implementation is then 'associated' with a control.<br />
<br />
The LocalizableText object can be used to provide an implementation of ILocalizableText where the text comes directly from a resource bundle. The constructor needs the UpdatableResourceBundle and the key:<br />
<br />
<code><br />
ILocalizableText title = new LocalizedText(resourceBundle, "Title") //$NON-NLS-1$<br />
</code><br />
<br />
This localizable text object is then 'associated' with a control. This is done by creating an object derived from the abstract LocalizedTextInput class and providing an implementation of the updateControl method. The updateControl method should set the text into the appropriate control. So, for the title of a part, the following code may be used:<br />
<br />
localizableTextSet.associate(<br />
new LocalizedTextInput(title) {<br />
@Override<br />
public void updateControl(String text) {<br />
ViewPart.this.setText(text);<br />
}<br />
}<br />
);<br />
<br />
The updateControl method is called initially and also whenever the user provides a different translation of the text. Thus the user will see the changed text immediately. This immediate feedback right into the user's running application is important to encourage contributions and also to ensure users know what they are changing.<br />
<br />
Now suppose there are two possible titles to the view, depending, perhaps, on the state of a checkbox in the view. Suppose both possible titles are taken from the resource bundle, and the title flips between them as the checkbox is checked. The application, when changing the title, could make another called to 'associate'. The problem is, there would then be two updateControl implementations, and the original would be called also. To solve this issue, the 'associate' method has another form in which an object is passed as the first parameter. You can pass any object, but it must be the same object each time 'associate' is called to set the title. This object is used as the key is a map, and if the key matches a previous key then the entry is replaced. In the above example of setting the title, you could use, say, a String object with a value of "title" as the key, or you could use the ViewPart object itself.<br />
<br />
It is a little long winded to provide an implementation of updateControl for every text message. Other forms of the 'associate' method are provided that do this for you. For example, to associate text with a Label, simply call <br />
<br />
<code><br />
associate(Label labelControl, ILocalizableText text) <br />
</code><br />
<br />
The first parameter is used both as the key in the map and also it the control into which the text is set.<br />
<br />
Most methods are overloaded versions of 'associate'. However, some have different names to avoid ambiguity. For example, to associate text with the tooltip of a label control, you would use:<br />
<br />
<code><br />
associateTooltip(Label labelControl, ILocalizableText tooltip) <br />
</code><br />
<br />
When a new translation is set into an active control, the container layout may need to be re-calculated. If a dialog box, this may even cause the size of the dialog box to change. This could be done in the updateControl implementations. However, that would mean the implementations supplied by the LocalizableTextSet object cannot be used. An alternative method is to implement the Layout method in the LocalizableTextSet object. By implementing the layout in this method, the layout will be re-calculated only once even if the user changed multiple text values.<br />
<br />
== Persistence ==<br />
<br />
If you restart Eclipse, you will see your text changes are still there. The messages are stored in a properties file in the runtime workspace.<br />
<br />
The message changes should be communicated to the servers running Aptana's code contribution. This work has not been done. Before this can be done, a programmatic interface is required.<br />
<br />
An update command should be added that fetches the latest translations from the server and updates the delta files.<br />
<br />
== The DynamicNLS Class ==<br />
<br />
A new class has been provided that replaces NLS. To provide translatable messages, extend from DynamicNLS. Change all the messages from String objects to ILocalizableText objects. The bind methods also return ILocalizableText objects.<br />
<br />
The initialization method is slightly different. Your class would typically contain the following code:<br />
<br />
<code><br />
static {<br />
// A little risky using the plugin activator in a static initializer.<br />
// Let's hope it is in a good enough state.<br />
initializeMessages(BUNDLE_NAME, Messages.class, Activator.getDefault());<br />
}<br />
</code><br />
<br />
You will see an extra parameter. The plug-in activator is mainly required because getStateLocation is called to get the location in which the language delta files are maintained. The plug-in activator is also used to get the OSGi bundle id so that it can be displayed in the tooltip giving the origins of each text.<br />
<br />
== Implementation ==<br />
<br />
The code to build the menu is one of the trickier parts of this plug-in. <br />
<br />
1. It is possible to traverse the menu, but that gains us little as we have no means of determining where each text originated. We solve this by traversing the menu bar contribution tree. This is rather trickier because the tree does not map simply to the actual menu but needs some knowledge of the various contribution classes in order to get the menu tree to match the menu.<br />
<br />
2. Having access to the contribution objects still does not get us to the origins of each piece of text. The problem is that the code to parse the plugin.xml files will replace any keys with the actual localized text. The way we get back to the key is to re-parse plugin.xml ourselves. This is obviously not the most efficient. Basically we know what elements to look for in the plugin.xml file based on the type of the menu contribution object.<br />
<br />
3. The last problem concerns updating the menu dynamically after the user has edited a message. Sometimes this is as easy as calling 'setText' on the contribution item followed by a call to 'update'. Sometimes 'setText' is private, for some reason. It would be possible to update the underlying menu items, but that runs the risk that the change could be overwritten.<br />
<br />
The above could all be made rather simpler if we were able to make changes to the core eclipse code. It will probably to a lot easier to get the changes into the core if the Babel runtime code is already working and the concept proven.</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Babel&diff=84052Babel2008-02-23T21:49:12Z<p>Nigel.miegel.org: /* Babel Documents */</p>
<hr />
<div>Eclipse is a global community. It is in everyone’s interest to ensure that Eclipse is available and translated in as many locales as possible. Babel will be a set of tools to make the job of globalizing Eclipse projects easier. We also want to provide ways for people world wide, who are interested, to contribute translations in their language of choice. <br />
<br />
[http://www.eclipse.org/babel/ Babel Project Home]<br />
<br />
[http://babel.eclipse.org/babel Babel Translation Tool]<br />
<br />
== Babel Documents ==<br />
<br />
[[Babel / Server Tool Specification]]<br />
<br />
[[Babel / Server Tool Project Plan]]<br />
<br />
[[Babel / Server Tool Development Process]]<br />
<br />
[[Babel / Runtime Translation Editor]]</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Equinox/p2/Getting_Started&diff=84010Equinox/p2/Getting Started2008-02-23T00:02:15Z<p>Nigel.miegel.org: /* Steps to using the agent */</p>
<hr />
<div>__TOC__<br />
<br />
== Overview ==<br />
<br />
What is the first thing that you would expect to do with some provisioning code - install something, of course! This section is to guide you through a happy-path using equinox provisioning to install an Eclipse SDK.<br />
<br />
There are four basic concepts that will help you understand the install:<br />
<br />
* '''Agent''' - the program that will perform the install. In general, the provisioning agent could appear in various forms - a standalone application, a silent install demon, a perspective in the ide. We will use the [[Equinox p2 Admin UI Users Guide | Admin UI application]] to do our install. Note that this Admin UI will not be what regular users will experience.<br />
* '''Metadata''' - the information about what can be installed. The metadata is used by the agent to analyze dependencies and perform the installation steps. Metadata lives in one or more repositories.<br />
* '''Artifacts''' - the actual bits that will be installed. There are various kinds of artifacts that are processed differently during the install. Associated metadata determines how a given artifact is processed. Artifacts live in one or more repositories. The metadata and artifacts generally come from different repositories and may be widely distributed.<br />
* '''Profile''' - in the most simple form, a profile is the location where the bits will be installed. The term 'profile' is not a very good term and probably will disappear from end user concepts (there's a bug about this), but it is the term we are using for now.<br />
<br />
== Steps to using the agent ==<br />
<br />
In this example, we will be installing a 3.4M5 SDK. Versions prior to M5 no longer work with the Eclipse test site. The example uses the windows-based agent, but other platforms are available on the [http://download.eclipse.org/eclipse/equinox/ Equinox download site].<br />
<br />
=== Step 1 - Downloading the agent ===<br />
<br />
The Admin agent application is available from the [http://www.eclipse.org/downloads/download.php?file=/eclipse/equinox/drops/S-3.4M5-200802071530/equinox-p2-agent-3.4M5-win32.zip Equinox download site] - click the link and you should see (Firefox)<br />
<br />
[[Image:AgentDownload.jpg]]<br />
<br />
The zip file is ~11 MB. Download it and unzip it anywhere on a writable local drive. The result of this step is that you will have a directory (equinox.p2) containing the agent:<br />
<br />
[[Image:ProvDirectory.jpg]]<br />
<br />
=== Step 2 - Exploring the agent ===<br />
<br />
Double-click on the eclipse.exe and the Admin UI will come up. It looks something like ''(resized to fit here)'':<br />
<br />
[[Image:InitialRCPAgent.jpg]]<br />
<br />
Note that you see here all four concepts:<br />
<br />
# Agent - the main window.<br />
# Metadata - the exposed '''Metadata Repositories''' view.<br />
# Artifacts - the hidden '''Artifact Repositories''' view.<br />
# Profiles - the '''Profiles''' view.<br />
<br />
The Metadata Repositories view is empty, so first let's add a repository on eclipse.org which contains metadata for the Eclipse SDK, and other goodies. You can do this from the popup menu in the Metadata Repositories view.<br />
<br />
[[Image:SelectAddRepository.jpg]]<br />
<br />
<br />
You'll see a dialog that lets you add a URL (or a local directory or jar file). We're going to use a test update site on eclipse.org (http://download.eclipse.org/eclipse/testUpdates/). (This may take awhile, we're working on the performance here)...<br />
<br />
[[Image:AddMetadataRepo.jpg]]<br />
<br />
Once the repository has been added, you should see something like this:<br />
<br />
[[Image:RCPAgent.jpg]]<br />
<br />
<br />
The Profiles view shows the Equinox Provisioning UI profile. This is the profile defining the install location for the Admin UI app you are running. If you right click on the list item and select properties, you will see some information about this profile:<br />
<br />
[[Image:AgentProfileProperties.jpg]]<br />
<br />
If a Metadata repository or a Profile is not empty, then you can expand it to see the installable units (which are really installed units) in the profile. A preference is available to show only the installable units which are a Group; the default for this preference is true. Expanding to show the groups will give you something like this:<br />
<br />
[[Image:ExpandedInstallableUnits.jpg]]<br />
<br />
Now, we'll switch to the Artifact Repositories view. It is empty because you have not yet added an artifact repository. <br />
<br />
The metadata repository you added describes what software is available, while the artifact repository contains the actual software that will be downloaded. These repositories don't have to be located at the same URL, but they can be. <br />
<br />
The server on eclipse.org has the metadata and artifacts in the same location, so you can add an artifact repository using the same URL we used for the metadata repository (by using the popup menu in the Artifact Repositories view). Once the repository has been added, you should see the actual artifacts in the Artifact Repository view:<br />
<br />
[[Image:Artifacts.jpg]]<br />
<br />
=== Step 3 - Creating a new profile ===<br />
<br />
You will need to decide where you want to install the SDK and create a profile for that location. In the profile view, right click and select 'Add profile...':<br />
<br />
[[Image:SelectNewProfile.jpg]]<br />
<br />
then fill in the appropriate data in the Profile properties dialog:<br />
<br />
[[Image:NewProfile.jpg]]<br />
<br />
The meanings of many of these properties are advanced, so don't play with the default settings unless you want to explore error conditions!<br />
<br />
=== Step 4 - Doing the install ===<br />
<br />
The '''sdk''' group is near the bottom of the list of group installable units in the repository, so scroll down until '''sdk''' is in view. There may be multiple versions of the sdk available. If so, find the one you are interested in.<br />
<br />
'''NOTE: Due to [[https://bugs.eclipse.org/bugs/show_bug.cgi?id=208143 bug 208143]] you should install the 1101-0010 version of the SDK IU.'''<br />
<br />
The Admin UI supports two ways of initiating an install: 1). you can right click on the '''sdk''' group, select Install..., then choose the profile in the resulting popup dialog; or 2). you can drag&drop the '''sdk''' group onto the profile. Let's do d&d since it is easier (the little smudge over SDK is the drop cursor):<br />
<br />
[[Image:DropSDK.jpg]]<br />
<br />
You will see a progress indicator while the agent figures out what needs to be downloaded. Next, you will be shown more detail about what is to be installed, such as the size of the artifacts needed. (We'll be showing more information here as the project evolves, such as license information or detail). <br />
<br />
[[Image:InstallDialog.jpg]]<br />
<br />
Click the install button, and the install will start (assuming you have network connectivity org.eclipse.download, no firewall issues, etc):<br />
<br />
[[Image:InstallProgress.jpg]]<br />
<br />
Anecdotally, the install takes slightly less time than the download of a corresponding Eclipse SDK zip (one datapoint: 21 minutes for equinox provisioning install vs. 23 minutes for download of the zip).<br />
<br />
=== Step 5- After the install ===<br />
<br />
The install will finish with a whimper, not a bang, as the progress dialog disappears and the new profile you created is populated with the groups and installable units that are now installed into the profile:<br />
<br />
[[Image:AgentPostInstall.jpg]]<br />
<br />
The directory you chose for your profile location will look like this, before running the eclipse you just installed:<br />
<br />
[[Image:InstalledSDK.jpg]]<br />
<br />
=== Step 6- Installing the end user UI ===<br />
<br />
The Agent UI is really intended for system administrators and power users who want to browse and manage the applications they have installed. A typical end user of an Eclipse-based application doesn't want to be exposed to all these concepts of metadata, artifacts, profiles, and IUs. They just want to install, run, and update their software. <br />
<br />
For this purpose, there is a p2-based end user UI intended for dropping into an Eclipse application. Once you have installed the SDK, you can install this end-user UI by dragging the "userui" group from the metadata repository into the profile that you just installed the SDK into. <br />
<br />
[[Image:InstallUserUI.jpg]]<br />
<br />
<br />
Now, when you start up the SDK, there will be a new menu entry (Help > Software Updates (Incubation), that you can use to manage and update the running application.<br />
<br />
You can find out more about this UI in [[Equinox p2 Update UI Users Guide]]<br />
<br />
== See also ==<br />
<br />
If you encounter bugs, or would like to enter enhancement requests for this work, please use the Equinox Incubator category in [https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Equinox Bugzilla]. You can add the prefix "[prov]" to the subject line of the bug report to help us with bug triage.<br />
<br />
For more detailed information, visit one or more of the following pages:<br />
<br />
* [[Equinox p2]] Top level site for the provisioning work going on in Equinox.<br />
* [[Equinox p2 Admin UI Users Guide]] For additional information about the agent UI you just used.<br />
* [[Equinox p2 Update UI Users Guide]] Information about the "end user" UI that can be dropped into an SDK (or any other Eclipse RCP application).<br />
* [[Equinox p2 Console Users Guide]] For OSGI geeks who enjoy starting and stopping bundles.<br />
* [[Equinox p2 Getting Started for Developers]] For developers who want to create applications that extend or exploit equinox provisioning.<br />
<br />
[[Category:Equinox p2|Getting Started]]</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Equinox/p2/Getting_Started&diff=84009Equinox/p2/Getting Started2008-02-22T23:59:58Z<p>Nigel.miegel.org: /* Step 1 - Downloading the agent */</p>
<hr />
<div>__TOC__<br />
<br />
== Overview ==<br />
<br />
What is the first thing that you would expect to do with some provisioning code - install something, of course! This section is to guide you through a happy-path using equinox provisioning to install an Eclipse SDK.<br />
<br />
There are four basic concepts that will help you understand the install:<br />
<br />
* '''Agent''' - the program that will perform the install. In general, the provisioning agent could appear in various forms - a standalone application, a silent install demon, a perspective in the ide. We will use the [[Equinox p2 Admin UI Users Guide | Admin UI application]] to do our install. Note that this Admin UI will not be what regular users will experience.<br />
* '''Metadata''' - the information about what can be installed. The metadata is used by the agent to analyze dependencies and perform the installation steps. Metadata lives in one or more repositories.<br />
* '''Artifacts''' - the actual bits that will be installed. There are various kinds of artifacts that are processed differently during the install. Associated metadata determines how a given artifact is processed. Artifacts live in one or more repositories. The metadata and artifacts generally come from different repositories and may be widely distributed.<br />
* '''Profile''' - in the most simple form, a profile is the location where the bits will be installed. The term 'profile' is not a very good term and probably will disappear from end user concepts (there's a bug about this), but it is the term we are using for now.<br />
<br />
== Steps to using the agent ==<br />
<br />
In this example, we will be installing a 3.4M3 SDK. The example uses the windows-based agent, but other platforms are available on the [http://download.eclipse.org/eclipse/equinox/ Equinox download site].<br />
<br />
=== Step 1 - Downloading the agent ===<br />
<br />
The Admin agent application is available from the [http://www.eclipse.org/downloads/download.php?file=/eclipse/equinox/drops/S-3.4M5-200802071530/equinox-p2-agent-3.4M5-win32.zip Equinox download site] - click the link and you should see (Firefox)<br />
<br />
[[Image:AgentDownload.jpg]]<br />
<br />
The zip file is ~11 MB. Download it and unzip it anywhere on a writable local drive. The result of this step is that you will have a directory (equinox.p2) containing the agent:<br />
<br />
[[Image:ProvDirectory.jpg]]<br />
<br />
=== Step 2 - Exploring the agent ===<br />
<br />
Double-click on the eclipse.exe and the Admin UI will come up. It looks something like ''(resized to fit here)'':<br />
<br />
[[Image:InitialRCPAgent.jpg]]<br />
<br />
Note that you see here all four concepts:<br />
<br />
# Agent - the main window.<br />
# Metadata - the exposed '''Metadata Repositories''' view.<br />
# Artifacts - the hidden '''Artifact Repositories''' view.<br />
# Profiles - the '''Profiles''' view.<br />
<br />
The Metadata Repositories view is empty, so first let's add a repository on eclipse.org which contains metadata for the Eclipse SDK, and other goodies. You can do this from the popup menu in the Metadata Repositories view.<br />
<br />
[[Image:SelectAddRepository.jpg]]<br />
<br />
<br />
You'll see a dialog that lets you add a URL (or a local directory or jar file). We're going to use a test update site on eclipse.org (http://download.eclipse.org/eclipse/testUpdates/). (This may take awhile, we're working on the performance here)...<br />
<br />
[[Image:AddMetadataRepo.jpg]]<br />
<br />
Once the repository has been added, you should see something like this:<br />
<br />
[[Image:RCPAgent.jpg]]<br />
<br />
<br />
The Profiles view shows the Equinox Provisioning UI profile. This is the profile defining the install location for the Admin UI app you are running. If you right click on the list item and select properties, you will see some information about this profile:<br />
<br />
[[Image:AgentProfileProperties.jpg]]<br />
<br />
If a Metadata repository or a Profile is not empty, then you can expand it to see the installable units (which are really installed units) in the profile. A preference is available to show only the installable units which are a Group; the default for this preference is true. Expanding to show the groups will give you something like this:<br />
<br />
[[Image:ExpandedInstallableUnits.jpg]]<br />
<br />
Now, we'll switch to the Artifact Repositories view. It is empty because you have not yet added an artifact repository. <br />
<br />
The metadata repository you added describes what software is available, while the artifact repository contains the actual software that will be downloaded. These repositories don't have to be located at the same URL, but they can be. <br />
<br />
The server on eclipse.org has the metadata and artifacts in the same location, so you can add an artifact repository using the same URL we used for the metadata repository (by using the popup menu in the Artifact Repositories view). Once the repository has been added, you should see the actual artifacts in the Artifact Repository view:<br />
<br />
[[Image:Artifacts.jpg]]<br />
<br />
=== Step 3 - Creating a new profile ===<br />
<br />
You will need to decide where you want to install the SDK and create a profile for that location. In the profile view, right click and select 'Add profile...':<br />
<br />
[[Image:SelectNewProfile.jpg]]<br />
<br />
then fill in the appropriate data in the Profile properties dialog:<br />
<br />
[[Image:NewProfile.jpg]]<br />
<br />
The meanings of many of these properties are advanced, so don't play with the default settings unless you want to explore error conditions!<br />
<br />
=== Step 4 - Doing the install ===<br />
<br />
The '''sdk''' group is near the bottom of the list of group installable units in the repository, so scroll down until '''sdk''' is in view. There may be multiple versions of the sdk available. If so, find the one you are interested in.<br />
<br />
'''NOTE: Due to [[https://bugs.eclipse.org/bugs/show_bug.cgi?id=208143 bug 208143]] you should install the 1101-0010 version of the SDK IU.'''<br />
<br />
The Admin UI supports two ways of initiating an install: 1). you can right click on the '''sdk''' group, select Install..., then choose the profile in the resulting popup dialog; or 2). you can drag&drop the '''sdk''' group onto the profile. Let's do d&d since it is easier (the little smudge over SDK is the drop cursor):<br />
<br />
[[Image:DropSDK.jpg]]<br />
<br />
You will see a progress indicator while the agent figures out what needs to be downloaded. Next, you will be shown more detail about what is to be installed, such as the size of the artifacts needed. (We'll be showing more information here as the project evolves, such as license information or detail). <br />
<br />
[[Image:InstallDialog.jpg]]<br />
<br />
Click the install button, and the install will start (assuming you have network connectivity org.eclipse.download, no firewall issues, etc):<br />
<br />
[[Image:InstallProgress.jpg]]<br />
<br />
Anecdotally, the install takes slightly less time than the download of a corresponding Eclipse SDK zip (one datapoint: 21 minutes for equinox provisioning install vs. 23 minutes for download of the zip).<br />
<br />
=== Step 5- After the install ===<br />
<br />
The install will finish with a whimper, not a bang, as the progress dialog disappears and the new profile you created is populated with the groups and installable units that are now installed into the profile:<br />
<br />
[[Image:AgentPostInstall.jpg]]<br />
<br />
The directory you chose for your profile location will look like this, before running the eclipse you just installed:<br />
<br />
[[Image:InstalledSDK.jpg]]<br />
<br />
=== Step 6- Installing the end user UI ===<br />
<br />
The Agent UI is really intended for system administrators and power users who want to browse and manage the applications they have installed. A typical end user of an Eclipse-based application doesn't want to be exposed to all these concepts of metadata, artifacts, profiles, and IUs. They just want to install, run, and update their software. <br />
<br />
For this purpose, there is a p2-based end user UI intended for dropping into an Eclipse application. Once you have installed the SDK, you can install this end-user UI by dragging the "userui" group from the metadata repository into the profile that you just installed the SDK into. <br />
<br />
[[Image:InstallUserUI.jpg]]<br />
<br />
<br />
Now, when you start up the SDK, there will be a new menu entry (Help > Software Updates (Incubation), that you can use to manage and update the running application.<br />
<br />
You can find out more about this UI in [[Equinox p2 Update UI Users Guide]]<br />
<br />
== See also ==<br />
<br />
If you encounter bugs, or would like to enter enhancement requests for this work, please use the Equinox Incubator category in [https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Equinox Bugzilla]. You can add the prefix "[prov]" to the subject line of the bug report to help us with bug triage.<br />
<br />
For more detailed information, visit one or more of the following pages:<br />
<br />
* [[Equinox p2]] Top level site for the provisioning work going on in Equinox.<br />
* [[Equinox p2 Admin UI Users Guide]] For additional information about the agent UI you just used.<br />
* [[Equinox p2 Update UI Users Guide]] Information about the "end user" UI that can be dropped into an SDK (or any other Eclipse RCP application).<br />
* [[Equinox p2 Console Users Guide]] For OSGI geeks who enjoy starting and stopping bundles.<br />
* [[Equinox p2 Getting Started for Developers]] For developers who want to create applications that extend or exploit equinox provisioning.<br />
<br />
[[Category:Equinox p2|Getting Started]]</div>Nigel.miegel.orghttps://wiki.eclipse.org/index.php?title=Trying_Out_Maya&diff=73514Trying Out Maya2008-01-10T19:52:07Z<p>Nigel.miegel.org: /* Overview */</p>
<hr />
<div>== Overview ==<br />
<br />
'''NOTE: These instructions are out of date. The maya project has recently had a name change, now maynstall. So the repositories have changed as well. In addition to that maynstall is undergoing many changes in preparation for p2, the new provisioning effort. So this page does not have the correct information available. For instance the dependency to hibernate has been removed. <br />
'''<br />
<br />
The following instructions highlight how to try out Maya. At this time, Maya does not have a formal "release" available however we understand that certain developers may wish to setup Maya to begin experimenting how it could work in their environment. The follow steps are designed to use a local Derby database and include example plugins that have a local update site run to expose the Maya features and plugins as needed. In addition, a set of JUnit tests are used to populate the database including configuring default profiles and scanning standard update sites. Once you experiment with this configuration, you can deviate from these steps including registering additional update sites and potentially switching to use other database technologies.<br />
<br />
== The Environment ==<br />
<br />
You will use the following components in trying out Maya.<br />
<br />
* '''Eclipse'''<br />
** To build and run the database, update site, and Maya server<br />
* '''Maya Server'''<br />
** To expose the web services needed for Maya to operate<br />
** To host the local update site for testing (in this example)<br />
* '''Derby DB'''<br />
** To store the meta information for Maya to perform provisioning<br />
* '''Maya Javastrap'''<br />
** A Java implementation of Maya's bootstrap to initiate provisioning<br />
* '''Maya Launcher'''<br />
** Run by the bootstrap and allows selection of profile to be executed<br />
<br />
== Trying Out Maya ==<br />
<br />
# Install the [http://java.sun.com/javase/downloads/index.jsp Sun JRE 1.6] (if not already installed)<br />
#* Note: Needed for testing of Maya when automatic VM distribution is enabled (currently default)<br />
# Start Eclipse, download from [http://download.eclipse.org/eclipse/downloads/ Eclipse.org] if needed<br />
#* Note: We've tested with 3.2.2 as well as 3.3M6+<br />
# Import Maya's Getting Started team project set<br />
#* Download the Team Project Set (right-click Save As...)<br />
#** For Maya committers: [http://www.eclipse.org/maya/resources/maya-with-derby-committer.psf maya-with-derby-committer.psf]<br />
#** For anonymous access: [http://www.eclipse.org/maya/resources/maya-with-derby-anon.psf maya-with-derby-anon.psf]<br />
#* Use '''Import > Team > Team Project Set''' and browse to the PSF file<br />
#* You will get build errors until you complete later steps<br />
# Add [http://sourceforge.net/project/showfiles.php?group_id=40712&package_id=127784&release_id=498399 Hibernate] Jars to '''org.eclipse.maya.server.example.hibernate''' project<br />
#* Place Hibernate files in the '''org.eclipse.maya.server.example.hibernate/lib''' folder. <br />
#* Copy Jars from the downloaded hibernate zip's top-level directory:<br />
#** hibernate3.jar<br />
#* Copy Jars from the downloaded hibernate zip's lib directory:<br />
#** antlr-2.7.6.jar<br />
#** asm.jar<br />
#** asm-attrs.jar<br />
#** c3p0-0.9.1.jar<br />
#** cglib-2.1.3.jar<br />
#** commons-collections-2.1.1.jar<br />
#** dom4j-1.6.1.jar<br />
#** jta.jar<br />
#* Once Jars in place, all build errors should go away (if not, do a clean build)<br />
# Start the Derby network server<br />
#* Run the server using the launch config '''Derby Network Server'''<br />
# Create zip file of the Sun 1.6.0 JRE and place in JRE folder<br />
#* On Windows navigate to the directory where there is folders like '''bin & lib''' and some other files and create a zip file just containing those files<br />
#* Place that in the JRE folder for your os in the '''org.eclipse.maya.server.example.db''' plug-ins (Note: the file must be named '''jre_1.6.0.zip''')<br />
#** For Windows, place the file at '''org.eclipse.maya.server.example.db/jre/win/jre_1.6.0.zip'''<br />
#** For Linux, place the file at '''org.eclipse.maya.server.example.db/jre/linux/jre_1.6.0.zip'''<br />
# Build Update Site for the Maya software<br />
#* Open the '''site.xml''' located in the '''update_site''' folder of the '''org.eclipse.maya.server.example.db''' project click '''Build All'''<br />
#* Note: Under Eclipse 3.3M7 you may receive an error building the update site, typically this can be ignored<br />
# Start the Maya Web Server<br />
#* Run the server using the launch config '''Maya Server (Win)'''<br />
# Prepare the Maya Database including initial population <br />
#* Run using the '''Initialize Maya Database''' launch config<br />
#* Part of preparation includes running update site sync which can take 10-60 minutes depending on network connection. Subsequent runs of the update site sync will run significantly faster as it will only retrieve incremental changes<br />
# Run the Maya Launcher via Bootstrap<br />
#* Launch the '''Maya Javastrap''' launch config from the Run... menu<br />
#* When prompted for a user name and password, specify '''user''' / '''pass''' or '''admin''' / '''admin'''<br />
<br />
== What to Try Next ==<br />
<br />
* '''Distributed Testing'''<br />
** Even though you are testing with Maya running on a local Derby DB, this setup will allow you to test from a remote system. Since the meta information cached in the Derby DB includes the base URL to update sites, the Maya plugins and features will be referenced based on the hostname of the test server. In environments where WINS is configured, you should be able to modify the '''Maya Javastrap''' to have the hostname of the server specified under VM arguments as '''-Dmaya.host=&lt;hostname&gt;'''. If you do not have WINS configured, you will need to specify '''-Dmaya.host=&lt;a.b.c.d&gt;''' where a.b.c.d is the server's IP address. Please note that while you can set the Maya hostname for testing, typically the native bootstrap you would deploy would be installed and configured ready for a given server. Note: If the server's IP address or name changes, you may need to re-run '''Initialize Maya Database''' which will dump the tables and re-create from scratch.<br />
* '''Create Additional Profiles'''<br />
** At this time, the user interface is not quite complete for administrating profiles. If you would like to test creating a new profile, create a derivative of the '''AddJavaPorfile.java''' test case. You can create as many profiles as you like. Please note that for purposes of simplifying the examples, we are using a simple user and group mechanism. If you need to test profiles allocated to specific groups, modify the '''org.eclipse.maya.server.example.user/users/users.xml''' file or provide an alternate implementation of those functions tied to your own authentication system.<br />
<br />
== Database Maintenance ==<br />
<br />
Once you've created the Maya database, you may want to periodically run the '''Rescan Update Sites''' launch configuration. This will have Maya go out and verify that all of the features exposed on the registered update sites are stored within Maya's meta cache. In addition, for this Derby-based usage of Maya, the database itself will have information including the machine's hostname to be used as the web site for the Maya plugins exposed by the update site. In a full installation these files would be hosted on a stable server, though in this setup, since the hostname of the machine could change, you may need to re-initialize the database if certain configuration changes occur.</div>Nigel.miegel.org