KDE i18n Howto


This document gives a brief introduction howto prepare KDE applications to successfully support other languages and to be used in other countries. It also lists some common problems and how to avoid them.


Contents

Introduction

To support internationalization (i18n) and localization (l10n) KDE offers the class KLocale which is contained in kdecore. KLocale has a lot of functionality to make it as easy as possible for developers to make their code i18n aware. Nevertheless there are some things to take care of, so that applications are useable in other languages and countries, too.

To use KLocale, you don't have to create an instance of it by your own, but you have access to the global KLocale object with KGlobal::locale(). The object you receive takes care of all user settings and will be deleted automatically on application exit. The next few paragraphs will show in more detail how to use the functionality of KLocale and what you have to take care of.

i18n

i18n is a short for internationalization, and means that the program will be displayed in the language you choose. In KDE, all strings should be translated before they are displayed on the user's screen. What you should not translate are debug messages and similiar.

How to prepare the code

To make translations possible, the programmer has to use i18n() on all strings that should be displayed. i18n() takes a const char* as an argument and returns a translated QString or the original string if no translation was found. As you see on the returned value, which is of type QString, you should use QString for all strings, that can be translated, because it uses internally unicode characters and therefore can handle strings in all languages. While when you you are using the classical char* string, you will have to take care of the different possible charsets by your own. (If you are wondering where to find documentation of the i18n() function: it is defined as a global function in klocale.h and uses KLocale::translate() internally)

Since all equal strings are summarized and are therefore translated with the same string, there is an additional extended function i18n() which takes two const char* arguments. The first argument is an additional description of the second string (which is shown to the user) and both strings together are used to find the corresponding translation. In addition the first argument is shown to the translators as hint of the meaning or context of this string.

Example: Think of a file manager, where you can open a context menu on a file and select View to view the file. In this context View is a verb. Additionaly the window of the file manager has a menu View in the menubar. In this context View is a noun. In the english version of the application everything looks fine, but in most other languages one of the strings will be wrong and confuses the user. Even if equal strings would not be translated with the same string, it would be difficult for the translators to find out, which of these strings is used as verb and which as noun. The solution for this is to use the extended i18n() function: For the context menu something like i18n("to view something","View") and for the menu in the menubar i18n("the view","View"). This way both strings are translated as separate strings and the translator has a hint how to translate these strings.

In general it is a very good idea to use this extended function, if the string to translate is short and the meaning is hard to find out, when the context is not exactly known.

You may have seen another translation function in application templates or other existing code: I18N_NOOP(). This function does not actually translate a string, but just marks the string for translation, so that the string will get extracted and included in the po files. If you want to translate the string, you still have to use i18n() with exactly the same string afterwards. 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. So it is safe to use always i18n() and never I18N_NOOP() if you are sure, that the code will be executed after construction of KApplication.

Things to take care of

Although using i18n() for all visible messages is the main work to get your application translated, there are some traps, which prevent your application to be usable in some languages. Mainly these are layout problems and problems with string concatenation.

Makefiles and distributing translations

If your application is in KDE CVS you don't have to do anything. The messages are automatically extracted and will then translated by the KDE translation teams.

If your application is not in the KDE CVS you have to extract the messages by yourself and provide the translated po files within your distribution. To extract the messages you need to have gettext installed and extractrc from kdesdk has to be in your path. (Note:KDE uses a patched version of gettext to use the above mentioned additional context information. You can find this patch in kdesdk/scripts). Then just call in the base directory of your distribution make -f admin/Makefile.common package-messages and after that you will find a file <appname>.pot, which contains all messages of your application, in the subdirectory po. If there is not already a Makefile.am in this directory create one with the following single line as content:

POFILES = AUTO

and add the po-directory to SUBDIRS in Makefile.am of the base directory. Now you just have to find translators to translate the extracted messages into the various languages. ;-) Translated po files then have to be stored in the po-directory with the naming scheme <languagecode>.po.
If you are extracting messages when you already have translated po files of older versions, just call make -f admin/Makefile.common package-merge and the new contents of the pot file will be merged into the already translated po files. This way translators only have to translate new or changed messages.

Technical details

The actual translation is done with the gettext package. It contains tools for extracting the messages from source files and to handle changed messages, so that translators does not have to start over and over again. The extracted messages and the translations are stored in so called po files using different encodings. These files are then compiled into a binary format (mo files) which then get installed.

All translations of a language has to be stored in the same encoding, which is defined in the charset file. KLocale reads this file when constructed and uses this information to decode the translations.

l10n

l10n is a short for localization, and means that the program will be aware of your location (i.e. where you live) and use that information when the program asks for input or print something to the screen. For example to format numbers or money strings. Below is a list of the most important l10n supported by KLocale. All input and output of your application should use these functions. The usage of this function should be straight forward. See the documentation of KLocale for more details.

Function Arguments Returns
formatMoney() double number e.g. QString("DM -100 000,00")
formatNumber() double number, int precision = -1 e.g. QString("-100 000,00")
formatDate() QDate date, bool shortfmt=false e.g. QString("20 October 1999")
formatTime() QTime _time, bool includesecs=false e.g. QString("10:00 pm") or QString("22:00")
formatDateTime() QDateTime _datetime e.g. QString("20 October 1999 10:00 pm") or QString("20 October 1999 22:00")
readMoney() QString moneystring, bool *ok = 0 e.g. double(-100000.00)
readNumber() QString number, bool *ok = 0 e.g. double(-100000.00)

Technical details

The user's configuration is stored in kdeglobals and the different country profiles are stored in share/locale/l10n/+country_code. country_code is replaced with the short version of ISO 3166 country code for the country in lower case.

Links and additional information


Last updated: 3 February 2001, Matthias Kiefer <kiefer@kde.org>