Seite 1 von 1

Sprache zur Laufzeit ändern

Verfasst: 20. Dezember 2010 15:12
von darkshine
Hallo,

nachdem ich mit QLinguist eine deutsche und englische Sprachversion erstellt habe. Möchte ich gerne die Sprache zur Laufzeit ändern können.
Ich habe im Netz ein paar Dinge gefunden. Es scheint aber alles recht kompliziert. Oft werden Beispiele an an sehr alten Qt-Versionen beschieben und ich weiß nicht, ob es jetzt einen "einfacheren" Weg gibt.

Also bis jetzt ist es ganz klassisch in der main.cpp:

Code: Alles auswählen

QTranslator myappTranslator;
myappTranslator.load("meinProgramm_en");
app.installTranslator(&myappTranslator);
Leider habe ich mich mit der main.cpp nie beschäftigt. Ich habe am Anfang ein einfaches Hello World Programm als Beispiel geladen und danach weiter entwickelt. Die main musste ich dabei nie ändern. Ich habe keinen Schimmer was da überhaupt passiert ;)
Aber ich denke mal es muss irgendwie aus der main in mein MainWindow wandern.

Gibt es für den Sprachwechsel zur Laufzeit auch einen schlanken Drei-Zeiler?

Vielen Dank

Verfasst: 20. Dezember 2010 16:20
von Giesbert
Naja, fast :-)

Lade den Translator dynamisch (mit new) in deinem mainWindow ganz am anfang.

Bei sprachumschaltung, das selbe mit dem neuen translator machen und den alten removen, fertig :-)

Verfasst: 20. Dezember 2010 16:21
von jackmack
Hier nen Code Auszug wie ich das mach. Bischen mehr wir 3 Zeilen sinds aber so, weil dass net ganz so easy geht. Aber dafür ists dynamisch, sprich kannst einfach weitere Sprachen hinzufügen per lang_de.qm, lang_en.qm, lang_es.qm usw.

Falls Du Qt Klassen benutzt wie QMessageBox::information() mit Ok/Cancel Buttons, die ja nen vordefinierten Text haben, musst den 2. Translater (m_qtTranslator) anlegen.
Dieser lädt dann die Qt Sprach-Dateien (qt_de.qm etc.). Nach denen suchste im Qt Verz. und kopierst sie ebenfalls nach "languages". Ich glaube, es sind nicht alle qt_xx.qm vollständig, musste eben kontrollieren und evtl. mit dem Liguist vervollständigen.

Hier der Code:

Code: Alles auswählen

class MyWindow : public QMainWindow
{
	Q_OBJECT

private:
	...
	QTranslator m_appTranslator;	/**< The application translator of current used language. */
	
	QTranslator m_qtTranslator;		/**< The Qt library translator of current used language. */
	
	QString m_langPath;				/**< Path of language files. This is always fixed to /languages. */
	...

public:
	...
};

	
MyWindow::MyWindow(QWidget* parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{

	// do some initializing
	...
	
	// installing translators and create supported languages menu
	m_langPath = "languages"; // Sprach-Dateien liegen bei mir im Unterverzeichnis "languages" der Applikation!
	qApp->installTranslator(&m_qtTranslator);
	qApp->installTranslator(&m_appTranslator);
	createLanguageMenu();
	...
}

// Menu-Eintrag dynamisch erzeugen, d.h. wenn mal weitere Sprachen hinzufügen möchtest z.B. 
// lang_de.qm, lang_en.qm, dann einfach nach /languages kopieren!
void MyWindow::createLanguageMenu()
{
	QActionGroup* langGroup = new QActionGroup(ui.menuLanguage);
	langGroup->setExclusive(true);

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

	// format systems language
	QString defaultLocale = QLocale::system().name();       // "de_DE"
	defaultLocale.truncate(defaultLocale.lastIndexOf('_')); // "de"

    QDir dir(m_langPath);
    QStringList fileNames;
	
	fileNames = dir.entryList(QStringList("lang_*.qm"));

	for (int i = 0; i < fileNames.size(); ++i) 
	{
		// get locale extracted by filename
        QString locale;
		locale = fileNames[i];						// "lang_de.qm"
		locale.truncate(locale.lastIndexOf('.'));	// "lang_de"
        locale.remove(0, locale.indexOf('_') + 1);	// "de"

		QString lang = QLocale::languageToString(QLocale(locale).language());
		
		QAction *action = new QAction(lang, this);
        action->setCheckable(true);
        action->setData(locale);
        
		ui.menuLanguage->addAction(action);
        langGroup->addAction(action);
        
		// set default translators and language checked 
		if (defaultLocale == locale)
		{
			m_appTranslator.load("lang_" + action->data().toString(), m_langPath);
			m_qtTranslator.load("qt_" + action->data().toString(), m_langPath);
			action->setChecked(true);
			retranslateUi();
		}
    }
}


// falls Sprache geändert wird über Systemsteuerung wollen wir das auch mitbekommen!
void MyWindow::changeEvent(QEvent *event)
{
	 if (event->type() == QEvent::LocaleChange) 
	 {
		QString locale = QLocale::system().name();
		locale.truncate(locale.lastIndexOf('_'));

		m_qtTranslator.load("qt_" + locale, m_langPath);
		m_appTranslator.load("lang_" + locale, m_langPath);
		retranslateUi();
	 }

	 QMainWindow::changeEvent(event);
}

// Aufruf, wenn über Menu-Eintrag die Sprache gewechselt wird!
void MyWindow::slotLanguageChanged(QAction* action)
{
	m_appTranslator.load("lang_" + action->data().toString(), m_langPath);
    m_qtTranslator.load("qt_" + action->data().toString(), m_langPath);
 	retranslateUi();
}

Verfasst: 21. Dezember 2010 08:29
von darkshine
Danke,

ich werde mich jetzt mal ans Werk machen.

Ich habe alles mit dem Qt Designer erstellt. Dort gibt es eine Funktion ui.retranslate, mit der es wohl recht komfortabel zu lösen sein.

Also bei jackmack sind es klar mehr als drei Zeilen. :)

Verfasst: 21. Dezember 2010 11:23
von Giesbert
Hi jackmack,

das ganze funktioniert aber nur, wenn du nur mit einem fenster arbeitest, oder das retranslate bei allen aufrufst. Wenn du den Translator lädst (installTranslator) wird ein event erzeugt (kannst du mittels QWidget::changeEvent abfangen, der type ist QEvent::LanguageChanged) auf das du reagieren kannst um deinen Texte neu zu setzen. das ist allgemeiner und funktioniert ach bei mehereren gleichzeitig offenen Fenstern.

Verfasst: 21. Dezember 2010 12:56
von darkshine
Ich taste mich langsam an die Sache ran.

Ich habe jetzt zu Beginn, zwei Buttons erstellt. Die werden später einem Auswahlmenü weichen. Aber zum Testen ist es ganz gut.

Mit der Hilfe von Beispielen habe ich mir jetzt folgendes zusammengestrickt.

Code: Alles auswählen

void myProg::on_pushButton_deutsch_clicked()
{
	qDebug() << "Deutsch";

	QTranslator myappTranslator;
        myappTranslator.load("myProg_de");
	QApplication::installTranslator(&myappTranslator);
	 Application::setLanguage("de_De");	
	ui.retranslateUi(this);	
}

void myProg::on_pushButton_englisch_clicked()
{
	qDebug() << "Englisch";
	QTranslator myappTranslator;
         myappTranslator.load("myProg_en");
	QApplication::installTranslator(&myappTranslator);
	Application::setLanguage("en_En");	
	ui.retranslateUi(this);	
	
}
In der Application siet setLanguage so aus:

Code: Alles auswählen

void Application::setLanguage(const QString& locale)
{
	// remove previous
	if (current)
	{
		removeTranslator(current);
	}

	// install new
	current = translators.value(locale, 0);
	if (current)
	{
		installTranslator(current);
	}
}
Das klappt auch für mein Hauptfenster.

Ich besitze allerdings auch ein Infofenster. Das habe ich mit dem qt Designer erstellt und besitzt nur ein QLabel. Das rufe ich immer mal wieder mit unterschiedlichen Texten auf.

In dem Header meines MainWindow steht es so:

Code: Alles auswählen

Ui::MainWindow ui;	//Das "Fenster"		
Ui::Info infofenster; //Das Fenster für "Infos"
In meinem Hauptprogramm definiere ich es dann so:

Code: Alles auswählen

infowidget = new QWidget();
infofenster.setupUi(infowidget);
Dann rufe ich das infowidget immer auf wenn ich es gerade brauche und schließe es. Z.B :

Code: Alles auswählen

infofenster.label->setText(tr("Daten OK"));
modeminfowidget->show();
Ich hatte mit weiteren Fenster immer Probleme gehabt und bin mir nicht sicher ob es so überhaupt sein muss. Aber es funktioniert so gut.

Wenn ich die *.qm in der main.cpp lade, dann werden auch alle Texte übersetzt angezeigt.
Aber so wie ich es jetzt habe läuft es nicht.

Auch ein infofenster.retranslateUi(infowidget) hilft mir nicht :(

Verfasst: 21. Dezember 2010 14:11
von darkshine
Ich bin wieder einen ein wenig schlauer.

Ich habe nochmal Linguist gestartet und dabei ist mir aufgefallen, das ganz links in der Spalte (ich glaube es heisst Kontextmenü) u.a folgende Fenster stehen.

MainWindow (habe ich erwartet)
infofenster (habe ich auch erwartet)

myProg (woher kommt das?)

das myProg ist doch mein MainWindow.

und bei myProg stehen alle meine Strings die ich in meinen Infofenster anzeigen lasse.

wie kriege ich denn myProg übersetzt? Mit "ui.*" komme ich da dann ja nicht ran....oder doch?

Verfasst: 23. Dezember 2010 11:56
von jackmack
Giesbert hat geschrieben:Hi jackmack,

das ganze funktioniert aber nur, wenn du nur mit einem fenster arbeitest, oder das retranslate bei allen aufrufst. Wenn du den Translator lädst (installTranslator) wird ein event erzeugt (kannst du mittels QWidget::changeEvent abfangen, der type ist QEvent::LanguageChanged) auf das du reagieren kannst um deinen Texte neu zu setzen. das ist allgemeiner und funktioniert ach bei mehereren gleichzeitig offenen Fenstern.
Hallo darkshine,

ich werde mir das mal anschaun und nen kleines Test-Progrämmli zusammenhacken. Jedenfalls funzt es mit QMessageBox'en, die ja dynamisch erzeugt werden. Wie sich das mit mehreren, gleichzeit offenen Fenster verhält, weiss ich gerade nicht (Hab nur nen MainWindow bisher + modale Dialoge).