How to create a multi language application: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
'''English''' [[How to create a multi language application German|German]] [[How to create a multi language application Greek|Ελληνικά]]
[[Category:HowTo]]<br />'''English''' [[How_to_create_a_multi_language_application_German|German]] [[How_to_create_a_multi_language_application_Greek|Ελληνικά]]


=How to create a multi lingual application that can switch the language at runtime?=
[toc align_right=&quot;yes&amp;quot; depth=&quot;2&amp;quot;]


==Create a standard application, e.g. with a main window==
= How to create a multi lingual application that can switch the language at runtime? =


[[Image:LanguageApp.png|Hauptfenster der Applikation]]<br /> In this example, we create a main window with a menu Language and some widgets. If the user opened the language menu, there is a selection of languages, which is created on startup of the application, dependant on the existing language files.<br />[[Image:LanguageAppMenu.png|Hauptfenster der Applikation mit Sprachmenü]]
== Create a standard application, e.g. with a main window ==


==File system structure of the application:==
[[Image:http://lh3.ggpht.com/_m1PNLlZctqY/TRELoZ10m5I/AAAAAAAAAC0/qskj_psAyCI/s800/LanguageApp.png|Hauptfenster der Applikation]]<br />In this example, we create a main window with a menu Language and some widgets. If the user opened the language menu, there is a selection of languages, which is created on startup of the application, dependant on the existing language files.<br />[[Image:http://lh3.ggpht.com/_m1PNLlZctqY/TRELoozTsDI/AAAAAAAAAC4/AWTMerfK-ME/s800/LanguageAppMenu.png|Hauptfenster der Applikation mit Sprachmenü]]


* &lt;Application directory&gt;
== File system structure of the application: ==
 
* &amp;lt;Application directory&amp;amp;gt;
** binaries
** binaries
* &lt;Application directory&gt;/languages
* &amp;lt;Application directory&amp;amp;gt;/languages
** For each installed language, there is an (optional) image of the size 16×16 pixel with a flag (e.g. de.png)
** For each installed language, there is an (optional) image of the size 16x16 pixel with a flag (e.g. de.png)
** The translated text files of the application (TranslationExample_*.qm, where * could be de, en, …)
** The translated text files of the application (TranslationExample_'''.qm, where''' could be de, en, …)
** the translation files of Qt (qt_*.qm)
** the translation files of Qt (qt_'''.qm)
 
<br />h2. Class definition
==Class definition==
<br />In the class MainWindow, the virtual method &quot;changeEvent(QEvent''')&quot;:http://doc.qt.nokia.com/latest/qwidget.html#changeEvent is overwritten. For each translation file, that is needed, a &quot;QTranslator&amp;quot;:http://doc.qt.nokia.com/latest/qtranslator.html instance is created (in our example 2, on for the application texts, one for qt). The current language is stored to suppress events, if the user tries to load the same language twice.
 
In the class MainWindow, the virtual method [http://doc.qt.nokia.com/latest/qwidget.html#changeEvent changeEvent] ''[doc.qt.nokia.com]'' is overwritten. For each translation file, that is needed, a [http://doc.qt.nokia.com/latest/qtranslator.html QTranslator] ''[doc.qt.nokia.com]'' instance is created (in our example 2, on for the application texts, one for qt). The current language is stored to suppress events, if the user tries to load the same language twice.
 
==Creation of the language menus==
 
The language menu is created dynamically during application start, depending on the existing translation files. The advantage of this solution is, you can deliver any translation later on, and it will just work after application restart. In this example, all text files are located in the sub folder “languages”. It is possible to place some icons there (language.png) which is used as icon in the menu (e.g. a flag).
 
Each language is represented by a [http://doc.qt.nokia.com/latest/qaction.html QAction] ''[doc.qt.nokia.com]'' object which is added to a [http://doc.qt.nokia.com/latest/qactiongroup.html QActionGroup] ''[doc.qt.nokia.com]''. This is done to achieve, that only one slot is needed for all languages:


==Switching the language==
<code><br />class MainWindow : public QMainWindow<br />{<br /> …


If the language should be switched, the needed target language is extracted from the [http://doc.qt.nokia.com/latest/qaction.html QAction] ''[doc.qt.nokia.com]'' object and the existing translators are removed ([http://doc.qt.nokia.com/latest/qapplication.html#removeTranslator QApplication::removeTranslator] ''[doc.qt.nokia.com]'' ). After that, the new language files are loaded, and if successful, the translator is installed again ([http://doc.qt.nokia.com/latest/qapplication.html#installTranslator QApplication::installTranslator] ''[doc.qt.nokia.com]'' ). This is done to ensure, a <br />[http://doc.qt.nokia.com/latest/qevent.html#Type-enum QEvent::LanguageChange] ''[doc.qt.nokia.com]'' event is emitted by the application object. It the application only contains one top level window, that is completely created by designer, it is also possible to just read the new translation files and call '''ui.retranslateUi(this)''' directly.<br />
protected:<br /> /** this event is called, when a new translator is loaded or the system language is changed<br /> '''/<br /> void changeEvent(QEvent''');


* [http://doc.qt.nokia.com/latest/qevent.html#Type-enum QEvent::LanguageChange] ''[doc.qt.nokia.com]'' will always be called, if a translator object is installed in the application object
protected slots:<br /> /** this slot is called by the language menu actions<br /> '''/<br /> void slotLanguageChanged(QAction''' action);
* [http://doc.qt.nokia.com/latest/qevent.html#Type-enum QEvent::LocaleChange] ''[doc.qt.nokia.com]'' is called, when the system language is switched


==Add translations to the project==
private:<br /> /** loads a language by the given language shortcur (e.g. de, en, …)<br /> '''/<br /> void loadLanguage(const QString&amp;amp; rLanguage);
<br /> /'''* creates the language menu dynamically from the content of m_langPath<br /> '''/<br /> void createLanguageMenu(void);
<br /> Ui::MainWindow ui; /&lt; ui definition from designer'''/<br /> QTranslator m_translator; /*'''&lt; contains the translations for this application'''/<br /> QTranslator m_translatorQt; /*'''&lt; contains the translations for qt'''/<br /> QString m_currLang; /*'''&lt; contains the currently loaded language'''/<br /> QString m_langPath; /*'''&lt; Path of language files. This is always fixed to /languages.'''/<br />};<br /></code>


In your [http://doc.qt.nokia.com/latest/qmake-manual.html QMake] ''[doc.qt.nokia.com]'' project file, the following variable [http://doc.qt.nokia.com/latest/qmake-variable-reference.html#translations '''<span class="caps">TRANSLATIONS</span>'''] ''[doc.qt.nokia.com]'' has to be added and must contain all language filesyou want to create initially.<br />
== Creation of the language menus ==


By calling [http://doc.qt.nokia.com/latest/linguist-manager.html#lupdate lupdate] ''[doc.qt.nokia.com]''<br /> You create the language files (*.ts), which you translate by using the tool [http://doc.qt.nokia.com/latest/linguist-manual.html Qt Linguist] ''[doc.qt.nokia.com]''
The language menu is created dynamically during application start, depending on the existing translation files. The advantage of this solution is, you can deliver any translation later on, and it will just work after application restart. In this example, all text files are located in the sub folder &quot;languages&amp;quot;. It is possible to place some icons there (language.png) which is used as icon in the menu (e.g. a flag).


After doing this, you call [http://doc.qt.nokia.com/latest/linguist-manager.html#lrelease lrelease] ''[doc.qt.nokia.com]'' to create the binary language files (*.qm):
Each language is represented by a &quot;QAction&amp;quot;:http://doc.qt.nokia.com/latest/qaction.html object which is added to a &quot;QActionGroup&amp;quot;:http://doc.qt.nokia.com/latest/qactiongroup.html. This is done to achieve, that only one slot is needed for all languages:


===Deploying to Symbian===
<code><br />connect(langGroup, SIGNAL (triggered(QAction *)), this, SLOT (slotLanguageChanged(QAction *)));<br /></code>


In case your deploy target is a Symbian device then you need to add a special rule in the .pro file to pack the .qm files along with the executable or else the translation wont work. So:<br />
<code><br />// we create the menu entries dynamically, dependant on the existing translations.<br />void MainWindow::createLanguageMenu(void)<br />{<br /> QActionGroup* langGroup = new QActionGroup(ui.menuLanguage);<br /> langGroup-&gt;setExclusive(true);


Hopefully, this can help you.
connect(langGroup, SIGNAL (triggered(QAction *)), this, SLOT (slotLanguageChanged(QAction *)));


===Categories:===
// format systems language<br /> QString defaultLocale = QLocale::system&amp;amp;#40;&amp;#41;.name(); // e.g. &quot;de_DE&amp;quot;<br /> defaultLocale.truncate(defaultLocale.lastIndexOf('''')); // e.g. &quot;de&amp;quot;
<br /> m_langPath = QApplication::applicationDirPath();<br /> m_langPath.append(&quot;/languages&amp;quot;);<br /> QDir dir(m_langPath);<br /> QStringList fileNames = dir.entryList(QStringList(&quot;TranslationExample''*.qm&amp;quot;));


* [[:Category:HowTo|HowTo]]
for (int i = 0; i &lt; fileNames.size(); +''i)<br /> {<br /> // get locale extracted by filename<br /> QString locale;<br /> locale = fileNames[i]; // &quot;TranslationExample_de.qm&amp;quot;<br /> locale.truncate(locale.lastIndexOf('.')); // &quot;TranslationExample_de&amp;quot;<br /> locale.remove(0, locale.indexOf('''') + 1); // &quot;de&amp;quot;
<br /> QString lang = QLocale::languageToString(QLocale(locale).language());<br /> QIcon ico(QString(&quot;%1/%2.png&amp;quot;).arg(m_langPath).arg(locale));
<br /> QAction *action = new QAction(ico, lang, this);<br /> action-&gt;setCheckable(true);<br /> action-&gt;setData(locale);
<br /> ui.menuLanguage-&gt;addAction(action);<br /> langGroup-&gt;addAction(action);
<br /> // set default translators and language checked<br /> if (defaultLocale == locale)<br /> {<br /> action-&gt;setChecked(true);<br /> }<br /> }<br />}<br /></code>
<br />h2. Switching the language
<br />If the language should be switched, the needed target language is extracted from the &quot;QAction&amp;quot;:http://doc.qt.nokia.com/latest/qaction.html object and the existing translators are removed (&quot;QApplication::removeTranslator&amp;quot;:http://doc.qt.nokia.com/latest/qapplication.html#removeTranslator ). After that, the new language files are loaded, and if successful, the translator is installed again (&quot;QApplication::installTranslator&amp;quot;:http://doc.qt.nokia.com/latest/qapplication.html#installTranslator ). This is done to ensure, a<br />&quot;QEvent::LanguageChange&amp;quot;:http://doc.qt.nokia.com/latest/qevent.html#Type-enum event is emitted by the application object. It the application only contains one top level window, that is completely created by designer, it is also possible to just read the new translation files and call '''ui.retranslateUi(this)''' directly.<br /><code><br />// Called every time, when a menu entry of the language menu is called<br />void MainWindow::slotLanguageChanged(QAction* action)<br />{<br /> if(0 != action)<br /> {<br /> // load the language dependant on the action content<br /> loadLanguage(action-&gt;data().toString());<br /> setWindowIcon(action-&gt;icon());<br /> }<br />}
<br />void switchTranslator(QTranslator&amp;amp; translator, const QString&amp;amp; filename)<br />{<br /> // remove the old translator<br /> qApp-&gt;removeTranslator(&amp;translator);
<br /> // load the new translator<br /> if(translator.load(filename))<br /> qApp-&gt;installTranslator(&amp;translator);<br />}
<br />void MainWindow::loadLanguage(const QString&amp;amp; rLanguage)<br />{<br /> if(m_currLang != rLanguage)<br /> {<br /> m_currLang = rLanguage;<br /> QLocale locale = QLocale(m_currLang);<br /> QLocale::setDefault(locale);<br /> QString languageName = QLocale::languageToString(locale.language());<br /> switchTranslator(m_translator, QString(&quot;TranslationExample''%1.qm&amp;quot;).arg(rLanguage));<br /> switchTranslator(m_translatorQt, QString(&quot;qt_%1.qm&amp;quot;).arg(rLanguage));<br /> ui.statusBar-&gt;showMessage(tr(&quot;Current Language changed to %1&amp;quot;).arg(languageName));<br /> }<br />}<br /></code>
<br />* &quot;QEvent::LanguageChange&amp;quot;:http://doc.qt.nokia.com/latest/qevent.html#Type-enum will always be called, if a translator object is installed in the application object<br />* &quot;QEvent::LocaleChange&amp;quot;:http://doc.qt.nokia.com/latest/qevent.html#Type-enum is called, when the system language is switched
<br /><code><br />void MainWindow::changeEvent(QEvent* event)<br />{<br /> if(0 != event)<br /> {<br /> switch(event-&gt;type())<br /> {<br /> // this event is send if a translator is loaded<br /> case QEvent::LanguageChange:<br /> ui.retranslateUi(this);<br /> break;<br /> // this event is send, if the system, language changes<br /> case QEvent::LocaleChange:<br /> {<br /> QString locale = QLocale::system&amp;amp;#40;&amp;#41;.name();<br /> locale.truncate(locale.lastIndexOf('_'));<br /> loadLanguage(locale);<br /> }<br /> break;<br /> }<br /> }
<br /> QMainWindow::changeEvent(event);<br />}<br /></code>
<br />h2. Add translations to the project
<br />In your &quot;QMake&amp;quot;:http://doc.qt.nokia.com/latest/qmake-manual.html project file, the following variable &quot;'''TRANSLATIONS'''&quot;:http://doc.qt.nokia.com/latest/qmake-variable-reference.html#translations has to be added and must contain all language filesyou want to create initially.<br /><code><br />TRANSLATIONS = languages/TranslationExample_en.ts  languages/TranslationExample_de.ts<br /></code>
<br />By calling &quot;lupdate&amp;quot;:http://doc.qt.nokia.com/latest/linguist-manager.html#lupdate<br /><code><br />lupdate -verbose TranslationExample.pro<br /></code><br />You create the language files ('''.ts), which you translate by using the tool &quot;Qt Linguist&amp;quot;:http://doc.qt.nokia.com/latest/linguist-manual.html
<br /><code><br />linguist languages/TranslationExample_en.ts languages/TranslationExample_de.ts<br /></code>
<br />After doing this, you call &quot;lrelease&amp;quot;:http://doc.qt.nokia.com/latest/linguist-manager.html#lrelease to create the binary language files ('''.qm):
<br /><code><br />lrelease TranslationExample.pro<br /></code>
<br />h3. Deploying to Symbian
<br />In case your deploy target is a Symbian device then you need to add a special rule in the .pro file to pack the .qm files along with the executable or else the translation wont work. So:<br /><code><br />symbian: {<br />addFiles.sources = TranslationExample_en.qm TranslationExample_de.qm<br />addFiles.path = .<br />DEPLOYMENT''= addFiles<br />}<br /></code>

Revision as of 14:19, 23 February 2015


English German Ελληνικά

[toc align_right="yes&quot; depth="2&quot;]

How to create a multi lingual application that can switch the language at runtime?

Create a standard application, e.g. with a main window

Hauptfenster der Applikation
In this example, we create a main window with a menu Language and some widgets. If the user opened the language menu, there is a selection of languages, which is created on startup of the application, dependant on the existing language files.
Hauptfenster der Applikation mit Sprachmenü

File system structure of the application:

  • &lt;Application directory&amp;gt;
    • binaries
  • &lt;Application directory&amp;gt;/languages
    • For each installed language, there is an (optional) image of the size 16x16 pixel with a flag (e.g. de.png)
    • The translated text files of the application (TranslationExample_.qm, where could be de, en, …)
    • the translation files of Qt (qt_.qm)


h2. Class definition
In the class MainWindow, the virtual method "changeEvent(QEvent)":http://doc.qt.nokia.com/latest/qwidget.html#changeEvent is overwritten. For each translation file, that is needed, a "QTranslator&quot;:http://doc.qt.nokia.com/latest/qtranslator.html instance is created (in our example 2, on for the application texts, one for qt). The current language is stored to suppress events, if the user tries to load the same language twice.

<br />class MainWindow : public QMainWindow<br />{<br /> 

protected:<br /> /** this event is called, when a new translator is loaded or the system language is changed<br /> '''/<br /> void changeEvent(QEvent''');

protected slots:<br /> /** this slot is called by the language menu actions<br /> '''/<br /> void slotLanguageChanged(QAction''' action);

private:<br /> /** loads a language by the given language shortcur (e.g. de, en, …)<br /> '''/<br /> void loadLanguage(const QString&amp;amp; rLanguage);
<br /> /'''* creates the language menu dynamically from the content of m_langPath<br /> '''/<br /> void createLanguageMenu(void);
<br /> Ui::MainWindow ui; /&lt; ui definition from designer'''/<br /> QTranslator m_translator; /*'''&lt; contains the translations for this application'''/<br /> QTranslator m_translatorQt; /*'''&lt; contains the translations for qt'''/<br /> QString m_currLang; /*'''&lt; contains the currently loaded language'''/<br /> QString m_langPath; /*'''&lt; Path of language files. This is always fixed to /languages.'''/<br />};<br />

Creation of the language menus

The language menu is created dynamically during application start, depending on the existing translation files. The advantage of this solution is, you can deliver any translation later on, and it will just work after application restart. In this example, all text files are located in the sub folder "languages&quot;. It is possible to place some icons there (language.png) which is used as icon in the menu (e.g. a flag).

Each language is represented by a "QAction&quot;:http://doc.qt.nokia.com/latest/qaction.html object which is added to a "QActionGroup&quot;:http://doc.qt.nokia.com/latest/qactiongroup.html. This is done to achieve, that only one slot is needed for all languages:

<br />connect(langGroup, SIGNAL (triggered(QAction *)), this, SLOT (slotLanguageChanged(QAction *)));<br />
<br />// we create the menu entries dynamically, dependant on the existing translations.<br />void MainWindow::createLanguageMenu(void)<br />{<br /> QActionGroup* langGroup = new QActionGroup(ui.menuLanguage);<br /> langGroup-&gt;setExclusive(true);

connect(langGroup, SIGNAL (triggered(QAction *)), this, SLOT (slotLanguageChanged(QAction *)));

// format systems language<br /> QString defaultLocale = QLocale::system&amp;amp;#40;&amp;#41;.name(); // e.g. &quot;de_DE&amp;quot;<br /> defaultLocale.truncate(defaultLocale.lastIndexOf('''')); // e.g. &quot;de&amp;quot;
<br /> m_langPath = QApplication::applicationDirPath();<br /> m_langPath.append(&quot;/languages&amp;quot;);<br /> QDir dir(m_langPath);<br /> QStringList fileNames = dir.entryList(QStringList(&quot;TranslationExample''*.qm&amp;quot;));

for (int i = 0; i &lt; fileNames.size(); +''i)<br /> {<br /> // get locale extracted by filename<br /> QString locale;<br /> locale = fileNames[i]; // &quot;TranslationExample_de.qm&amp;quot;<br /> locale.truncate(locale.lastIndexOf('.')); // &quot;TranslationExample_de&amp;quot;<br /> locale.remove(0, locale.indexOf('''') + 1); // &quot;de&amp;quot;
<br /> QString lang = QLocale::languageToString(QLocale(locale).language());<br /> QIcon ico(QString(&quot;%1/%2.png&amp;quot;).arg(m_langPath).arg(locale));
<br /> QAction *action = new QAction(ico, lang, this);<br /> action-&gt;setCheckable(true);<br /> action-&gt;setData(locale);
<br /> ui.menuLanguage-&gt;addAction(action);<br /> langGroup-&gt;addAction(action);
<br /> // set default translators and language checked<br /> if (defaultLocale == locale)<br /> {<br /> action-&gt;setChecked(true);<br /> }<br /> }<br />}<br />


h2. Switching the language


If the language should be switched, the needed target language is extracted from the "QAction&quot;:http://doc.qt.nokia.com/latest/qaction.html object and the existing translators are removed ("QApplication::removeTranslator&quot;:http://doc.qt.nokia.com/latest/qapplication.html#removeTranslator ). After that, the new language files are loaded, and if successful, the translator is installed again ("QApplication::installTranslator&quot;:http://doc.qt.nokia.com/latest/qapplication.html#installTranslator ). This is done to ensure, a
"QEvent::LanguageChange&quot;:http://doc.qt.nokia.com/latest/qevent.html#Type-enum event is emitted by the application object. It the application only contains one top level window, that is completely created by designer, it is also possible to just read the new translation files and call ui.retranslateUi(this) directly.

<br />// Called every time, when a menu entry of the language menu is called<br />void MainWindow::slotLanguageChanged(QAction* action)<br />{<br /> if(0 != action)<br /> {<br /> // load the language dependant on the action content<br /> loadLanguage(action-&gt;data().toString());<br /> setWindowIcon(action-&gt;icon());<br /> }<br />}
<br />void switchTranslator(QTranslator&amp;amp; translator, const QString&amp;amp; filename)<br />{<br /> // remove the old translator<br /> qApp-&gt;removeTranslator(&amp;translator);
<br /> // load the new translator<br /> if(translator.load(filename))<br /> qApp-&gt;installTranslator(&amp;translator);<br />}
<br />void MainWindow::loadLanguage(const QString&amp;amp; rLanguage)<br />{<br /> if(m_currLang != rLanguage)<br /> {<br /> m_currLang = rLanguage;<br /> QLocale locale = QLocale(m_currLang);<br /> QLocale::setDefault(locale);<br /> QString languageName = QLocale::languageToString(locale.language());<br /> switchTranslator(m_translator, QString(&quot;TranslationExample''%1.qm&amp;quot;).arg(rLanguage));<br /> switchTranslator(m_translatorQt, QString(&quot;qt_%1.qm&amp;quot;).arg(rLanguage));<br /> ui.statusBar-&gt;showMessage(tr(&quot;Current Language changed to %1&amp;quot;).arg(languageName));<br /> }<br />}<br />


* "QEvent::LanguageChange&quot;:http://doc.qt.nokia.com/latest/qevent.html#Type-enum will always be called, if a translator object is installed in the application object
* "QEvent::LocaleChange&quot;:http://doc.qt.nokia.com/latest/qevent.html#Type-enum is called, when the system language is switched


<br />void MainWindow::changeEvent(QEvent* event)<br />{<br /> if(0 != event)<br /> {<br /> switch(event-&gt;type())<br /> {<br /> // this event is send if a translator is loaded<br /> case QEvent::LanguageChange:<br /> ui.retranslateUi(this);<br /> break;<br /> // this event is send, if the system, language changes<br /> case QEvent::LocaleChange:<br /> {<br /> QString locale = QLocale::system&amp;amp;#40;&amp;#41;.name();<br /> locale.truncate(locale.lastIndexOf('_'));<br /> loadLanguage(locale);<br /> }<br /> break;<br /> }<br /> }
<br /> QMainWindow::changeEvent(event);<br />}<br />


h2. Add translations to the project


In your "QMake&quot;:http://doc.qt.nokia.com/latest/qmake-manual.html project file, the following variable "TRANSLATIONS":http://doc.qt.nokia.com/latest/qmake-variable-reference.html#translations has to be added and must contain all language filesyou want to create initially.

<br />TRANSLATIONS = languages/TranslationExample_en.ts  languages/TranslationExample_de.ts<br />


By calling "lupdate&quot;:http://doc.qt.nokia.com/latest/linguist-manager.html#lupdate

<br />lupdate -verbose TranslationExample.pro<br />


You create the language files (.ts), which you translate by using the tool "Qt Linguist&quot;:http://doc.qt.nokia.com/latest/linguist-manual.html

<br />linguist languages/TranslationExample_en.ts languages/TranslationExample_de.ts<br />


After doing this, you call "lrelease&quot;:http://doc.qt.nokia.com/latest/linguist-manager.html#lrelease to create the binary language files (.qm):


<br />lrelease TranslationExample.pro<br />


h3. Deploying to Symbian


In case your deploy target is a Symbian device then you need to add a special rule in the .pro file to pack the .qm files along with the executable or else the translation wont work. So:

<br />symbian: {<br />addFiles.sources = TranslationExample_en.qm TranslationExample_de.qm<br />addFiles.path = .<br />DEPLOYMENT''= addFiles<br />}<br />