Hi,

I have been annoyed for a long time by the combox for choosing UI language: it shows English (UK), English (UK)... where as only one en.po exists. This patch solves this problem. The way it is implemented is to decide that the first language that corresponds to a given .po file is the one that gets displayed. The languages file is therefore reorganized in order to be sorted by GuiName, which works weird.

I wanted to avoid having to create a new list of UI languages that would have to be kept in sync when adding new languages. The only remaining glitch is for Arabic, where the choice is between displaying "Arabic (Arabi)" and "Arabic (ArabTeX)".

Thoughts?

JMarc
>From 7f5c652c743f5a69ce12b8de84a1c3eb234d2596 Mon Sep 17 00:00:00 2001
From: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date: Thu, 7 May 2015 17:20:23 +0200
Subject: [PATCH] Improve list of available languages for UI l10n.

Expose realCode in Messages.h; get rid of available().

When reading languages, build a list of GUI languages. This avoids duplicates (like "English" and "English (UK)") and languages for which no translation exists. Note that the removal of duplicates takes in account the order of languages.

Sort languages by GUINames in lib/languages file.

Add in GuiApplication a function guiLanguageModel() that creates a model for the Prefs dialog. Use it in GuiPrefs.
---
 lib/languages                        |  297 +++++++++++++++++-----------------
 src/Language.cpp                     |   24 ++-
 src/Language.h                       |   10 +-
 src/frontends/qt4/GuiApplication.cpp |   36 ++++-
 src/frontends/qt4/GuiApplication.h   |    2 +
 src/frontends/qt4/GuiPrefs.cpp       |   27 +---
 src/support/Messages.cpp             |   16 +-
 src/support/Messages.h               |    7 +-
 8 files changed, 224 insertions(+), 195 deletions(-)

diff --git a/lib/languages b/lib/languages
index 1661699..ca7526c 100644
--- a/lib/languages
+++ b/lib/languages
@@ -91,6 +91,9 @@ End
 #
 # Real languages
 #
+# The languages are sorted by GUIName. WARNING: if several languages
+# correspond to the same .po file, it is the name of the first one
+# that will appear in the Preference GUI language picker.
 
 # not yet supported by polyglossia
 Language afrikaans
@@ -110,33 +113,6 @@ Language albanian
 	LangCode         sq_AL
 End
 
-Language american
-	GuiName          "English (USA)"
-	BabelName        american
-	PolyglossiaName  english
-	PolyglossiaOpts  "variant=american"
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         en_US
-End
-
-# In Babel, this is supported since v. 1.8a of babel-greek (2013-12-03)
-# We introduce it with LyX 2.2 to give the support time to settle.
-Language ancientgreek
-	GuiName           "Greek (ancient)"
-	BabelName         greek
-	PostBabelPreamble
-	\languageattribute{greek}{ancient}
-	EndPostBabelPreamble
-	PolyglossiaName   greek
-	PolyglossiaOpts   variant=ancient
-	QuoteStyle        french
-	Encoding          iso8859-7
-	InternalEncoding  true
-	FontEncoding      LGR
-	LangCode          grc_GR
-End
-
 # FIXME: dummy babel language for arabic_arabtex to be able
 # to switch the language the way of the ArabTeX-package
 Language arabic_arabtex
@@ -170,58 +146,6 @@ Language armenian
 	LangCode         hy_AM
 End
 
-Language australian
-	GuiName          "English (Australia)"
-	BabelName        australian
-	PolyglossiaName  english
-	PolyglossiaOpts  "variant=australian"
-	Encoding         iso8859-15
-	QuoteStyle       english
-	LangCode         en_AU
-End
-
-# In polyglossia, this is supported since release 1.33.4 (May 2014)
-# We introduce it with LyX 2.2 to give the support time to settle.
-Language austrian
-	GuiName          "German (Austria, old spelling)"
-	BabelName        austrian
-	PolyglossiaName  german
-	PolyglossiaOpts  "variant=austrian,spelling=old,babelshorthands=true"
-	QuoteStyle       german
-	Encoding         iso8859-15
-	LangCode         de_AT
-End
-
-# In polyglossia, this is supported since release 1.33.4 (May 2014)
-# We introduce it with LyX 2.2 to give the support time to settle.
-Language naustrian
-	GuiName          "German (Austria)"
-	BabelName        naustrian
-	PolyglossiaName  german
-	PolyglossiaOpts  "variant=austrian,babelshorthands=true"
-	QuoteStyle       german
-	Encoding         iso8859-15
-	LangCode         de_AT
-End
-
-Language bahasa
-	GuiName          "Indonesian"
-	BabelName        bahasa
-	PolyglossiaName  bahasai
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         id_ID
-End
-
-Language bahasam
-	GuiName          "Malay"
-	BabelName        bahasam
-	PolyglossiaName  bahasam
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         ms_MY
-End
-
 Language basque
 	GuiName          "Basque"
 	BabelName        basque
@@ -244,15 +168,6 @@ Language belarusian
 	AsBabelOptions   true
 End
 
-Language brazilian
-	GuiName          "Portuguese (Brazil)"
-	BabelName        brazil
-	PolyglossiaName  brazil
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         pt_BR
-End
-
 Language breton
 	GuiName          "Breton"
 	BabelName        breton
@@ -262,16 +177,6 @@ Language breton
 	LangCode         br_FR
 End
 
-Language british
-	GuiName          "English (UK)"
-	BabelName        british
-	PolyglossiaName  english
-	PolyglossiaOpts  "variant=british"
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         en_GB
-End
-
 Language bulgarian
 	GuiName          "Bulgarian"
 	BabelName        bulgarian
@@ -281,28 +186,6 @@ Language bulgarian
 	LangCode         bg_BG
 End
 
-# not yet supported by polyglossia
-Language canadian
-	GuiName          "English (Canada)"
-	BabelName        canadian
-#	PolyglossiaName  english
-#	PolyglossiaOpts  "variant=canadian"
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         en_CA
-End
-
-# not yet supported by polyglossia
-Language canadien
-	GuiName          "French (Canada)"
-	BabelName        canadien
-#	PolyglossiaName  french
-#	PolyglossiaOpts  "variant=canadien"
-	QuoteStyle       french
-	Encoding         iso8859-15
-	LangCode         fr_CA
-End
-
 Language catalan
 	GuiName          "Catalan"
 	BabelName        catalan
@@ -326,8 +209,8 @@ End
 Language chinese-traditional
 	GuiName         "Chinese (traditional)"
 	QuoteStyle       english
-	Encoding        utf8-cjk
-	LangCode        zh_TW
+	Encoding         utf8-cjk
+	LangCode         zh_TW
 	Requires         CJK
 End
 
@@ -393,6 +276,57 @@ Language english
 	LangCode         en_US
 End
 
+Language australian
+	GuiName          "English (Australia)"
+	BabelName        australian
+	PolyglossiaName  english
+	PolyglossiaOpts  "variant=australian"
+	Encoding         iso8859-15
+	QuoteStyle       english
+	LangCode         en_AU
+End
+
+# not yet supported by polyglossia
+Language canadian
+	GuiName          "English (Canada)"
+	BabelName        canadian
+#	PolyglossiaName  english
+#	PolyglossiaOpts  "variant=canadian"
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         en_CA
+End
+
+Language newzealand
+	GuiName          "English (New Zealand)"
+	BabelName        newzealand
+	PolyglossiaName  english
+	PolyglossiaOpts  "variant=newzealand"
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         en_NZ
+End
+
+Language british
+	GuiName          "English (UK)"
+	BabelName        british
+	PolyglossiaName  english
+	PolyglossiaOpts  "variant=british"
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         en_GB
+End
+
+Language american
+	GuiName          "English (USA)"
+	BabelName        american
+	PolyglossiaName  english
+	PolyglossiaOpts  "variant=american"
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         en_US
+End
+
 # Esperanto has no country code because it is an auxiliary language.
 # We therefore the name of its hunspell dictionary.
 Language esperanto
@@ -457,6 +391,17 @@ Language french
 	EndPostBabelPreamble
 End
 
+# not yet supported by polyglossia
+Language canadien
+	GuiName          "French (Canada)"
+	BabelName        canadien
+#	PolyglossiaName  french
+#	PolyglossiaOpts  "variant=canadien"
+	QuoteStyle       french
+	Encoding         iso8859-15
+	LangCode         fr_CA
+End
+
 Language galician
 	GuiName          "Galician"
 	BabelName        galician
@@ -479,6 +424,16 @@ Language georgian
 	LangCode         ka_GE
 End
 
+Language ngerman
+	GuiName          "German"
+	BabelName        ngerman
+	PolyglossiaName  german
+	PolyglossiaOpts  "babelshorthands=true"
+	QuoteStyle       german
+	Encoding         iso8859-15
+	LangCode         de_DE
+End
+
 # german does not use a country code (due to the variety)
 Language german
 	GuiName          "German (old spelling)"
@@ -491,14 +446,28 @@ Language german
 	LangVariety      alt
 End
 
-Language ngerman
-	GuiName          "German"
-	BabelName        ngerman
+# In polyglossia, this is supported since release 1.33.4 (May 2014)
+# We introduce it with LyX 2.2 to give the support time to settle.
+Language austrian
+	GuiName          "German (Austria, old spelling)"
+	BabelName        austrian
 	PolyglossiaName  german
-	PolyglossiaOpts  "babelshorthands=true"
+	PolyglossiaOpts  "variant=austrian,spelling=old,babelshorthands=true"
 	QuoteStyle       german
 	Encoding         iso8859-15
-	LangCode         de_DE
+	LangCode         de_AT
+End
+
+# In polyglossia, this is supported since release 1.33.4 (May 2014)
+# We introduce it with LyX 2.2 to give the support time to settle.
+Language naustrian
+	GuiName          "German (Austria)"
+	BabelName        naustrian
+	PolyglossiaName  german
+	PolyglossiaOpts  "variant=austrian,babelshorthands=true"
+	QuoteStyle       german
+	Encoding         iso8859-15
+	LangCode         de_AT
 End
 
 # In Babel, this is supported since release 2.7 of babel-german (Dec 2013)
@@ -539,6 +508,23 @@ Language greek
 	LangCode          el_GR
 End
 
+# In Babel, this is supported since v. 1.8a of babel-greek (2013-12-03)
+# We introduce it with LyX 2.2 to give the support time to settle.
+Language ancientgreek
+	GuiName           "Greek (ancient)"
+	BabelName         greek
+	PostBabelPreamble
+	\languageattribute{greek}{ancient}
+	EndPostBabelPreamble
+	PolyglossiaName   greek
+	PolyglossiaOpts   variant=ancient
+	QuoteStyle        french
+	Encoding          iso8859-7
+	InternalEncoding  true
+	FontEncoding      LGR
+	LangCode          grc_GR
+End
+
 Language polutonikogreek
 	GuiName           "Greek (polytonic)"
 	BabelName         polutonikogreek
@@ -593,6 +579,15 @@ Language icelandic
 	LangCode         is_IS
 End
 
+Language bahasa
+	GuiName          "Indonesian"
+	BabelName        bahasa
+	PolyglossiaName  bahasai
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         id_ID
+End
+
 # Interlingua has no official country code because it is an auxiliary
 # language. We therefore the name of its hunspell dictionary.
 Language interlingua
@@ -734,6 +729,15 @@ Language magyar
 	LangCode         hu_HU
 End
 
+Language bahasam
+	GuiName          "Malay"
+	BabelName        bahasam
+	PolyglossiaName  bahasam
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         ms_MY
+End
+
 # not supported by babel
 Language marathi
 	GuiName          "Marathi"
@@ -753,16 +757,6 @@ Language mongolian
 	AsBabelOptions   true
 End
 
-Language newzealand
-	GuiName          "English (New Zealand)"
-	BabelName        newzealand
-	PolyglossiaName  english
-	PolyglossiaOpts  "variant=newzealand"
-	QuoteStyle       english
-	Encoding         iso8859-15
-	LangCode         en_NZ
-End
-
 Language norsk
 	GuiName          "Norwegian (Bokmaal)"
 	BabelName        norsk
@@ -790,16 +784,6 @@ Language occitan
 	LangCode         oc_FR
 End
 
-# Currently not supported (file format change!)
-# Russian orthography from the Petrine orthographic reforms of
-# 1708 to the 1917 orthographic reform
-# Language oldrussian
-# 	GuiName          "Russian (Petrine orthography)"
-# 	PolyglossiaName  russian
-# 	PolyglossiaOpts  spelling=old
-# 	LangCode         ru_petr1708
-# End
-
 Language polish
 	GuiName          "Polish"
 	BabelName        polish
@@ -818,6 +802,15 @@ Language portuguese
 	LangCode         pt_PT
 End
 
+Language brazilian
+	GuiName          "Portuguese (Brazil)"
+	BabelName        brazil
+	PolyglossiaName  brazil
+	QuoteStyle       english
+	Encoding         iso8859-15
+	LangCode         pt_BR
+End
+
 Language romanian
 	GuiName          "Romanian"
 	BabelName        romanian
@@ -838,6 +831,16 @@ Language russian
 	LangCode         ru_RU
 End
 
+# Currently not supported (file format change!)
+# Russian orthography from the Petrine orthographic reforms of
+# 1708 to the 1917 orthographic reform
+# Language oldrussian
+# 	GuiName          "Russian (Petrine orthography)"
+# 	PolyglossiaName  russian
+# 	PolyglossiaOpts  spelling=old
+# 	LangCode         ru_petr1708
+# End
+
 Language samin
 	GuiName          "North Sami"
 	BabelName        samin
diff --git a/src/Language.cpp b/src/Language.cpp
index 28ce4e2..b6ddd75 100644
--- a/src/Language.cpp
+++ b/src/Language.cpp
@@ -224,6 +224,10 @@ void Language::readLayoutTranslations(Language::TranslationMap const & trans, bo
 
 void Languages::read(FileName const & filename)
 {
+	// This is used to populate the list of GUI languages
+	gui_vector_.clear();
+	set<string> real_codes;
+
 	Lexer lex;
 	lex.setFile(filename);
 	lex.setContext("Languages::read");
@@ -254,8 +258,26 @@ void Languages::read(FileName const & filename)
 			LASSERT(ignore_language == 0, continue);
 			static const Language ignore_lang = l;
 			ignore_language = &ignore_lang;
-		} else
+		} else {
 			languagelist[l.lang()] = l;
+			/** also populate the list of GUI translations. Discard
+			 * (1) the languages without translation and () the
+			 * languages for which the translation is alsready
+			 * claimed. The algorithm relies on the fact that entries
+			 * in the "languages" file are sorted to have the
+			 * reference language first. (e.g. "french" before
+			 * "canadien").
+			 */
+			string const real_code = Messages::realCode(l.code());
+			if ((!real_code.empty() // only when translation is available
+				 // don't add twice the same language
+				 && real_codes.find(real_code) == real_codes.end())
+				// never skip the currently selected language
+				|| l.lang() == lyxrc.gui_language) {
+				real_codes.insert(real_code);
+				gui_vector_.push_back(make_pair(l.lang(), l.display()));
+			}
+		}
 	}
 
 	default_language = getLanguage("english");
diff --git a/src/Language.h b/src/Language.h
index b532d9c..9958778 100644
--- a/src/Language.h
+++ b/src/Language.h
@@ -19,6 +19,7 @@
 #include "support/trivstring.h"
 
 #include <map>
+#include <vector>
 
 
 namespace lyx {
@@ -147,6 +148,8 @@ public:
 	///
 	typedef LanguageList::size_type size_type;
 	///
+	typedef std::vector< std::pair<trivstring, std::string> > DescVector;
+	///
 	void read(support::FileName const & filename);
 	///
 	void readLayoutTranslations(support::FileName const & filename);
@@ -158,11 +161,16 @@ public:
 	const_iterator begin() const { return languagelist.begin(); }
 	///
 	const_iterator end() const { return languagelist.end(); }
-	///
+	/// Return a vector of pairs (name, display) of languages that
+	/// correspond to available UI translations.
+	DescVector const & getGuiLanguages() const { return gui_vector_; }
+
 
 private:
 	///
 	LanguageList languagelist;
+	///
+	DescVector gui_vector_;
 };
 
 /// Global singleton instance.
diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp
index 160df4a..450a1d8 100644
--- a/src/frontends/qt4/GuiApplication.cpp
+++ b/src/frontends/qt4/GuiApplication.cpp
@@ -895,8 +895,8 @@ public:
 
 struct GuiApplication::Private
 {
-	Private(): language_model_(0), meta_fake_bit(NoModifier),
-		global_menubar_(0)
+	Private(): language_model_(0), gui_language_model_(0),
+	           meta_fake_bit(NoModifier), global_menubar_(0)
 	{
 	#if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400)
 	#if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)
@@ -914,7 +914,9 @@ struct GuiApplication::Private
 	}
 
 	///
-	QSortFilterProxyModel * language_model_;
+	QAbstractItemModel * language_model_;
+	///
+	QAbstractItemModel * gui_language_model_;
 	///
 	GuiClipboard clipboard_;
 	///
@@ -2455,6 +2457,34 @@ QAbstractItemModel * GuiApplication::languageModel()
 }
 
 
+QAbstractItemModel * GuiApplication::guiLanguageModel()
+{
+	if (d->gui_language_model_)
+		return d->gui_language_model_;
+
+	QAbstractItemModel * lang_model = new QStandardItemModel(this);
+	lang_model->insertColumn(0);
+
+	Languages::DescVector const & guivec = lyx::languages.getGuiLanguages();
+	Languages::DescVector::const_iterator it = guivec.begin();
+	Languages::DescVector::const_iterator end = guivec.end();
+	for (; it != end; ++it) {
+		int const current_row = lang_model->rowCount();
+		lang_model->insertRow(current_row);
+		QModelIndex item = lang_model->index(current_row, 0);
+		lang_model->setData(item, qt_(it->second), Qt::DisplayRole);
+		lang_model->setData(item, toqstr(it->first), Qt::UserRole);
+	}
+	lang_model->sort(0);
+	lang_model->insertRow(0);
+	QModelIndex item = lang_model->index(0, 0);
+	lang_model->setData(item, qt_("Default"), Qt::DisplayRole);
+	lang_model->setData(item, toqstr("auto"), Qt::UserRole);
+	d->gui_language_model_ = lang_model;
+	return d->gui_language_model_;
+}
+
+
 void GuiApplication::restoreGuiSession()
 {
 	if (!lyxrc.load_session)
diff --git a/src/frontends/qt4/GuiApplication.h b/src/frontends/qt4/GuiApplication.h
index c6258ea..81fd883 100644
--- a/src/frontends/qt4/GuiApplication.h
+++ b/src/frontends/qt4/GuiApplication.h
@@ -135,6 +135,8 @@ public:
 	ColorCache & colorCache();
 	///
 	QAbstractItemModel * languageModel();
+	///
+	QAbstractItemModel * guiLanguageModel();
 
 	/// return a suitable serif font name.
 	QString const romanFontName();
diff --git a/src/frontends/qt4/GuiPrefs.cpp b/src/frontends/qt4/GuiPrefs.cpp
index 995f8fa..a696c46 100644
--- a/src/frontends/qt4/GuiPrefs.cpp
+++ b/src/frontends/qt4/GuiPrefs.cpp
@@ -2296,38 +2296,15 @@ PrefLanguage::PrefLanguage(GuiPreferences * form)
 	startCommandED->setValidator(new NoNewLineValidator(startCommandED));
 	endCommandED->setValidator(new NoNewLineValidator(endCommandED));
 
-	uiLanguageCO->clear();
-
-	QAbstractItemModel * language_model = guiApp->languageModel();
-	// FIXME: it would be nice if sorting was enabled/disabled via a checkbox.
-	language_model->sort(0);
 	defaultDecimalPointLE->setInputMask("X; ");
 	defaultDecimalPointLE->setMaxLength(1);
 
 	defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM);
 	defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::IN]), Length::IN);
 
-	set<string> added;
+	QAbstractItemModel * gui_language_model = guiApp->guiLanguageModel();
 	uiLanguageCO->blockSignals(true);
-	uiLanguageCO->addItem(qt_("Default"), toqstr("auto"));
-	for (int i = 0; i != language_model->rowCount(); ++i) {
-		QModelIndex index = language_model->index(i, 0);
-		// Filter the list based on the available translation and add
-		// each language code only once
-		string const name = fromqstr(index.data(Qt::UserRole).toString());
-		Language const * lang = languages.getLanguage(name);
-		if (!lang)
-			continue;
-		// never remove the currently selected language
-		if (name != form->rc().gui_language
-		    && name != lyxrc.gui_language
-		    && (!Messages::available(lang->code())
-			|| added.find(lang->code()) != added.end()))
-				continue;
-		added.insert(lang->code());
-		uiLanguageCO->addItem(index.data(Qt::DisplayRole).toString(),
-			index.data(Qt::UserRole).toString());
-	}
+	uiLanguageCO->setModel(gui_language_model);
 	uiLanguageCO->blockSignals(false);
 }
 
diff --git a/src/support/Messages.cpp b/src/support/Messages.cpp
index fd5d228..6b9e49f 100644
--- a/src/support/Messages.cpp
+++ b/src/support/Messages.cpp
@@ -151,10 +151,8 @@ Messages::Messages(string const & l)
 }
 
 
-namespace {
-
 // Find the code we have for a given language code. Return empty if not found.
-string realCode(string code)
+string Messages::realCode(string code)
 {
 	// this loops at most twice
 	while (true) {
@@ -167,19 +165,7 @@ string realCode(string code)
 	}
 	return string();
 }
-}
-
-
-bool Messages::available(string const & c)
-{
-	return !realCode(c).empty();
-}
-
 
-string Messages::language() const
-{
-	return realCode(lang_);
-}
 
 namespace {
 
diff --git a/src/support/Messages.h b/src/support/Messages.h
index dd24e1c..4a03fb8 100644
--- a/src/support/Messages.h
+++ b/src/support/Messages.h
@@ -28,9 +28,10 @@ public:
 	///
 	docstring const get(std::string const & msg) const;
 	/// What is the language associated with this translation?
-	std::string language() const;
-	/// Is an (at least partial) translation of language with code \p c available?
-	static bool available(std::string const & c);
+	std::string language() const { return realCode(lang_); }
+
+	/// Find the code we have for a given language code. Return empty if not found.
+	static std::string realCode(std::string code);
 	///
 	static void guiLanguage(std::string const & l) { gui_lang_ = l; }
 	///
-- 
1.7.9.5

Reply via email to