/*! \page i18n Internationalisation Guidelines \htmlinclude i18n-toc.html \section intro Introduction This document provides guidelines on developing locale-aware applications for the MeeGo Touch UI Framework. Developers, translators, and user interface designers are the main target audience of this document. Generally, as the MeeGo Touch UI Framework uses Qt as it’s base, some of the Qt internationalisation practices also apply. However, the MeeGo Touch UI Framework provides additional functionalities, hence it is recommended that developers always use MeeGo Touch UI Framework classes to achieve full internationalisation support in their applications. This document discusses several general internationalisation guidelines for user interface designers. They are general enough and may also be applicable in another projects and vice versa. \section architecture Architecture \image html i18n-class.png "" \section supportedlanguages Supported Languages and calendar systems Below is the list of officially supported languages both for writing systems and text rendering: - American English - Arabic - Basque - Brazilian Portuguese - British English - Canadian French - Catalan - Chinese Simplified - Chinese Traditional - Chinese Hongkong - Danish - Dutch - Finnish - French - Galician - German - Greek - Hebrew - Hindi - Hungarian - Indonesian - Italian - Malay - Norwegian - Persian - Polish - Portuguese - Romanian - Russian - Spanish - Spanish in Latin America - Slovak - Swedish - Thai - Turkish - Ukranian - Urdu Although the implementation contains support for several calendar systems, officially the MeeGo Touch UI Framework currently supports only Gregorian and Islamic calendar. \section localesystem Locale system \subsection localesystemsettings Settings The MeeGo Touch UI locale system uses the following main settings:
MLocale main settings
gconf key description example value
/meegotouch/i18n/language main language setting en_US
/meegotouch/i18n/lc_time for date, time, and calendar ar\@calendar=islamic
/meegotouch/i18n/lc_collate for sorting de_DE\@collation=phonebook
/meegotouch/i18n/lc_numeric formatting of numbers hi
/meegotouch/i18n/lc_monetary for formatting of amounts of money fi_FI\@currency=EUR
Each of these settings can be set to a ICU locale specifier as described in the ICU User Guide. The value of \c /meegotouch/i18n/language (“Language”) tells the locale system about the UI language of the device. This affects all UI texts, writing direction and widget layouts (It does not affect the user content, i.e. it does not affect things like the browser content language etc.). “Language” is also used as the default for time, date, calendar, sorting, number formatting, and currency formatting if the more specific settings are empty. “LcTime” selects how time and date are formatted. If it is left empty the value of “Language” is used. Examples: \c ar\@calendar=islamic means to format date and time the Arabic way using Islamic calendar, \c ar\@calendar=gregorian would use Arabic formatting but with Gregorian calendar, \c fi_FI would use Finnish formatting rules for time and date. “LcCollate” selects how textual data is sorted. If it is left empty the value of “Language” is used. Examples: \c de_DE\@collation=phonebook sorts the way German phone books are sorted, \c de_DE\@collation=standard (or \c de_DE ) sorts the “normal” way German dictionaries are sorted. \c zh_CN\@collation=pinyin sorts Chinese according to the pinyin phonetics, \c zh_CN\@collation=stroke sorts Chinese according to the stroke count of the characters. “LcNumeric” selects how numbers are formatted. If it is left empty the value of “Language” is used. Examples: \c hi formats numbers according to the rules for the Hindi language, using localized digits, i.e. Devanagari numerals (०,१,२,३,४,५,६,७,८,९), \c ar formats numbers using Eastern Arabic numerals (٠,١,٢,٣,٤,٥,٦,٧,٨,٩), \c de_CH formats the Swiss German way with apostrophes as thousands separators (12'345'670.89), and \c en_US formats the American English way (12,345,670.89). “LcMonetary” selects how currency amounts are formatted. If it is left empty the value of “Language” is used. \subsection localesysteminitialisation Initialisation A MeeGo Touch UI application is normally using the system default MLocale object; \code MLocale myLocale; // get the current locale \endcode If the application needs to use different locale settings than the system locale, then a MLocale is created by making an instance of a MLocale object: \code MLocale locale ("fi_FI"); \endcode where "fi" and "FI" mean to use Finnish language in Finland. \subsection Collator Collator To do collation, get the comparator with \c MLocale::collator() method or create it MCollator() for default locale collator. This object acts as a functor and can be passed to Qt's \c qSort() or any other sorting methods. The comparator basically does the comparison of two items as "lessThan" function and returns true if the first parameter should come before the second one. If other collation system than the locale's default is needed, then use \c setCollation() method before getting the comparator. After all are set then the sorting can be started by using Qt's \c qSort() function. To use the default collation: \code QStringList sl; // This contains the strings which need to be sorted ... MLocale myLocale; // get the current locale MCollator c = myLocale.collator(); // getting the comparator ... qSort(sl.begin, sl.end, c); // start to sort! ... \endcode To use the different collation: \code QStringList sl; // This contains the strings which need to be sorted ... MLocale myLocale; // get the current locale myLocale.setCollation (MLocale::PhonebookCollation); // sort using German's phonebook sorting order MCollator c = myLocale.collator(); // getting the comparator ... qSort(sl.begin, sl.end, c); // start to sort! ... \endcode \subsection formatters Formatters MeeGo Touch UI comes with several formatters for several data types. (Almost) Always use the formatters before displaying locale-dependant data to the screen to achieve uniformity and consistency of the data presentation. \subsubsection numbers Numbers To format a number use \c formatNumber() method. It works with \c qlonglong, \c short, \c int, \c double, and \c float data types. \code ... MLocale myLocale; // get the current locale ... int number = 1234; QString formattedNumber = myLocale.formatNumber(number); // format the number, the result is in QString ... \endcode \subsubsection dateandtime Date and time Use \c formatDateTime() to format the date and time. \code ... MLocale myLocale; // get the current locale ... QDateTime now = QDateTime::currentDateTime(); QString formattedDateTime = myLocale.formatDateTime(now); ... \endcode As mentioned previously, date format can also be affected by the device language, region, and calendar settings. \code ... MLocale myLocale; // get the current locale ... QDateTime now = QDateTime::currentDateTime(); QString formattedDateTime = myLocale.formatDateTime(now, MLocale::IslamicCalendar); // format using IslamicCalendar ... \endcode Custom formatting is supported with ISO-14652 format (also used in libc's \c strftime ) by using \c formatDateTime() . \subsubsection percentage Percentage \c formatPercent() is used to format a percentage value. \code ... MLocale myLocale; // get the current locale ... double percent = 0.29; // = 29% int decimals = 2; QString formattedPercentage = myLocale.formatPercent(percent, decimals); ... \endcode \subsubsection Currency Currency To format any amount of money with a currency, use \c formatCurrency() method. \code ... MLocale myLocale; // get the current locale ... double money = 150.40; QString currency = "EUR"; QString formattedCurrency = myLocale.formatCurrency(money, currency); ... \endcode \subsubsection Name Name Use MName class to populate the name information, and use \c MLocale::formatName() method to format the name. \subsubsection Address Address Use MAddress class to populate the address information, and use \c format() method to format the name using the format specified as parameter. \subsection Calendar Calendar MLocale provides Gregorian as well as non-Gregorian calendar support. Use \c formatDateTime() to format the date according to the custom of the selected calendar. To set another calendar than the default Gregorian calendar, use \c setCalendarType() method. \code MLocale myLocale; // get the current locale ... myLocale.setCalendarType(MLocale::IslamicCalendar); // set the calendar to use Islamic calendar ... \endcode Further date manipulations can be done using MCalendar object. \subsection iteratingwords Iterating words On general case iterating words in a string is not possible by searching whitespace: e.g. thai language just concatenates words and in chinese language a character is a word. For this need a MBreakIterator class can be used. It is constructed with a locale and a string and provides an interface for iterating word boundaries. Following example iterates word boundaries from beginning to the end: \code MLocale myLocale; // current locale QString text("this is text to be iterated"); MBreakIterator iterator(myLocale, text, MBreakIterator::WordIterator); while (iterator.hasNext()) { int next = iterator.next(); ... } \endcode \section translationsystem Translation system \subsection logicalidandengineeringenglish Logical ID and engineering English The MeeGo Touch UI Framework can use both the Qt standard \c tr() method or the idbased qtTrId() method. For the Nokia internal localisation process, only \c qtTrId() should be used. Other parties using logical IDs instead of engineering English IDs for the UI messages might also find \c qtTrId() useful. Contrary to the approach of using engineering English as the message ids, which is commonly used in the open source community, the logical ID approach uses message ids which are guaranteed to be globally unique. With \c qtTrId(), the logical ID is an argument of the function and the engineering English is supplied as a comment above. See the example in the Qt documentation of qtTrId(), reproduced here for convenience: \code //% "%Ln fooish bar(s) found.\n" //% "Do you want to continue?" QString text = qtTrId("qtn_foo_bar", n); \endcode \subsection generatingengineeringenglish Generating the engineering English .qm files If no translation files at all are available, \c qtTrId() would return the logical ID which looks pretty ugly and is not nice for testing the user interface. But from code which uses \c qtTrId() with the special engineering English comments, \c .qm files with engineering English translations can be generated automatically. This can be done as follows: Create a subdirectory \c translations/ somewhere in your source tree. In that folder, create a \c translations.pro file with the contents: \code LANGUAGES = # empty if only engineering English is needed! CATALOGNAME = foobar # what ever catalog name you want to use SOURCEDIR = $$PWD/.. # more then one directory is possible TRANSLATIONDIR = $$PWD include($$[QT_INSTALL_DATA]/mkspecs/features/meegotouch_defines.prf) include($$[QT_INSTALL_DATA]/mkspecs/features/meegotouch_translations.prf) \endcode Introducing the extra \c translations/translations.pro file makes it necessary to add the \c translations/ directory to the list of sub-directories in a .pro file higher up in the directory hierarchy. I.e. you usually need something like \code SUBDIRS = \ src \ translations \ ... \endcode After doing that, a \c foobar.ts and a \c foobar.qm file which contain the engineering English translations will be automatically generated when calling “make” for your project. And “make install” will install \c foobar.qm to the usual place as described in section \ref translationdatastorage. Minor detail: with the above setup, when creating \c foobar.qm from \c foobar.ts, lrelease uses the option \c -markuntranslated to prepend the string “!! ” at the beginning of each engineering English string. I.e. if the engineering English string in the source code is “Hello”, it will be written as “!! Hello” into the \c foobar.qm file and will be displayed as “!! Hello” at runtime. This is to make it obvious that engineering English for testing purposes is displayed and not the “real” English which is done by the translators. \subsection translationsystemsetup Translation system setup To setup the translation system using \c qtTrId(), you can use the following code snippets in your main function: By default, the system uses the name of the application executable (without the directory path) as the name for the file of the translation catalog and loads this catalog automatically. So you can start using \c qtTrId() immediately: \code ... int main(int argc, char** argv){ ... MApplication app (argc, argv); ... //% "hello" qtTrId("xxx_hello"); ... } ... \endcode In the above example, if the application executable is for example \c /usr/bin/foo, i.e. the base file name of the executable is \c foo, the translation catalog \c <top-directory>/foo_<locale-code>.qm will be used. If you need to specify a file for the translation catalog wich differs from the name of the executable you can use the optional third parameter \c appIdentifier of the MApplication constructor as in this example: \code ... int main(int argc, char** argv){ ... MApplication application(argc, argv, "bar"); ... //% "hello" qtTrId("xxx_hello"); ... } ... \endcode In the above example, the translation catalog \c <top-directory>/bar_<locale-code>.qm will be used no matter what the file name of the application executable is. But note that the \c appIdentifier is used not only for localization files but also for themes. I.e. changing the appIdentifier will also affect themes. Usually this should be no problem because in most cases these should be kept the same, if possible. When it is not possible to use the \c appIdentifier to specify the translation catalog which should be loaded, one can use the \c installTrCatalog() function to load a translation catalog with a completely different name as in this example: \code ... int main(int argc, char** argv){ ... MApplication app (argc, argv); // create a MLocale. Without parameters in the constructor, // it gets a copy of the system default locale, which may already // have some translation catalogs, for example it usually already // has the “common” translation catalog. MLocale locale; // add a different translation catalog for this locale. // This catalog is added to the list of already loaded catalogs. // Catalogs loaded last are used with highest priority. locale.installTrCatalog("othercatalog"); // the order is important, set the locale as the default *after* // installing the translation catalog: MLocale::setDefault(locale); ... // Now the following call to qtTrId() will use messages // from the translation catalog file othercatalog_.qm // with highest priority: //% "hello" qtTrId("xxx_hello"); ... } ... \endcode To setup your translation using the \c tr() method known from regular Qt programs, you can use the \c installTrCatalog() method as in the following example: \code ... int main(int argc, char** argv){ ... MApplication app (argc, argv); // create a MLocale. Without parameters in the constructor, // it gets a copy of the system default locale, which may already // have some translation catalogs, for example it usually already // has the “common” translation catalog. MLocale locale; // install the catalog for use with tr(). It is probably // a good idea to use the application name for "mycatalog": locale.installTrCatalog("mycatalog"); // Make the locale the default to enable the message catalog just // installed above for tr(). The order is important, do this *after* // installing the translation catalog: MLocale::setDefault(locale); ... // Now you can use tr() as in regular Qt programs: tr("hello"); ... } ... \endcode \subsection translationsystemsetupinlibraries Translation system setup in libraries Let’s say there is an MApplication “foo” which uses a library “libbar”. And the library “libbar” also uses the MeeGo Touch Framwork and has some translations of its own which are in files like \c libbar_.qm. Now the question is how to load the “libbar” translation catalog. On way to do it would be to let the application “foo” load it, i.e. “foo” would do something like \code ... int main(int argc, char** argv){ ... MApplication app (argc, argv); ... // translations from the “foo” translation catalog // can already be used without any setup when the binary // name is identical to the catalog name: //% "hello" qtTrId("qtn_foo_hello"); ... // get a copy of the system default locale // which already has the translation catalogs for “common” and “foo” // installed:create a MLocale. Without parameters in the constructor, MLocale locale; // add a the “libbar” translation catalog: locale.installTrCatalog("libbar"); // set the locale with the “libbar” catalog added as the // new system default: MLocale::setDefault(locale); ... // and a call of a function in the library “libbar” // may use messages from the “libbar” translation catalog: ... libbar_some_function(); ... } ... \endcode The disadvantage of this way of doing it is that the application “foo” needs to know how the translation catalog of “libbar” is called and maybe even require an packages like “libbar-l10n-*”. That creates unnecessary dependencies between “foo” and “libbar”. To avoid this, the recommended way of loading the “libbar” translations is letting the “libbar” library take care of this. I.e. “libbar” somewhere has an initialization function like \code ... void libbar_init() { ... MLocale locale; // get copy of system locale locale.installTrCatalog("libbar"); // add a the “libbar” translation catalog MLocale::setDefault(locale); // set new system default with “libbar” catalog added ... // other initialization stuff if necessary ... } ... \endcode The application “foo” then does not have to load the translations for “libbar” and only does: \code ... int main(int argc, char** argv){ ... MApplication app (argc, argv); ... // translations from the “foo” translation catalog // can already be used without any setup when the binary // name is identical to the catalog name: //% "hello" qtTrId("qtn_foo_hello"); ... // initialize “libbar” which also installs the “libbar” // catalog into the default system locale: libbar_init(); // now a call of a function in the library “libbar” // may use messages from the “libbar” translation catalog: ... libbar_some_function(); ... } ... \endcode Instead of having a public initialization function in “libbar” one could also make “libbar” call some internal initialization code when any public function of “libbar” is used for the first time, i.e. one could design “libbar” to make the following code already work: \code ... int main(int argc, char** argv){ ... MApplication app (argc, argv); ... // translations from the “foo” translation catalog // can already be used without any setup when the binary // name is identical to the catalog name: //% "hello" qtTrId("qtn_foo_hello"); ... // Calling any public function in the library “libbar” // triggers installation of the “libbar” translation catalog // into the default system locale and “libbar” can then // use messages from its translation catalog: ... libbar_some_function(); ... } ... \endcode Whether a special initialization function is used or not, the important thing is that “libbar” does the installing of its translation catalog into the system default locale. The application “foo” then does not need to know how the catalog is called and does not need to require translation packages of “libbar”. “libbar” should require its translation package of course. But this way of doing it reduces the dependencies between “foo” and “libbar”. \subsection translatingmessages Translating messages \c qtTrId() is used to translate the UI messages. \code QString qtTrId ( const char * id, int n = -1 ) \endcode \c id is the logical name for a UI message which needs to be translated. If \c n \c >= \c 0, all occurrences of \c \%Ln or \c \%n in the resulting string are replaced with a decimal representation of \c n. In addition, depending on \c n’s value, the translation text may vary. The difference between \%Ln and \%n is that \%Ln may be replaced using localized numerals like Arabic-Indic numerals in Arabic locales whereas \%n is always replaced using Arabic (= Western) numerals. qtTrId() is useful only if the project is using logical names as the UI message. If your project is using English string then use \c tr() instead. \subsection parametersintranslations Parameters in translations The positional parameters \%1 to \%99 and \%L1 to \%L99 which are used in QString can also be used in translations for the MeeGo Touch UI Framework. For a description of \%L1 to \%L99 see also the documentation of QLocale. For parameters which are integer numbers, \%L1 to \%L99 is a better choice than \%1 to \%99 because \%L1 to \%L99 automatically do locale specific number formatting which achieves the same results as using MLocale’s formatNumber() for the current system locale. Let’s illustrate the behaviour in detail with an example. We assume that an application is running with the language locale settings set to Arabic to get Arabic translations (for example if the gconf key “/meegotouch/i18n/language” is set to “ar”) and the numeric locale settings are also set to Arabic to get Arabic number formatting (for example if the gconf key “/meegotouch/i18n/lc_numeric” is also set to “ar” or is empty and this the numeric locale settings are inherited from the language settings). Now a message id is translated using qtTrId("xx_some_message_id"). And let’s assume that the Arabic translation of this happens to be “\%L1 \%2”. The following example code illustrates how numbers used as parameters would be formatted in that case: \code QString translation = qtTrId("xx_some_message_id"); // “translation” now contains “%L1 %2”. translation.arg("123456.7").arg("123456.7"); // The line above returns “123456.7 123456.7”. // // I.e. if strings are used as the arguments // there is no difference in the behaviour of %L1 and %2. translation.arg(123456).arg(123456); // The line above returns “١٢٣٬٤٥٧ 123457” // // Here the arguments are numbers and we can see the // difference: In case of %L1 the number is formatted // by using QLocale which is set by MLocale to the numeric // settings of MLocale. Therefore, %L1 is replaced by // Arabic-Indic numerals here. However, %2 is still replaced // by Western-Arabic numerals, and has no thousands separators either. // In English locale the replacement for %2 would be “123457” // and not “123,456”, the place holders %1 to %99 // never do any automatic locale specific number formatting. translation.arg(123456.7, 0, 'g', 10).arg(123456.7, 0, 'g', 10); // The line above returns “١٢٣٬٤٥٦٫٧ 123456.7” MLocale locale; translation.arg(locale.formatNumber(123456.7)).arg(locale.formatNumber(123456.7)); // The line above returns “١٢٣٬٤٥٦٫٧ ١٢٣٬٤٥٦٫٧” // // Here the number formatting is done using MLocale. // locale.formatNumber(123456.7) already returns a QString // containing “١٢٣٬٤٥٦٫٧”, i.e. the arguments used for %L1 // and %2 in the translations are not numbers but QStrings. // Therefore, no further formatting is done by %L1 and %2. \endcode Passing an integer number as the argument from %L1 and letting QLocale format that number always gives the same result as passing the the result of formatNumber() using the system MLocale for that integer. The reason is that the MeegoTouch framework always sets QLocale to the value of the numeric setting of the system default MLocale and both the number formatter in MLocale and the number formatter in QLocale use the CLDR data for the number format. \subsection placeholdersinmessageids Place holders in message ids Message ids do not have to indicate whether the translation for this id contains place holders or not. For example if the message id is “xx_greet_user" and the English translation is “Hello %1”, then the following code works fine: \code // The following returns “Hello Joe” if the translation is “Hello %1”. // If no translation can be found it returns “xx_greet_user”: qTrId("xx_greet_user").arg("Joe"); \endcode It is possible to include place holders in message ids, for example if the message id for the translation were “xx_greet_user_%1”, the following code would work just as well: \code // The following returns “Hello Joe” if the translation is “Hello %1” // If no translation can be found it returns “xx_greet_user_Joe”: qTrId("xx_greet_user_%1").arg("Joe"); \endcode So it doesn’t matter whether a message id for a translation which contains place holders contains these place holders itself or not. Although place holders in message ids are possible, the message ids used by MeeGo Touch never contain any place holders. The message ids used in MeeGo Touch only use lowercase letters from “a” to “z” and underscores “_”. This is perfectly OK and does not cause any problems for translations which use place holders. \subsection pluralmessages Plural messages In a plural message, pass the number to select the correct plural translation as the second argument \c n in \c qtTrId() (This works the same way with qtTrId() as it does with \c tr()). \code int n = messages.count(); //% "%Ln message(s) saved" showMessage(qtTrId("xx_messages_saved", n)); \endcode Usually, the number of different translations used for plural, among which the parameter “n” selects the appropriate one, depends on the language, see also the “Qt Translation Rules for Plurals” and the “CLDR Language Plural Rules”. However, for the Meego Touch UI framework, it has been decided to use only 2 plural forms and only English rules. I.e. the .ts translation files used by the Meego Touch UI framework always contain only two different translations for plural and are always marked in the xml as English language translation files, even if the language is not English. For example if a .ts file for English translation contains something like \code message_context ... %Ln event %Ln event %Ln events ... %Ln day %Ln day %Ln days ... \endcode the corresponding Russian translation file might contain something like: \code message_context ... %Ln event %Ln событие Событий: %Ln ... %Ln day %Ln день %Ln дн. ... \endcode Note that this Russian translation file has “language="en"” in the header and thus English rules are used to select the plural forms, i.e. the first plural form is selected if “n” is equal to 1, the second plural form for all other cases. Usually, Russian would use one plural form for “n” in 1, 21, 31, 41, 51, 61…, another one for “n” in 2-4, 22-24, 32-34…, and yet another one for “n” in 0, 5-20, 25-30, 35-40…. If only 2 forms with English rules are used as above, i.e. only “n” equal to 1 is special cased, the second plural form has to be translated in a way that it is acceptable for all other values of “n”. In the Russian example translation file above this is in one case achieved by abbreviating, i.e. using “\%Ln дн.” for all “n” not equal to one and thus hide the different plural forms with the abbreviation dot. In the other case, the number is grammatically “detached”, i.e. by writing “Событий: \%Ln” the part of the translation before the “:” is detached from the part with the number and thus the word “Событий” does not need to change for different values of “n”. \subsubsection percent_ln_percent_l1 \%Ln versus \%L1 in plural messages Messages using plural should use the place holder \%Ln and not \%L1, i.e. the source code should should look like \code int n = messages.count(); //% "%Ln message(s) saved" showMessage(qtTrId("xx_messages_saved", n)); \endcode and the .ts file with the translations should look like: \code message_context ... %Ln event %Ln message saved. %Ln messages saved. ... \endcode The second parameter “n” of qtTrId() does two things: If \%L1 were used instead of \%Ln in the translation, the second parameter of qtTrId() would still select the correct translation for the value of “n” but would not replace \%L1, i.e. in this case the code \code showMessage(qtTrId("xx_messages_saved", 2)); \endcode would display “\%L1 messages saved.”. If it is known that the plural translations mistakenly use \%L1 instead of \%Ln, one can work around the issue by using an extra .arg() in the code like this: \code showMessage(qtTrId("xx_messages_saved", 2).arg(2)); \endcode In this example, the “2” used as the second parameter of would select that correct plural form, i.e. “\%L1 messages saved.” and the .arg(2) would replace the \%L1 with 2 so the final result would be “2 messages saved.” as desired. But as soon as the translation is fixed to use the correct \%Ln this code prints a warning \verbatim QString::arg: Argument missing: "2 messages saved." , 2 \endverbatim because the .arg(2) tries to replace a \%L1 which is not there. \subsection translationdatastorage Translation data storage The convention for the path to store the compiled translation data (in .qm format) on the device is: \code /_.qm \endcode \c top-directory can be anywhere on the device. \c locale-code is something like \c en_US for US-English, \c en_GB for Britisch English, \c zh_CN for Simplified Chinese, \c de_DE for German in Germany, \c de_CH for Swiss German, etc. is usually the name of the application. If a translation for a more specific locale name like \c en_US cannot be found, a less specific locale name like \c en is tried. For example, if the application name is \c foo and the locale name is \c en_US, the first one of the following files which exists is used: \code /foo_en_US.qm /foo_en_US /foo_en.qm /foo_en /foo.qm /foo \endcode See also the documentation of QTranslator::load(). The \c top-directory used by default is \c /usr/share/l10n/meegotouch (This is defined as \c M_TRANSLATION_DIR in \c meegotouch_defines.prf which can be found in \c ./mkspecs/features/meegotouch_defines.prf` in the libmeegotouch source code). `/usr/share/l10n/meegotouch` is also the default directory used by translation packages to store the .qm files. Applications can set additional search paths by using \c MLocale::setTranslationPaths() and \c MLocale::addTranslationPath() . This supports the variability needed for over-the-air translation installation as well as for user defined translations. \subsection translationdatapackaging Translation data packaging The packaging of translations into debian packages is illustrated here using the demo application “widgetsgallery” as an example.
Example for package names and contents of translation packages
Package name Contents
meegotouch-demos-widgetsgallery-l10n-engineering-english
/usr/share/l10n/meegotouch/widgetsgallery.qm
/usr/share/doc/meegotouch-demos-widgetsgallery-l10n-engineering-english/widgetsgallery.ts
/usr/share/doc/meegotouch-demos-widgetsgallery-l10n-engineering-english/changelog.Debian.gz
meegotouch-demos-widgetsgallery-l10n-ar
/usr/share/l10n/meegotouch/widgetsgallery_ar.qm
/usr/share/doc/meegotouch-demos-widgetsgallery-l10n-ar/changelog.Debian.gz
...
...
meegotouch-demos-widgetsgallery-l10n-zh-cn
/usr/share/l10n/meegotouch/widgetsgallery_zh_CN.qm
/usr/share/doc/meegotouch-demos-widgetsgallery-l10n-zh-cn/changelog.Debian.gz
Every application needing translations should supply also a debian package containing the “engineering English” translations. The package name for the engineering English translations should end with -l10n-engineering-english as in the above example. The package name “...-engineering-english” should make it clear that these are not real translations, instead they are completely auto-generated from the source code. In the above example, the package “meegotouch-demos-widgetsgallery-l10n-engineering-english” contains “widgetsgallery.qm” and “widgetsgallery.ts”. “widgetsgallery” is the name of the application executable. “widgetsgallery.ts” is automatically generated from the source code using “lupdate”. “widgetsgallery.qm” is automatically generated from “widgetsgallery.ts” using “lrelease”. The make files in the application source code should contain support to do this automatically when building the application without extra effort (The current source code of widgetsgallery already gives an example how this can be done). The “widgetsgallery.qm” file serves several purposes:
  1. It is used at runtime by the application to display engineering English instead of message ids to make testing the application easier while no real translations are available yet.
  2. It supplies fallback engineering English when real translations are available but incomplete. Of course this should never happen in the final product but it will happen during the development and testing and then this fallback engineering English is useful.
  3. It gives us an easy way to extract a list of ids which are actually used in the source code. Using the tool “lconvert” one can easily extract all ids from a .qm file. If all meegotouch applications supply “...-l10n-engineering-english” packages, one can easily install all these packages (for example with “apt-get”) and then extract all ids which are actually used. Then these ids can be used for cross-checking with the ids used in the specifications and in the real translations.
“widgetsgallery” is only a test application used by the libmeegotouch developers for testing and demos. Therefore, the localisation department will not supply translations for “widgetsgallery”. The libmeegotouch developers supply some demo translations for “widgetsgallery” to test their code and to make sure the system works. Only because of this, “widgetsgallery” has some “real” translation packages like “meegotouch-demos-widgetsgallery-l10n-zh-cn” containing “/usr/share/l10n/meegotouch/widgetsgallery_zh_CN.qm” (see the table above). In that respect, “widgetsgallery” is an exception. For a “real” application, say “camera” which is intended to be shipped to the customer, the “real” translation packages are supplied by the translation department, not by the developers. I.e. the developers will only supply “camera-l10n-engineering-english” and all the other packages “camera-l10n-ar”, “camera-l10n-zh-cn”, ..., will be supplied by the translation department. As long as the real translations are still missing, the engineering English is displayed. As soon as the real translations are available and installed, they are used automatically. As can be seen in the above table, there is no file conflict between the engineering English packages and the real translations, they can both be installed at the same time without problems. For the final product, the engineering English packages can be omitted. If it has been verified during the testing phase that the “real” translations are complete, the engineering English is not needed anymore. \subsection translationfordotdesktop Translation for .desktop files The translation of .desktop files for MeeGo Touch UI differs a bit from the usual practise of Freedesktop.org. The rationale behind it is that we have different localisation processes which make it impossible to modify the source of .desktop files during build time. To accommodate the special needs of our localisation processes, the .desktop file shall contain at least two extra (key, value) pairs: - X-MeeGo-Logical-Id=<logical name>: The value for this key provides the logical name of the section name - X-MeeGo-Translation-Catalog=<catalog name>: The value for this key provides the catalog where the logical name exists For example: \code [Desktop Entry] # engineering english Name=Setting # logical name of "Setting" X-MeeGo-Logical-Id=xx_setting_something # the catalog name X-MeeGo-Translation-Catalog=meegotouchsettings \endcode For the freedesktop specification of the .desktop files see http://standards.freedesktop.org/desktop-entry-spec/latest/ In MeeGo Touch UI, such .desktop files are parsed using MDesktopEntry. \subsection otatranslationinstallation Over-the-air translation installation FIXME: No settings available now Translation data can be downloaded to the device and the translation system can immediately use the new downloaded data. \section uiprogramming UI programming \subsection localechange Reacting to changes in the locale settings The current language setting is stored in the gconf key \c /meegotouch/i18n/language . From the command line, the current language can be queried using \c gconftool-2 like this: \code ~$ gconftool-2 -g /meegotouch/i18n/language ar \endcode In the above example, the current language is Arabic. Setting the current language from the command line can of course also be done with \c gconftool-2 : \code ~$ gconftool-2 -t string -s /meegotouch/i18n/language zh_CN \endcode The above command sets the current language to simplified Chinese. The preferred way to query the current language from a \c MApplication works like this: \code MLocale currentLocale; QString language = currentLocale.name(); \endcode \c MLocale currentLocale; gets a copy of the system default locale which is connected to the gconf settings and follows the gconf settings. Alternatively it is possible to read the gconf settings directly: \code MGConfItem languageItem("/meegotouch/i18n/language"); QString language = languageItem.value().toString(); \endcode This has the same effect as getting the current system locale and using \c currentLocale.name(). Setting the current language permanently from a \c MApplication works like this: \code MGConfItem languageItem("/meegotouch/i18n/language"); languageItem.set("zh_CN"); \endcode One can also set a new current language temporarily from a \c MApplication by doing: \code MLocale newLocale("zh_CN"); MLocale::setDefault(newLocale); \endcode This does not change the gconf settings and therefore this change will be lost as soon as one of the locale related gconf keys changes again. And it will be lost when the application restarts. Nevertheless this can be useful for temporary changes for testing and it is currently the only way to change the current language on systems without gconf like Windows or Mac OS X. If a the system locale changes, either because a locale related gconf key changed or because \c MLocale::setDefault() has been called explicitly by the application, the following things happen:
  • All translation catalogs are reloaded according to the new locale settings
  • \c QEvent::LanguageChange will be sent to the Application, if necessary. \c MWindow will propagate a \c QEvent::LanguageChange to all \c MWidgets on the scene. A \c MWidget which receives this event by calls its \c retranslateUi() method.
  • \c QEvent::ApplicationLayoutDirectionChange will be sent to the Application, if necessary. \c MWindow will propagate a \c QEvent::LayoutDirectionChange to all \c MWidgets as appropriate to enable the widgets to change their layout on the fly.
  • The signal \c settingsChanged() will be emitted by the locale.
  • The signal \c localeSettingsChanged() will be emitted by the \c MApplication .
In most cases, an application doesn’t have to use the above signals \c settingsChanged() and \c localeSettingsChanged() because most stuff like reloading the translation catalogs already happens automatically. If \c retranslateUi() methods are implemented for the widgets used in the application, the language of the user interface will already change automatically. Optionally, an application can use these signals though, if it wants to do additional special things which do not happen automatically. For example: \code main.cpp: #include "foohandlelocalechange.h" ... int main (int argc, char **argv) { ... FooHandleLocaleChange fooHandleLocaleChange; QObject::connect(&application, SIGNAL(localeSettingsChanged()), &fooHandleLocaleChange, SLOT(fooHandleLocaleChange())); ... } \endcode where the FooHandleLocaleChange class looks like: \code foohandlelocalechange.h: class FooHandleLocaleChange : public QObject { Q_OBJECT public slots: void fooHandleLocaleChange(); }; foohandlelocalechange.cpp: void FooHandleLocaleChange::fooHandleLocaleChange() { // do whatever is needed when the system locale // changes, but remember that the basic stuff like // reloading the translation catalogs and changing the layout // direction already happens automatically. // // Therefore, unless you have very special needs, you do not // need to do anything here. // // In any case, do *not* do anything here which changes the // system default locale again because this would trigger // an endless loop. } \endcode \subsection retranslateui The retranslateUi() method of MWidget A \c MWidget which receives the \c QEvent::LanguageChange calls its virtual method \code virtual void retranslateUi(); \endcode \c MWidgets can reimplement this \c retranslateUi() method to do whatever is necessary to retranslate itself, as in the following example: \code foopage.h class FooPage : public MWidget { ... private: ... MLabel* label; ... }; foopage.cpp void FooPage::createContent() { label = new MLabel(); retranslateUi(); } void FooPage::retranslateUi() { ... //% "Label Text" propertiesLabel->setText(qtTrId("qtn_label_text")); ... } \endcode This can be quite tricky in some cases but makes it possible to re-translate the user interface of an application on the fly if the locale settings change. \subsection widgetmirroring Widget mirroring and layout direction Widget mirroring is the automatic behaviour of putting the widgets in the reverse direction when the language is switched to Right-to-left languages (such as Arabic or Hebrew). In this direction, the widgets are put following the natural flow of text writing direction. Widget mirroring works automatically when the widgets are arranged using QGraphicsLayout or MLayout, with some exceptions with the specialist MLayout policies. The layout direction will be automatically set to the correct value by MApplication when the language is changed. The current layout direction can be obtained from \c MApplication::layoutDirection() . Note that during the application lifetime, the direction may change if the user changes it from the global setting. If you are developing a widget in which it does not make sense for the layout to be reversed (for example, a number keypad), then use \c QGraphicsWidget::setLayoutDirection() to override the layout direction. If you need to paint your widget differently in right-to-left mode, simply call `qApp->layoutDirection()` and draw as appropriate. If you are implementing a custom MAbstractLayoutPolicy, however, you should use the \c MLayout::layoutDirection() function instead so that the user can override it. In advanced situations you can handle the \c QEvent::ApplicationLayoutDirectionChange() event directly in your widget's event handler. \section currentstatusrtlsupportinmeegotouchwidgets Current status of RTL support in MWidgets
Current status of RTL support in MWidgets
Widget Works with RTL Comments
MAnimatedIcon OK Nothing to do for RTL
MApplicationMenu broken? In widgetsgallery, click "Application Menu", then click "Application Menu" in the navigation bar. A menu with offering the names "Plato", "Twain", "Einstein", "Adams" is openened. Hit Control-D to change the layout direction, you see that the these names which were originally "almost" centred are aligned right in RTL mode. They should be aligned in a mirrored way, i.e. if they are a bit left of the centre in LTR mode, they should be a bit right of the centre in RTL mode. Is this a problem with MApplicationMenu or with MAction?
MApplicationPage OK Nothing to do for RTL
MApplicationWindow OK Nothing to do for RTL
MButton OK But the switches in the switchpage of widgetsgallery (which are MButtons) do not reverse the alignment of their ON/OFF texts. Problem in MButton or somewhere else?
MButtonGroup OK Nothing to do for RTL
MComboBox OK
MContainer OK Nothing to do for RTL
MDialog OK
MDockWidget OK Nothing to do for RTL
MEscapeButtonPanel OK Nothing to do for RTL
MGrid broken There seems to be a grid with gray squares in the background and blue buttons in the foreground in the widgetsgallery grid page. In LTR mode, the gray squares align with the blue buttons, i.e. on top of each gray square is a blue button. In LTR mode, the two arrays are shifted against each other. This doesn't look right.
MHomeButtonPanel OK Nothing to do for RTL
MImage OK Nothing to do for RTL
MInfoBanner broken Always slides in from the left side, see "Dialogs and Notifications" page in widgetsgallery.
MLabel OK It did not change alignment on the fly until recently but this is fixed now, see NB#144377
MMessageBox OK
MModalSceneWindow OK Nothing to do for RTL
MNavigationBar broken Icon in the navigation bar is always on the left side
MObjectMenu probably OK Where is this used?
MPannableViewport OK Position indicator correctly changes side
MPannableWidget OK Nothing to do for RTL
MPopupList OK
MProgressIndicator OK
MPositionIndicator broken Is always on the right side. Can be seen on the start page of Widgetsgallery.
MSeekBar broken slides correctly from the right in RTL mode but the black area showing the "already" downloaded stuff is only visible in LTR mode.
MSeparator OK Nothing to do for RTL
MSlider OK
MSlideShow OK Nothing to do for RTL
MTextEdit OK NB#104397 is very obvious here, but this is not the fault of MTextEdit.
MToolBar OK
MWindow OK Nothing to do for RTL
\section charsetconversion Charset Conversions The MeeGo Touch UI Framework uses the Qt character set conversion mechanisms directly. Therefore, developers can follow the Qt documentation to find out how to use the character set conversion functionalities. \section generalchecklist General Checklist \subsection General General \subsubsection fontsize Fonts size Some languages require bigger font size than the one used in the English text. This may impact the layout design. \subsubsection Plural Plural Some languages use plural and some do not. Some other languages use more than one form of plurals. \subsubsection Sorting Sorting Sorting order is dependent on the language setting. Always use MeeGo Touch UI collator to sort the strings. \subsubsection wordboundaries Word boundaries In some languages there is no space between words. In most cases the line wrapping will work and the system will break the sentence into smaller chunks. If it fails, translators shall use whitespace to force word boundaries. \subsubsection wordorder Word order, variables When a sentence contains several variables, the order of the words in other languages may be different. Use QString place marker to define the order of the variables. \code //% "Download and install %1 from %2? (Size is %L3 MB)" QString s = qtTrId("xx_download_and_install_from_size_mb") .arg(packageName).arg(repository).arg(size); \endcode When translating, translators shall also keep the place markers and put them in the correct places. Note how %L3 was used for the size parameter which is a number. Using %L3 instead of just %3 has the advantage that localized numerals may be used. For example if the language of the locale is Arabic and the numeric settings of the locale do not override it, %L3 causes Arabic-Indic numerals to be used. If the translator wants to disable this behaviour for this particular message and force usage of Arabic (= Western) numerals always, no matter what the locale settings are, the translator can use %3 instead of %L3 on purpose. \subsection Developers Developers \subsubsection alwaysusemeegotouch Always use MeeGo Touch UI Framework API This is the general checklist which need to be confirmed during the development. Use only MeeGo Touch UI Framework locale system API to gain full internationalisation support. Use of POSIX and libc API is not recommended and may cause discrepancies in the representation of the data. To do sorting, never use Qt's QString localeAwareCompare(), use MeeGo Touch UI collation system instead. \subsubsection avoidhardcoding Avoid hardcoding Some data such as graphics, icons, sounds, etc sometimes need to be correctly loaded dependent on the regional setting. In this case, never hard code the data directory, instead use the regional setting information to build the string to point to the correct directory containing the data. \subsubsection neverconcatstrings Never concatenate strings If you need to construct a string involving variables, never concate the UI strings. The string order is never guaranteed to the same in all languages. Never do this: \code QString message = "You have " + numMessages + " messages"; \endcode Instead use a variable when constructing the string: \code //% "You have %Ln messages" QString message = qtTrId("xx_you_have_messages", numMessages); \endcode \subsubsection dataformat Data formatting Date, time, numbers, name, address, currency data are required to be formatted before displayed on the screen. Never display unformatted data as it breaks the data presentation consistency. Formatted data always use the correct presentation according to the regional setting. Special case for address data, it shall be formatted according to the customary of the country which stated in the address. \subsection uidesign UI Designers \subsubsection Abbreviations Abbreviations In general, avoid using abbreviations as part of the UI string. The abbreviations ofter are misleading and confuse the translators. Instead, allow for more text expansion \subsubsection Emphasis Emphasis Never use casing when indicating functionality or emphasis. Some languages do not observe distinction between lowercase and uppercase. The translator may have difficulties to find out how to emphasise the string when the original English string uses uppercase for the emphasis. Other methods such as using certain typeface to show emphasis also discouraged as not all writing systems support them. \subsubsection characterrepertoire Character repertoire Never use characters outside the ASCII repertoire as part of original English strings. The font needed to display the character may not available in the device variant used for other languages. \subsubsection Compounds Compounds Some languages create words by combining a few words together. The resulting words are often longer than the original English string. Make sure that the UI allows the text expansion in these languages. \subsubsection Digits Digits Some languages use their own digits (term: national digits) to show the numbers. Allow the usage of national digits in some cases (for example when displaying general strings containing numbers) and force the UI to only use the Latin digits in other cases (for example when displaying IP addresses). \subsubsection writingdirection Writing direction Some languages use different writing direction than the Latin based languages. The UI presentation generally follows the natural flow of the writing direction. Therefore, the widget layout and composition is mirrored when the device language is set to the languages which use the right-to-left writing direction. The mirroring is done automatically by the MeeGo Touch UI Framework. If the automatic mirroring is not sufficient then consult the developers to support different layout for right-to-left direction. MeeGo Touch UI Framework currently only supports left-to-right and right-to-left writing directions. \subsubsection Gender Gender Some languages use gender when referring to objects or words. \subsubsection colorandgraphics Colour and graphics Colours often have different meanings and connotations in different cultures. In Western culture, red is often used to indicate stop or danger. In China, red is symbolic of celebration, luck and prosperity. White signifies purity, virginity, or death. In Western culture it is the colour worn at weddings. In parts of Japan and China the colour worn at funerals. Never embed text and/or numbers in graphics, otherwise the graphics need to be translated and it may be difficult and expensive. Some icons or drawings considered offensive in some cultures. \subsubsection slitstrings Split strings when containing date and time format See section "Translation involving date/time format" above. */