Developer Translation Documentation
Improve this pageMumble makes use of the Qt framework. This is also the case for translations. We follow the Qt tools and translation workflow.
Translators can translate our project in our Mumble Weblate project without a need for Git, Code, or programs other than their web browser.
The .ts
translation files are located in the Mumble repository in src/mumble/mumble_*.ts
.
We currently version a mumble_en.ts
as a reference file for translations, and individual files for each locale we support (which each holds the source strings too anyway).
Qt supports both an ID-based approach as well as a source + translated text approach. Weblate calls the ID based approach monolingual (a ts file does not contain the source text) and bilingual (a ts files contains both source and translated text).
We effectively work with the bilingual file approach, but have the Weblate project set up as if it were ID based. This is for historic reasons and should be changed in the future.
Adding a language
To add a new language the ts file is created with lupdate
, and a file reference is added to the ts_files
variable in src/mumble/CMakeLists.txt
.
Creating translatable strings
In Qt translation strings have a context – a class context. The fallback is the QApplication context. But any Q_OBJECT
class introduces their own context. In the ts
file texts are grouped by context.
Literal text is translated (“marked”), typically through the QObject::tr
method, which in turn calls QCoreApplication::translate with an adequate.
NOTE: To provide structure to the many translation strings, tr
should be called on the most reasonably specific class. (Calling it on the base QObject
will make it fall back to the generic QApplication
context.)
Classes not extending from QObject can also be extended with the tr
context functionality.
See also upstream documentation Using tr() for All Literal Text (and the context around it).
Numbers and Dates
Special care has to be taken for formatting date and time and numbers. The format of these differs by locale, and may be disassociated from the language a user uses too.
See also QLocale and other Qt classes for date, time and numbers.
- Using tr() to Localize Numbers (shows only one case/may not be the best approach)
Disambiguation
Identical text in the same context can be disambiguated with an additional identifying string.
QLabel *senderLabel = new QLabel(tr("Name:", "sender"));
QLabel *recipientLabel = new QLabel(tr("Name:", "recipient"));
Plurals
Plurals have special handling in general and between languages. Depending on the locale/language, a plural (word) may differ between 0, 1, 2. And they may differ in different ways.
Numbered plurals are marked with a (s)
word postfix like %n word(s)
.
Notably this will not show up as word(s)
in the program, but as word
or words
depending on the parameter value.
The translation files (ts files) may have any number of <numerusform>
elements as translations, rather than just one translation text.
<message numerus="yes">
<source>Ban List - %n Ban(s)</source>
<translation>
<numerusform>Bannliste - %n Bann</numerusform>
<numerusform>Bannliste - %n Bann(s)</numerusform>
</translation>
</message>
Other languages may have three forms.
Handling Plurals Translation Rules for Plurals
Numbered Arguments (Ordered)
The order of arguments within a string may change with a text translation. Numbering them and passing values with arg()
will allow translators to change the order as they see fit.
label.setText(tr("%1 of %2 files copied.\nCopying: %3")
.arg(done)
.arg(total)
.arg(currentFile));
A translator comment may help them identify parameters if not obvious from the source text.
Mnemonics
Programs typically show these while holding down ALT, and single characters can be used to activate controls allowing for keyboard-based usage of GUI applications. While ALT is pressed the mnemonic key is usually underlined.
The typical ampersand &
markers are used to define mnemonics on a control text.
For example:
E&xit
would lead tox
being the mnemonic&Exit
would lead toe
being the mnemonic
In both cases, the displayed text on the control will be Exit
.
Accelerator Values
Use QKeySequence
to use keyboard shortcuts so they are translatable too.
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
Translating text outside of classes
Classes provide code structure. Yet sometimes text may end up outside of classes and Qt classes, and reasonably so.
Then tr
can be called as a public static method on an appropriate class the text belongs to. Or QCoreApplication::translate
can be called directly.
For text without context the QT_TR_NOOP
and QT_TRANSLATE_NOOP
macros can be used.
Translator Comments
Translating text often requires context. It can be difficult to grasp a texts context from just the source string. Without the program or source code open and next to the source string, it can be impossible to grasp the context.
Translator comments can help provide context to a source string.
//: This name refers to a host name.
hostNameLabel->setText(tr("Name:"));
/*: This text refers to a C++ code example. */
QString example = tr("Example");
Metadata
Additional metadata can be attached to translatable text for advanced behavior, also further down the line on translation platforms.
CMake integration
We make use of qt5_create_translation
. This will call lupdate
and lrelease
.
The ts translation files are stripped of unrelated, unused texts (they contain text for multiple platforms while the program is compiled for just one), and then packaged into the application (through the Qt resource system; qrc definition file).
Regarding Qt resources see The Qt Resource System.