Translation
In the frontend (JavaScript) and the backend (CakePHP backend) we use English as base language and wrap strings in translation functions. Those strings are extracted from the code and translated to other languages.
Translation Functions
Backend
In the backend PHP code the __() function translates strings, for example:
$this->Flash->success(__('The note has been saved.'));
The strings may contain placeholders.
__('The following {0} types are missing: {1}.',
$missingScope,
implode(', ',$missing_links)
)
See the I18n CakePHP documentation.
Frontend
In JS files, the strings are translated using the t() function from the
lingui package:
import {i18n} from '/js/lingui.js';
i18n.t('String to be translated')
Generating Translation Files
The translation functions read translation files.
For creating those translation files, we use POT and PO files.
POT files (Portable Object Template) are text files extracted from the code.
They contain the strings to be translated after the msgid key,
followed by an empty string with the key msgstr in the next line:
msgid "Hello world"
msgstr ""
Those template files are copied to or merged with PO (Portable Object) files.
In the PO files, the empty strings after msgstr are replaced by appropriate translations using Poedit (see below).
Each language lives in its own file. The following lines are an example from a French PO file:
msgid "Hello world"
msgstr "Bonjour le monde"
POT and PO files follow the GNU Gettext format,
We use a structure containing source code references after #:, for example:
#: Model/Entity/Article.php:583
#: Model/Entity/Project.php:230
msgid "Norm data"
msgstr "Normdaten"
MO (Machine Object) files are binary versions that can be created with the msgfmt program.
MO files are not currently used by Epigraf.
Extract Translation Templates from Backend Code (PHP)
The strings are automatically extracted from the code to create translation files. To extract all strings into a single POT file, run the following command in the root of the repository:
bin/cake i18n extract --paths /var/www/html/src,/var/www/html/templates,\
/var/www/html/plugins/Epi/src,/var/www/html/plugins/Epi/templates,\
/var/www/html/plugins/Files/src,/var/www/html/plugins/Files/templates,\
/var/www/html/plugins/Batch/src,/var/www/html/plugins/Batch/templates,\
/var/www/html/plugins/Widgets/src,\
/var/www/html/plugins/Rest/src
Notes for using the extract function:
- Skip extracting messages from CakePHP core
- Confirm the output path with Enter
The resulting POT file contains the strings to be translated.
From the POT file, one single PO file is created or updated for each language using Poedit (see below).
The German file, for example, is stored in code/html/resources/locales/de_DE/default.po.
Translation begins in this one file.
Extract Translation Templates from Frontend Code (JavaScript)
Strings to be translated are extracted from JavaScript code with npm, which calls lingui extract:
npm run lingui-extract
This will update the file resources/locales/en_DE/js_messages.po.
Which Javascript files are taken into account is defined in the lingui.config.js file in the include key:
import { formatter } from "@lingui/format-po";
module.exports = {
locales: ["de_DE"],
sourceLocale: "en",
catalogs: [
{
path: "resources/locales/{locale}/js_messages",
exclude: ["plugins/Widgets/webroot/js/*.min.js"],
include: [
"plugins/Widgets/webroot/js/*.js",
"plugins/Epi/webroot/js/*.js"
]
}
],
format: formatter({ explicitIdAsDefault: true })
};
The path key defines the name of the resulting PO file, ready for translations.
Translations with Poedit
For translations, we use the program Poedit. After starting Poedit, select “Edit translation”, navigate to the appropriate location in the repository and select the PO file.
Only PO files are translated, not the templates. If new strings have been extracted from the PHP or JS code, the common POT file must be merged into the PO file:
- Choose “Catalog” -> “Update from POT file”.
- The new POT file is now automatically compared with the current PO file,
Poedit will automatically list all strings that need to be translated. Work through the list. If you are unsure, you can mark entries for revision in the program. They will be highlighted in orange. Remember to save the file after translating.
Update Translations
In order for the translations to be displayed, the backend cache needs to be cleared after changes to the translation files:
bin/cake cache clear_all
The frontend translations are loaded from JavaScript files in the htdocs/msg folder.
Update the file by the following npm command (which triggers calls to lingui compile and webpack):
npm run lingui-build