Development/Tutorials/Localization/i18n
What is Internationalization and Localization?
Internationalization, or i18n ('i', followed by 18 letters, then an 'n'), is the process of writing your application so that it can be run in any locale. This means taking into account data output such as:
- textual messages that are displayed to the user
- data input from the user, files and other sources
- format of dates, numbers, currency, dates, etc.
Localization, or l10n ('l', followed by 10 characters, then an 'n'), is the process of taking an internationalized application and adapting it for a specific locale.
Generaly speaking, programmers internationalize their applications and translation teams localize them.
Why is This Important?
KDE development happens primarily in English as this allows the broadest reach into the development and translation communities. However, English is not the primary language of most people on the planet. With literally thousands of languages and many different formatting styles it becomes necessary to provide software in multiple languages to approach the largest audience possible.
As an international project that spans the globe this is core value within the KDE culture. In fact, while many KDE developers write their software in English they use the desktop in their native locale.
Writing Translatable Code With i18n()
To ensure your application is ready to be localized you have to follow a few simple rules. All user-visible strings in your application should be translated before they are displayed on the user's screen, exceptions to this being debugging messages, configuration keys and similar types of text data.
KDE provides the KLocale class as part of libkdecore to facilitate the technical details of localization. KLocale makes it as easy as possible for developers to make their code i18n aware, but there are some things you need to be aware of so that applications are usable in other languages and countries.
Access to a global KLocale object is provided via KGlobal::locale(). This KLocale object is created automatically by KInstance for you and take care of all user i18n related settings. It is deleted automatically on application exit.
Translations are made possible by the QString i18n(const char*) method which you must wrap all strings that should be displayed in. The QString returned by i18n() is the translated (if necessary) string. This makes creating translatable widgets as simple as in this example:
QPushButton* myButton = new QPushButton(i18n("Translate this!"));
QString's native Unicode support ensures that all translations are represented correctly. All string handling done by your application should therefore use QString.
I18N_NOOP
The i18n() method requires that a KInstance (e.g. KApplication) has been created. For any strings that are created prior to this there is a macro provided: I18N_NOOP(). This allows one to mark strings that should be translated later as such.
When you want to actually translate the string at runtime, you still have to use i18n() with exactly the same string. I18N_NOOP() is typically used for strings given to KAboutData, because it is constructed before the KApplication and you can use i18n() only after the construction of the KApplication. Other than these special cases, it is always safe to use i18n() if you are sure that the code will be executed after construction of KApplication or some other KInstance.
Adding Context
There is an extended version of i18n() which takes two const char* arguments. The first argument is an additional contextual description of the second, translated string. The first string is used to find the proper corresponding translation at run-time and is shown to translators to help them understand the meaning of the string.
Use this variety of i18n() when the purpose of the text might be ambiguous without further context. For example, consider a context menu in a file manager with an entry called "View" which opens a viewer for the currently selected file. In this context "View" is a verb. However, the same application also may have a menu called "View" in the menubar. In that context "View" is a noun. In the English version of the application everything looks fine, but in most other languages one of the two "View" strings will be incorrect.
Additionally, translators sometimes need extra help in understanding what the text is actually refering to during the translation purpose.
In the file manager example above, one might therefore write:
contextMenu->addAction(i18n("verb, to view something", "View"));
viewMenu->addAction(i18n("noun, the view", "View"));
Now the two strings will be properly translatable, both by the human translators and at runtime by KLocale.
Use this form of i18n whenever the string to translate is short or the meaning is hard to discern when the context is not exactly known. For example:
QString up = i18n("Go one directory up in the hierarchy", "Up");
QString relation = i18n("A person's name and their familial relationship to you.", "%1 is your %2").arg(name, relationship);
Plurals
Plurals are handled differently from language to language. Many languages have different plurals for 2, 10, 20, 100, etc. When the string you want translated refers to more than one item, you must use the third form of i18n: QString i18n(const char* signular, const char* plural, int number). For example:
msgStr = i18n("Creating index file: 1 message done",
"Creating index file: %n messages done", num);
This form of i18n() gets expanded to as many cases as required by the user's language. In English, this is just two forms while in other languages it may be more depending on the value of the number parameter.
Note that this form should be used even if the string always refers to more than one item as languages use a singular form even when referring to a multiple (typically for 21, 31, etc.). This code:
i18n("%1 files were deleted").arg(numFilesDeleted);
is therefore incorrect and should instead be:
i18n("%1 files were deleted",
"%1 files were deleted",
numFilesDeleted).arg(numFilesDeleted);