c++ - Translation of "dynamic" content if using Internationalization with Qt -
i evaluating c++ framework qt v5.4.1. trying understand , apply internationalization qt.
i implemented switching of human language @ runtime via of article how create multi lingual application can switch language @ runtime? , know how-to work qt linguist translation source (.ts) files , how generate qt linguist message (.qm) files. use build system cmake automate generation , works nice.
in project translations loaded qt resource collection (.qrc) file compiled application. know how-to translate "static" strings via member functions qobject::tr() , qobject::translate().
now comes tricky part: want add languages while application evolves. have following 2 .ts files:
foo_ui_de_de.tsfoo_ui_en_us.ts
these compiled via lrelease following 2 .qm files build process:
foo_ui_de_de.qmfoo_ui_en_us.qm
the build process automatically generates .qrc file translations.qrc , compiles file executable via rcc.
relevant source code declaration file (.h):
#include <qmainwindow> #include <qlocale> #include <qstring> #include <qtranslator> class mainwindow : public qmainwindow { q_object public: /** * initializes new instance of mainwindow class given parent. * * @param parent parent. */ explicit mainwindow(qwidget* parent = 0); private slots: /** * loads language given language shortcut (e.g. `de_de`, `en_us`). */ void loadlanguage(qlocale const& klocale); void switchtranslator(qtranslator& translator, qstring const& klocale, qstring const& kfilename); /** * creates language menu dynamically. */ void createlanguagemenu(); protected: /** * handler activated when new translator loaded or system * language changed. */ void changeevent(qevent* event); protected slots: /** * slot called language menu actions. */ void slotlanguagechanged(qaction* action); private: /** * translations application. */ qtranslator translator_; /** * translations qt widgets used in application. */ qtranslator qt_translator_; /** * contains loaded locale. */ qlocale locale_; /** * main window of application. */ ui::mainwindow* ui_; }; relevant source code definition file (.cc):
#include <qlibraryinfo> #include "main_window.h" #include "ui_main_window.h" mainwindow::mainwindow(qwidget* the_parent) : qmainwindow{the_parent}, ui_{new ui::mainwindow} { ui_->setupui(this); createlanguagemenu(); } mainwindow::~mainwindow() { delete ui_; } void mainwindow::loadlanguage(qlocale const& knewlocale) { qlocale::setdefault(knewlocale); qstring const klanguagename{qlocale::languagetostring(knewlocale.language())}; switchtranslator(translator_, "qt_" + knewlocale.bcp47name(), qlibraryinfo::location(qlibraryinfo::translationspath)); switchtranslator(qt_translator_, qapp->applicationname() + '_' + knewlocale.name(), ":/translations"); statusbar()->showmessage( tr("language changed %1").arg(klanguagename)); locale_ = knewlocale; } void mainwindow::switchtranslator(qtranslator& translator, qstring const& klocale, qstring const& kfilename) { qapp->removetranslator(&translator); if (translator.load(klocale, kfilename)) { qapp->installtranslator(&translator); } } void mainwindow::createlanguagemenu() { // todo(wolters): not optimal, since not work automatically // .qm files added resource application. //: translation human language german. qt_tr_noop("german"); //: translation human language english. qt_tr_noop("english"); qactiongroup* language_group{new qactiongroup(ui_->menulanguage)}; language_group->setexclusive(true); connect(language_group, signal(triggered(qaction*)), this, slot(slotlanguagechanged(qaction*))); qlocale const kdefaultlocale{qlocale::system()}; qdir const kdirectory{qapplication::applicationdirpath() + "/.."}; qstringlist const kfilenames{kdirectory.entrylist(qstringlist("*.qm"))}; (qstring const& kfilename : kfilenames) { qlocale const klocale{qfileinfo{kfilename}.completebasename().replace( qapp->applicationname() + "_", "")}; qstring const kcountrycode{ klocale.name().tolower().mid(klocale.name().lastindexof('_') + 1)}; qicon const kicon{":/icons/flags/" + kcountrycode + ".png"}; qaction* action{new qaction{ kicon, // todo(wolters): not work. tr(qlocale::languagetostring(klocale.language()).tostdstring().c_str()), this}}; action->setcheckable(true); action->setdata(klocale); ui_->menulanguage->addaction(action); language_group->addaction(action); if (kdefaultlocale == klocale) { action->setchecked(true); } } } void mainwindow::changeevent(qevent* the_event) { if (nullptr != the_event) { switch (the_event->type()) { // qevent::languagechange send if translator loaded. case qevent::languagechange: ui_->retranslateui(this); break; // qevent::localechange send, if system language changes. case qevent::localechange: loadlanguage(qlocale::system()); break; default: break; } } qmainwindow::changeevent(the_event); } void mainwindow::slotlanguagechanged(qaction* action) { if (nullptr != action) { loadlanguage(qvariant_cast<qlocale>(action->data())); } } the source code describes problem have in comments.
- if application started, current system locale used re-translate ui. works , can see items in menu
languagesappear in german human language (i've translated both items in .ts files). when switch language via menu german english, both item labels do not translated. - the approach in general not optimal, since not want modify source code (
qt_tr_noopabove), if new human language added application. optimal work flow be:- add supported languages .ts files in proper language.
- dynamically translate menu items.
i think misunderstanding something, couldn't found solution while searching www while.
update 2015-04-01: think use wrong approach. important part languages menu created dynamically in member function createlanguagemenu(). need answer question how-to translate dynamically created menu items. it's line qaction* action{new qaction{kicon, tr(qlocale::languagetostring(klocale.language()).tostdstring().c_str()), this}}; in function. need kind of lookup-functionality available @ compile time think...
as mentioned need lookup-functionality in real time. suggest such hack: when creating qaction objects use object name language identifer
qt_tr_noop("lang_eng") qaction* langaction = ...; langaction->setobjectname("lang_eng"); on language change event call method retreanslate actions
void retranslatelangactions() { qlist<qaction*> widgetactions = this->findchildren<qaction*>(); foreach(qaction* act, widgetactions) // qt foreach macro { qstring objname = act->objectname(); if (objname.startswith("lang_")) { act->settext(tr(objname.tostdstring().c_str())); } } }
Comments
Post a Comment