The following patch implements a way to retranslate dialogs when the GUI language changes. For now I only did About and Bibtex. I have yet to understand how to do Bibitem and other InsetParamWidget children.

Comments welcome. Is this worth doing, considering that it requires work (but not so much code).

In some cases, the situation is a bit complicated, like the long tooltip defined explicitly in InsetBibtex. Note that for this case, it is possible to use html:
https://stackoverflow.com/questions/17221621/how-to-set-qt-tooltip-width

Any comments? Should I do it differently? Should I do it at all?

JMarc

>From 24cbbff3f145f4f20fc0dc5a3344c382658d5be5 Mon Sep 17 00:00:00 2001
From: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date: Thu, 19 Jul 2018 00:13:28 +0200
Subject: [PATCH] Proof of concept: retranslate dialogs on the fly

This patch shows how to change the language of dialogs seemlessly
without restarting LyX. Currently only About and Bibtex are done. The
first uses DialogView and the second GuiVIew. The changes are minimal,
although there are details to handle...

The trick is to use the functon retranslateUi which is created by uic
in the ui_*.h files. This requires unfortunately to call the function
explicitely in each dialog.
---
 src/frontends/qt4/Dialog.cpp         |  7 ++++---
 src/frontends/qt4/Dialog.h           |  9 ++++++++-
 src/frontends/qt4/DialogView.cpp     |  2 +-
 src/frontends/qt4/DockView.cpp       |  2 +-
 src/frontends/qt4/GuiAbout.cpp       | 16 ++++++++++++++--
 src/frontends/qt4/GuiAbout.h         |  6 ++++++
 src/frontends/qt4/GuiApplication.cpp | 11 +++++++++++
 src/frontends/qt4/GuiApplication.h   |  2 ++
 src/frontends/qt4/GuiBibtex.cpp      | 13 ++++++++++---
 src/frontends/qt4/GuiBibtex.h        |  5 +++++
 src/frontends/qt4/GuiDialog.cpp      |  2 +-
 src/frontends/qt4/GuiView.cpp        | 14 +++++++++-----
 src/frontends/qt4/GuiView.h          |  2 ++
 13 files changed, 74 insertions(+), 17 deletions(-)

diff --git a/src/frontends/qt4/Dialog.cpp b/src/frontends/qt4/Dialog.cpp
index 2369738c5c..b74be6825f 100644
--- a/src/frontends/qt4/Dialog.cpp
+++ b/src/frontends/qt4/Dialog.cpp
@@ -44,8 +44,9 @@ using namespace lyx::support;
 namespace lyx {
 namespace frontend {
 
-Dialog::Dialog(GuiView & lv, QString const & name, QString const & title)
-	: name_(name), title_(title), lyxview_(lv)
+Dialog::Dialog(GuiView & lv, QString const & name,
+               QString const & prefix, QString const & title)
+	: name_(name), title_prefix_(prefix), title_(title), lyxview_(lv)
 {}
 
 
@@ -171,7 +172,7 @@ void Dialog::prepareView()
 	checkStatus();
 
 	QWidget * w = asQWidget();
-	w->setWindowTitle(title_);
+	w->setWindowTitle(title_prefix_ + qt_(title_));
 
 	QSize const hint = w->sizeHint();
 	if (hint.height() >= 0 && hint.width() >= 0)
diff --git a/src/frontends/qt4/Dialog.h b/src/frontends/qt4/Dialog.h
index 5f958e79d0..71360d09d8 100644
--- a/src/frontends/qt4/Dialog.h
+++ b/src/frontends/qt4/Dialog.h
@@ -55,13 +55,17 @@ public:
 	/// \param name is the identifier given to the dialog by its parent
 	/// container.
 	/// \param title is the window title used for decoration.
-	Dialog(GuiView & lv, QString const & name, QString const & title);
+	Dialog(GuiView & lv, QString const & name,
+	       QString const & prefix, QString const & title);
 
 	virtual ~Dialog();
 
 	virtual QWidget * asQWidget() = 0;
 	virtual QWidget const * asQWidget() const = 0;
 
+	/// This should be implemented by each dialog
+	virtual void retranslate() {};
+
 	/// Session key.
 	/**
 	 * This key must be used for any session setting.
@@ -263,6 +267,7 @@ public:
 protected:
 	///
 	void setTitle(QString const & title) { title_ = title; }
+	void setTitlePrefix(QString const & prefix) { title_prefix_ = prefix; }
 	///
 	virtual void apply();
 	/// To be called when the buffer view has changed
@@ -274,6 +279,8 @@ private:
 	 */
 	QString const name_;
 	///
+	QString title_prefix_;
+	///
 	QString title_;
 	///
 	GuiView & lyxview_;
diff --git a/src/frontends/qt4/DialogView.cpp b/src/frontends/qt4/DialogView.cpp
index 9b114ec507..b715dafece 100644
--- a/src/frontends/qt4/DialogView.cpp
+++ b/src/frontends/qt4/DialogView.cpp
@@ -18,7 +18,7 @@ namespace lyx {
 namespace frontend {
 
 DialogView::DialogView(GuiView & lv, QString const & name, QString const & title)
-	: QDialog(&lv), Dialog(lv, name, "LyX: " + title)
+	: QDialog(&lv), Dialog(lv, name, "LyX: ", title)
 {
 	connect(&lv, SIGNAL(bufferViewChanged()),
 	        this, SLOT(onBufferViewChanged()));
diff --git a/src/frontends/qt4/DockView.cpp b/src/frontends/qt4/DockView.cpp
index de9a51c78f..4845f240a8 100644
--- a/src/frontends/qt4/DockView.cpp
+++ b/src/frontends/qt4/DockView.cpp
@@ -21,7 +21,7 @@ namespace frontend {
 DockView::DockView(GuiView & parent, QString const & name,
                    QString const & title, Qt::DockWidgetArea area,
                    Qt::WindowFlags flags)
-	: QDockWidget(&parent, flags), Dialog(parent, name, title)
+	: QDockWidget(&parent, flags), Dialog(parent, name, QString(), title)
 {
 	setObjectName(name);
 	parent.addDockWidget(area, this);
diff --git a/src/frontends/qt4/GuiAbout.cpp b/src/frontends/qt4/GuiAbout.cpp
index 747723ff06..53d5c8c34a 100644
--- a/src/frontends/qt4/GuiAbout.cpp
+++ b/src/frontends/qt4/GuiAbout.cpp
@@ -252,11 +252,18 @@ struct GuiAbout::Private
 
 
 GuiAbout::GuiAbout(GuiView & lv)
-	: DialogView(lv, "aboutlyx", qt_("About LyX")),
+	: DialogView(lv, "aboutlyx", N_("About LyX")),
 	d(new GuiAbout::Private)
 {
 	d->ui.setupUi(this);
+	setContents();
 
+	d->ui.tab->setUsesScrollButtons(false);
+}
+
+
+void GuiAbout::setContents()
+{
 	d->ui.copyrightTB->setPlainText(copyright());
 	d->ui.copyrightTB->append(QString());
 	d->ui.copyrightTB->append(license());
@@ -268,8 +275,13 @@ GuiAbout::GuiAbout(GuiView & lv)
 	d->ui.releasenotesTB->setHtml(release_notes());
 	d->ui.releasenotesTB->setOpenExternalLinks(true);
 	d->ui.creditsTB->setHtml(credits());
+}
 
-	d->ui.tab->setUsesScrollButtons(false);
+
+void GuiAbout::retranslate()
+{
+	d->ui.retranslateUi(this);
+	setContents();
 }
 
 
diff --git a/src/frontends/qt4/GuiAbout.h b/src/frontends/qt4/GuiAbout.h
index 200f0b7837..845370042e 100644
--- a/src/frontends/qt4/GuiAbout.h
+++ b/src/frontends/qt4/GuiAbout.h
@@ -25,6 +25,9 @@ public:
 	// Constructor
 	GuiAbout(GuiView & lv);
 
+	///
+	void retranslate();
+
 private Q_SLOTS:
 	void on_buttonBox_rejected();
 
@@ -36,6 +39,9 @@ private:
 	bool isBufferDependent() const { return false; }
 	///@}
 
+	///
+	void setContents();
+
 	struct Private;
 	Private * const d;
 };
diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp
index 25eff65ec2..8c3d327ea4 100644
--- a/src/frontends/qt4/GuiApplication.cpp
+++ b/src/frontends/qt4/GuiApplication.cpp
@@ -2514,6 +2514,9 @@ void GuiApplication::setGuiLanguage()
 	default:
 		setLayoutDirection(Qt::LeftToRight);
 	}
+
+	// Retranslate the dialogs
+	retranslate();
 }
 
 
@@ -2909,6 +2912,14 @@ void GuiApplication::hideDialogs(string const & name, Inset * inset) const
 }
 
 
+void GuiApplication::retranslate() const
+{
+	QList<GuiView *> const views = d->views_.values();
+	for (GuiView * view : views)
+		view->retranslateDialogs();
+}
+
+
 Buffer const * GuiApplication::updateInset(Inset const * inset) const
 {
 	Buffer const * buffer_ = 0;
diff --git a/src/frontends/qt4/GuiApplication.h b/src/frontends/qt4/GuiApplication.h
index fafdd46eea..9e33c136b2 100644
--- a/src/frontends/qt4/GuiApplication.h
+++ b/src/frontends/qt4/GuiApplication.h
@@ -85,6 +85,8 @@ public:
 	///
 	void hideDialogs(std::string const & name, Inset * inset) const;
 	///
+	void retranslate() const;
+	///
 	void resetGui();
 
 	///
diff --git a/src/frontends/qt4/GuiBibtex.cpp b/src/frontends/qt4/GuiBibtex.cpp
index 6d1c8c12a5..86751e593d 100644
--- a/src/frontends/qt4/GuiBibtex.cpp
+++ b/src/frontends/qt4/GuiBibtex.cpp
@@ -53,7 +53,7 @@ namespace frontend {
 
 
 GuiBibtex::GuiBibtex(GuiView & lv)
-	: GuiDialog(lv, "bibtex", qt_("BibTeX Bibliography")),
+	: GuiDialog(lv, "bibtex", "BibTeX Bibliography"),
 	  params_(insetCode("bibtex"))
 {
 	setupUi(this);
@@ -144,6 +144,13 @@ GuiBibtex::GuiBibtex(GuiView & lv)
 }
 
 
+void GuiBibtex::retranslate()
+{
+	retranslateUi(this);
+	add_->retranslate();
+}
+
+
 void GuiBibtex::addBBClicked(QAbstractButton * button)
 {
 	switch (add_->buttonBox->standardButton(button)) {
@@ -335,9 +342,9 @@ void GuiBibtex::updateContents()
 	bool biblatex = usingBiblatex();
 
 	if (biblatex)
-		setTitle(qt_("Biblatex Bibliography"));
+		setTitle(N_("Biblatex Bibliography"));
 	else
-		setTitle(qt_("BibTeX Bibliography"));
+		setTitle(N_("BibTeX Bibliography"));
 
 	databaseLW->clear();
 
diff --git a/src/frontends/qt4/GuiBibtex.h b/src/frontends/qt4/GuiBibtex.h
index 4dbe107fa6..4f96ff36b7 100644
--- a/src/frontends/qt4/GuiBibtex.h
+++ b/src/frontends/qt4/GuiBibtex.h
@@ -33,6 +33,9 @@ public:
 		QDialog::setModal(true);
 		setWindowModality(Qt::WindowModal);
 	}
+
+	void retranslate() {  retranslateUi(this); }
+
 };
 
 
@@ -43,6 +46,8 @@ class GuiBibtex : public GuiDialog, public Ui::BibtexUi
 public:
 	explicit GuiBibtex(GuiView & lv);
 
+	void retranslate();
+
 private Q_SLOTS:
 	void addBBClicked(QAbstractButton * button);
 	void change_adaptor();
diff --git a/src/frontends/qt4/GuiDialog.cpp b/src/frontends/qt4/GuiDialog.cpp
index 4fcff16a23..2a3fae09cd 100644
--- a/src/frontends/qt4/GuiDialog.cpp
+++ b/src/frontends/qt4/GuiDialog.cpp
@@ -26,7 +26,7 @@ namespace lyx {
 namespace frontend {
 
 GuiDialog::GuiDialog(GuiView & lv, QString const & name, QString const & title)
-	: QDialog(&lv), Dialog(lv, name, "LyX: " + title), updating_(false),
+	: QDialog(&lv), Dialog(lv, name, "LyX: ", title), updating_(false),
 	  is_closing_(false)
 {
 	connect(&lv, SIGNAL(bufferViewChanged()),
diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp
index d1991aa08b..8417e4bbea 100644
--- a/src/frontends/qt4/GuiView.cpp
+++ b/src/frontends/qt4/GuiView.cpp
@@ -4686,13 +4686,17 @@ void GuiView::hideAll() const
 }
 
 
-void GuiView::updateDialogs()
+void GuiView::retranslateDialogs()
 {
-	map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-	map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+	for (auto & dpair : d.dialogs_)
+		dpair.second->retranslate();
+}
 
-	for(; it != end; ++it) {
-		Dialog * dialog = it->second.get();
+
+void GuiView::updateDialogs()
+{
+	for(auto & dpair : d.dialogs_) {
+		Dialog * dialog = dpair.second.get();
 		if (dialog) {
 			if (dialog->needBufferOpen() && !documentBufferView())
 				hideDialog(fromqstr(dialog->name()), 0);
diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h
index 2d0ad0097a..8ad0c771df 100644
--- a/src/frontends/qt4/GuiView.h
+++ b/src/frontends/qt4/GuiView.h
@@ -348,6 +348,8 @@ public:
 	///
 	void disconnectDialog(std::string const & name);
 	///
+	void retranslateDialogs();
+	///
 	bool develMode() const { return devel_mode_; }
 
 private:
-- 
2.17.1

Reply via email to