diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 430c18f511d..d2fdcb6dc81 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -5215,23 +5215,33 @@ QStringList QLocale::uiLanguages(TagSeparator separator) const localeIds.append(QLocaleId::fromName(entry)); if (localeIds.isEmpty()) localeIds.append(systemLocale()->fallbackLocale().d->m_data->id()); - // If the system locale (isn't C and) didn't include itself in the list, - // or as fallback, presume to know better than it and put its name - // first. (Known issue, QTBUG-104930, on some macOS versions when in - // locale en_DE.) Our translation system might have a translation for a - // locale the platform doesn't believe in. + /* Note: Darwin allows entirely independent choice of locale and of + preferred languages, so it's possible the locale implied by + LanguageId, ScriptId and TerritoryId is absent from the UILanguages + list and that this faithfully reflects the user's wishes. None the + less, we include it (if it isn't C) in the list below, after the last + with the same language and script or (if none has) at the end, in + case there is no better option available. (See, QTBUG-104930.) + */ const QString name = QString::fromLatin1(d->m_data->id().name(sep)); // Raw name if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) { // That uses contains(name) as a cheap pre-test, but there may be an // entry that matches this on purging likely subtags. const QLocaleId id = d->m_data->id(); - const QLocaleId mine = id.withLikelySubtagsRemoved(); - const auto isMine = [mine](const QString &entry) { - return QLocaleId::fromName(entry).withLikelySubtagsRemoved() == mine; - }; - if (std::none_of(uiLanguages.constBegin(), uiLanguages.constEnd(), isMine)) { - localeIds.prepend(id); - uiLanguages.prepend(QString::fromLatin1(id.name(sep))); + const QLocaleId max = id.withLikelySubtagsAdded(); + const QLocaleId mine = max.withLikelySubtagsRemoved(); + // Default to putting at the end: + qsizetype lastAlike = uiLanguages.size() - 1; + bool seen = false; + for (qsizetype i = 0; !seen && i < uiLanguages.size(); ++i) { + const auto its = QLocaleId::fromName(uiLanguages.at(i)).withLikelySubtagsAdded(); + seen = its.withLikelySubtagsRemoved() == mine; + if (!seen && its.language_id == max.language_id && its.script_id == max.script_id) + lastAlike = i; + } + if (!seen) { + localeIds.insert(lastAlike + 1, id); + uiLanguages.insert(lastAlike + 1, QString::fromLatin1(id.name(sep))); } } } else @@ -5410,7 +5420,7 @@ QStringList QLocale::uiLanguages(TagSeparator separator) const } } if (found) // Don't duplicate. - break; // any further truncations of prefix would also be found. + continue; // Some shorter truncations may still be missing. // Now we're committed to adding it, get it into known: (void) known.hasSeen(prefix); if (justAfter) { diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 254d4312418..35f14d459b9 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -4540,8 +4540,8 @@ void tst_QLocale::mySystemLocale_data() u"nb"_s}; QTest::addRow("en-Latn") // Android crash << u"en-Latn"_s << QLocale::English - << QStringList{u"en-Latn-US"_s, u"en-US"_s, u"en-Latn"_s, u"en"_s, - u"en-Latn-NO"_s, u"en-NO"_s}; + << QStringList{u"en-Latn-NO"_s, u"en-NO"_s, + u"en-Latn-US"_s, u"en-US"_s, u"en-Latn"_s, u"en"_s}; QTest::addRow("anglo-dutch") // QTBUG-131894 << u"en-NL"_s << QLocale::English @@ -4571,8 +4571,8 @@ void tst_QLocale::mySystemLocale_data() QTest::addRow("english-germany") << u"en-DE"_s << QLocale::English // First two were missed out before fix to QTBUG-104930: - << QStringList{u"en-Latn-DE"_s, u"en-DE"_s, - u"en-Latn-GB"_s, u"en-GB"_s, + << QStringList{u"en-Latn-GB"_s, u"en-GB"_s, + u"en-Latn-DE"_s, u"en-DE"_s, u"de-Latn-DE"_s, u"de-DE"_s, u"de-Latn"_s, u"de"_s, // Fallbacks implied by those: u"en-Latn"_s, u"en"_s}; @@ -4609,7 +4609,8 @@ void tst_QLocale::mySystemLocale_data() QTest::addRow("pa-Arab-GB") << u"pa-Arab-GB"_s << QLocale::Punjabi - << QStringList{u"pa-Arab-GB"_s, u"pa-Arab-PK"_s, u"pa-PK"_s, u"pa-Arab"_s, + << QStringList{u"pa-Arab-PK"_s, u"pa-PK"_s, u"pa-Arab"_s, + u"pa-Arab-GB"_s, u"en-Latn-GB"_s, u"en-GB"_s, // Truncations: u"en-Latn"_s, u"en"_s, @@ -4624,8 +4625,9 @@ void tst_QLocale::mySystemLocale_data() u"en-Latn-GB"_s, u"en-GB"_s, u"en-Latn"_s, u"en"_s}; QTest::newRow("en-mixed") << u"en-FO"_s << QLocale::English - << QStringList{u"en-Latn-FO"_s, u"en-FO"_s, u"en-Latn-DK"_s, u"en-DK"_s, + << QStringList{u"en-Latn-DK"_s, u"en-DK"_s, u"en-Latn-GB"_s, u"en-GB"_s, + u"en-Latn-FO"_s, u"en-FO"_s, u"fo-Latn-FO"_s, u"fo-FO"_s, u"fo-Latn"_s, u"fo"_s, u"da-Latn-FO"_s, u"da-FO"_s, u"da-Latn-DK"_s, u"da-DK"_s, u"da-Latn"_s, u"da"_s, @@ -4633,12 +4635,12 @@ void tst_QLocale::mySystemLocale_data() u"en-Latn"_s, u"en"_s}; QTest::newRow("polylingual-CA") << u"de-CA"_s << QLocale::German - << QStringList{u"de-Latn-CA"_s, u"de-CA"_s, u"en-Latn-CA"_s, u"en-CA"_s, - u"fr-Latn-CA"_s, u"fr-CA"_s, u"de-Latn-AT"_s, u"de-AT"_s, + << QStringList{u"en-Latn-CA"_s, u"en-CA"_s, u"fr-Latn-CA"_s, u"fr-CA"_s, + u"de-Latn-AT"_s, u"de-AT"_s, u"de-Latn-CA"_s, u"de-CA"_s, u"en-Latn-GB"_s, u"en-GB"_s, u"fr-Latn-FR"_s, u"fr-FR"_s, u"fr-Latn"_s, u"fr"_s, // Fallbacks: - u"de-Latn"_s, u"de"_s, u"en-Latn"_s, u"en"_s}; + u"en-Latn"_s, u"en"_s, u"de-Latn"_s, u"de"_s}; QTest::newRow("und-US") << u"und-US"_s << QLocale::C