Back to Contents


Localized Strings

Summary:

See also: Programs, FGLPROFILE


Definition

Localized Strings provide a means of writing applications in which the text of strings can be customized on site. This feature can be used to implement internationalization in your application, or to use site-specific text (for example, when business terms change based on territory).

This string localization feature does not define language identification.  It is a simple way to define external resource files which the runtime system can search, in order to assign text to strings in the BDL application. The text is replaced at runtime in the p-code modules (42m), in the compiled form specification files (42f), and in any XML resource files loaded in the Abstract User Interface tree (4ad, 4st, 4tb, and so on).

By using a simple notation, you can identify the Localized Strings in the source code:

01 MAIN
02   DISPLAY %"my text"
03 END MAIN

The fglcomp and fglform compilers have been extended to support a new option to extract the Localized Strings. This way, the Localized Strings can be extracted into Source String Files

From the original Source String File, you can create other files containing different text (for example, one file for each language you want to support).

You must use the fglmkstr tool to compile the source string files into a binary version. By convention, compiled string resource files must have the 42s extension.

By default, the compiled string files are loaded at runtime, according to the name of the program (42r). It is also possible to define global string files in the FGLPROFILE configuration file. See also: Using String Files at Runtime.

In 42m p-code modules, the Localized Strings are coded in our specific binary format. But, for XML files such as compiled form files (42f), the localized strings must be identified with a specific node, following the XML standards.

To support localized strings in XML files, any file loaded into the Abstract User Interface tree is parsed to search for <LStr> nodes.

The <LStr> nodes define the same attributes as in the parent node with localized string identifiers, for example:

01 <Label text="Hello!" >
02   <LStr text="label01" />
03 </Label>

The runtime system automatically replaces corresponding attributes in the parent node (text="Hello!"), with the localized text found in the compiled string files, according to the string identifier (label01). After interpretation, the <LStr> nodes are removed from the XML data.


Syntax

Syntax 1: Static Localized String

  %"sid"

Syntax 2: Dynamic Localized String

  LSTR(eid)

Notes:

  1. sid is a character string literal that defines both the string identifier and the default text.
  2. eid is a character string expression used at runtime as string identifier to load the text.

Usage:

A Localized String can be used in the source code of program modules or form specification files to identify a text string that must be converted at runtime.

Static Localized Strings

A Localized String begins with a percent sign (%),  followed by the name of the string which will be used to identify the text to be loaded. Since the name is a string, you can use any kind of characters in the name, but it is recommended that you use a proper naming convention. For example, you can specify a path by using several identifiers separated by a dot, without any special characters such as space or tab:

01 MAIN
02   DISPLAY %"common.helloworld"
03 END MAIN

The string after the percent sign defines both the localized string identifier and the default text to be used for extraction, or the default text when no string resource files are provided at runtime.

You can use this notation in form specification files as well, at any place where a string literal can be used.

01 LAYOUT
02   VBOX
03     GROUP g1 (TEXT=%"group01")
04 ...

Warning: It is not possible to specify a static localized string directly in the area of containers like GRID, TABLE or SCROLLGRID. You must use label fields to use localized strings in layout labels:

01 LAYOUT
02   GRID
03   {
04     [lab01  |f001              ]
05   {
06   END
07 END
08 ATTRIBUTES
09 LABEL lab01 : TEXT=%"myform.label01";
10 EDIT f001 = FORMONLY.field01;
11 END

Dynamic Localized Strings

The language provides a special operator to load a Localized String dynamically, using an expression as string identifier. The name of this operator is LSTR(), and the syntax is described above.

The following code example builds a Localized String identifier with an integer and loads the corresponding string with the LSTR() operator:

01 MAIN
02   DEFINE n INTEGER
03   LET n = 234
04   DISPLAY LSTR("str"||n)  -- loads string 'str234'
05 END MAIN

See also: The SFMT() operator


Source String Files

By convention, the source files of Localized Strings have the .str extension.

Defining a string:

You define a list of string identifiers, and the corresponding text, by using the following syntax:

"identifier" = "string"

Special characters:

The fglmkstr compiler accepts the backslash "\" as the escape character, to define non-printable characters:

\l   \n   \r   \t   \\

Example:

01 "id001" = "Some text"
02 "this.is.a.path.for.a.very.long.string.identifier" = "Customer List"
03 "special.characters.backslash" = "\\"
04 "special.characters.newline" = "\n"

Extracting Strings

In order to extract Localized String from Source String Files, use the fglcomp and fglform compilers with the -m option:

$ fglcomp -m mymodule.4gl

The compilers dumps all localized string to stdout. This output can be redirected to a file to generate the default Source String File with all the localized strings used in the 4gl file.


Compiling String Files

The Source String Files (.str) must be compiled to binary files (.42s) in order to be used at runtime.

To compile a Source String File, use the fglmkstr compiler:

$ fglmkstr filename.str

This tool generates a .42s file with the filename prefix.


Using String Files at Runtime

Where does the runtime system search for string files?

The runtime system searches for string files with the "42s" extension in the current directory and in the path list defined in the DBPATH environment variable.

Default string files used by the runtime system

By default, the runtime system searches for a Compiled String File having the same name prefix as the current "42r" program. For example, if you have a program named "customer.42r", the runtime system will search for the compiled string file "customer.42s" when the program is started.

Defining a list of resource files in FGLPROFILE

You can specify a list of Compiled String Files with entries in the FGLPROFILE configuration file. The file name must be specified without a file extension. The runtime system searches for a file with the "42s" extension in the current directory and in the path list defined in the DBPATH environment variable.

List of resource files

To define the list of resource files to be used, specify the total number of files with:

fglrun.localization.file.count = integer

And for each file, define the filename (without the 42s extension), including an index number, with:

fglrun.localization.file.index.name = "filename"

Start index at 1.

Warning switches

If the text of a string is not found at runtime, the DVM can show a warning, for development purposes.

fglrun.localization.warnKeyNotFound = boolean

By default, this warning switch is disabled.

Distributing string resource files

Compiled string resource files must be distributed with the program files in a directory specified in the DBPATH environment variable.


Example

The Source String File "common.str" (a compiled version must be created):

01 "common.accept" = "OK"
02 "common.cancel" = "Cancel"
03 "common.quit" = "Quit"

The Source String File "actions.str" (a compiled version must be created):

01 "action.append" = "Append"
02 "action.modify" = "Modify"
03 "action.delete" = "Delete"

The Source String File "customer.str" (a compiled version must be created):

01 "customer.mainwindow.title" = "Customers"
02 "customer.listwindow.title" = "Customer List"
03 "customer.l_custnum" = "Number:"
04 "customer.l_custname" = "Name:"
05 "customer.c_custname" = "The customer name"
06 "customer.g_data" = "Customer data"
07 "customer.g_actions" = "Actions"
08 "customer.qdelete" = "Are you sure you want to delete this customer?"

The FGLPROFILE configuration file parameters:

01 fglrun.localization.file.count = 2
02 fglrun.localization.file.1.name = "common"
03 fglrun.localization.file.2.name = "actions"

Remark: The 'customer' string file does not have to to listed in FGLPROFILE since it is loaded as it has the same name as the program.

The form specification file "f1.per":

01 LAYOUT (TEXT=%"customer.mainwindow.title")
02   GRID
03   {
04    <g g1                                    >
05     [lab1       ] [f01            ]
06     [lab2       ] [f02                     ]
07 
08    <g g2                                    >
09     [b1               ] [b2                ]
10 
11   }
12   END
13 END
14 ATTRIBUTES
15   LABEL  lab1 : TEXT=%"customer.l_custnum";
16   EDIT   f01  = FORMONLY.custnum;
17   LABEL  lab2 : TEXT=%"customer.l_custname";
18   EDIT   f02  = FORMONLY.custname, COMMENT=%"customer.c_custname";
19   BUTTON b1   : edit, TEXT=%"action.modify";
20   BUTTON b2   : quit, TEXT=%"common.quit";
21   GROUP  g1   : TEXT=%"customer.g_data";
22   GROUP  g2   : TEXT=%"customer.g_actions";
23 END

The program "customer.4gl" using the strings file:

01 MAIN
02   DEFINE rec RECORD
03             custnum INTEGER,
04             custname CHAR(20)
05          END RECORD
06   OPEN WINDOW w1 WITH FORM "f1"
07   MENU
08     ON ACTION edit
09        INPUT BY NAME rec.*
10     ON ACTION quit
11        EXIT MENU
12   END MENU
13 END MAIN