Using resourcestrings
│
English (en) │
español (es) │
Bahasa Indonesia (id) │
русский (ru) │
Resource strings provide a mechanism to internationalize (and to some degree localize) your application.
rationale
Resource strings are constants with an extra level of indirection. The default value (as written in your source code) is stored in the executable program. That means it is always available, even if loading the translation fails.
common steps
The first step is to use resource strings for every string that potentially needs translation. In this tutorial we want to internationalize our Hello World program:
program helloWorld(input, output, stdErr);
resourceString
hello = 'Hello world';
begin
writeLn(hello);
end.
The FPC creates a file ending in .rsj
(resource string JSON) for every compiled module containing a resourceString
section.
For the above program it looks like this (pretty-format added):
{
"version": 1,
"strings": [
{
"hash": 20229140,
"name": "helloworld.hello",
"sourcebytes": [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100],
"value": "Hello world"
}
]
}
This intermediate file format was created, so the compiler does not need any knowledge of the utilized translation tool.
It just needs to create .rsj
files.
The following steps differ on the used internationalization mechanism. As of 2021 the FPC only supports GNU gettext entirely. The reason gettext was chosen is that it is more or less standard on Unix-like systems, like Linux or FreeBSD.
GNU get text
limitations
As mentioned, GNU gettext is widely available on Unix-like systems. However, gettext is horribly inefficient. Also, gettext is context insensitive, that means it operates on the string itself: Sometimes the same word/sentence must be translated differently according to the context, but this is not possible.
procedure
- Convert the
.rsj
file into GNU gettext’s portable object format:rstconv -f po -i helloWorld.rsj -o helloWorld.po
- Create a working copy of the generated file, e. g.and translate it with your favorite translation tool or simply with a text editor.
cp helloWorld.po helloWorld-de.po
#: helloworld:hello msgid "Hello world" msgstr "Hallo Welt"
- Convert the PO file to an MO (machine object) file using gettext’s utility
msgfmt
:msgfmt -o helloWorld-de.mo helloWorld-de.po
- Integrate gettext in your program:The
program helloWorld(input, output, stdErr); uses gettext; resourceString hello = 'Hello world'; begin translateResourceStrings('helloWorld-%s.mo'); writeLn(hello); end.
%s
is substituted with the locale’s name. Examining anstrace
you will see, that for example firsthelloWorld‑de.mo
is attempted to open. If it does not exist, it trieshelloWorld‑de_DE.mo
. If neither file exists, the resource string’s default values as specified in your source code are used. - Run the program and celebrate your achievement:
LANG='de_DE.UTF-8' ./helloWorld
For more details see the gettext unit documentation.
resource DLLs
The FPC’s standard RTL does not yet contain portable functions for loading texts from resource DLLs containing translations (as Delphi does), but the first step would be:
- Convert the
.rsj
file into a resource compiler script:rstconv -f rc -i helloWorld.rsj -o helloWorld.rc
message files
The FPC currently does not support this, but the first step would be:
- Convert the
.rsj
file in an IBM OS/2 message file:The component identifier indicated byrstconv -f msg -c HWX -i helloWorld.rsj -o helloWorld.msg
‑c
may be any three upper-case ASCII letters, but it should be unique within your project.
alternatives
To implement another mechanism, 3 things are needed:
- Update rstconv so it can output another format.
- Tools to manipulate the other format.
- Implement a unit that loads the other format at run-time.
Routines to directly manipulate a program’s resource string tables, i. e. the extra level of indirection for resource strings, were available in the objpas unit until revision 31687.
history
Formerly, the FPC created text files ending in .rst
.
While changing to the JSON format, the name of the rstconv
utility was preserved.
rstconv
can still convert .rst
files.
# hash value = 20229140
helloworld.hello='Hello world'