Like any commercial-quality product, Eclipse is fully internationalizable and pays attention to accessibility requirements. When contributing to Eclipse we want to preserve this characteristic and make sure that our plug-in is usable by anybody. In this section we look into tasks related to internationalization and accessibility:
Externalizing the strings from the plugin.xml
Externalizing strings from Java code
Paying attention to accessibility
All these tasks are highly mechanical, but need to be done. Let's start with externalizing the strings from the plugin.xml.
Some strings in the plugin.xml are shown to the end user, the label of an action, for example. Others are shown to the plug-in developer through PDE, like the name of an extension point. All these strings need to be translatable and need to be externalized. PDE supports this with the look-aside file plugin.properties, shown in Figure 28.1.
A string prefixed with “%” in the plugin.xml is looked up in the plugin.properties file. We have to externalize all of the extension point names and all of the user-visible strings in our contributions. Here is an excerpt from the externalized plugin.xml file:
Example . org.eclipse.contribution.junit/plugin.xml
<plugin ... name="%pluginName" ..."> <extension-point id="listeners" name="%testListeners"/> <extension point="org.eclipse.ui.propertyPages"> <page... name="%propertyPageName" </page> </extension> ... </plugin>
The manifest file feature.xml describing a feature includes externalizable strings similar to the plugin.xml. The conventions to externalize these strings are the same as for the plugin.xml. The look-aside file for the feature.xml is named feature.properties.
Eclipse uses the standard Java resource bundle mechanism to externalize strings. The subpackages of org.eclipse.ui.views
serve as good examples to illustrate the conventions:
Introduce a resource bundle for each major component in a plug-in. In the case of org.eclipse.views
, the components are the different views provided by the plug-in. Having a separate bundle for each component simplifies the bundle management and avoids having to merge conflicting changes when working in a team.
For each resource bundle, add a properties file, for example, messages.properties, with the externalized strings. Use a helper class like BookMarkExplorerMessages
in org.eclipse.ui.views.bookmarkexplorer
to access the bundle.
Use qualified keys to ensure uniqueness, for example, OpenBookmark.text
, OpenBookmark.toolTip
, OpenBookmark.errorTitle
.
Our contributed JUnit plug-in is simple enough that a single resource bundle is sufficient. To extract the strings, we use the string externalization support provided by the Eclipse Java tooling. Source > Find Strings to Externalize finds all the strings that are not yet marked as externalized. Eclipse uses the comment markers to tag externalized strings (//$NON-NLS-1$)
. The Source > Externalize Strings wizard extracts the strings and can create the bundle accessor class for us, as shown in Figure 28.2.
This is the generated helper class for accessing externalized strings:
Example . org.eclipse.contribution.junit/JUnitMessages
public class JUnitMessages { private static final String BUNDLE_NAME= "org.eclipse.contribution.junit.JUnitMessages"; //$NON-NLS-1$ private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME); private JUnitMessages() { } public static String getString(String key) { try { return RESOURCE_BUNDLE.getString(key); } catch (MissingResourceException e) { return '!' + key + '!'; } } }
Here is an excerpt of code with externalized strings:
Example . org.eclipse.contribution.junit/AutoTestPropertyPage
... Label label= new Label(composite, SWT.NONE); label.setText(JUnitMessages.getString( "PropertyPage.description"));//$NON-NLS-1$
To verify that you have externalized all strings, you might want to turn on the Usage of non-externalized strings Java compiler option (Window > Preferences > Java > Compiler).
One problem with internationalization is you don't want to wait to ship your plug-ins until all the translations are ready. To ship translations separately, Eclipse provides fragments. A fragment allows you to add code or resources to an existing plug-in. Once the translations are ready, you can package them up into a fragment that extends your base plug-in.
While you externalize strings, it's a good time to give attention to accessibility issues. The primary accessibility issues you need to address in your plug-in are:
Keyboard access—. Every action in the plug-in's UI needs to be accessible via the keyboard.
Object information—. Enable screen readers. Associate labels with controls. Information contained in images should also be available as text.
Display/sound—. Use color as an enhancement only. Support high contrast settings. Provide accessible alternatives for significant audio and video content.
In this chapter we will only touch on keyboard access and screen readers. The forward pointers contain guidelines for using color and sound.
An important requirement for an accessible application is that everything in an application can be reached with the keyboard. To make menu items and widgets in dialogs more easily accessible, we assign them mnemonics. This is done in both the plugin.xml and the code by prefixing the mnemonic letter with a “&”. A mnemonic is shown with a letter underlined in menus and dialogs. When pressing the mnemonic letter, the selection or focus will jump to this item.
Currently, none of our menu items and dialog items has a mnemonic. We should try hard to come up with unique mnemonic letter choices. Since Eclipse menus are extensible, collisions can happen. The only consequence of a collision is that the user will have to press the mnemonic letter more than once. The object contribution to run a test and the auto test label in the property page both need a mnemonic, as shown in Figure 28.3.
Example . org.eclipse.contribution.junit/plugin.properties
pluginName=Contributed Junit Plug-in
testListeners=Test Listeners
propertyPageName=Auto-test
runTestLabel=Run &Test
resultViewName=Contributed Result View
...
If you want to test whether your plug-in is accessible from the keyboard, use it while your mouse is unplugged.
Accessibility goes further than just defining mnemonics. For example, another requirement is that you have to accommodate screen readers. A screen reader can read the contents of widgets aloud. For example, our existing ResultView
doesn't address this requirement. It only shows a red/green/grey color indication of a test's status. To make the view accessible, the color indication has to include some textual label like OK, Failed, Unknown.
In this chapter we have made our plug-in internationalized and accessible.
Externalized strings
Added mnemonics
The final bit of work on our plug-in in the next chapter is to explicitly publish its API.
Testing your internationalized plug-ins—. Once you have externalized the strings, you also need to test how your dialogs look with longer strings on all the different platforms. For an in-depth article on testing an internationalized plug-in, refer to www.eclipse.org/articles/Article-TVT/how2TestI18n.html.
See www.section508.gov/ for more information on accessibility requirements. IBM provides a detailed checklist for developers that is available at www-3.ibm.com/able/guidelines/index.html.
For information on how to fulfill accessibility requirements in Eclipse, refer to www.eclipse.org/articles/Article-Accessibility/accessibility.html.
SWT provides additional APIs for accessibility in the package org.eclipse.swt.accessibility
.
For PDE support for creating projects representing a fragment, see New > Plug-in Development > Fragment Projects.