Internationalization of Strings in Code

The purpose of this page is to describe the mechanisms by which we externalize strings in the platform to make sure that all of engineering externalizes their strings in the same way.

Overall Standards

What strings get externalized?

All java code should have their strings externalized except for the following:

  • Test Cases - we do not need to externalize strings in test case classes
  • DEBUG/Trace messages do not need externalized either.

    Concatenation

    Concatenation of strings to formulate a message is a no-no in an internationalized application. To support this, you need to use replaceable parameters. This is because the subject and verb are in different places depending upon the language.
    Instead of
    String in messages.properties: SomeClass.FILE_NOT_FOUND_MSG=File was not found:
    Line of code: error(Messages.getString("SomeClass.FILE_NOT_FOUND_MSG") + theFileName);

Use this
String in messages.properties: SomeClass.FILE_NOT_FOUND_MSG=File was not found: {0}
Line of code: error(Messages.getString("SomeClass.FILE_NOT_FOUND_MSG", theFileName));

All messages need meaningful names

In the Eclipse string externalization dialog, Eclipse will default to simply numbering the un-externalized strings from zero. You need to replace that number with a meaningful name, using underscores for spaces, and using all uppercase letters:

Instead of
SomeClass.0=File was not found
Use this
SomeClass.FILE_NOT_FOUND_MSG=File was not found

Error Messages use getErrorString, not getString

For errors, we've determined that it's way easier for us to find where the problem is if the user has an error number to work from. That error number should be unique to the class prefix. The formatErrorMessage method in MessageUtil will produce a message that includes the error number, only if you remember to call getErrorString instead of getString. For example:

System.out.println(getString("ChartEngine.ERROR_0002_COULD_NOT_CREATE_CHART"));
Invalid chart definition

System.out.println(getErrorString("ChartEngine.ERROR_0002_COULD_NOT_CREATE_CHART"));
ChartEngine.ERROR_0002 - Invalid chart definition

Note that getErrorString will show the actual error number in the log. This lets us hone right in on the code that threw the message to the server log.

Message Prefixes

When creating messages for externalization, we have standards that are used to help the translator decide what strings to translate first. Here are the standards:

Prefix

Description

USER_

This is a message that appears in the user interface somewhere. It may be a message, a description, anything. If it shows up in the UI, it should begin with a USER_ prefix. For example: GlobalListsPublisher.USER_DESCRIPTION

ERROR_xxxx

For error messages. The xxxx is a sequential number for the specific class it's associated with. For example: Email.ERROR_0001_TO_NOT_DEFINED

CODE_

This indicates a string that shouldn't be translated.

DEBUG_

As it sounds, this is a DEBUG-level string that appears in the server log - internationalization not required for debug strings

TRACE_

As it sounds, this is a TRACE-level string that appears in the server log - internationalization not required for trace strings

WARN_

As it sounds, this is a WARN-level string that appears in the server log

INFO_

As it sounds, this is a INFO-level string that appears in the server log

Single Quotes

As much as possible, single-quotes need to be avoided in messages that contain replaceable parameters ({n}). In cases where it cannot be avoided, then you need to be sure to escape them (use two single-quotes). Simply re-wording the message is usually sufficient. Instead of using quotes to highlight a value in the text is not recommended - I suggest using square brackets. This could also be extremely problematic if the string ends up in the client as a piece of Javascript.

Here are some examples:

Instead of
The system couldn't find the file '{0}'
Use This
The file [{0}] could not be found.

Example of using Eclipse to externalize an error string

Step 1 - Find a string needing externalization

Assume you've created a new error string, or you're working through warnings in the application and stumble on a string requiring externalization. Here is what it should look like in the Java editor (assuming your compiler warnings are set properly - see Compiler Warning Settings).

Step 2 - Go into Externalize strings

Right-click in the source window, and follow the menus.

Step 3 - Set up the External Strings Dialog

There are some really important things to make sure of when you get to the Externalize Strings dialog. Here is approximately what it should look like:

IMPORTANT Stuff to Note

  1. Notice the first red-outlined box - the common prefix. This is, by convention, the name of the class.
  2. Next red box is the Key to be created. Notice the .0 part. This needs renaming
  3. The most important thing on this dialog is the Accessor class. This must be set to org.pentaho.messages.Messages or com.pentaho.messages.ProMessages.

Step 4 - Find the biggest error number in use

To locate the largest error number already in use, you should un-check the upper-right check-box for filtering out existing externalized entries. Then, you can see the error numbers already in use. If you're doing this on a class that has never had the strings externalized, then you won't have to worry about this step - you can just start numbering from 0001. In the case below, ERROR_0006 is the highest number in use.

Step 5 - Create the error string identifier

Now you know that you're creating ERROR_0007_<meaningful name> - create the name, all in uppercase using underscore (_) for spaces.

Step 6 - Click finish.

The next page of the process should show you a before-and-after look at the source. If it is prompting you to create a file, then you know you forgot to set the accessor class on the previous page. Go back and fix it if this is the case.

Step 7 - Fix the error message method call

When externalizing messages, be sure to correct the method call used for error messages. It should be getErrorString, not getString.

Using Eclipse to find broken externalized strings

This feature seems to have shown up in recent Eclipse releases (3.2 or later). You can use this feature to remove strings which are no longer being used.