Developing Zen Applications
Zen Localization
[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 when the application locale is different. Most of the information you need to localize Zen pages can be found in the Localizing Text in a CSP Application chapter in the book Using Caché Server Pages (CSP). Everything described in that chapter for development of CSP pages also applies to Zen pages.

There are a few additional details that apply only to Zen. This chapter:
Important:
In order for Zen localization techniques to work in any Zen class, the class must provide a value for the DOMAIN class parameter.
CSP Localization
Important:
This topic briefly outlines material from the Localizing Text in a CSP Application chapter in the book Using Caché Server Pages (CSP). If you are new to CSP, please read the other chapter before continuing in this book.
For a simple demonstration of a localized web application, enter the following URI while Caché is running. Substitute your Caché web server port number for 57772:
http://localhost:57772/csp/samples/language.csp
Localization Practices
Caché supports the following process for localizing web 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.
Message Dictionary
A Message Dictionary is a simple database of text strings organized by domain name, language name, and message ID:
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.
$$$Text Macros
Important:
For $$$Text macros to work in any Zen class, the class must provide a value for the DOMAIN class parameter.
The easiest way to create a Message Dictionary is to automatically generate Message Dictionary entries at compile time, by seeding the CSP class code with $$$Text macro calls. $$$Text automatically creates the message at compile time and generates the code that retrieves the message at runtime, as this topic explains.
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. See the section Managing a Message Dictionary in the “Localizing Text in a CSP Application” chapter of Using Caché Server Pages (CSP).
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 Arguments
$$$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 use any type of expression 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) A 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) An RFC1766 code specifying the language. Caché converts this string to all-lowercase. If not specified, language defaults as follows:
$$$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.
$$$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 = '#($$$TextJS("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. For details, see the section Localization from Class Code in the “Localizing Text in a CSP Application” chapter of Using Caché Server Pages (CSP).
Zen Localization
Important:
For the following conventions to work in any Zen class, the class must provide a value for the DOMAIN class parameter.
Zen pages are CSP pages. All CSP localization practices also apply to Zen pages. However, Zen adds the following conventions to make localization even easier:
Localization for Zen Components
If a Zen component has any string-valued properties with its datatype parameter ZENLOCALIZE set to 1, then when Zen generates the %CreatePage method from the <page> description, Zen automatically localizes the text supplied for those properties.
It is convenient to give all string-valued properties the Zen datatype %ZEN.Datatype.caption, which has ZENLOCALIZE automatically set to 1, but you can also set ZENLOCALIZE directly by including the datatype parameter ZENLOCALIZE=1 in the property definition.
If all of the following conditions are true:
Then the code that Zen generates for the %CreatePage method automatically calls $$$Text to localize each of these properties. Of course, you must provide the translations yourself, as described in Localization Practices.” However, if you do this and also use ZENLOCALIZE and $$$Text as described in this section, all of the mechanisms for delivering these translated strings work automatically. The result is that Zen automatically serves the correct translation to the user by detecting the language locale for the browser or the Caché server at runtime.
The following is a simple example:
<button caption="OK" />
Generates the following code in %CreatePage:
Set bttn.caption = $$$Text("OK")
Important:
If you programmatically build pages (without using <page>) there is no automatic localization of component properties, even if ZENLOCALIZE=1. In this case your code must issue a call to $$$Text for each one of these strings, as shown in the previous example of generated code for a button caption.
Localization for Custom Components
If you are creating a new component, you can define properties that should be localized as datatype %ZEN.Datatype.caption:
Property title As %ZEN.Datatype.caption;
Within your component, to refer to the property simply use the property name with double dot syntax (..title in this example). You do not need $$$Text within your custom component code unless you have some static text that you wish to localize. Whenever a <page> references your component, your property is automatically localized in the same way as built-in Zen components. For example:
<MyComponent title="AAA" />
Generates code like this in %CreatePage:
Set MyCmp = $$$Text("AAA")
Localization for Client-side Text
Zen supports a variant of $$$Text that you can use within JavaScript methods. This feature greatly simplifies the use of localized strings in client-side code.
The syntax for JavaScript localization is similar to the $$$Text macro in ObjectScript:
var str = $$$Text('This is a localized string.');
When a method containing this code runs in a Zen page, $$$Text returns a localized string if localization has been enabled by setting the DOMAIN parameter, and a localized version of the string is available. $$$Text takes an optional second argument, which is a DOMAIN name. This argument lets you override the default localization domain:
var str = $$$Text('This is a localized string.', 'MyDomain');
JavaScript does not support macros, so $$$Text is implemented as a function that returns a string. Strings in JavaScript can be quoted with either single quotes (') or double quotes ("), and both conventions are supported. Both arguments to $$$Text must be literal (quoted) strings or the function does not return localized values. The complete $$$Text() expression must be written on a single line of code. All occurrences of $$$Text('string') are processed, wherever they appear in the JavaScript, including in comments and strings. This does not effect the behavior of the code, but may add extra entries to the string table.
You can use explicit id values for strings, such as "@33@MyString", in the same manner as the server-side $$$Text.
In Caché version 2010.2, the $$$Text function exists but simply returns the string it is passed.
The JavaScript function, $$$FormatText is also supported. This substitutes all occurrences of %1,%2,%3,%4 with the values of up to four parameters:
alert($$$FormatText('Ok to delete file %1?', filename));
$$$Text automatically captures string content and adds it to the localization global. The macro preprocessor does this in the case of the $$$Text macro in ObjectScript. As there are no macros in JavaScript, the compiler that converts JavaScript methods into client-side functions scans JavaScript for occurrences of $$$Text('string','domain') and pulls the first argument (and the second if it is present) and constructs a JavaScript array of localized values, which is served as part of the page. The $$$Text function uses this array to convert strings to the localized version. The generation of the array uses the server-side $$$Text macro, which ensures that the JavaScript localized strings are created using the same mechanism as server-side strings.
When a Zen page is rendered, the array of localized strings is created for every type of component and superclasses of that component found on the page. If a component is added to a page dynamically and Zen determines that the class definition for this component must be dynamically loaded, then localized strings are generated for this component as well.
Localization with zenText
An additional client side equivalent of $$$Text is the zenText JavaScript function:
zenText(id,p1,p2,p3,p4)
This function finds a localized text message from a set of client-side text resources, where:
If no localized strings are defined for the supplied id, zenText returns a default string.
You can define a set of localized text messages by overriding the %OnGetJSResources callback method in your Zen page class, and filling it with Set statements, such as those that define the resources MyMessage and FieldValidation in the following example:
Method %OnGetJSResources(ByRef pResources As %String) As %Status [ Private ]
{
  Set pResources("MyMessage") = $$$Text("This is my message")
  Set pResources("FieldValidation") = $$$Text("Field %1 has an error")
  Quit $$$OK
}
The %OnGetJSResources method fills in an array containing pairs of resource identifiers and text strings. %OnGetJSResources is invoked automatically, allowing you to access these resources from JavaScript using the zenText function whenever you need it; for example:
alert(zenText('MyMessage'));
alert(zenText('FieldValidation','SSN')); 
Note:
It is possible to define client side resources that apply to every page in the application. To do this, override the %OnGetJSResources method within the application class rather than in the page class.
As with $$$Text, you must provide the translations for strings such as "This is my message" yourself, as described in Localization Practices.” However, if you do this and also use zenText and %OnGetJSResources as described in this section, all of the mechanisms for delivering these translated strings work automatically. The result is that Zen automatically serves the correct translation to the user by detecting the language locale for the browser or the Caché server at runtime.
There are some localized text strings already defined as resources for client side localization in all Zen page classes. The following display lists them. The syntax in this example is not complete, because the right-hand side of the display is truncated to keep the lines short. However, each line shows enough to indicate what to expect from this resource if you invoke it using zenText:
Set pResources("zenMonthNames") = $$$Text("January,February,March,April,May,June
Set pResources("zenMonthShortNames") = $$$Text("Jan,Feb,Mar,Apr,May,Jun,Jul,Augu
Set pResources("zenDayNames") = $$$Text("Sunday,Monday,Tuesday,Wednesday,Thursda
Set pResources("zenDayShortNames") = $$$Text("S,M,T,W,T,F,S","%ZEN")
Note:
For information about JavaScript functions other than zenText, see Client-Side Functions and Variables in the “Zen Page Classes” section of the chapter “Zen Pages.”