Skip to main content

Localizing Text in a CSP Application

This chapter describes how to localize text in a CSP application in the common scenario where you are using class-based development. For tag-based development, see “Localization and Tag-Based Development,” later in this book.

Also see the article String Localization and Message Dictionaries.

Localization Basics

When you localize the text for an application, you create an inventory of text strings in one language, then establish a convention for substituting translated versions of these messages in another language when the application locale is different.

Caché supports the following process for localizing strings:

  1. Developers include localizable strings within their code. Within a CSP application, the easiest approach is to use class-based development and to use one of the $$$Text macros. In the place of a hardcoded literal string, include an instance of the $$$Text macro (or a related macro), providing values for the macro arguments as follows:

    • The default string

    • The domain to which this string belongs (localization is easier to manage when the strings are grouped into domains)

    • The language code of the default string

    For example, instead of this:

    &html<<div>"Hello world"</div>>
    

    Include this:

    set hello=$$$Text("Hello world","sampledomain","en-us")
    &html<<div>#(hello)#</div>>
    
    
  2. When the code is compiled, the compiler generates entries in the message dictionary for each unique instance of the $$$Text macro (and its related macros).

    The message dictionary is a global and so can be easily viewed (for example) in the Management Portal. Caché provides class methods to help with common tasks.

  3. When development is complete, release engineers export the message dictionary for that domain or for all domains.

    The result is one or more XML message files that contain the text strings in the original language.

  4. Release engineers send these files to translators, requesting translated versions.

  5. Release engineers import the translated XML message files into the same namespace from which the original was exported.

    Translated and original texts coexist in the message dictionary.

  6. At runtime, the application chooses which text to display based on the browser default language.

For steps 1 and 2, also see the appendix “Localization and Tag-Based Development.”

For information on exporting and importing the message dictionary, see the article String Localization and Message Dictionaries.

$$$Text Macros

Caché provides three related $$$Text macros (in %occMessages.inc, which is included in %occInclude.inc):

Each of these macros takes three arguments: the default string, the domain to which this string belongs, and the language code of the default string. When code is compiled, the compiler generates entries in the message dictionary for each unique set of values of the arguments.

The %StringOpens in a new tab returned by $$$Text may be assigned to a variable, which you can use to represent the message in subsequent calls. For example:

 Set tmsg = $$$TextJS("Error saving production")
 &js<alert('#(tmsg)#: #($ZCVT($ZE,"O","JS"))#');>

Or, you can simply insert a $$$Text macro anywhere you need a string:

 &js<alert('#($$$TextJS("Error saving production"))#: #($ZCVT($ZE,"O","JS"))#');>

Argument Details

Formally, the $$$Text, $$$TextJS, and $$$TextHTML macros take the following arguments in order:

Argument Description
text

Non-empty string. text must be a literal string. It cannot be the value of a CSP runtime expression enclosed in #()# syntax. The format used for text may be:

"actualText"

Or:

"@textId@actualText"

Where textId is a message ID and actualText is the text of the message.

The string actualText may consist of any of the following items, separately or in combination:

  • Simple text, as permitted by the file format

  • Substitution arguments %1, %2, %3, or %4

  • HTML formatting

  • An ObjectScript string expression

If provided, the textId is used as the message ID. If @textId@ is not specified, the system generates a new textId by calculating the 32–bit CRC (Cyclic Redundancy Check) of this text. If the textId is specified and a message already exists with this ID, the existing message is checked to see if it has the same text as actualText. If not, an error is reported.

domain (Optional) String specifying the domain for the new message. If not specified, domain defaults to the value of the DOMAIN class parameter at compile time and %response.Domain at runtime.
language

(Optional) RFC1766Opens in a new tab code specifying the language. Caché converts this string to all-lowercase. If not specified, language defaults as follows:

  • At compile time: $$$DefaultLanguage.

  • At runtime: %response.Language, or if no value is defined for %response.Language then $$$DefaultLanguage.

Tag-based CSP pages automatically acquire a value for %response.Language from browser settings, so it is available as a default language. This is not true for class-based CSP pages, which must explicitly set a value for %response.Language to use it as a default.

You can assign a value to %response.Language by giving it the return value of the %Library.MessageDictionaryOpens in a new tab class method MatchLanguage(), discussed later in this chapter. Given a list of languages and a domain name, this method uses HTTP 1.1 matching rules (RFC2616Opens in a new tab) to find the best-match language within the domain.

$$$Text at Compile Time

When you compile a class that contains calls to $$$Text, $$$TextJS, or $$$TextHTML macros, each call generates a message in the message dictionary, with text, message ID, domain, and language as provided by the macro arguments.

The first time a message is added to a domain by $$$Text, $$$SessionLanguage is used whether the language argument is specified or not. Subsequent $$$Text macros for the same domain add messages with the same language as the first added message.

$$$Text at Runtime

If the message text contains arguments (%1, %2, %3, %4) you must specify the corresponding substitution text before displaying the text. Because $$$Text returns a string, you can use any string operation native to your coding language. For example, in JavaScript:

 var prompt = '#($$$TextHTML("Remove user %1 from this Role?"))#';
 prompt = prompt.replace(/%1/g,member.userName);

You can also use the $$$Text string as the first argument of the %response.FormatText method or a $$$FormatText macro.

Other Options for Displaying Localized Strings

The easiest way to display a localized string at runtime is to use one of the $$$Text macros as described earlier in this chapter.

This topic explains other ways to retrieve message text from the message dictionary at runtime. If the message text contains arguments (%1, %2, %3, %4) you must also specify the corresponding substitution text before displaying the text on the page.

%response.GetText Method

The %CSP.ResponseOpens in a new tab class offers a GetText instance method that enables you to retrieve text from the message dictionary and substitute values for any arguments the message may have. In CSP class code, the currently instantiated %CSP.ResponseOpens in a new tab object is represented by the variable %response. This topic refers to the method as %response.GetText.

The method signature is:

 method GetText(language As %String = "",
                domain As %String = "",
                id As %String,
                default As %String,
                args...) returns %String
Argument Description
domain (Optional) A string specifying the domain for the message. If not specified, domain defaults to %response.Domain.
language (Optional) An RFC1766Opens in a new tab code specifying the language. Caché converts this string to all-lowercase. If not specified, language defaults to the value of %response.Language, which automatically takes its runtime value from the browser settings.
id The message ID.
default The string to use if the message identified by language, domain, and id is not found.
arg1, arg2, and so on Substitution text for the message arguments. All of these are optional, so you can use %response.GetText() even if the message has no arguments.

FormatText Method

The %Library.MessageDictionaryOpens in a new tab class offers a FormatText() class method that enables you to substitute text for message arguments. You can use FormatText() when you already have the message text from the message dictionary.

The method signature is:

ClassMethod FormatText(text As %String, args...) As %String
Argument Description
text The message text. Use a %StringOpens in a new tab returned by %response.GetText or $$$Text.
arg1, arg2, and so on Substitution text for the message arguments.

$$$FormatText Macros

These macros enable you to substitute text for message arguments. You can use them when you already have the message text from the message dictionary:

  • $$$FormatText

  • $$$FormatTextJS (applies JavaScript escaping to the $$$FormatText result)

  • $$$FormatTextHTML (applies HTML escaping to the $$$FormatText result)

These macros are in %occMessages.inc, which is included in %occInclude.inc.

The $$$FormatText macro returns a %StringOpens in a new tab. The syntax is:

$$$FormatText(text,arg1,arg2,...)

Argument Description
text The message text. Use a %StringOpens in a new tab returned by %response.GetText or $$$Text.
arg1, arg2, and so on Substitution text for the message arguments.

The MatchLanguage() Method

You may need to set the Language property of the CSP response. To do so, set the %response.Language property, using the value returned by the MatchLanguage() method of %MessageDictionaryOpens in a new tab:

 Set language = ##class(%MessageDictionary).MatchLanguage(languages,domain,flag)

This finds the best language match to a language in the list of languages for the specified domain. The method uses HTTP 1.1 matching rules (RFC2616Opens in a new tab). The list of languages is a comma-separated list of RFC1766Opens in a new tab format language names. Each language in the list may be given an associated quality value which represents an estimate of the user’s preference for the languages specified by the list of languages. The quality value defaults to q=1.

For example, da, en-gb;q=0.8, en;q=0.7 would mean: I prefer Danish, but will accept British English and other types of English. A language from the list matches a supported language tag if it exactly equals the tag, or if it exactly equals a prefix of the tag such that the first tag character following the prefix is a hyphen (-). The special language asterisk (*), if present in the input list, matches every supported language not matched by any other language present in the list.

The language quality factor assigned to a supported language tag is the quality value of the longest language in the list that matches the language-tag. The language that is returned is the supported language that has been assigned the highest quality factor.

The s flag (system) is an optional flag indicating whether system or application messages are to be matched.

FeedbackOpens in a new tab