Using Caché Server Pages (CSP)
Localizing Text in a CSP Application
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

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. Supplied localization files are installed in the install-dir\Mgr\Locale directory.

For a simple demonstration of a localized CSP application, enter the following URL while Caché is running: http://localhost:57772/csp/samples/language.csp.
Caché supports the following process for localizing CSP application text:
  1. Developers determine where text strings are displayed in the application user interface.
  2. Developers create an XML message file that contains text strings in the original language.
  3. Developers import the XML into a Caché namespace.
    This adds new entries to the Message Dictionary in that namespace.
  4. Developers give the XML to a team of translators.
  5. Translators produce a new XML message file by substituting translated text for the original.
  6. Developers import the new XML into a Caché namespace.
    Translated and original texts coexist in the Message Dictionary.
  7. At runtime, the application chooses which text to display based on the browser default language.
This chapter explains:
Message Dictionaries
A Message Dictionary is a simple database of text strings organized by domain name, language name, and message ID:
Message Dictionary Storage
Each user-defined namespace in Caché stores its Message Dictionary in a subscripted global called ^CacheMsg. The order of subscripts in ^CacheMsg is domain, language, and message ID.
To view ^CacheMsg for a namespace:
  1. Start the Management Portal.
  2. To the right of the namespace name, click Globals.
  3. In the CacheMsg row, click Data.
    Caché displays the entire Message Dictionary for that namespace.
The following excerpt is taken from the Caché SAMPLES namespace. It shows the entries for two languages (English and Spanish) in a localization domain called sample. Where a line is too long to fit in this display, this example truncates the line at right:
^CacheMsg("sample","en","LangComment") = "Demo of displaying a page in the local
^CacheMsg("sample","en","LangDesc") = "This sample demonstrates how to display a
^CacheMsg("sample","en","LangDisplay") = "Display Resource"
^CacheMsg("sample","en","LangEnglish") = "English"
^CacheMsg("sample","en","LangSet") = "Set Language"
^CacheMsg("sample","en","LangText1") = $c(13,10)_"This page has been translated
^CacheMsg("sample","en","LangText2") = $c(13,10)_"To display this page in a lang
^CacheMsg("sample","en","LangText3") = $c(13,10)_"To display the XML resource fi
^CacheMsg("sample","en","LangText4") = $c(13,10)_"The source code of this page s
^CacheMsg("sample","en","LangTitle") = "Language Localization Example"
^CacheMsg("sample","en","Language") = "English"
^CacheMsg("sample","en","menu") = "Samples Menu"
^CacheMsg("sample","en","source") = "Source"
^CacheMsg("sample","es","LangComment") = "Demo de presentación de una p
^CacheMsg("sample","es","LangDesc") = "Este ejemplo muestra como presentar una p
^CacheMsg("sample","es","LangDisplay") = "Mostrar Recurso"
^CacheMsg("sample","es","LangEnglish") = "Spanish"
^CacheMsg("sample","es","LangSet") = "Establecer Lenguaje"
^CacheMsg("sample","es","LangText1") = $c(13,10)_"Esta página ha sido tra
^CacheMsg("sample","es","LangText2") = $c(13,10)_"Para mostrar esta págin
^CacheMsg("sample","es","LangText3") = $c(13,10)_"Para mostrar el fichero fuente
^CacheMsg("sample","es","LangText4") = $c(13,10)_"El código fuente de esta
^CacheMsg("sample","es","LangTitle") = "Ejemplo de Localización de Lenguaj
^CacheMsg("sample","es","Language") = "Español"
^CacheMsg("sample","es","menu") = "Menú Samples"
^CacheMsg("sample","es","source") = "Fuente"
Adding Entries to a Message Dictionary
To contribute messages to a Message Dictionary, you may use the options in the following table. For each option, the table lists the section in this chapter where more information is available.
Work Preference How to Add Entries to a Message Dictionary For More Information
Tag-based or class-based CSP development Edit an XML Message file using a text editor or XML authoring tool. Import this XML file into a Caché namespace. XML Message Files
Tag-based CSP development only Automatically generate Message Dictionary entries at compile time, by seeding the CSP page with tags that use a specific localization syntax. Localization from Tag-Based Files
Class-based CSP development only Automatically generate Message Dictionary entries at compile time, by seeding the CSP class code with $$$Text macro calls. Localization from Class Code
You may use any or all of these development options in the same application.
If you do combine development options, when it comes time to translate the application messages into another language, you can export the full list of messages for the original language out of the Message Dictionary by running an Export command. This generates a complete XML message file in the original language.
Important:
For export and import instructions, see the section Managing a Message Dictionary.”
XML Message Files
An XML message file is a description of a Message Dictionary in XML format. This is the format in which Caché exports Message Dictionary contents to an external file. This is also the required format for any messages that you wish to import into Caché XML.
Important:
For export and import instructions, see the section Managing a Message Dictionary.”
An XML message file may contain messages for one language and multiple domains. It conforms to the following DTD:
InstallDir\dev\csp\rules\CacheMessages.dtd
Where InstallDir is the Caché installation directory.
Whenever possible, XML message files should use UTF-8 encoding. However, in certain cases a developer or translator might use local platform encodings, such as shift-jis, for ease of editing the XML message file. Whatever encoding is used for the XML file, it must be supported by the Caché locale for the application, and it must be able to express the messages for the language.
<MsgFile> Element
The <MsgFile> element is the top-level container for the XML message file. There is only one <MsgFile> element per file.
<MsgFile> has one required attribute, Language. The value of the <MsgFile> Language attribute is an all-lowercase RFC1766 code that identifies the language for the file. It consists of one or more parts: a primary language tag (such as en or ja) optionally followed by a hyphen (-) and a secondary language tag (en-gb or ja-jp).
In the following example, this language is "en" (English).
<?xml version="1.0" encoding="utf-8" ?>
<MsgFile Language="en">
    <MsgDomain Domain="sample">
        <Message Id="source">Source</Message>
        <Message Id="menu">Samples Menu</Message>
    </MsgDomain>
</MsgFile>
<MsgFile> must contain at least one <MsgDomain> element. It may contain more than one <MsgDomain>.
<MsgDomain> Element
<MsgDomain> has one required attribute, Domain. The value of the <MsgDomain> Domain attribute is one of the domain names that you are using to organize the messages in your application.
Any <MsgDomain> element may contain zero or more <Message> elements.
<Message> Element
<Message> has one required attribute, Id. The value of the <Message> Id attribute is one of the message ID strings that you are using to organize the messages in your application.
Any <Message> element may contain a text string. The string may consist of any of the following items, separately or in combination:
The following example uses %1, %2, the HTML tag for bold formatting, and the ObjectScript string convention that two successive double quote characters indicate a single double quote:
<Message>
  The session $Username="&lt;b&gt;%1&lt;/b&gt;" $Roles="&lt;b>%2&lt;/b&gt;"
</Message>
Localization from Tag-Based Files
During tag-based development of CSP pages, you can configure certain tags so that they substitute a Message Dictionary entry for what would otherwise be literal text. Do this by providing the localization attributes language, domain, or textid inside the tag. The following tags support these attributes:
For the most part, these tags work only at runtime, when the values provided for language, domain, and textid indicate which message to retrieve from the Message Dictionary.
However, in limited cases these tags serve different purposes at compile time and runtime. They can automatically generate entries for the Message Dictionary at compile time, then retrieve and display these entries at runtime. The following sections explain how this works:
Localization Tags at Runtime
Important:
This topic applies to the CSP tags <csp:text>, <span>, <div>, <input>, and <button> only.
At runtime, when the CSP page displays, the tag replaces itself and its contents with text from the Message Dictionary. The choice of text is specified by the language, domain, and textid attribute values supplied by the tag.
For example, the following syntax is replaced by the message specified by the fr (French) language, sample domain, and menu message ID. The text provided inside the <csp:text> tag (Menu in this case) is ignored:
<csp:text textid="menu" language="fr" domain="sample">Menu</csp:text>
Defaults for language, domain, and textid are available if any of the attributes are omitted or empty (value ""):
Default Language
Most developers intentionally provide no language attribute so that, at runtime, the language defaults appropriately for the locale. If not supplied, language defaults to the value of %response.Language, which automatically takes its runtime value from the browser settings.
You can see examples of this convention in the source code for the localization example in the SAMPLES namespace. View it as follows:
  1. Start Studio.
  2. Change to the SAMPLES namespace.
  3. In the Workspace window, click the Namespace tab.
  4. Choose CSP Files.
  5. Open the file /csp/samples/language.csp.
Default Domain
The %response.Domain property is initialized with the value of the DOMAIN parameter of the CSP page class. You can also set a value for %response.Domain using the domain attribute of the <csp:class> tag, as in:
<csp:class domain="myDomainName">
Message Arguments
If the message text contains arguments (%1, %2, %3, %4) the following tag attributes let you specify the corresponding substitution text: arg1, arg2, arg3, arg4. You may provide literal values or use variables. For example:
<csp:text textid="sessionInfo" arg1="#(userName)#" arg2="#(roleID)#" />
Button Text
In tag-based CSP files, the text displayed on a button is normally specified using the value attribute of the <input type="button"> or <button> tag.
When an <input> tag uses localization attributes (language, domain, or textid) the value attribute is ignored. The text displayed on the button is the text from the Message Dictionary. If you want to localize the text on a <button> tag, use the language, domain, or textid attributes of the <csp:text> tag.
Localization Tags at Compile Time
Important:
This topic applies to the CSP tags <csp:text>, <span>, <div>, and <input> tags only.
The textid attribute may have the empty value "". If so, when you compile the tag-based CSP file a new message is automatically generated in the Message Dictionary. The text for the generated message consists of the contents of the CSP tag. Caché generates a message ID by calculating the 32–bit CRC (Cyclic Redundancy Check) of this text.
Only the <csp:text> tag permits you to actually omit the required textid attribute. The other localization tags require you to at least provide an empty value "".
If a <csp:text> tag lacks a textid attribute, the system automatically generates a new message and message ID value. In cases where you omit textid from <csp:text>, the text inside the tag may include an optional @textID@ string at the beginning. textID is the message ID that you wish to assign to the message. For example:
<csp:text>@simpleMenu@Menu</csp:text>
In the above example, Caché does not generate the message ID. It generates a message whose text is Menu and gives it the message ID simpleMenu.
When a CSP tag has been used to generate a Message Dictionary entry at compile time, it still works as a reference to retrieve that entry at runtime. See the section Localization Tags at Runtime.”
Localization from Class Code
During code-based development of CSP pages, you can provide code that substitutes a Message Dictionary entry for what would otherwise be literal text. You can do this using the options in the following table. For each option, the table lists the section in this chapter where more information is available.
Work Preference For More Information
Edit an XML message file and import it into Caché. This builds the Message Dictionary. XML Message Files
Call a variety of “get message” and “format text” routines and macros. These retrieve text from the Message Dictionary and prepare the message for display. Retrieving Messages at Runtime
Build, retrieve, and display a message with one call to a $$$Text macro. $$$Text automatically creates the message at compile time and generates the code that retrieves the message at runtime. $$$Text Macros at Compile Time and Runtime
Retrieving Messages at Runtime
This topic explains how 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.
The calls described in this topic work only if you have already placed entries in the Message Dictionary, for example by editing an XML message file and importing it into Caché. To build, retrieve, and display a message with one call, see the section $$$Text Macros at Compile Time and Runtime.”
%response.GetText Method
The %CSP.Response 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.Response 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 RFC1766 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.MessageDictionary 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 %String 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:
The $$$FormatText macro returns a %String. The syntax is:
$$$FormatText(text,arg1,arg2,...)
Argument Description
text The message text. Use a %String returned by %response.GetText or $$$Text.
arg1, arg2, and so on Substitution text for the message arguments.
$$$Text Macros at Compile Time and Runtime
The $$$Text macros offer shortcuts to localization. You can build, retrieve, and display a localized message using one call to a $$$Text macro. $$$Text automatically creates the message at compile time and generates the code that retrieves the message at runtime.
The return value of a $$$Text macro is a %String. The correct $$$Text macro to use depends on the format you need for this output string:
The %String 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"))#');>
$$$Text has the arguments text, domain, and language as described in the following table. Only the first argument, text, is required.
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:
Or:
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
  • A string expression in ObjectScript format
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) RFC1766 code specifying the language. Caché converts this string to all-lowercase. If not specified, language defaults as follows:
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.MessageDictionary class method MatchLanguage. Given a list of languages and a domain name, this method uses HTTP 1.1 matching rules (RFC2616) 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. Since $$$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 input the $$$Text string into the first argument of the %response.FormatText method or a $$$FormatText macro.
Translating a Message Dictionary
The conventions for translating a Message Dictionary are as follows:
  1. Developers export an XML message file from the application namespace.
    Important:
    For background information, see the section XML Message File.” For export instructions, see the section Managing a Message Dictionary.”
    If your only option for creating the Message Dictionary was to edit an XML message file and import it into Caché, you may skip this step.
  2. Developers send the XML message file and CacheMessages.dtd to a translator. Translators work with the XML message file using any XML authoring tool they prefer. Essentially they translate text from the original language to a new language, without changing the surrounding XML.
  3. Translators return a new XML message file that:
  4. Developers import the new XML message file into the application namespace.
    Important:
    For import instructions, see the section Managing a Message Dictionary.”
    The application now supports another language.
Managing a Message Dictionary
This section summarizes the %Library.MessageDictionary methods that are most commonly used while localizing a CSP application. You can use these methods to:
Importing an XML Message File
Caché offers utility methods for importing an XML message file.
From the Terminal prompt:
  1. Change to the namespace where you are developing the application:
     ZN "myNamespace"
  2. Run the import command. Keep in mind that Caché stores each language in a separate XML message file, appending the language to the name of each file. Thus:
  3. Examine the ^CacheMsg global in your namespace to see the result.
The following topics summarize both import methods.
Importing a Specific XML Message File
The %Library.MessageDictionary class method Import has the following signature:
classmethod Import(filepath As %String,
                   flag As %String = "") returns %Status
Argument Description
filepath Import the XML message file specified by filepath. Make sure that only XML message files are in the directory as other XML files generate errors.
flag (Optional) If provided, the d display flag indicates that the Terminal console will display confirmation messages as files are imported. Otherwise, there is no confirmation.
Importing All the XML Message Files in a Directory
The %Library.MessageDictionary class method ImportDir has the following signature:
classmethod ImportDir(directory As %String,
                      flag As %String = "") returns %Status
Argument Description
directory Import all of the XML message files in the specified directory.
flag (Optional) If provided, the d display flag indicates that the Terminal console will display confirmation messages as files are imported. Otherwise, there is no confirmation.
Exporting an XML Message File
Caché offers utility methods for exporting portions of a Message Dictionary to an XML message file. From the Terminal prompt:
  1. Change to the namespace where you are developing the application:
     ZN "myNamespace"
  2. Identify the output file and its location:
     SET file="C:\myLocation\Messages.xml"
  3. Run the export command:
The following topics summarize both export methods.
Exporting Specific Domains in One Language
The %Library.MessageDictionary class method ExportDomainList has the following signature:
classmethod ExportDomainList(file As %String,
                             domainList As %String,
                             language As %String) returns %Status
Argument Description
file
(Required) A template for the output filename in this format:
Caché names the output file by appending the language value to the filepath with an extension of ext.
domainList (Optional) A comma-separated list of domains to be exported.
language (Optional) Only the specified language is exported. The value must be an all-lowercase RFC1766 code. If not provided, the value defaults to the system default language, a value that is stored in the special variable $$$DefaultLanguage.
Exporting All Domains in Specific Languages
The %Library.MessageDictionary class method Export has the following signature:
classmethod Export(file As %String,
                   languages As %String = "",
                   flag As %String = "") returns %Status
Argument Description
file
(Required) A template for the output filename in this format:
Caché names the output file(s) by appending the languages value to the filepath with an extension of ext.
languages (Optional) A comma-separated list of languages. Each value in the list must be an all-lowercase RFC1766 code. If languages is not specified, or is empty, all languages in the database are exported. Caché exports each language to a separate file using the conventions described for the file argument.
flag (Optional) If provided, the s system flag indicates that system Message Dictionaries are to be exported. Otherwise, only application Message Dictionaries are exported.
Deleting Messages
To delete messages use:
 Set status = ##class(%MessageDictionary).Delete(languages,flag)
languages is an optional comma-separated list of languages. If languages is not specified, all languages are deleted. The default value is to delete application messages only. The s, system flag, is an optional flag indicating whether to also delete system messages. The message names associated with include files are always deleted, but not the include files. The d, display, flag is also supported.
Listing Messages
The list of all languages that have messages loaded for a specified domain may be obtained by using the GetLanguages function:
 Set list = ##class(%MessageDictionary).GetLanguages(domain,flag)
GetLanguages returns a %ListofDateTypes format list of languages in the standard RFC1766 format and all in lowercase. If domain is specified, then only languages which exist for the specified domain are put in the list. Otherwise, all languages are put in the list. The s, system flag, is an optional flag indicating whether languages supported by system or application messages are to be returned. The default value is to return the languages for application messages. The d, display, flag is also supported.
Finding Language Matches
To find the best available match for a language request:
 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 using HTTP 1.1 matching rules (RFC2616). The list of languages is a comma-separated list of RFC1766 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 by the 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, system flag, is an optional flag indicating whether system, s, or application messages are to be matched.