Deploying in Multiple Languages

Introduction

The Curl® Language provides tools to help you deploy Web applications in multiple natural languages. The only languages that are fully tested and supported by the Curl Runtime Environment (RTE) are U.S. English and Japanese. Most languages that read from left to right can be displayed by Curl applets and entered in Curl controls. The applet must request the appropriate font and the font must be available on the system where the applet is running.
There are two approaches to Curl multiple language support. For the parts of your application that consist primarily of text information, where you are using Curl as a markup language as you might use HTML, the best approach is to create alternate versions of the files in each language.
One of the Curl Language's strengths is that you can also use it as a sophisticated object oriented programming language to develop interactive applications. This type of use presents a different translation problem. It is not efficient to duplicate the entire application in each language. You may use a button labeled "Submit" hundreds of times in your application, but you do not want to translate the word "Submit" hundreds of times. The Curl language provides a localization mechanism to help you solve this translation problem.

The Localization Mechanism

The concept of locale is central to multiple-language deployment of Curl applications. The Locale class contains language and country information used to find appropriate language resources for the application. Locale also determines how the applet handles location-specific issues such as formatting dates, and selecting a grouping character for large numbers. The Curl RTE uses the name of the locale to find a translation dictionary.
The host locale is the locale set on the system where the application is running. For example, on Windows systems, you set the machine's locale with the Regional Options tool in the Windows Control Panel. The procedure get-host-locale returns the host locale. In addition, each application can specify a working locale. The procedure get-working-locale returns the working locale, and the procedure set-working-locale changes the working locale.
By default, the working locale is set to the host locale, which allows the applet to use the appropriate locale without further action on your part.
Any Curl application contains text that needs to be translated and text that should be left alone. Text that is part of the user interface, such as error messages and button labels, needs to be translated into the end-user's language. Text strings used internally for purposes such as command identifiers or option values should not be translated. You need to identify the text strings in your applet that should be translated and mark them using one of several expressions provided by the Curl language. See Mark Strings for Translation for information on these markup expressions.
Once you have marked the strings that need to be translated, you can use a script called extract-messages.xcurl to process the source file and write out a file containing the strings you have marked for translation, with XML markup that the Curl translation system understands. Your translator edits this message file and adds translations for each message. See Translate the Extracted Messages for more information on this file. The Curl IDE provides the message extraction script.
You must deploy the translation file along with the applet. At run time, the applet uses the translation file to find the proper translation for each string when it displays the string to the user. You can support multiple locales by providing a separate XML translation file for each locale.
When your applet is running, the translation file serves as a translation dictionary. When a string that was marked for translation is used at run time, the RTE looks up that string in the dictionary associated with the appropriate locale. If it finds a translation, it uses the translated text in the application. If it does not find a translation file for the locale, or does not find a translation for the string, it uses the original string. This scheme provides a fall-back action in case a translation is missing. It also avoids the use of numerical message identifiers, which can be hard to manage. Another benefit is that each distinct string is included in the dictionary only once and only needs to be translated once.

Using the Translation System

The following list presents the steps you need to take to use the Curl language translation system:
Each of the following sections discuss one of these steps in greater detail.

Mark Strings for Translation

The lmessage macro provides translated text in an application. Its simplest form is:
{lmessage original-text}
Where original-text is your original, untranslated text. The original text string is the default value returned by lmessage if it finds no translation, and is the key used to look up translated text in a TranslationDictionary. The Curl runtime generates the TranslationDictionary from the information in the translation file specified in the applet or package metadata. Additional arguments to lmessage enable you to supply a key that is different from the original text string, and to supply comments to the translator.
The macro lmessage uses the working locale. By default, this is the same as the host locale. If necessary, an applet can set the working locale explicitly, see Specifying the Locale. Additional macros lformat and localize are also available.

Extract the Text Messages

Once you have marked all the text messages in your application for translation, run the Curl script curl://install/ide/translate/bin/extract-messages.xcurl to generate a skeleton translation file. You must run this script through a batch file, or directly at a command prompt. The script reads through all the files in your application, following all includes. It processes all localization expressions, and puts the resulting output into the specified file.
This table describes the message extraction command line interface:
Syntax:curl extract-messages.xcurl [--help] | -o filename file1, file2, ..., filen
Where:
Option/ArgumentDescription
--help displays online help for the extract-messages script.
-o indicates the translation file. Replace filename with the path and name of the file.
file1, file2, ..., filen indicates the Curl source files to process. The script can accept any number of input files. Replace files with the paths and names of the files.
For example, type the following command on a single line in a command prompt window to run the message extraction tool on the Curl source file source-file.curl and put the results in translation-file.xml.
d:\automated-build-temp\build\win32-atom\bin\curl.exe curl://install/ide/translate/bin/extract-messages.xcurl -o translation-file.xml source-file.curl

Specify the Translation File

The translation file is an XML file containing the information an application uses to build a TranslationDictionary. The section Translate the Extracted Messages describes the structure of this file in detail.
There are two ways to specify the location of the translation file for a given locale and originating package (or applet):

Using a manifest-lookup system
By adding entries to the appropriate manifest. The default manifest for a package (see get-default-manifest) and its delegate manifests will be searched for a translations entry matching the package and locale.

This technique is described in more detail in Using Manifests to Locate Translation Files.
Using a file-lookup system
By specifying resource-directory and translations-file attributes in the package and applet declarations for all packages and applets requiring translation. The resource directory will be searched for a subdirectory for a matching locale that contains the specified file.

The file-lookup approach is only used after the manifest-lookup approach has failed to find the file.

This technique is described in more detail below.


The manifest-lookup technique is the more efficient of the two because it avoids the cost of searching the file system. It is also allows for more flexibility in the actual locations of the translation files and other localizable resources. The main drawback is the need to explicitly add resource entries to the manifests.
The file-lookup system uses a file path having the following structure:
resource-directory/locale-directory/translation-file
Each package in your application specifies a resource directory and a translation file. The name of the locale directory is the rfc1766 language tag for the locale used by the applet. File lookup uses the most specific locale directory name that exists.
For example, if the applet uses United States English, the language tag is en-US and the translation system looks for a translation file in this location:
resource-directory/en-US/translation-file
if that locale directory exists, or the location
resource-directory/en/ translation-file
if en-US does not exist, but en does. If no English translation file exists, the RTE checks for a directory called default. If that does not exist, the application does not build a TranslationDictionary and localization expressions like lmessage return the original, untranslated text.
As a more specific example, this package declaration:
{package DOC.CHECKBUTTONS,
    resource-directory = "resources",
    translations-file = "messages.xml"
}
and an applet using the locale "ja" together specify a translation file in the location resources/ja/messages.xml.
This diagram illustrates the relationship between the specified names and the resulting path to the translation file.
Figure: Relationship Between Specification and Path
This illustration shows translation files for US English, all other English, all French and all German. An applet with the specified locale en-CA (Canadian English) uses resources\en\messages.xml, one with locale fr-CA (Canadian French) uses resources\fr\messages.xml.
You can put the entire translation file specification in the applet declaration.
{applet
    locale = "ja",
    resource-directory = "resources",
    translations-file = "messages.xml"
}
You need to deploy the translation files along with the rest of the rest of the application. See the IDE documentation for information on managing deployment.

Translate the Extracted Messages

The translation file is an XML file that uses XML tags to delimit the original text, the text look-up key, any comment text, and the translation. Each text element is represented by a <string></string> tag in the translation file. Inside that tag is the information for that text, in this format:
<string>
<key></key>
<original></original>
<comment></comment>
<translation></translation>
</string>
The extract messages script generates a <string></string> element, and the contained <key></key>, <original></original>, and <comment></comment> elements for each localize expression. Any elements not present in the source localize expression are omitted.
For example, these two lmessage expressions:
{lmessage "Submit"}
{lmessage key = "submit alternate", comment = "Use 'click here' instead.", "Submit"}
Generate these entries in the skeleton translation file:
<translation-dictionary version="1">

<string>
<original>Submit</original>
</string>

<string>
<key>submit alternate</key>
<original>Submit</original>
<comment>Use 'click here' instead.</comment>
</string>

</translation-dictionary>
The translator adds <translation></translation> elements that contain translations of the original text.
Please note that unless you explicitly specify a different key in the localization expression in the Curl source code, the original text is the key used to look up the translation. If you change the original text in the Curl source file, you must also replicate the change in the corresponding text in the translation file.
Use the expressions lformat or lmessage when you need to include arguments in the text output. lformat is a variant of format that calls localize on the format string. When you use lformat, you should use rest argument indexing as described in format. For example, for string arguments, the format specifier for the first argument is %1!s!, for the second is %2!s!, and so forth. The reason is that different languages can require words, phrases or data values to appear in a different order.
lmessage expands into a call to lformat with Curl expressions replaced by string arguments to lformat and %s format specifiers in the format string. The generated %s format specifiers use rest argument indexing.
{lmessage
    This uses lmessage. We're going to include some data values
    here. This is int-min: {value int-min}, and this is int-max:
    {value int-max}.
}
Produces the following entry in the skeleton translation file:
<string> 
<original>
This uses lmessage. We're going to include some
data values here. This is int-min: %1!s!, 
and this is int-max: %2!s!.
</original> 
</string>
This code:
{lformat 
    "formatting int-min %1!d!, formatting int-max %2!d!, and a number
%3!.2f!, and another %4!.2f!", int-min, int-max, 22/7, 45/9 
}
Produces the following entry in the skeleton translation file:
<string>
<original>
formatting int-min %1!d!, formatting int-max %2!d!, 
and a number %3!.2f!, and another %4!.2f!
</original>
</string>

Choosing the Locale

In some specialized circumstances, you need to explicitly set a working locale for an applet machine, or use the host locale directly.

Specify the Working Locale

Some applications need to set a working locale that is different from the host locale of the machine running the applet. For example, consider a system visitors to a museum in a large city can use to get directions and other information. The machine running the system is installed in a museum in a specific country. Its host locale is set to a value appropriate to that country. Museum visitors using the system want to interact with buttons and messages in their own language. Such an application can let the user choose their preferred locale.
If you know that an applet should use a specific locale, you can specify the working locale by adding a locale parameter to the applet declaration.

Using the Host Locale

There are situations in which you want to use the host locale, even though the application as a whole has set a different working locale. The museum application mentioned in the previous section needs to provide error messages that should be interpreted by local museum personnel to appear in the local language, not the language chosen by a museum visitor.
The macro hlmessage uses the host locale, the Locale specified on the client machine where the Curl runtime is executing. The macros host-localize and hlformat are host locale variants of localize and lformat