Difference between revisions of "Supporting GUI Translation"
(→TO DO: Remove first two points of TO DO list as they have now been implemented.) |
m (Added info about translations in game engine code) |
||
(16 intermediate revisions by 5 users not shown) | |||
Line 2: | Line 2: | ||
== Mark translatable strings in the source code == | == Mark translatable strings in the source code == | ||
In order to make a string translatable you have to use one of the following | In order to make a string translatable you have to use one of the following macros in your code: | ||
* | * ''_(const char *)'' - The simplest way to mark and substitute strings at the same time. It is not a constant operation, i.e. it returns a translated version of the string and might have side effects, thus it should not be used for static data tables. For the majority of translatable strings using ''_()'' is the suggested method. This can also be used on variables, which contain strings marked for translation, and simply subsitutes the string then. | ||
* '' | * ''_c(const char *, const char *)'' - Another way to mark and substitute strings. It attaches the string to a context so that we can have different translations for the same string. The second argument is the context. This is not a constant operation either, so it should not be used for static data tables either. This can also be used on variables, which contain strings marked for translation, and simply subsitutes the string then. | ||
* | * ''_s(const char *)'' - Only mark a string to be translated. This is a constant operation, i.e. it also evaluates to the unchanged string. This is mainly used for marking translatable strings in static data tables. In this case you mark these strings with ''_s()'', and then use ''_()'' or ''_c()'' at the place where you need to perform the substitution. | ||
< | * ''_sc(const char *, const char *)'' - Another way to only mark strings for translations. It attaches the string to a context so that we can have different translations for the same string. The second argument is the context. Subsitution should be performed via ''_c()'' later. | ||
static const char* foo = _s("Some translatable text"); | * ''DECLARE_TRANSLATION_ADDITIONAL_CONTEXT(const char *, const char *)'' - Declare a string (first argument) to translate in a given context (second argument). This macro does not evaluate to any value. | ||
StaticTextWidget* bar = new StaticTextWidget(this, "name", _(foo), _("Some other translatable text for the tooltip")); | |||
</ | If you want to give some additional explanations to the translators, or your string could be understood in a different ways, it is recommended to precede it with a comment tagged I18N. | ||
<syntaxhighlight lang="cpp"> | |||
// I18N: This is explanation to the line below and will be included in .pot and .po files | |||
static const char *foo = _s("Some translatable text"); | |||
DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Some translatable text", "lowres") | |||
StaticTextWidget *bar = new StaticTextWidget(this, "name", _(foo), _("Some other translatable text for the tooltip")); | |||
StaticTextWidget *bar = new StaticTextWidget(this, "name", _c(foo, "lowres"), _("Some other translatable text for the tooltip")); | |||
StaticTextWidget *path = new StaticTextWidget(this, "name", _("None", "path")); | |||
// I18N: Some more explanations for the translators | |||
StaticTextWidget *soundfont = new StaticTextWidget(this, "name", _("None", "soundfont")); | |||
</syntaxhighlight> | |||
In the above example foo can be translated differently depending if it is attached to the context "lowres" or not. | |||
"None" can also be translated differently depending if it refers to a path or a soundfont. | |||
== Update the translation template file == | == Update the translation template file == | ||
# All the files that contain translatable text should be listed in | # All the files that contain translatable text should be listed in either po/POTFILES file for core files or engines/<engineName>/POTFILES for game engines. So if you are adding translatable text into a file, you should make sure that file is listed in POTFILES and otherwise add it to the list. | ||
# You should then update the scummvm.pot template file by running "''make updatepot''". You need to have the gettext tool installed to run that command. | # You should then update the scummvm.pot template file by running "''make updatepot''". You need to have the gettext tool installed to run that command. | ||
The translations are | The translations are transformed into a ''translations.dat'' file (which can be done by executing "''make translations-dat''"), and the gettext tools are not needed for the compilation or executation of ScummVM. They are only needed to update the scummvm.pot template file and the translations when translatable strings are added, removed or modified in the source code. | ||
== Translations file format == | |||
See [[Supporting GUI Translation/Translations DAT Format|Translations Data File Format]] for a description of the format of the ''translations.dat'' file. | |||
== TO DO == | == TO DO == | ||
* Updating interface without restart. This will require moving much code to reflowLayout() for all dialogs and is a big piece of work. | * Updating interface without restart. This will require moving much code to reflowLayout() for all dialogs and is a big piece of work. | ||
* Situations with strings not fitting into widgets. No code around that. Suggestions are welcome. | * Situations with strings not fitting into widgets. No code around that. Suggestions are welcome. | ||
* | * Behavior for non-ASCII hotkeys (surrounded by tildes) is undefined and was not even tested. |
Latest revision as of 04:40, 7 June 2020
This page describes what developers need to do to make some part of the ScummVM GUI translatable. Therefore it concerns in particular the porters and developers working on the GUI.
Mark translatable strings in the source code
In order to make a string translatable you have to use one of the following macros in your code:
- _(const char *) - The simplest way to mark and substitute strings at the same time. It is not a constant operation, i.e. it returns a translated version of the string and might have side effects, thus it should not be used for static data tables. For the majority of translatable strings using _() is the suggested method. This can also be used on variables, which contain strings marked for translation, and simply subsitutes the string then.
- _c(const char *, const char *) - Another way to mark and substitute strings. It attaches the string to a context so that we can have different translations for the same string. The second argument is the context. This is not a constant operation either, so it should not be used for static data tables either. This can also be used on variables, which contain strings marked for translation, and simply subsitutes the string then.
- _s(const char *) - Only mark a string to be translated. This is a constant operation, i.e. it also evaluates to the unchanged string. This is mainly used for marking translatable strings in static data tables. In this case you mark these strings with _s(), and then use _() or _c() at the place where you need to perform the substitution.
- _sc(const char *, const char *) - Another way to only mark strings for translations. It attaches the string to a context so that we can have different translations for the same string. The second argument is the context. Subsitution should be performed via _c() later.
- DECLARE_TRANSLATION_ADDITIONAL_CONTEXT(const char *, const char *) - Declare a string (first argument) to translate in a given context (second argument). This macro does not evaluate to any value.
If you want to give some additional explanations to the translators, or your string could be understood in a different ways, it is recommended to precede it with a comment tagged I18N.
// I18N: This is explanation to the line below and will be included in .pot and .po files
static const char *foo = _s("Some translatable text");
DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Some translatable text", "lowres")
StaticTextWidget *bar = new StaticTextWidget(this, "name", _(foo), _("Some other translatable text for the tooltip"));
StaticTextWidget *bar = new StaticTextWidget(this, "name", _c(foo, "lowres"), _("Some other translatable text for the tooltip"));
StaticTextWidget *path = new StaticTextWidget(this, "name", _("None", "path"));
// I18N: Some more explanations for the translators
StaticTextWidget *soundfont = new StaticTextWidget(this, "name", _("None", "soundfont"));
In the above example foo can be translated differently depending if it is attached to the context "lowres" or not. "None" can also be translated differently depending if it refers to a path or a soundfont.
Update the translation template file
- All the files that contain translatable text should be listed in either po/POTFILES file for core files or engines/<engineName>/POTFILES for game engines. So if you are adding translatable text into a file, you should make sure that file is listed in POTFILES and otherwise add it to the list.
- You should then update the scummvm.pot template file by running "make updatepot". You need to have the gettext tool installed to run that command.
The translations are transformed into a translations.dat file (which can be done by executing "make translations-dat"), and the gettext tools are not needed for the compilation or executation of ScummVM. They are only needed to update the scummvm.pot template file and the translations when translatable strings are added, removed or modified in the source code.
Translations file format
See Translations Data File Format for a description of the format of the translations.dat file.
TO DO
- Updating interface without restart. This will require moving much code to reflowLayout() for all dialogs and is a big piece of work.
- Situations with strings not fitting into widgets. No code around that. Suggestions are welcome.
- Behavior for non-ASCII hotkeys (surrounded by tildes) is undefined and was not even tested.