CopperSpice API  1.9.1
Modifying Your Source Code for Translation

The text portion of a user interface are the strings for the menu options, button labels, title bar of a table, text messages, etc. Programmers add these strings in their native spoken language however it is also very common for these to appear in English. For an application which is used world wide or in multiple countries, there needs to be a convenient mechanism to translate text without changing the program itself.

Any text which will be translated must be marked appropriately in the application. This is accomplished by using one of the following two methods.

  • QObject::tr()
  • QCoreApplication::translate()

After marking the text in your application, the CopperSpice Linguist programs are used to gather these strings into one common file so your translation team can enter the corresponding translations. The final translation files are then distributed with your project.

If the text which you are marking is located in a class which inherits from QObject use the QObject::tr() method. If the text is in a free function or a class which does not inherit from QObject use the static method QCoreApplication::translate().

The key difference between these two methods is how the context string is derived.

The context string indicates what entity the text is associated with, such as QPushButton or QDialog. For QObject::tr() the context string is automatically equal to the name of the current class. When using QCoreApplication::translate(), the context string is passed as the first parameter.

At run time your application can load one or more translation files as needed by the user. For each translation file create a new QTranslator object, load the translation file, then install the translator.

// typically placed in main
QTranslator translator;
translator.load("myApp_de");
app.installTranslator(&translator);

For more information refer to QTranslator, QObject::tr.

Linguist Programs

The CopperSpice translation tool lupdate is used to generate a .TS file from your source code files. Any text marked with a call to tr() or translate() will be saved in a section of the translation file which corresponds to the context string. A new translation file is considered to be "empty" since there are no translations, simply the source text.

A separate .TS file should be used for each target language. It does not make sense to include the German translations in the French translation file and there is no way to put multiple translations for one source text.

After this file is generated edit the .TS by hand or use the Linguist Application to enter the translated strings. Once this step has been completed run the lrelease program to compile each .TS file into a .QM file.

For more information refer to Linguist lupdate Application and Linguist lrelease Application.

Mark text for Translation

The following example shows how to indicate some text or phrase should be marked for translation. The "context" string will be set to MyClassA by the lupdate application. The "source" text will be First Name.

void MyClassA::setUp() {
label->setText(tr("First Name"));
}

In some situations it is might be required to override the context string. In the following example the context will be equal to MyClassB.

QString text = MyClassB::tr("First Name");

The phrase "First Name" will be added to the translation file when lupdate is run. The following is a portion of the XML translation file (TS) for the two calls to tr() shown above.

<context>
<name>MyClassA</name>
<message>
<source>First Name</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MyClassB</name>
<message>
<source>First Name</source>
<translation type="unfinished"></translation>
</message>
</context>

To generate a file which contains the German translations for your application, first run lupdate. The file name must be passed to lupdate and should be meaningful. Typically for a German translation file the letters "de" are part of the name. A new TS file should be generated for every supported language.

Once the TS file has been generated then a translator will add the correct phrases. The modified TS is shown below.

<context>
<name>MyClassA</name>
<message>
<source>First Name</source>
<translation>Vorname</translation>
</message>
</context>
<context>
<name>MyClassB</name>
<message>
<source>First Name</source>
<translation>Vorname</translation>
</message>
</context>

For more information and examples refer to QTranslator, QObject::tr, QCoreApplication::translate(), and qtTrId.

Special Cases for Marking Text

If the text which needs translating is not in a method of a class which inherits from QObject you will need to use the tr() method from a class which does inherit from QObject or use QCoreApplication::translate().

// example 1
void global_function1(LoginWidget *widget) {
QLabel *label = new QLabel(LoginWidget::tr("Password:"), widget);
}
// example 2
void global_function2(LoginWidget *widget) {
QLabel *label = new QLabel(QCoreApplication::translate("LoginWidget", "Password:"), widget);
}

Using tr() for Localization

Localization is the process of adapting to local conventions. For example, presenting dates and times using the locally preferred formats. Such localizations can be accomplished using appropriate tr() strings. For localized numbers use the QLocale class.

void Clock::setTime(const QTime &time) {
if (tr("AMPM") == "AMPM") {
// 12-hour clock
} else {
// 24-hour clock
}
}

Missing Translations

At run time if a translation is missing or not available the native language text will be displayed.

Translator Comments

Information about each source string can be added just before the call to tr(). This is typically used to help the team who is doing the translations. The comments are extracted when lupdate is used to create the .ts file. The following syntax shows two different ways to add a comment to a call to tr(). This technique can also be used for calls to translate().

//: This name refers to a login account
hostNameLabel->setText(tr("User Name:"));
/*: This text refers to a code example */
QString example = tr("Example");

Adding Meta Data

Additional data can be attached to each source string. These are extracted by lupdate and then added to the .TS file.

There are two different kinds of meta data. The first is an id which is specified by the example shown below. This can be used to give the source text a unique identifier to support other tools which utilize id values.

//= <id>

The second type of meta data is a key value pair as shown below. The key must use an underscore or a dash instead of a space. The tag in the XML .TS file will prepend the word "extra-" to your key.

//~ <field name> <field contents>

//= special_id
//~ prefix-someKey someValue
QString text = MyClass::tr("Word Wrap");

Distinguishing Between Identical Strings

If the exact same source string can be translated in different ways, the translation is ambiguous. The tr() and translate() methods have an optional parameter to distinguish the translations, so the correct one is selected. When the comment string is passed it will be used to select the correct translation.

MyWindow::MyWindow() {
QLabel *senderLabel = new QLabel(tr("Name:", "sender"));
QLabel *recipientLabel = new QLabel(tr("Name:", "recipient"));
}

Dynamic Translation

This section applies to applications which support changing the translated language at run time. As an example suppose the default language is English and the user selected German and then at some point needs to switch to French.

In order to make widgets aware of this run time change, reimplement the widget's changeEvent() to check for a LanguageChange event.

void MyWindow::changeEvent(QEvent *event) {
if (e->type() == QEvent::LanguageChange) {
titleLabel->setText(tr("Document Title")); // retranslate text
okPushButton->setText(tr("&OK"));
} else {
}
}

All other change events should be passed by calling the default implementation of the function.

The list of installed translators might change in reaction to a LocaleChange event, or the application might provide a user interface that allows the user to change the current application language.

The default event handler for QWidget subclasses responds to the QEvent::LanguageChange event, and will call this function when necessary.

LanguageChange events are posted when a new translation is installed using the QCoreApplication::installTranslator() function. Additionally, other application components can also force widgets to update themselves by posting LanguageChange events to them.

Numbers

Handling Plurals

Some phrases may need a numeric value which is only available at run time. To handle this situation %n is added to the source text. This serves as a placeholder which will be replaced by the translation system when the user is running the program.

An additional integer value must be passed to QObject::tr() or QCoreApplication::translate() for plurals to be handled correctly. The value for n will be substituted for the %n in the translated string. This value will also be used to select the translation with the correct plural form.

The following is code which would appear in your application.

int n = messages.count();
showMessage(tr("Attending %n conference(s)", "conference count", n));

The following is a portion of a valid .TS file which contains the translations from English to German. If the numeric value is 1 the first translation will be used and if the numeric value is 2 or greater the second translation will be used.

// portion of a translation file with German translations
<context>
<name>MyClass</name>
<message numerus="yes">
<source>Attending %n conference(s)</source>
<translation>
<numerusform>Teilnahme an %n Konferenz</numerusform>
<numerusform>Teilnahme an %n Konferenzen</numerusform>
</translation>
</message>
</context>

We strongly recommended you do not use the following code when calling tr(). This may work for some languages however it will not work universally.

n == 1 ? tr("Attending %n conference)") : tr("Attending %n conferences") // not recommended

The lupdate application has a -pluralonly command line option which allows the creation of TS files containing only entries with plural forms.

Localizing Numbers

The source string which will be translated can contain %Ln which indicates the locale rules should be used for converting the supplied number to a string. A summary of supported languages and the rules used to translate strings containing plurals can be obtained by running "lupdate -list-languages".

Handling Numbered Arguments

Some phrases may need a numeric value which is only available at run time. To handle this situation a percent sign followed by a digit is added to the source text. This serves as a placeholder which will be replaced by the translation system when the user is running the program.

Given the following example: "After processing file %1, file %2 will be processed".

At run time %1 and %2 will be replaced with the first and second file names. Both of these numbered arguments must appear in the translation text. For some languages %2 may appear before %1 in the translation.

Accelerator Keys

Changing Keyboard Accelerators

A keyboard accelerator is a key combination which is pressed and some defined action will occur. There are two kinds of keyboard accelerators: Alt and Ctrl key accelerators.

Use QKeySequence() for Accelerator values

Accelerator values such as Ctrl+Q or Alt+F may need to be translated in your application. The correct way is to use the two argument version of QObject::tr() to mark the accelerators for translation. The string "Quit" will help the translator understand the meaning of the shortcut.

exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcuts(tr("Ctrl+Q", "Quit"));

Alt Key Accelerators

Alt key accelerators are used in menu selections and buttons. The underlined character in a menu item or button label signifies that pressing the Alt key with the underlined character will perform the same action as clicking the menu item or pressing the button.

For example, most applications have a File menu with the "F" in the word File underlined. This menu option can be invoked either by clicking the mouse on the word File or by pressing Alt+F. To identify an accelerator key in the translation text add an ampersand, &File.

The translator can change the character part of the Alt key accelerator, if the translated phrase does not contain the same character or if that character has already been used in the translation of some other Alt key accelerator.

If text which should be translated contains an ampersand then the translation for that string should also have an ampersand in it, preferably in front of the corresponding character.

Ctrl Key Accelerators

Ctrl key accelerators can exist independently of any visual control. They are often used to invoke actions in menus that would otherwise require multiple keystrokes or mouse clicks. They may also be used to perform actions that do not appear in any menu or on any button.

As an example, consider as application with a File menu which has a submenu containing Open. The Open item might appear as "Open File Ctrl+O", which means it can be called by simply pressing Ctrl+O instead of clicking the mouse on File and then clicking Open.

Warning
You should not translate the words Alt, Ctrl or Shift. CopperSpice relies on these being in English and will automatically translate them to the target language.