Summary:
See also: Localization, Programs, FGLPROFILE
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
MAIN02
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 allows the Localized Strings to be extracted into Source String Files. From the original .str Source String File, you can create other files containing different text (for example, one file for each language you want to support). Then, 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 a
proprietary binary format. But, for XML files such as Action
Defaults files (4ad), the localized strings must be written 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.
Note that to take effect, a localized attribute in the LStr node must have a corresponding attribute in the parent node.
%"sid"
LSTR(eid)
<ParentNode attribute = "default-text" [...]
>
<LStr attribute = "sid" [...]
/>
</ParentNode>
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 type
of characters in the name, but it is recommended that you use a 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
MAIN02
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
LAYOUT02
VBOX03
GROUP g1 (TEXT=%"group01")04
...
Note that 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
LAYOUT02
GRID03
{04
[lab01 |f001 ]05
{06
END07
END08
ATTRIBUTES09
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
MAIN02
DEFINE n INTEGER03
LET n = 23404
DISPLAY LSTR("str"||n) -- loads string 'str234'05
END MAIN
See also: The SFMT() operator
In order to internationalize an existing application, follow the process described below:
"Customer List" = "Customer List"
"customer.list.title" = "Customer List"
/opt/app/resource/strings/en_US.iso8859-1
-- English strings in iso8859-1 code-set
/opt/app/resource/strings/fr_FR.iso8859-1
-- French strings in iso8859-1 code-set
/opt/app/resource/strings/jp_JP.utf8
-- Japanese strings in utf-8 code-set
Future edits to the .per and .4gl source files should be done in the ASCII locale, and .str string files must be edited with their specific locale.
By convention, the source files of Localized Strings have the .str extension.
You define a list of string identifiers, and the corresponding text, by using the following syntax:
"identifier" =
"string"
The fglmkstr compiler accepts the backslash "\" as the escape character, to define non-printable characters:
\l \n \r
\t \\
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"
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.
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.
When compiling a string file, you must set the locale (character set) corresponding to the encoding used in the .str file.
The "42s
" Compiled
String Files must be distributed with the program files in
a directory specified in the DBPATH/FGLRESOURCEPATH
environment variable.
The locale (character set) corresponding to the encoding used in the .42s files must be set before starting the application. If the locale is wrong, the strings will not be loaded correctly.
Searching for a string resource in the .42s files follows this order of precedence:
42r
" program,default.42s
".For each string file, the runtime system searches in the following directories:
FGLDIR/lib
directory.A string is loaded in memory only once (if the same string is defined in another file, it is ignored).
If a localized string is not defined in a resource files, the runtime system uses the string identifier as default text.
When a localized string is defined in several resource files, the runtime system uses the first string found.
For example, if the string "hello" is defined in program.42s
as "hello from program", and in default.42s
as
"hello from default", the runtime system will use the text "hello
from program".
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/FGLRESOURCEPATH
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.
A set of .42s files using the same language and code-set is typically copied in a distribution directory with a name identifying the locale.
For example:
/opt/app/resource/strings/en_US.iso8859-1 --
English strings in iso8859-1 code-set
/opt/app/resource/strings/fr_FR.iso8859-1 --
French strings in iso8859-1 code-set
/opt/app/resource/strings/jp_JP.utf8
-- Japanese strings in utf-8 code-set
At runtime, the list of string files is defined with fglrun.localization entries in FGLPROFILE, and you specify the search path for the current locale with the DBPATH/FGLRESOURCEPATH environment variable.
In some situations, the runtime system needs to display text to the user. For example, the runtime system library includes a report viewer, which displays a form. By default the text is in English, and you may need to localize the text in another language. So the strings of this component must be 'localizable', as in other application strings.
To customize the built-in strings, the runtime system uses the mechanism of localized strings.
All strings used by the runtime system are centralized in a unique file:
$FGLDIR/src/default.str
which is compiled into:
$FGLDIR/lib/default.42s
This file is always loaded by the runtime system.
To overwrite the defaults, you can re-define these strings in your own localized string files. See also: Using String Files at Runtime.
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 = 202
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
GRID03
{04
<g g1 >05
[lab1 ] [f01 ]06
[lab2 ] [f02 ]07
08
<g g2 >09
[b1 ] [b2 ]10
11
}12
END13
END14
ATTRIBUTES15
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
MAIN02
DEFINE rec RECORD03
custnum INTEGER,04
custname CHAR(20)05
END RECORD06
OPEN WINDOW w1 WITH FORM "f1"07
MENU08
ON ACTION edit09
INPUT BY NAME rec.*10
ON ACTION quit11
EXIT MENU12
END MENU13
END MAIN