Many applications use language-dependent text throughout to provide localized menu selections, warning and error message descriptions, and help text. Often, the display of language-dependent text requires the insertion of locale-dependent string arguments into a message template. The processing used to construct a composite message from various components can introduce unwanted language dependencies and can act as a barrier to localization. The following example shows a locale-specific way to construct a composite message:
displayWarningFor: userName operation: anOperation "Display a warning message on the Transcript warning the user called userName that the operation called anOperation cannot be performed." Transcript cr; show: 'Sorry, ', userName; show: ' I cannot perform', anOperation; show: '!'.
This technique is commonly used in the construction of messages displayed to users. This technique is a barrier to localization because it embeds language-specific semantics in the processing used to construct the message. Some languages might require that the contents of the userName field appear after the anOperation field, or that a punctuation mark other than an exclamation mark (!) be used to terminate the message. The approach illustrated in the preceding example cannot support these requirements and is not suitable for use in an internationalized application.
IBM Smalltalk provides a mechanism for replacing tokens in a message template with variable arguments. A template string is a String or DBString containing constant text and token identifiers that are replaced with arguments specified by the developer. Token identifiers consist of a percent character (%) and a numeric field identifier in the range one to nine (1-9).
A template string is expanded based on arguments provided by the developer using the bindWith:, bindWith:with:, bindWith:with:with:, bindWith:with:with:with:, or bindWithArguments: methods. The numeric portion of the token identifier indicates which argument should replace the token when the template is expanded to create a composite message (for example, %1 corresponds to the first argument, %2 corresponds to the second argument, etc.). The double percent escape sequence ('%%') is replaced by a single percent character in the composite message.
A template string permits arguments to be printed selectively, and in
arbitrary order as illustrated in the following table. Although
arguments are provided in a fixed order, there is no restriction placed on
their order of appearance in the template string. Arguments that are
not referenced in the template string are ignored; an error is generated
if a template string references a missing argument.
Table 49. Sample message templates and results
Sample template and arguments | Resultant message |
---|---|
'%1 %2 %3' bindWith: 'one' with: 'two' with: 'three' | 'one two three' |
'%3 %2 %1' bindWith: 'one' with: `two' with: 'three' | 'three two one' |
'%1 %2 %1' bindWith: 'one' with: 'two' with: 'three' | 'one two one' |
'An %1 of embedded text' bindWith: 'example' | 'An example of embedded text' |
'This is a percent sign %%.' bindWith: '' | 'This is a percent sign %' |
'Unused are %1.' bindWith: 'ignored' with: 'unused' | 'Unused are ignored' |
'Missing arguments are %2.' bindWith: 'errors' | Exception occurs |
The following example shows the use of message templates to assist in internationalizing an application. It illustrates how the use of a message template avoids the language-specific dependencies exhibited by the previous example. Notice that languages that require the contents of the userName field to appear after the anOperation field, or different punctuation, can be supported simply by changing the template string. Normally, the template string would be externalized, thereby permitting the application to be localized without modification of source code.
displayWarningFor: userName operation: anOperation "Display a warning message on the Transcript warning the user called userName (a String) that the operation called anOperation (a String) cannot be performed." | template | template := 'Sorry, %1, I cannot perform %2!'. Transcript cr; show: (template bindWith: userName with: anOperation).
Note: | This example is not fully internationalized because it contains a hard-coded reference to the template 'Sorry, %1 I cannot perform %2!'. Tools and techniques for removing hard coded references to strings are discussed in Removing hard-coded strings. |