Demo how to use localization (translate your game into multiple languages) with Castle Game Engine.
We use CastleLocalizationGetText, based on FPC GetText unit, for this. See CGE manual about text and localization: https://castle-engine.io/manual_text.php .
To translate strings used in Pascal code:
Place strings in
resourcestring. You can use English text in code, or you can use internal translation identifiers (never to be seen by normal users) -- both approaches are possible.
game.potfile (that describes the possible strings to translate).
Note that this step is optional. If you want, you can work without any
game.potfile, and just create translations by manually creating files like
game.pl.pofor each language. The syntax of PO files is trivial, see
game.potcan serve a basis for translations. You can create it using strings from the source code:
Compile the game (
rstconv(distributed with FPC) like this:
rstconv -i castle-engine-output/compilation/x86_64-linux/game.rsj -o po_files/game.pot
Note that FPC will create one
xxx.rsjfile for each unit. But this should not limit you. It's normal to put all the strings from the complete application into a single
xxx.potfile. In general, the format of the
.potand .po` files (they are the same) is trivial, they are simple text files that can be concatenated together etc.
To translate user interface:
Design it using the CGE editor, and write as
xxx.castle-user-interfacefiles. (More complex scenarios can also be handled using CastleLocalizationGetText utilities, like TranslateDesign.)
GenerateGetTextPo. See the trivial utility inside
po_files/generator/po_generator.lprin this example.
Then translate the PO files.
xxxx.pot, you create a file like
xxxx.ll.poinserting the 2-latter character code indicating a language.
You can create the
.potjust by copying it -- it's the same file format, the
.pot(PO Template) extension is just a way to indicate "this is a basis for translation".
Or you can create the
msginit --locale=pl --input=game.pot --no-translator --output-file=game.pl.po. This creates
game.pl.po, with the initial translated strings having contents from
game.pot. This makes sense if
game.potcontains English text, and it's a good starting point for a new translation.
E.g. you copy
game.pl.poto translate to Polish the resourcestrings, and you copy
user_interface.pl.poto translate to Polish the user interface designed using the CGE Editor.
plstands for a Polish translation,
enfor English etc.
game.pl.pousing a normal text editor. Or use a specialized editor like https://poedit.net/
Generate .mo file:
msgfmt po_files/game.pl.po --output-file=data/locale/game.pl.mo. We have a trivial script here
update_translations.shdoing that. You need to rerun it after every modification to
Using translations from Pascal code
Call in Pascal
CastleTranslateResourceStrings('castle-data:/locale/game.pl.mo');to use the Polish translation. This simply updates all
resourcestringcontents to the Polish versions.
TranslateAllDesigns('castle-data:/locale/user_interface.pl.mo');to translate all user interface to Polish.
If needed, you can also translate custom things, using more PO files.
var Language: String; Translations: TCastleMOFile; begin Language := 'pl'; Translations := LoadGetTextMo('castle-data:/locale/game.' + Language + '.mo'); Writeln('Translated: ', Translations.Translate('message identifier to translate')); FreeAndNil(Translations); end.
Note that we also adjust font in this application. The default font contains only basic ASCII (English) characters, so we load a font with additional German, Polish, Russian and Ukrainian characters. See https://castle-engine.io/manual_text.php about loading fonts in Castle Game Engine.
While we don't use Lazarus LCL code in CGE, but this mechanism is consistent with how Lazarus application can be localized. So a lot of Lazarus documentation apply also to us:
See also resources about gettext:
All the tools and editors for gettext files should work fine. There are even online services that take a ready PO file for translating.