PDA

View Full Version : Dynamic translation (was: How to get QApplication pointer)



MarkoSan
22nd January 2008, 04:14
Hi to all!

I have an QApplication object in which QTranslator is installed. It works perferctly. But now I have a problem. I have a "grandchild" qwidget that holds language selection QPushButton subclassed objects. How do I launch QApplication::loadTranslator from this window??

Gopala Krishna
22nd January 2008, 05:55
Hi to all!

I have an QApplication object in which QTranslator is installed. It works perferctly. But now I have a problem. I have a "grandchild" qwidget that holds language selection QPushButton subclassed objects. How do I launch QApplication::loadTranslator from this window??

Use qApp (http://doc.trolltech.com/4.3/qapplication.html#qApp)
qApp->loadTranslator();

MarkoSan
22nd January 2008, 06:09
Hmm, this does not work:
void CLanguageSelectorWidget::translateSlovene()
{
m_Translator.load("translations/eROSystem_client_SL"); // loads translator
//QApplication::installTranslator(&m_Translator); // installs it
qApp->installTranslator(&m_Translator); // installs it
emit accept(); // closes window
}

Why not???

In main.cpp there is a very similar code that works:
// translator setup
QTranslator qtTranslator;
qtTranslator.load("translations/eROSystem_client_SL");
a.installTranslator(&qtTranslator);

Why the upper code chunk does not work?? Signals/Slots are ok, I've checked.

jpn
22nd January 2008, 06:46
In main() the QTranslator object remains alive because QApplication::exec() blocks until the application quits. Is CLanguageSelectorWidget allocated on the stack? The translator object goes out of scope as soon as CLanguageSelectorWidget is destructed.

MarkoSan
22nd January 2008, 06:51
How come, if m_Translator is defined in its header file:
#ifndef CLANGUAGESELECTORWIDGET_H_
#define CLANGUAGESELECTORWIDGET_H_

/*!
* \class CLanguageSelectorWidget
* \author VSistemi Marko Frelih s.p.
* \version 1.0
* \date January 2007
* \brief This Qt based class represents a language selector widget, which constist of number of
* CFlagButton objects.
* \details version 1.00 (revision 84): basic functionality
*/

// qt includes
#include <QDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QList>
#include <QFont>
#include <QPalette>
#include <QTranslator>
#include <QApplication>

class QWidget; // forward declaration

// custom includes
#include "CFlagButton.h"

class CLanguageSelectorWidget : public QDialog
{
Q_OBJECT

public:
CLanguageSelectorWidget(QWidget* pParent);
~CLanguageSelectorWidget();
inline QPointer<QHBoxLayout> langaugeButtonsLayout() { return m_pLanguageButtonsLayout; };
inline QPointer<QVBoxLayout> mainLayout() { return m_pMainLayout; };
//inline QList<CFlagButton> languageButtonsList() { return mLanguageButtonsList; };
inline QPalette widgetPalette() { return m_WidgetPalette; };
inline QPointer<QPushButton> sloLangButton() { return m_pSloLangButton; };
inline QPointer<QPushButton> ukLangButton() { return m_pUKLangButton; };
inline QPointer<QPushButton> deuLangButton() { return m_pDeuLangButton; };
inline QPointer<QPushButton> itaLangButton() { return m_pItaLangButton; };

public:
// TODO: this member should be private
//QList<CFlagButton> mLanguageButtonsList; // language buttons list

private:
QPointer<QHBoxLayout> m_pLanguageButtonsLayout; // horizontal layout
QPointer<QVBoxLayout> m_pMainLayout; // main layouts
QPointer<QPushButton> m_pSloLangButton; // slo lang
QPointer<QPushButton> m_pUKLangButton; // eng lang
QPointer<QPushButton> m_pDeuLangButton; // deu lang
QPointer<QPushButton> m_pItaLangButton; // ita lang
QPalette m_WidgetPalette; // widget palette
QTranslator m_Translator; // application translator

private slots:
void translateSlovene(); // launches slovenian translation
void translateEnglish(); // launches english translation
void translateDeutsch(); // launches german translation
void translateItaliano(); // launches italian translation
};

#endif /*CLANGUAGESELECTORWIDGET_H_*/

jpn
22nd January 2008, 06:58
Where do you show/exec CLanguageSelectorWidget? Consider following code:


{
CLanguageSelectorWidget dialog(this);
if (dialog.exec() == QDialog::Accepted)
{
}
} // the translator gets destructed here together with CLanguageSelectorWidget

MarkoSan
22nd January 2008, 07:20
So, what do you suggest, how should I recode?

jpn
22nd January 2008, 07:24
Allocate the translator on the heap. In other words, create the translator with keyword "new". It must remain alive after the dialog gets destructed, right?

MarkoSan
22nd January 2008, 07:48
Yes, you are right. God damn, I've forgot the basics ... I've allocated it, but same result. I think object gets destructed again after leaving QDialog:
m_pTranslator=new QTranslator(this); // creats new translator
Q_CHECK_PTR(m_pTranslator); // checks creation
m_pTranslator->load("translations/eROSystem_client_ITA"); // loads translator
//QApplication::installTranslator(&m_Translator); // installs it
qApp->installTranslator(m_pTranslator); // installs it
emit accept(); // closes window

Am I right?

jpn
22nd January 2008, 07:50
Don't pass "this" as its parent. Every QObject will automatically delete its children. Here, the dialog will delete the translator. Try passing for example "qApp" as parent instead.

MarkoSan
22nd January 2008, 07:57
I did, still no result. Is it possible the path to translator file is corrupted??? Is it ok to use "/" in path under windows instead of "\'

jpn
22nd January 2008, 08:02
I did, still no result. Is it possible the path to translator file is corrupted???
QTranslator::load() returns true if the translation is successfully loaded; otherwise returns false. So check the return value!


Is it ok to use "/" in path under windows instead of "\'
Yes, it's ok. Qt will translate your paths to conform to the underlying operating system.

MarkoSan
22nd January 2008, 08:10
Here is the code:
m_pTranslator=new QTranslator(qApp); // creats new translator
Q_CHECK_PTR(m_pTranslator); // checks creation
if(m_pTranslator->load("translations/eROSystem_client_ITA")) // loads translator
{
//QApplication::installTranslator(&m_Translator); // installs it
qApp->installTranslator(m_pTranslator); // installs it
emit accept(); // closes window, success
} else {
emit reject(); // failure
}Every language button succesfully loads translator. But still no result!!!:crying::confused::o:(

jpn
22nd January 2008, 08:27
Every language button succesfully loads translator. But still no result!
What does this mean? Do your widgets catch QEvent::LanguageChange?

PS. QDialog::accept() and QDialog::reject() are not signals so drop those "emits" for sake of clarity.

jpn
22nd January 2008, 09:14
Oh, and for dynamic translation you might want to check this wiki article out: Dynamic translation

MarkoSan
22nd January 2008, 13:15
I've read the wiki, but what is the point of translating application using QLinguist if I must enter tr() texts MANUALY in changeEvent. And how does application know which language was changed to???

jpn
22nd January 2008, 13:28
I've read the wiki, but what is the point of translating application using QLinguist if I must enter tr() texts MANUALY in changeEvent.
You might want to read it again, you must have missed something. If you mean text written in Designer, UIC provides a retranslateUi() method which is mentioned in the article.


And how does application know which language was changed to???
QObject::tr() and QApplication::translate() work based on installed translators.

MarkoSan
22nd January 2008, 13:33
You might want to read it again, you must have missed something. If you mean text written in Designer, UIC provides a retranslateUi() method which is mentioned in the article.


QObject::tr() (http://doc.trolltech.com/latest/qobject.html#tr) and QApplication::translate() (http://doc.trolltech.com/latest/qapplication.html#translate) work based on installed translators.

I do not use Designer, all my classes are handcoded.

jpn
22nd January 2008, 13:43
So what's the problem? Everything in your code marked for translation (QObject::tr(), QApplication::tr(), etc.) is shown in Linguist. Let's say you write strings in code in English. You already have English version of your app without providing any translations. In Linguist you write translations to other languages.

Edit: Oh, I think I just understood what you meant. No, you don't pass translated version to QObject::tr() and co. The whole point is to keep it for example English only in code and with help of tr() you get automatically provided the translation from installed translators. You just have to reset translatable strings when the language changes.

MarkoSan
22nd January 2008, 13:54
But I have Slovenian version in code. Then I've made 4 .ts files:
- copy of Slovenian translation
- English
- Deutsch
- Italiano

Now, I smply do not know what to put in retranslate() function. All other things are getting clear now.

jpn
22nd January 2008, 13:59
Then just keep all the strings in code Slovenian. Sorry, but I don't understand what in this concept is it so hard to understand. Once you have installed a German translator, QObject::tr("some Slovenian text") will return the text in German, provided that the particular string was translated.

MarkoSan
22nd January 2008, 14:15
Ok, but I still do not get what do I have to implement in retranslate() function. I just set arbitrary tr() strings in it then if, for instance, german translator is automatically loaded?

jpn
22nd January 2008, 14:50
It's YOU who installs the translator:


// <no translator installed>
qDebug() << tr("slovenian text"); // outputs "slovenian text" in slovenian

qApp->installTranslator(germanTranslator);
qDebug() << tr("slovenian text"); // outputs "slovenian text" in german

qApp->installTranslator(italianTranslator);
qDebug() << tr("slovenian text"); // outputs "slovenian text" in italian


Now, lets take a QLabel holding a string as an example. QLabel does not automatically translate anything because it doesn't make any sense. First of all, not all strings all translated and secondly, it would add unnecessary overhead. Every widget receives a language change event when language changes. This is the point when you have to ract. You must catch the event and reset all strings you want to translate in current language.



// this will create a new label with string "slovenian text" in current language, whatever the current translator happens to be
QLabel* label = new QLabel(tr("slovenian text"));

// later on, you switch the language by installing another translator
// the label introduced above will not react anyhow, you will have to catch the event and do it yourself
// this time, QObject::tr() returns the same string in different language, in language which was just installed
void SomeWindow::changeEvent(QEvent* event)
{
if (event->type() == QEvent::LanguageChange)
label->setText(tr("slovenian text"));
}

Gopala Krishna
22nd January 2008, 14:56
@admins: would it possible to rename this helpful thread to what exactly it reflect ?

Sorry for being offtopic.

NTwoO
4th April 2008, 09:08
I use dynamic translation extensively in my application.

The way I solved the problem is by inheriting QApplication to MyApp.

In the header of MyApp I have a list of QTranslator members for each language/locale. In MyApp I also have a ChangeLang(LangEnum LANG) function.

This will load the chosen language.

In MyApp I have some strings that are application wide specific (eg: translation of the days of the week or the months) Open windows get an event as described in the helpfile at Trolltech.

MyApp is accessed as


MyApp* locApp= (MyApp*)qApp;
locApp->LoadLanguage(ENG);//loads english
locApp->LoadLanguage(NLD);//loads Dutch
locApp->LoadLanguage(ZHO);//loads Mandarin


void MyApp::ChangeLang(LangEnum LANG)
{
if(lang!=CurLang)
{
CurLang=lang;
//Ensure that we have no translation loaded
removeTranslator(&SPAtran);
removeTranslator(&ENG_AUtran);
removeTranslator(&DEUtran);
removeTranslator(&FRAtran);
removeTranslator(&NLDtran);
removeTranslator(&ZHOtran);
removeTranslator(&PORtran);
removeTranslator(&ENG_UStran);
removeTranslator(&ENGtran);
switch(lang)
{
case ENGLISH:
#ifdef VER_US
installTranslator(&ENG_UStran);
#elif defined(VER_AU)
installTranslator(&ENG_AUtran);
#elif defined(VER_UK)
installTranslator(&ENGtran);
#else
installTranslator(&ENGtran);
#endif
break;
case GERMAN:
installTranslator(&DEUtran);

break;
case DUTCH:
installTranslator(&NLDtran);
break;
case SPANISH:
installTranslator(&SPAtran);
break;
case FRENCH:
installTranslator(&FRAtran);
break;
case MANDARIN:
installTranslator(&ZHOtran);
break;
case ITALIAN:
//Not defined
break;
case GREEK:
//Not defined
break;
case PORTUGESE:
installTranslator(&PORtran);
break;
case UNINITIALISED:
default:
break;
}
if(MANDARIN==lang)
{
CentralFont.setFamily( "mandarin" );
}
else
{
CentralFont.setFamily( "Freesans" );
}
MyCurSet.LoadPresentations();
langInit();
FillEditLists();
emit newLang();

}
}
The translations are removed before loading a new one. The documentation has nothing about reloading an already loaded translation, so out of memory paranoia I simply remove all that is not used and load the one I use.

The header looks something like

typedef enum _LangEnum
{//This enum must match the enum in the SGCP document
UNINITIALISED=-1,
ENGLISH=0,
GERMAN,
DUTCH,
SPANISH,
FRENCH,
MANDARIN,
ITALIAN,
GREEK,
PORTUGESE
} LangEnum;
class MyApp : public QApplication
{
Q_OBJECT

public:
QFont CentralFont;
LangEnum CurLang;
QTranslator SPAtran;
QTranslator ENGtran;
QTranslator ENG_AUtran;
QTranslator DEUtran;
QTranslator FRAtran;
QTranslator NLDtran;
QTranslator ZHOtran;
QTranslator PORtran;
QTranslator ENG_UStran;
void ChangeLang(LangEnum lang);
signals:
void newLang();
}


As you can see this version also switches fonts for writing mandarin. Looks really neat! Our customers are very impressed! The planning of the competition also took a speedbump with this nice little extra.

MarkoSan
4th April 2008, 09:43
Well, I've done it. Thanks to all that helped me. I now even can support dynamic number of languages. I have a list of languages in mysql database table. I load it at runtime an then the magic works!!! :D

Nippler
16th May 2008, 07:31
Well, I've done it. Thanks to all that helped me. I now even can support dynamic number of languages. I have a list of languages in mysql database table. I load it at runtime an then the magic works!!! :D

How have you done it?
At the moment I am working exactly on this problem!

Thanks for an answer.

jpn
16th May 2008, 07:33
How have you done it?
At the moment I am working exactly on this problem!
Did you read the wiki article: Dynamic translation?