diff options
Diffstat (limited to 'Article-Internationalization/how2I18n.html')
-rw-r--r-- | Article-Internationalization/how2I18n.html | 1255 |
1 files changed, 1255 insertions, 0 deletions
diff --git a/Article-Internationalization/how2I18n.html b/Article-Internationalization/how2I18n.html new file mode 100644 index 0000000..929e39f --- /dev/null +++ b/Article-Internationalization/how2I18n.html @@ -0,0 +1,1255 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + +<head> +<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<META name="GENERATOR" content="IBM WebSphere Studio Homepage Builder V6.0.2 for Windows"> +<META http-equiv="Content-Style-Type" content="text/css"> +<title>How to Internationalize your Eclipse Plug-In</title> +<link rel="stylesheet" href="../../default_style.css"> +</head> +<BODY link="#0000ff" vlink="#800080" bgcolor="#ffffff" leftMargin="2" topMargin="2" marginwidth="2" marginheight="2"> +<div align="right"> <font face="Times New Roman, Times, serif" size="2">Copyright + © 2002 International Business Machines Corp.</font> + <table border=0 cellspacing=0 cellpadding=2 width="100%"> + <tr> + <td align=LEFT valign=TOP colspan="2" bgcolor="#0080C0"><b><font face="Arial,Helvetica"><font color="#FFFFFF"> Eclipse + Corner Article</font></font></b></td> + </tr> + </table> +</div> +<div align="left"> + <h1><img src="images/Idea.jpg" height=86 width=120 align=CENTER></h1> +</div> +<p> </p> + +<h1 ALIGN="CENTER">How to Internationalize your Eclipse Plug-In</h1> +<BLOCKQUOTE> +<b>Summary</b> +<br> +This article is a roadmap for writing Eclipse plug-ins destined for the +international market. We'll begin with a brief review of the motivations +and technical challenges of internationalization, followed by step-by-step +instructions of how to internationalize your Eclipse plug-in. +<p><B>By Dan Kehn, Scott Fairbrother, and Cam-Thu Le</b><br> +IBM Eclipse ISV Enablement +(Jumpstart) Team + + <p>August 23, 2002</p> + <p>Editor's note: This article reflects Eclipse release 2.0.</p> +</blockquote> +<H2>Introduction</H2> +<p>An old joke in the internationalization community goes like this:</p> +<blockquote>"A person who speaks three languages is called trilingual. + And a person who speaks two languages is called bilingual. + So what do you call someone who only speaks one language?" +<P><I><insert dramatic pause here></I></P> +</blockquote> +<blockquote> + "American." +</blockquote> +<p>Today, providing a software product solely in English is no longer acceptable + from a usability, quality, marketing, and in some cases, legal standpoint. Enabling your product for the world market simply makes economic sense. And the enablement process is relatively straightforward, as this article will show.</p> +<p>A few notes before we begin. Because the Eclipse +Platform adopts the internationalization +implementation provided with the Java SDK, it's helpful +to read the <a href="http://java.sun.com/docs/books/tutorial/i18n/intro/index.html">Java + Tutorial: Internationalization</a> trail before continuing. The tutorial presents a fine overview of the issues and + steps involved in the process. We will assume that you've already read the tutorial + so we can underscore the key points, surface other noteworthy items, and cover + Eclipse-specific issues and steps in this article. And when you run into unfamiliar + terminology or acronyms in this article, +jump to our <a href="#glossary">glossary</a>.</p> +<H3><a name="overview">Overview of internationalization</a></H3> +<p><i>Internationalization</i> is the process of creating software for the world market. + Besides the economic benefits, some countries require products to pass certain localization requirements set by the government before it can be introduced to their markets.</p> +<p>The process of internationalition is usually accomplished in two steps:</p> +<ol> +<li> +<b>NLS-enabling the product.</b> +<br /> + This step covers coding techniques and user interface + design issues. Enabling a product for National Language Support (NLS) ensures the product is designed for national language function + and uses proper APIs to handle national language data. During this step, smart + coding practices -- such as avoiding hardcoded strings, making input buffers + large enough to hold translatable text, properly parsing strings that contain + non-Latin characters, not localizing strings saved as part of a file format, + and isolating the national language elements from program code -- must be weighed + and considered so the translation can be completed with minimal expense and + effort. +<p> + </li> +<li> +<b>Translating the product.</b> +<br />This step involves translating the domestic +language elements + into a foreign language. As with words and phrases, pictures + and symbols may also be interpreted differently +by various cultures. It is during + the translation verification step that +all translations are reviewed for contextual + accuracy, icons or clip art are modified +to ensure there are no user misinterpretations, + and page layouts are checked for inadvertent +text truncation. While verifying + the product's functional integrity after +translation, this step also looks for + hidden cultural impacts. +</li> +</ol> +<H3><a name="affected">What does internationalization affect?</a></H3> +<p><i>Monoglots take note</i>: This is the beginning of your sensitivity training. + There may be a quiz at end of this article. :-)</p> +<p>Let's begin with a distillation of the list of culturally dependent data +presented in the Java Internationalization tutorial, reordered by the likelihood +that the typical developer will encounter it, and followed by details on +each:</p> +<ol> +<li> +<a href="#data_text">Text</a> +<br />Messages, labels on GUI components + <br />Online help (*.html), Plug-in manifest (plugin.xml)<br /> + </li> +<li> +<a href="#data_formatting">Data formatting</a> +<br />Numbers, dates, times, currencies + <br />Phone numbers, postal addresses<br /> + </li> +<li> +<a href="#data_regional">Regional and personal substitutions</a> +<br />Measurements + <br />Honorifics and personal titles<br /> + </li> +<li> +<a href="#data_multimedia">Multimedia considerations</a> +</li> +</ol> +<H4><a name="data_text">Text</a></H4> +<p><b>Messages, labels on GUI components</b> +<br /> +Resource bundles nicely handle language-dependent +texts. The strategy is either to load all +strings at once into a <a href="http://java.sun.com/j2se/1.3/docs/api/java/util/class-use/ResourceBundle.html">ResourceBundle</a> subclass, or to retrieve them individually. +The Eclipse Java Development Tooling (JDT) +in version 2.0 provides wizards to support +the detection of translatable strings. We'll +return to them shortly in <a href="#steps">Internationalization steps</a>.</p> +<p>Loading translated strings into memory is only the first step. The next +step is to pass them to the appropriate controls for display (such as a +label, text field, menu choice, etc.). The page designer and programmer +must work together to assure that the chosen layout allows for appropriate +resizing and reflowing of the dialog. The layout support in the Standard +Widget Toolkit (SWT) library relies heavily on the programmer to "do +the right thing" by specifying layout descriptions that react appropriately +to changes in field sizes. The article <A href="http://eclipse.org/articles/Understanding%20Layouts/Understanding%20Layouts.htm">Understanding Layout in SWT</A> covers the implementation issues in detail.</p> +<p>This is particularly important because text +length increases during translation. English +phrases are often shorter than their equivalent +translations, usually on the order of 40%. +Font sizes also may need to be modified to +accommodate the local language. +</p> +<p> +<b> +<a name="plugin_xml_attribs">Online help (*.html), Plug-in manifest (plugin.xml)</a> +</b> +<br /> + These forms of text content are more involved than simple key/value-oriented + properties files, so the steps to their externalization are slightly more complex.</p> +<p>In the case of the manifest file, it is coupled +with a similarly named property file, plugin.properties, + containing only the externalized text. +Special care must be taken with manifest +files like plugin.xml and fragment.xml, since +the attributes of the tags can contain both +translated and untranslated text. Consider +the benign example below:</p> +<a name="c1"><b>Listing 1. Plug-in manifest file, before translation</b></a><table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#CCCCCC"> +<tr><td><pre><code> <plugin + name="Jumpstart Example Plug-in" + id="com.ibm.jumpstart.example" + version="2.0.0" + provider-name="IBM Corporation" + class="com.ibm.jumpstart.example.ExamplePlugin"> +</code></pre></td></tr> +</table> +<p>Here we see a mix of translatable text, untranslatable text, and "gray + area" translatable text, all as tag attributes. Clearly the +<code>id</code> and <code>class</code> attributes are not translatable, +since they represent programming identifiers. It is equally certain that the +<code>name</code> attribute should be translated.</p> +<p>You might be tempted to consider the +<code>version</code> attribute (because of the locale-dependent decimal separator) or <CODE>provider-name</CODE> attribute (because of the locale-dependent legal attribution "Corporation") +as candidates for translation, since they will be displayed to the end +user. However, version numbers are generally left untranslated for two +reasons: end users attribute little meaning to their numeric value, and +programmers sometimes write code that expects version numbers to be a composed +string like "3.5.4". It is arguably a better design decision +that the version information be stored as separate numbers like major, +minor, and service update to avoid the need to parse a version string, +but that discussion is beyond the scope of this article.</p> +<p>The <CODE>provider-name</CODE> may be left untranslated as well, since "Corporation" has legal meaning that can defy accurate translation. After identifying what text needs to be externalized, our example now looks like this:</p> +<a name="c2"><b>Listing 2. Plug-in manifest file, after translation</b></a><table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#CCCCCC"> +<tr><td><pre><code> <plugin + name="<B>%<span class="boldcode">plugin.name</span></B>" + id="com.ibm.jumpstart.example" + version="2.0.0" + provider-name="IBM Corporation" + class="com.ibm.jumpstart.example.ExamplePlugin"> +</code></pre></td></tr> +</table> +<p>where <code>plugin.properties</code> contains the externalized string, "Jumpstart + Example Plug-in" associated with the key <code>plugin.name</code>.</p> +<p>This simple example demonstrates +that translating isn't simply providing equivalent +words or phrases for your text; it also involves +an understanding of the local cultural considerations +and potential legal impacts. This is why +a translation professional is necessary, +as well as translation verification testing.</p> +<H4><a name="data_formatting">Data formatting</a></H4> +<p><b>Numbers, dates, times, currencies</b> +<br /> +The Java library includes classes that handle the necessary formatting for numbers + (decimal separator, thousands separator, grouping), dates (MDY, DMY, first day + of work week), times (12- or 24-hour format, separator), and currencies (local + symbol, shown as suffix or prefix, leading separator or none).</p> +<p> +<b>Phone numbers, postal addresses</b> +<br /> +These are more subtle and less common text +translation concerns, but still noteworthy. +Many applications simply allow free-format +entry of phone numbers since there are so +many local variations. Postal addresses are +straightforward: Adding a "State/Province" +field and allowing for multiple address lines +is generally sufficient.</p> +<H4><a name="data_regional">Regional and personal substitutions</a></H4> +<p><b>Honorifics and personal titles</b> +<br /> +Though less common in the United States, the proper enablement + of honorifics (Mr., Mrs., Dr.) is considered absolutely necessary elsewhere to avoid a + serious breach of etiquette.</p> +<p> +<b>Measurements</b> +<br /> +These are less frequently encountered. This +involves substitution of measurement indications +with corresponding conversion (for example, miles +versus kilometers). In many cases, users +will need either simultaneous display of +a measure in different units, or an easy +way of toggling between them.</p> +<H4><a name="data_multimedia">Multimedia considerations</a></H4> +<p>In general, products should select regionally + neutral sounds, colors, graphics, and icons.</p> +<p>This means no Homer Simpson "D'oh!" sound associated with +error messages. If you're thinking that +no serious development organization would +do such a thing, consider an icon that is +typical of those that are proposed and rejected:</p> +<p> +<IMG src="images/route66.jpg" width="39" height="39" alt="Route 66 icon" /> +</p> +<p>The developer wanted to convey a metaphor for "IP router" by using a symbol harkening back to a national highway that traversed the United States from Chicago to Los Angeles, called <A href="http://www.national66.org/66hstry.html">Route 66</A>. Most Americans would find this metaphor obtuse; imagine the confusion of the hapless non-US user.</p> +<p>Similarly, the image below may be intuitive to many North American users: +<p> +<IMG src="images/mailbox.jpg" width="85" height="95" alt="Mailbox icon" /> +</p> + <p>But in recognition studies, others from outside +the United States have guessed that this +is a birdhouse. This is the more +universally accepted image for mail:</p> +<p> +<IMG src="images/envelope.jpg" width="23" height="23" alt="Envelope icon" /> +</p> +<p>To avoid confusing and potentially offensive visuals, the best course is to engage professional graphic artists who are aware of cultural issues.</p> +<H3><a name="steps">Internationalization steps</a></H3> +<p>Now let's turn to the actual steps for internationalizing your Eclipse plug-in:</p> +<ol> +<li> +<a href="#step1">Move translatable strings into *.properties + files</a> +</li> +<li> +<a href="#step2">Separate presentation-dependent parameters</a> +</li> +<li> +<a href="#step3">Use proper locale-sensitive data formatting, + substitutions APIs</a> +</li> +<li> +<a href="#step4">Test in domestic language</a> +</li> +<li> +<a href="#step5">Create initial translated plug-in fragment</a> +</li> +<li> +<a href="#step6">Prepare and send domestic language materials + for translation</a> +</li> +<li> +<a href="#step7">Repackage and validate translated materials</a> +</li> +<li> +<a href="#step8">Deploy fragments</a> +</li> +</ol> +<p>We'll discuss each of these steps in detail.</p> +<H4><a name="step1">Step 1. Move translatable strings into *.properties +files</a></H4> +<p>Fortunately, Eclipse's Java Development Tooling provides considerable help to properly separate translatable strings. The <b>Source > Find Strings to Externalize</b> menu choice displays the <b>Externalize Strings</b> wizard. This wizard will lead you through +the steps to locate hardcoded strings in +your code, classify them as translatable +or not, then modify the code to use a resource +bundle where appropriate.</p> +<p>We'll introduce the <b>Externalize Strings</b> wizard with an example, + the canonical "Hello World" <i>before</i> using the wizard:</p> +<a name="c3"><b>Listing 3. Hello world, before translation</b></a><table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#CCCCCC"> +<tr><td><pre><code> package com.jumpstart.nls.example.helloworld; + public class HelloWorld { + static public void main(String[] args) { + System.out.println("Copyright (c) IBM Corp. 2002."); + System.out.println("Hello."); + System.out.println("How are you?"); + System.out.println("Goodbye."); + } +} +</code></pre></td></tr> +</table> +<p>Selecting <CODE>HelloWorld.java</CODE> and then <b>Source > Externalize Strings</b> will display the wizard shown in Figure 1:</p> +<p> +<a name="f2"><b>Figure 1. Externalize Strings wizard</b></a><br /><IMG src="images/image2.jpg" width="576" height="430" alt="Externalize Strings wizard" /> +</p> +<p>By selecting an entry from the table and +then one of the pushbuttons to the + right, you can mark the strings as belonging +to one of three cases:</p> +<ul> +<li> +<IMG src="images/translate.jpg" width="10" height="10" alt="Translate" /> + Translate +<br /> +Action: An entry is added in the properties files; the auto-generated key and + access code is substituted in the code for the original string. The string used + to specify the key is marked as non-translatable with a comment marker, such as +"<code>// $NON-NLS-1$</code>"<br /> +<br /> +</li> +<li> +<IMG src="images/never.jpg" width="12" height="11" alt="Never translate" /> + Never Translate<br /> +Action: The string is marked as non-translatable with a comment marker. The + <b>Externalize Strings</b> wizard will not flag it as untranslated in subsequent + executions.<br /> +<br /> +</li> +<li> +<IMG src="images/skip.jpg" width="11" height="11" alt="Skip" /> +Skip<br /> +Action: Nothing is modified. Subsequent executions of the <b>Externalize Strings</b> wizard will flag the string as potentially translatable.</li> +</ul> +The trailing number in the <code>// $NON-NLS-1$</code> comment marker indicates which + string is not to be translated in the case where are there are several strings + on a single line. For example: + <blockquote> +<code>x.foo("Date", "TOD", "Time"); // $NON-NLS-2$</code> +</blockquote> + <p>Here the middle parameter is flagged as non-NLS. The other two are skipped.</p> +<p>Returning to our example, note that the total number of strings for each category + is summarized below the list. The key names of the externalized strings are + auto-generated based on the string value, but they can be renamed directly in + the table. In addition, an optional prefix can be specified (<code>S_</code> + in the example below).</p> +<p> +<a name="f6"><b>Figure 2. Externalize Strings wizard</b></a><br /><IMG src="images/image6.jpg" width="576" height="434" alt="Externalize Strings wizard" /> +</p> +<p> +<i>Hint</i>: Clicking the icon in the first column of a given row will advance + to the next choice: Translate, Never Translate, or Skip.</p> +<p>Now that we've identified what strings are translatable, continue to the next + step to choose how they will be externalized. Here's the page displayed after + selecting <b>Next</b>; the <b>Property file name</b> and resource bundle accessor + <b>Class name</b> were modified to more specific values than the defaults:</p> +<p> +<a name="f7"><b>Figure 3. Externalize Strings wizard</b></a><br /><IMG src="images/image7.jpg" width="576" height="434" alt="Externalize Strings wizard" /> +</p> +<p>The resource bundle accessor class will contain code to load the properties + file and a static method to fetch strings from the file. The wizard will generate + this class, or you can specify your own existing alternative implementation. + In the latter case, you may want to uncheck the <b>Use default substitution + choice</b> and specify an alternative code pattern for retrieving externalized + strings. If the accessor class is outside of the package (for example, a centralized + resource bundle accessor class), you can optionally specify that you want to + <b>Add [an] import declaration</b> to the underlying source.</p> +<p>The <b>Externalize Strings</b> wizard uses the JDT Refactoring framework, so + the next two pages should look familiar. First, a list of warnings:</p> +<p> +<a name="f8"><b>Figure 4. Externalize Strings wizard</b></a><br /><IMG src="images/image8.jpg" width="576" height="357" alt="Externalize Strings wizard" /> +</p> +<p>And finally a side-by-side presentation of the proposed changes:</p> +<p> +<a name="f9"><b>Figure 5. Externalize Strings wizard</b></a><br /><IMG src="images/image9.jpg" width="576" height="356" alt="Externalize Strings wizard" /> +</p> +<p>Once you select <b>Finish</b>, the wizard performs the source code modifications, + creates the resource bundle accessor class, and generates the initial properties + file. Here is the code for the standard resource bundle accessor class:</p> +<a name="c4"><b>Listing 4. Standard resource bundle accessor class</b></a><table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#CCCCCC"> +<tr><td><pre><code> package com.jumpstart.nls.example.helloworld; + import java.util.MissingResourceException; + import java.util.ResourceBundle; + + public class HelloWorldMessages { + + private static final String BUNDLE_NAME = + "com.jumpstart.nls.example.helloworld.HelloWorld"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE = + ResourceBundle.getBundle(BUNDLE_NAME); + + private HelloWorldMessages() {} + + public static String getString(String key) { + try { + return RESOURCE_BUNDLE.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!"; + } + } + } +</code></pre></td></tr> +</table> +<p>The only variation in this generated code +is the value assigned to the static final, +<code>BUNDLE_NAME</code>. Before we continue to the next +step, below are some noteworthy guidelines +contributed by Erich Gamma and Thomas Mäder +of the JDT team.</p> +<H4><a name="gln">Guidelines for managing resource bundles and properties files</a></H4> +<p>These guidelines are designed to:</p> +<ul> +<li>Reduce the number of NLS errors, in other words, the values of externalized strings + that are not found at runtime</li> +<li>Enable cross-referencing between the keys + referenced in the code and the keys defined + in the properties file</li> +<li>Simplify the management of the externalized strings. Using a centralized + property file can result in frequent change conflicts. In addition, it requires + the use of prefixes to make keys unique and complicates the management of + the keys.</li> +</ul> +<p>To achieve these goals, we propose the following guidelines: </p> +<ol> +<li> +<b>Use a properties file per package, and qualify +the keys by class name</b> +<p>For example, all the strings for the JDT +search component are in SearchMessages.properties, +with key/value pairs like:<br /> +<br /> +<code>SearchPage.expression.pattern=(? = any character, * = any string) <BR> + ShowTypeHierarchyAction.selectionDialog.title=Show in Type Hierarchy </code> +</p> +</li> +<li> +<b>Use a dedicated static resource bundle accessor +class </b> +<p>Let the <b>Externalize Strings</b> wizard generate this class. It should be +named like the properties file. So in our +example, it would be called SearchMessages. +When you need to create formatted strings, +add the convenience methods to the bundle +accessor class. For example:</p> +<a name="c5"><b>Listing 5. Static resource bundle accessor class</b></a><table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#CCCCCC"> +<tr><td><pre><code> public static String getFormattedString(String key, Object arg) { + String format= null; + try { + format= RESOURCE_BUNDLE.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$ + } + if (arg == null) + arg= ""; //$NON-NLS-1$ + return MessageFormat.format(format, new Object[] { arg }); + } + public static String getFormattedString (String key, String[] args) { + return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args); + } +</code></pre></td></tr> +</table> +<br /> +</li> +<li> +<b>Do not use computed keys</b> +<p>There is no easy way to correlate a computed +key in the code with the key in the properties file. In particular +it is almost impossible to determine whether a key is no longer in use.</p> +</li> +<li> +<b>The convention for the key name is <classname>.<qualifier></b> +<p>Example: PackageExplorerPart.title</p> +</li> +</ol> +<H4><a name="step2">Step 2. Separate presentation-dependent parameters</a></H4> +<p>Not all externalized text is simply words and phrases that will be translated to a target language. Some are more specifically related to your plug-in's implementation. Examples include properties, preferences, and default dialog settings.</p> +<p>Here are a few specific examples that might +find their way into a properties file:</p> +<ul> +<li>Size or layout constraints. For example, + the appropriate width of a non-resizable + table column</li> + <li>Default fonts that are dependent on the language or operating system. A good + default font for Latin-1 languages is an invalid choice for DBCS languages.</li> +</ul> +<p>For those plug-ins that subclass from <a href="http://eclipse.org/documentation/html/plugins/org.eclipse.platform.doc.isv/doc/reference/api/org/eclipse/ui/plugin/AbstractUIPlugin.html">AbstractUIPlugin</a>, NL-related parameters can also be found +in its <a href="http://eclipse.org/documentation/html/plugins/org.eclipse.platform.doc.isv/doc/guide/preferences_prefs.htm">default + preference</a> stores (pref_store.ini) and <a href="http://eclipse.org/documentation/html/plugins/org.eclipse.platform.doc.isv/doc/guide/dialogs_settings.htm">dialog + settings </a>(dialog_settings.xml). The Eclipse Workbench itself does not use + default preference stores, opting instead to store defaults in properties files + and then initialize them via AbstractUIPlugin's <code>initializeDefaultPreferences(IPreferenceStore)</code> method.</p> +<H4><a name="step3">Step 3. Use proper locale-sensitive data formatting, substitutions APIs</a></H4> +<p>Please refer to the detailed coverage in the <a href="http://java.sun.com/docs/books/tutorial/i18n/intro/index.html">Java Tutorial: Internationalization</a> trail.</p> +<H4><a name="step4">Step 4. Test in domestic language</a></H4> +<p>Testing the readiness of a product for translation is non-trivial and beyond +the scope of this article. However, the follow-on article <a href="http://eclipse.org/articles/Article-TVT/how2TestI18n.html">How to Test your Internationalized Eclipse Plug-in</a> presents strategies for validating the NL-sensitive aspects of your product.</p> +<H4><a name="step5">Step 5. Create initial translated plug-in fragment</a></H4> +<p>At this point, we could simply copy our domestic language property files to +similarly named files with locale-specific suffixes (for example, MyMessages_xx.properties, +where xx is the language), and move to step 6, <a href="#step6">Prepare and send domestic language materials for translation</a>. In this case, the product is delivered with its code and whatever languages it supports as a single install.</p> +<p>However, this approach has a few drawbacks. +Firstly, the code and its national language +resources are intermingled in the same directory +/ JAR file. If the translation lags the code +delivery, the plug-in JAR file must be updated, +despite the fact that the underlying code +is unchanged. Secondly, files other than +property files are not inherently locale-sensitive, +so they must be segregated to separate directories +for each language (for example, HTML, XML, images).</p> +<p>To address these issues, the Eclipse Platform +introduces the notion of another reusable +component that complements plug-ins, called +a <i>plug-in fragment</i>. A plug-in fragment provides +additional functionality to its target plug-in. +At runtime, these plug-in contributions +are merged along with all dependent fragments. +These contributions can include code contributions +and contributions of resources associated +with a plug-in, like property and HTML files. +In other words, the plug-in has access to +the fragment's contents via the plug-in's classloader.</p> +<H4><a name="g1">How and why to use fragments to provide the translatable information</a></H4> +<p>A plug-in fragment is an ideal way to distribute +Eclipse-translated information including +HTML, XML, INI, and bitmap files. Delivering +translations in a non-intrusive way, the +Eclipse Platform translations are packaged +in fragment JAR files and are added to existing +Eclipse installations without changing or +modifying any of the original runtime elements. +This leads to the notion of a <i>language +pack</i>.</p> +<p>The Eclipse Platform merges plug-in fragments +in a way that the runtime elements in the +fragment augment the original targeted plug-in. +The target plug-in is not moved, removed, +or modified in any way. Since the fragment's +resources are located by the classloader, the plug-in developer +has no need to know whether resources are +loaded from the plug-in's JAR file or +one of its fragments' JAR files.</p> +<H4><a name="g2">Eclipse Language Pack JAR</a></H4> +<p>The Java language supports the notion of a language pack +with the resource bundle facility. The Java +resource bundles do not require modification +of the application code to support another +language. The *.properties file namespace +avoids collisions through the following naming +convention: <i>basename_lang_region_variant</i>. At runtime, the <a href="http://java.sun.com/j2se/1.3/docs/api/java/util/class-use/ResourceBundle.html">ResourceBundle</a> facility finds the appropriate properties +file for the current locale.</p> +<p>The approach to deploying files such as HTML +and XML files in fragments is slightly different +than Java resource bundles in that the Eclipse +fragment uses a directory structure to sort +out the different language versions.</p> +<p> +<b>Example fragment contents</b> +<br /> +The plug-ins and the plug-in fragments reside +in separate subdirectories found immediately +under the eclipse subdirectory. Looking at +our example fragment, as deployed on a German +system, we see an \nl folder, fragment.xml +and an nl1.jar file.</p> +<p> +<a name="f20"><b>Figure 6. Fragments subdirectories</b></a><br /><IMG src="images/image20.jpg" width="504" height="278" border="0" alt="" /> +</p> +<p>Typically, translated *.properties files +are suffixed according to the resource bundle +rules and deployed in JAR files. In contrast, +when a view needs an input file type whose +name is not locale-sensitive like resource +bundles (such as *.xml), we define a subdirectory +structure for each language version of the +file. The de subdirectory above +is one such example, where de = German.</p> +<p> +<b>Fragment manifest</b> +<br /> +Each plug-in folder can optionally contain a fragment +manifest file, fragment.xml. The manifest +file describes the plug-in fragment, and +is almost identical to the plug-in manifest +(plugin.xml), with the following two exceptions:</p> +<ul> +<li>The <code>class</code> attribute is gone since + fragments do not have a plug-in class. They + just follow their target's specification.</li> +<li>There are no dependencies because the fragments have the same dependencies + as their target plug-in.</li> +</ul> +<p>Manifests used to describe a national language +fragment are typically quite simple, specifying +only the <code><fragment></code> and <code><runtime>/<library></code> tags. Here's the example +fragment manifest file in its entirety:</p> +<a name="c6"><b>Listing 6. Fragment manifest file</b></a><table border="1" cellspacing="0" cellpadding="5" width="100%" bgcolor="#CCCCCC"> +<tr><td><pre><code><?xml version="1.0" encoding="UTF-8"?> +<fragment + id="com.jumpstart.nls.example.helloworld.nl1" + name="NLS Example Plugin NL Support" + version="1.0.0" + provider-name="IBM" + plugin-id="com.jumpstart.nls.example" + plugin-version="1.0.0"> +<runtime> + <library name="nl1.jar" type="resource"/> + <library name="$nl$/"/> +</runtime> +</fragment> +</code></pre></td></tr> +</table> +<p>The <code><fragment></code> tag attributes are:</p> +<ul> +<li> +<b> +<code>name</code> +</b> -- User-displayable name for the extension.</li> +<li> +<b> +<code>id</code> +</b> -- Identifier for this fragment configuration. +Used to uniquely identify this fragment instance.</li> +<li> +<b> +<code>plugin-id</code> +</b> -- Reference to the target extension point. This plug-in fragment merges with this target extension.</li> +<li> +<b> +<code>plugin-version</code> +</b> -- Version of the fragment plug-in. </li> +<li> +<b> +<code>version</code> +</b> -- Version specification in major.minor.service +format.</li> + <li><B><CODE>type</CODE></B> -- The default is '"code". Specifying "resource" indicates the library includes resource files and no code. This improves overall performance significantly because resource-only libraries are skipped when loading code.</li> + </ul> +<p>The <code><runtime></code> section contains a definition of one or more libraries that make up the +plug-in fragment runtime. The referenced libraries are used by the platform +execution mechanisms where the plug-in loads, merges, and executes the +correct code required by the plug-in. The <CODE>name</CODE> attribute accepts a library name ("nl1.jar" above) or directory +containing resources. A directory reference must contain a trailing path +separator. Optionally, the specification may include a substitution variable. +In the example above, the second library includes a variable substitution +<CODE>$nl$</CODE> based on the locale; it is used above to add a language/region specific +folder to the library search path (e.g., a locale of "it" = Italy, +"fr" = France, or "de" = Germany, etc. would add the +corresponding plug-in subdirectory <CODE>it/</CODE>, <CODE>fr/</CODE>, or <CODE>de/</CODE> to the list of searched paths). The value of the <CODE>nl</CODE>, <CODE>os</CODE>, <CODE>ws</CODE>, and <CODE>arch</CODE> substitutions variables can be displayed and modified on the <B>Window > Preferences > Plug-in Development > Target Environment</B> page. The <CODE>nl</CODE> substitution variable is used in those cases where it is not possible or practical to suffix files with the locale name.</p> +<p> +<b>Building a fragment</b> +<br /> +The Eclipse Workbench comes with a tool used +in plug-in development: <i>the Plug-in Development Environment +(PDE)</i>. The PDE contains support for developing +plug-in fragments.</p> +<p>Let's now examine how to build a fragment +for national language translations using +the PDE. There is no practical limit to the +number of languages in a given fragment. +The fragment then is the basis of our "Language +Pack" containing one or more language +translations. However, in this example, we'll +confine our language pack to the German translation.</p> +<p>To build a plug-in fragment, start the New +Project wizard (<b>File</b> > <b>New</b> > <b>Project...</b>), select the <b>Plug-in Development</b> category, then <b>Fragment Project</b> type. On the first page of the New Fragment +Wizard, type the project name. Keep in mind +that the project name will also become the +fragment ID. For example, starting a project +adding national language support to the HelloWorld +example, we would name our project "com.jumpstart.nls.example.helloworld.nl1". +The trailing ".nl1" is not required, +but does help distinguish fragments that +represent "language packs" from +fragments that add additional code and functionality.</p> +<p> +<a name="f7"><b>Figure 7. Starting a fragment project</b></a><br /><IMG src="images/fraggen1.jpg" border="0" width="500" height="500" alt="Starting a fragment project" /> +</p> +<p>Press <b>Next</b>. We see the default values for the project's +source folder and runtime library on the +second page:</p> +<p> +<a name="f8"><b>Figure 8. Defining fragment folders</b></a><br /><IMG src="images/fraggen2.jpg" border="0" width="500" height="500" alt="Defining fragment folders" /> +</p> +<p>These values seem reasonable, so pressing +<b>Next</b> again, we arrive at the "Fragment Code +Generators" page. Select the second +radio button to indicate we want to create +the fragment manifest file from a template, +then select the <b>Default Fragment Generator</b> wizard from the list.</p> +<p> +<a name="f9"><b>Figure 9. Selecting the default wizard</b></a><br /><IMG src="images/fraggen3.jpg" border="0" width="500" height="500" alt="Selecting the default wizard" /> +</p> +<p>After pressing <b>Next</b>, we see the "Simple Fragment Content" +page. This page has two entries used to target +our fragment on an existing plug-in. We must +supply the plug-in target id and version. +We can use the <b>Browse</b> button to select the plug-in that we want +to extend.</p> +<p> +<a name="f10"><b>Figure 10. Targeting the fragment</b></a><br /><IMG src="images/image23.jpg" border="0" width="500" height="500" alt="Targeting the fragment" /> +</p> +<p>Now let's proceed to the fragment manifest editor, which is similar to the plug-in manifest editor in that +it is a multi-page editor with Overview, +Runtime, Extensions, Extension Points, and +Source pages.</p> +<p> +<a name="f11"><b>Figure 11. Fragment manifest editor</b></a><br /><IMG src="images/image24.jpg" border="0" width="518" height="492" alt="Fragment manifest editor" /> +</p> +<p>Notice the tabbed pages corresponding to +sections of the fragment xml file. We will +be using the <b>Runtime</b> page to point the fragment +classpath at the libraries containing our +translations.</p> +<p>We specified the nl1.jar in the new fragment wizard so that library is already + included in the classpath of this fragment. What is missing at this point is + the inclusion of the locale-specific folder. You can add new runtime libraries + by selecting <b>More</b> from the Runtime Libraries section of the Overview + page, or by turning to the Runtime page, selecting <b>New...</b>, then entering + $nl$/.</p> +<p> +<a name="f12"><b>Figure 12. Fragment runtime information</b></a><br /><IMG src="images/image25.jpg" border="0" width="502" height="317" alt="Fragment runtime information" /> +</p> +<p>Taking a look at the Source page of the fragment +manifest editor, we see that the PDE generates +all the XML necessary to describe our plug-in +fragment.</p> +<p> +<a name="f13"><b>Figure 13. Fragment source</b></a><br /><IMG src="images/image26.jpg" border="0" width="444" height="374" alt="Fragment source" /> +</p> +<H4><a name="step6">Step 6. Prepare and send domestic language materials for translation</a></H4> +<p><br /> +Producing correct translations requires specific skills, which you must purchase. (Unfortunately, your four years +of high school German classes do not qualify you!) There are many +companies that will gladly produce professional-quality translations.</p> +<p>For the Eclipse Platform, this step was accomplished +in two phases. The first phase involved sending +all the externalized text to a translation +center. This first-pass translation is done +"out of context." The translator +does not see the running product, nor do +they have product-specific experience. They +have tools at their disposal to help speed +the translations and assure consistency, +but ultimately they rely on translation testers +to validate the running product in the target +language (the second phase).</p> +<p>The risk and consequences of performing an +out-of-context translation, the results of +which are sometimes quite amusing, are +discussed in the follow-on article <a href="http://eclipse.org/articles/Article-TVT/how2TestI18n.html">How To Test your Internationalized Eclipse Plug-in</a>.</p> +<H4><a name="step7">Step 7. Repackage and validate translated materials</a></H4> +<p>Now having the translated files, we reassemble +them in their appropriate directories/JAR +files as described in step 5, <a href="#step5">Create initial translated plug-in fragment</a>. The NL1 Fragment folder contains +language versions of the plugin.properties +file. After translating the HelloWorld.properties +file to German, we rename it to HelloWorld_de.properties +and store it in the NL1 Fragment +source folder. Note that the nl\de (German) +folder is new and is created manually, not +by the PDE. These language-specific folders +segregate the versions of non-properties +files (such as hello.xml shown +below) as we add translations over time.</p> +<p> +<a name="f14"><b>Figure 14. Reassembled fragment project</b></a><br /><IMG src="images/nav3.jpg" border="0" width="326" height="323" alt="Reassembled fragment project" /> +</p> +<p>Be aware that the translated properties files will very likely contain accented + characters that are codepage dependent, so properties files must be converted + to the ISO 8859-1 codepage expected by the <a href="http://java.sun.com/j2se/1.3/docs/api/java/util/PropertyResourceBundle.html">PropertyResourceBundle</a> + class. The native2ascii utility will handle codepage conversions and insert + any necessary Unicode escapes.</p> +<p>The term <i>Unicode escape</i> deserves a bit more explanation. +The native2ascii conversion utility, included +with the Java SDK, accepts a source encoding +and produces output encoded in ISO 8859-1, +plus it transforms characters outside this +codepage to the notation known as Unicode +escapes. This notation is \udddd, where dddd += the codepoint of the desired character +in the Unicode codepage.</p> +<p>Here's an example. Consider +the French phrase "Son père est +allé à l'hôtel" +(his father went to the hotel). This contains +four accented characters that +are not part of the Latin-1 codepage. Transforming +this phrase with the native2ascii utility +yields: +<br /> +<br /> +<code>Son p\u00e8re est all\u00e9 \u00e0 h\u00f4tel</code> +</p> +<p>There are no longer any accented characters, and the resulting string is +composed entirely of characters having codepoints that are found in ISO +8859-1. But what are the <code>\u00e8</code>, +<code>\u00e9</code>, <code>\u00e0</code>, and <code>\u00f4</code> that were substituted? +They are the Unicode codepoints of the accented +characters in \udddd notation.</p> +<p>A little caveat when using the native2ascii utility: +It assumes that the source encoding is the +same as the active codepage of the machine +that executes it. However, translators typically +save the translations in their default country +codepage, and this codepage is different +in each country and each operating system. +So the person responsible for integrating +the translations will need to either (a) +know in which codepage that the translators +save their files, or (b) ask that they save +it in a common codepage. You can specify +the source encoding when invoking native2ascii +with the<code>-encoding</code> parameter.</p> +<p> <i>Tip:</i> If you are uncertain of the source codepage, you can spot-check + the output of native2ascii against <a href="#unicode_table">Unicode codepoints + of common accented Latin characters</a> table later in this article. If you + find \udddd notations in your converted files that are not in this table (such + as \u0205), it is likely that you specified the incorrect source encoding. There + is no equivalent spotcheck for DBCS languages, where practically all the characters + in the converted files are Unicode escapes. You simply have to be careful and + validate against the running product.</p> +<p>Testing the translation merits its own article. The follow-on article <a href="http://eclipse.org/articles/Article-TVT/how2TestI18n.html">How to Test your Internationalized Eclipse Plug-in</a> describes the process and lessons learned during the recent translation verification of the Eclipse Platform, and includes a view (an Eclipse plug-in, of course!) for performing a quick check of property file translations.</p> +<H4><a name="step8">Step 8. Deploy fragments</a></H4> +<p>Fragment sources, similar to plug-in sources, +may be packaged in a JAR file. Using the +PDE to generate the JAR package, select the +"fragment.xml" file and choose +"<b>Create Fragment JARs...</b>" from the pop-up menu. A wizard will guide you in creating a build script to produce all the required JARs for your fragment. If your <CODE>fragment.xml</CODE> file includes translatable strings, separate them into a <CODE>plugin.properties</CODE> file (just as you would for a plugin.xml file, i.e., there is no such thing as a "fragment.properties" file). This works because fragments are an extension of a plug-in and therefore inherits it dependencies, including its <CODE>plugin.properties</CODE> file values.</p> +<p> +<a name="f15"><b>Figure 15. Selecting the fragment.xml file</b></a><br /><IMG src="images/image28.jpg" border="0" width="320" height="241" alt="Selecting the fragment.xml file" /> +</p> +<p>To deploy this example fragment, copy the fragment.xml, the \nl directory, +and JAR to the com.jumpstart.example.helloworld.nl1 subdirectory in the +plugins directory. This completes our example and the steps for internationalization.</p> +<H3><a name="summary">Summary</a></H3> +<p>Enabling your product for the world market simply makes economic sense. And + the steps above show that the process is relatively straightforward. Now here's + that quiz we mentioned in the introduction:</p> +<blockquote>True or False: The majority of IBM's worldwide +software sales revenue is within the United +States.</blockquote> +<p> +False. Indeed, more than 50% of IBM software revenue +comes from outside the United States.</p> +<p>Fortunately, +those developers with products based on the Eclipse platform +benefit from having ready translations of +the base product. All that is left is to +follow the clear steps outlined in this article +to open your Eclipse-based product to a worldwide +market!</p> +<H4><a name="glossary">Glossary</a></H4> +<p> +<i>Codepoint</i> +<br /> + Characters can be represented by one or more bytes of information. Codepoints + are the hexadecimal values assigned to each graphic character.</p> +<p> +<i>Codepage</i> +<br /> + A codepage is a specification of code points for each graphic character in + a set, or in a collection of graphic character sets. Within a given codepage, + a codepoint can have only one specific meaning. You can display the active + codepage on the Windows® operating system with the CHCP command (only one codepage is active at any given moment).</p> +<p> +<i>Encoding</i> +<br /> + The codepage associated with a given piece of data. A file is said to be "encoded" + in a given code page; for example, Notepad will encode its data in code page + 437 on a US-English machine by default. The <b>Save As</b> dialog allows the + user to select several other possible encodings, Unicode and UTF-8 most notable + among them.</p> +<p> +<i>Internationalization (sometimes abbreviated "I18N")</i> +<br /> + Internationalization refers to the process of developing programs without prior + knowledge of the language, cultural data, or character encoding schemes they + are expected to handle. In system terms, it refers to the provision of interfaces + that enable internationalized programs to change their behavior at run time + for specific language operation.</p> +<p> +<i>Single-Byte Coded Character Set (SBCS)</i> +<br /> + In a single-byte coded character set, a one-byte codepoint represents + each character in the set. Typically, SBCS is used to represent the characters + of the English language, the European languages, the Cyrillic languages, the + Arabic language, and the Hebrew language, to name a few.</p> +<p> +<i>Double-Byte Coded Character Set (DBCS)</i> +<br /> + In a double-byte coded character set (DBCS), a two-byte codepoint represents + each character in the set. Languages that are ideographic in nature, such as + Japanese, Chinese, and Korean, have more characters than can be represented + internally by 256 code points and thus require double-byte coded character sets.</p> +<p> +<i>Localization (sometimes abbreviated "L10N")</i> +<br /> + Localization refers to the process of establishing information within a computer + system specific to each supported language, cultural data, and coded character + set combination.</p> +<p> +<i>Mixed-Byte Character Set</i> +<br /> + A mixed-byte coded character set is a set of characters containing both single-byte + characters and double-byte characters. On the MBCS, each byte of data must be + examined to see if it is the first byte of a double-byte or single-byte character. + If the byte is in a certain range (greater than X'80', for example), then it + is the first byte of a double-byte character.</p> +<p> +<i>NLS</i> +<br /> + National Language Support.</p> +<p> +<i>Unicode</i> +<br /> + Directly from <A href="http://www.unicode.org">http://www.unicode.org</A>: "Unicode + provides a unique number for every character, no matter what the platform, no + matter what the program, no matter what the language." +<br />Note: While it is true that Java text manipulation classes are Unicode-centric, + this is often not the case for data stored outside of your program's auspices. + Java programmers must take into consideration the data encoding by performing + local codepage-to-Unicode transformations where necessary.</p> +<H4><a name="unicode_table">Unicode codepoints of common accented Latin characters</a></H4> +<table width="39%" border="1" cellpadding="0" cellspacing="0"> + + + <tr bgcolor="#CCCCCC"> + <td colspan="2"> + <div align="center"><b>Characters</b></div> + </td> + </tr> + <tr> + <td width="48%">\u00e0 </td> + <td width="52%">a grave</td> + </tr> + <tr> + <td width="48%">\u00e1</td> + <td width="52%"> a acute</td> + </tr> + <tr> + <td width="48%">\u00c0 </td> + <td width="52%">A grave</td> + </tr> + <tr> + <td width="48%">\u00c1 </td> + <td width="52%">A acute</td> + </tr> + <tr> + <td width="48%">\u00c2 </td> + <td width="52%">A circumflex</td> + </tr> + <tr> + <td width="48%">\u00e2</td> + <td width="52%">a circumflex</td> + </tr> + <tr> + <td width="48%">\u00c3 </td> + <td width="52%">A tilde</td> + </tr> + <tr> + <td width="48%">\u00e4 </td> + <td width="52%">a dieresis</td> + </tr> + <tr> + <td width="48%">\u00c4 </td> + <td width="52%">A dieresis</td> + </tr> + <tr> + <td width="48%">\u00e8 </td> + <td width="52%">e grave</td> + </tr> + <tr> + <td width="48%">\u00c8 </td> + <td width="52%">E grave</td> + </tr> + <tr> + <td width="48%">\u00e9 </td> + <td width="52%">e acute</td> + </tr> + <tr> + <td width="48%">\u00c9 </td> + <td width="52%">E acute</td> + </tr> + <tr> + <td width="48%">\u00ea </td> + <td width="52%">e circumflex</td> + </tr> + <tr> + <td width="48%">\u00eb </td> + <td width="52%">e dieresis</td> + </tr> + <tr> + <td width="48%">\u00cb </td> + <td width="52%">E dieresis</td> + </tr> + <tr> + <td width="48%">\u00ea </td> + <td width="52%">e circumflex</td> + </tr> + <tr> + <td width="48%">\u00ca </td> + <td width="52%">E circumflex</td> + </tr> + <tr> + <td width="48%">\u00ef </td> + <td width="52%">i dieresis</td> + </tr> + <tr> + <td width="48%">\u00ec</td> + <td width="52%"> i grave</td> + </tr> + <tr> + <td width="48%">\u00ed </td> + <td width="52%">i acute</td> + </tr> + <tr> + <td width="48%">\u00cc</td> + <td width="52%"> I grave</td> + </tr> + <tr> + <td width="48%">\u00cd </td> + <td width="52%">I acute</td> + </tr> + <tr> + <td width="48%">\u00ee </td> + <td width="52%">i circumflex</td> + </tr> + <tr> + <td width="48%">\u00ce </td> + <td width="52%">I circumflex</td> + </tr> + <tr> + <td width="48%">\u00f6 </td> + <td width="52%">o dieresis</td> + </tr> + <tr> + <td width="48%">\u00d6 </td> + <td width="52%">O dieresis</td> + </tr> + <tr> + <td width="48%">\u00e3 </td> + <td width="52%">a tilde</td> + </tr> + <tr> + <td width="48%">\u00f4 </td> + <td width="52%">o circumflex</td> + </tr> + <tr> + <td width="48%">\u00d4 </td> + <td width="52%">O circumflex</td> + </tr> + <tr> + <td width="48%">\u00f2 </td> + <td width="52%">o grave</td> + </tr> + <tr> + <td width="48%">\u00d2 </td> + <td width="52%">O grave</td> + </tr> + <tr> + <td width="48%">\u00f3 </td> + <td width="52%">o acute</td> + </tr> + <tr> + <td width="48%">\u00d3 </td> + <td width="52%">O acute</td> + </tr> + <tr> + <td width="48%">\u00f5 </td> + <td width="52%">o tilde</td> + </tr> + <tr> + <td width="48%">\u00d5 </td> + <td width="52%">O tilde</td> + </tr> + <tr> + <td width="48%">\u00f1 </td> + <td width="52%">n tilde</td> + </tr> + <tr> + <td width="48%">\u00d1 </td> + <td width="52%">N tilde</td> + </tr> + <tr> + <td width="48%">\u00f9 </td> + <td width="52%">u grave</td> + </tr> + <tr> + <td width="48%">\u00d9 </td> + <td width="52%">U grave</td> + </tr> + <tr> + <td width="48%">\u00fa </td> + <td width="52%">u acute</td> + </tr> + <tr> + <td width="48%">\u00da </td> + <td width="52%">U acute</td> + </tr> + <tr> + <td width="48%">\u00fb </td> + <td width="52%">u circumflex</td> + </tr> + <tr> + <td width="48%">\u00db </td> + <td width="52%">U circumflex</td> + </tr> + <tr> + <td width="48%">\u00fc </td> + <td width="52%">u dieresis</td> + </tr> + <tr> + <td width="48%">\u00dc </td> + <td width="52%">U dieresis</td> + </tr> + <tr> + <td width="48%">\u00df </td> + <td width="52%">s sharp</td> + </tr> + <tr bgcolor="#CCCCCC"> + <td colspan="2"> + <div align="center"><b>Special symbols</b></div> + </td> + </tr> + <tr> + <td width="48%">\u00ba </td> + <td width="52%">masculine ordinal indicator</td> + </tr> + <tr> + <td width="48%">\u00a7 </td> + <td width="52%">section sign</td> + </tr> + <tr> + <td width="48%">\u00aa </td> + <td width="52%">feminine ordinal indicator</td> + </tr> + <tr> + <td width="48%">\u00ac </td> + <td width="52%">not sign</td> + </tr> + <tr> + <td width="48%">\u00b9 </td> + <td width="52%">1 superscript</td> + </tr> + <tr> + <td width="48%">\u00b2 </td> + <td width="52%">2 superscript</td> + </tr> + <tr> + <td width="48%">\u00b3 </td> + <td width="52%">3 superscript</td> + </tr> + <tr> + <td width="48%">\u00a3 </td> + <td width="52%">pound sign</td> + </tr> + <tr> + <td width="48%">\u00a2 </td> + <td width="52%">cents sign</td> + </tr> + <tr> + <td width="48%">\u00b0 </td> + <td width="52%">degree sign</td> + </tr> + + +</table> +<h3><A name="authors" />About the authors</A><A name="authors" /><BR><BR> +</A></H3> +<P><A name="authors" /><B>Dan Kehn</B> is a Senior Software Engineer at IBM in + Research Triangle Park, North Carolina. + His + interests in object-oriented programming + go back to 1985, long before it enjoyed + the + acceptance it has today. He has a broad + range + of software experience, having worked + on + development tools like VisualAge for + Smalltalk, + operating system performance and memory + analysis, + and user interface design. Dan worked + as + a consultant for object-oriented development + projects throughout the U.S. as well + as four + years in Europe. His recent interests + include + object-oriented analysis/design, programming + tools, and Web programming with the + WebSphere + Application Server. Last year he joined + the + Eclipse Jumpstart team, whose primary + goal + is to help ISVs to create commercial + offerings + based on the Eclipse Platform. In another + life, Dan authored several articles + about + diverse Smalltalk topics like meta-programming, + team development, and memory analysis. + You + can find them on</A> +<A href="http://www.ibm.com/software/ad/smalltalk/discussion/index.html">Eye on SmallTalk</A>. + +<P><B>Scott Fairbrother</B> works on the Eclipse Jumpstart team at IBM in Research Triangle Park, +North Carolina. He is a software developer with over 20 years of experience. +He has developed object-oriented application frameworks for business process +management. He has written specifications for IBM middleware on Windows +2000 and has also authored on the subject of Microsoft Visual Studio .NET.</P> +<P><A name="authors" /><B>Cam-Thu Le</B> joined IBM in 1983. Cam's experience spans + many aspects of software creation: +development, + testing, and National Language Support +(NLS) + planning and coordination. Cam has +led the + National Language versions of IBM products + to worldwide concurrent general availability, + including the 4690 Point of Sales product + and VisualAge for Smalltalk. Cam joined +the + Eclipse Project last year as the NLS +focal + point. Cam coordinated the building +and testing + of the NL versions of the Eclipse Workbench + and WebSphere Studio Workbench.</A> + + +</BODY> +</html> |