From 0118e2e9151ae3e1e1cd72f24e8c129eaa69dc4f Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 29 Apr 2019 12:33:55 +0200 Subject: [PATCH] Include likely-adjusted uiLanguages for the system locale QLocale::uiLanguages() on the system locale uses whatever the system locale's query(QSystemLocale::UILanguages,...) returns. On Android, this is just a list of locales. However, for non-system locales, we also include some results of removing likely sub-tags from the locale name, where equivalent. Thus zh-CN would also get zh and zh-Hans-CN added to it; however, if the system locale is zh-Hans-CN, the shorter forms are omitted. So post-process the system locale list in the same way, albeit tweaked to avoid duplicates and rearranged so that we can insert likely-adjusted entries between what they adjust and what followed it. Added QLocalePrivate::rawName() in the process, since it looks likely to be useful in other contexts (and I needed its value): it just joins such tags as are non-Any. This, however, uses QByteArrayList, so added that (it's small) to the bootstrap library and qmake. This follows up on commit 8796e3016fae1672e727e2fa4e48f671a0c667ba. [ChangeLog][QtCore][QLocale] The system locale's UI languages list now includes, as for that of an ordinary locale, the results of adding likely sub-tags from each locale name, and of removing some, where this doesn't change which locale is specified. This gives searches for translation files a better chance of finding a suitable file. Fixes: QTBUG-75413 Change-Id: Iaafd79aac6a0fdd5f44aed16e445e84a2267c9da Reviewed-by: Paul Wicking Reviewed-by: Qt CI Bot Reviewed-by: Thiago Macieira --- qmake/Makefile.unix | 8 ++- qmake/Makefile.win32 | 1 + src/corelib/text/qlocale.cpp | 84 ++++++++++++++++++++++++------- src/corelib/text/qlocale_p.h | 1 + src/tools/bootstrap/bootstrap.pro | 1 + 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index e895feaef4..4d4f05e78a 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -27,7 +27,7 @@ QOBJS = \ qjsonarray.o qjson.o qjsondocument.o qjsonobject.o qjsonparser.o qjsonvalue.o \ qmetatype.o qsystemerror.o qvariant.o \ quuid.o \ - qarraydata.o qbitarray.o qbytearray.o qbytearraymatcher.o \ + qarraydata.o qbitarray.o qbytearray.o qbytearraylist.o qbytearraymatcher.o \ qcalendar.o qgregoriancalendar.o qromancalendar.o \ qcryptographichash.o qdatetime.o qhash.o qlist.o \ qlocale.o qlocale_tools.o qmap.o qregexp.o qringbuffer.o \ @@ -106,7 +106,8 @@ DEPEND_SRC = \ $(SOURCE_PATH)/src/corelib/serialization/qtextstream.cpp \ $(SOURCE_PATH)/src/corelib/serialization/qxmlstream.cpp \ $(SOURCE_PATH)/src/corelib/serialization/qxmlutils.cpp \ - $(SOURCE_PATH)/src/corelib/text/qbytearray.cpp\ + $(SOURCE_PATH)/src/corelib/text/qbytearray.cpp \ + $(SOURCE_PATH)/src/corelib/text/qbytearraylist.cpp \ $(SOURCE_PATH)/src/corelib/text/qbytearraymatcher.cpp \ $(SOURCE_PATH)/src/corelib/text/qlocale.cpp \ $(SOURCE_PATH)/src/corelib/text/qlocale_tools.cpp \ @@ -309,6 +310,9 @@ qarraydata.o: $(SOURCE_PATH)/src/corelib/tools/qarraydata.cpp qbytearray.o: $(SOURCE_PATH)/src/corelib/text/qbytearray.cpp $(CXX) -c -o $@ $(CXXFLAGS) $< +qbytearraylist.o: $(SOURCE_PATH)/src/corelib/text/qbytearraylist.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + qvsnprintf.o: $(SOURCE_PATH)/src/corelib/text/qvsnprintf.cpp $(CXX) -c -o $@ $(CXXFLAGS) $< diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index 672df47953..7324817af2 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -69,6 +69,7 @@ QTOBJS= \ qfsfileengine_iterator.obj \ qarraydata.obj \ qbytearray.obj \ + qbytearraylist.obj \ qvsnprintf.obj \ qbytearraymatcher.obj \ qcalendar.obj \ diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 48d57e5e6e..75a5bc802e 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -345,6 +345,23 @@ QByteArray QLocalePrivate::bcp47Name(char separator) const return localeId.withLikelySubtagsRemoved().name(separator); } +/*! + \internal + */ +QByteArray QLocalePrivate::rawName(char separator) const +{ + QByteArrayList parts; + if (m_data->m_language_id != QLocale::AnyLanguage) + parts.append(languageCode().latin1()); + if (m_data->m_script_id != QLocale::AnyScript) + parts.append(scriptCode().latin1()); + if (m_data->m_country_id != QLocale::AnyCountry) + parts.append(countryCode().latin1()); + + return parts.join(separator); +} + + static const QLocaleData *findLocaleDataById(const QLocaleId &lid) { QLocaleId localeId = lid.withLikelySubtagsAdded(); @@ -4367,30 +4384,63 @@ QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats */ QStringList QLocale::uiLanguages() const { + QStringList uiLanguages; + QVector locales; #ifndef QT_NO_SYSTEMLOCALE if (d->m_data == systemData()) { QVariant res = systemLocale()->query(QSystemLocale::UILanguages, QVariant()); if (!res.isNull()) { - QStringList result = res.toStringList(); - if (!result.isEmpty()) - return result; + uiLanguages = res.toStringList(); + // ... but we need to include likely-adjusted forms of each of those, too: + for (const auto entry : qAsConst(uiLanguages)) + locales.append(QLocale(entry)); } - } + } else #endif - QLocaleId id = QLocaleId::fromIds(d->m_data->m_language_id, d->m_data->m_script_id, - d->m_data->m_country_id); - const QLocaleId max = id.withLikelySubtagsAdded(); - const QLocaleId min = max.withLikelySubtagsRemoved(); - - QStringList uiLanguages; - uiLanguages.append(QString::fromLatin1(min.name())); - if (id.script_id) { - id.script_id = 0; - if (id != min && id.withLikelySubtagsAdded() == max) - uiLanguages.append(QString::fromLatin1(id.name())); + { + locales.append(*this); + } + for (int i = locales.size(); i-- > 0; ) { + const QLocale &locale = locales.at(i); + int j; + QByteArray prior; + if (i < uiLanguages.size()) { + // Adding likely-adjusted forms to system locale's list. + // Name the locale is derived from: + const QString &name = uiLanguages.at(i); + prior = name.toLatin1(); + // Don't try to likely-adjust if construction's likely-adjustments + // were so drastic the result doesn't match the prior name: + if (locale.name() != name && locale.d->rawName() != prior) + continue; + // Insert just after prior: + j = i + 1; + } else { + // Plain locale, not system locale; just append. + j = uiLanguages.size(); + } + const auto data = locale.d->m_data; + + QLocaleId id + = QLocaleId::fromIds(data->m_language_id, data->m_script_id, data->m_country_id); + const QLocaleId max = id.withLikelySubtagsAdded(); + const QLocaleId min = max.withLikelySubtagsRemoved(); + id.script_id = 0; // For re-use as script-less variant. + + // Include version with all likely sub-tags (last) if distinct from the rest: + if (max != min && max != id && max.name() != prior) + uiLanguages.insert(j, QString::fromLatin1(max.name())); + + // Include scriptless version if likely-equivalent and distinct: + if (data->m_script_id && id != min && id.name() != prior + && id.withLikelySubtagsAdded() == max) { + uiLanguages.insert(j, QString::fromLatin1(id.name())); + } + + // Include minimal version (first) unless it's what our locale is derived from: + if (min.name() != prior) + uiLanguages.insert(j, QString::fromLatin1(min.name())); } - if (max != min && max != id) - uiLanguages.append(QString::fromLatin1(max.name())); return uiLanguages; } diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index 5ebed9b385..edee3a89c7 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -359,6 +359,7 @@ public: quint16 countryId() const { return m_data->m_country_id; } QByteArray bcp47Name(char separator = '-') const; + QByteArray rawName(char separator = '-') const; inline QLatin1String languageCode() const { return languageToCode(QLocale::Language(m_data->m_language_id)); } inline QLatin1String scriptCode() const { return scriptToCode(QLocale::Script(m_data->m_script_id)); } diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index f9ffd1bbea..09a1c68001 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -75,6 +75,7 @@ SOURCES += \ ../../corelib/serialization/qxmlutils.cpp \ ../../corelib/serialization/qxmlstream.cpp \ ../../corelib/text/qbytearray.cpp \ + ../../corelib/text/qbytearraylist.cpp \ ../../corelib/text/qbytearraymatcher.cpp \ ../../corelib/text/qlocale.cpp \ ../../corelib/text/qlocale_tools.cpp \