Sprache zur Laufzeit ändern

Alles rund um die Programmierung mit Qt
Antworten
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Sprache zur Laufzeit ändern

Beitrag 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
Giesbert
Beiträge: 33
Registriert: 16. Oktober 2009 00:50
Wohnort: Hessdorf bei Erlangen
Kontaktdaten:

Beitrag 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 :-)
jackmack
Beiträge: 13
Registriert: 1. Juni 2010 10:51

Beitrag 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();
}
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Beitrag 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. :)
Giesbert
Beiträge: 33
Registriert: 16. Oktober 2009 00:50
Wohnort: Hessdorf bei Erlangen
Kontaktdaten:

Beitrag 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.
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Beitrag 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 :(
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Beitrag 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?
jackmack
Beiträge: 13
Registriert: 1. Juni 2010 10:51

Beitrag 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).
Antworten