From dd98e362017f9919b4bde7a735d2c2695098d703 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 17 Aug 2022 17:40:59 +0200 Subject: [PATCH] Work round macOS's omission of en_DE from its own uiLanguages() When the system locale is en_DE, macOS seems to think we should use en_GB as the right translation. While that probably is a sensible choice in the absence of an en_DE translation, we should definitely use the en_DE translation if available, especially if en_GB isn't available (which lead to a fall-back to de_DE, given later entries in macOS's list). So prepend the system locale's own pcp47Name() if it (isn't the C locale and) is missing from what we would otherwise have used for uiLanguages(), after likely sub-tag perturbations. Add a test simulating (some approximation to) what macOS was doing that would have caught this case; and add a scope-guard reporter to the test to report what shows up when lists don't match. Fixes: QTBUG-104930 Change-Id: I116234708067e1717d9157aebc84da76e04a9f38 Reviewed-by: Volker Hilsheimer (cherry picked from commit 753bfdf6a1336cc296e5fc8175aedd000c2cc013) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/text/qlocale.cpp | 18 ++++++++++++++++++ .../auto/corelib/text/qlocale/tst_qlocale.cpp | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 3cd281443ce..69aef517e2f 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -4419,6 +4419,24 @@ QStringList QLocale::uiLanguages() const locales.append(QLocale(entry)); if (locales.isEmpty()) locales.append(systemLocale()->fallbackLocale()); + // 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. + const QString name = bcp47Name(); + 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 mine = d->m_data->id().withLikelySubtagsRemoved(); + const auto isMine = [mine](const QString &entry) { + return QLocaleId::fromName(entry).withLikelySubtagsRemoved() == mine; + }; + if (std::none_of(uiLanguages.constBegin(), uiLanguages.constEnd(), isMine)) { + locales.prepend(*this); + uiLanguages.prepend(name); + } + } } else #endif { diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 5d4769796d4..f464b427a0c 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -3238,7 +3238,12 @@ public: QVariant query(QueryType type, QVariant /*in*/) const override { - return type == UILanguages ? QVariant(QStringList{m_name}) : QVariant(); + if (type == UILanguages) { + if (m_name == u"en-DE") // QTBUG-104930: simulate macOS's list not including m_name. + return QVariant(QStringList{QStringLiteral("en-GB"), QStringLiteral("de-DE")}); + return QVariant(QStringList{m_name}); + } + return QVariant(); } QLocale fallbackLocale() const override @@ -3267,6 +3272,12 @@ void tst_QLocale::systemLocale_data() QTest::addRow("ukrainian") << QString("uk") << QLocale::Ukrainian << QStringList{QStringLiteral("uk"), QStringLiteral("uk-Cyrl-UA"), QStringLiteral("uk-UA")}; + QTest::addRow("english-germany") + << QString("en-DE") << QLocale::English + // First two were missed out before fix to QTBUG-104930: + << QStringList{QStringLiteral("en-DE"), QStringLiteral("en-Latn-DE"), + QStringLiteral("en-GB"), QStringLiteral("en-Latn-GB"), + QStringLiteral("de-DE"), QStringLiteral("de-Latn-DE"), QStringLiteral("de")}; QTest::addRow("german") << QString("de") << QLocale::German << QStringList{QStringLiteral("de"), QStringLiteral("de-Latn-DE"), QStringLiteral("de-DE")}; @@ -3291,7 +3302,11 @@ void tst_QLocale::systemLocale() MySystemLocale sLocale(name); QCOMPARE(QLocale().language(), language); QCOMPARE(QLocale::system().language(), language); + auto reporter = qScopeGuard([]() { + qDebug("\n\t%s", qPrintable(QLocale::system().uiLanguages().join(u"\n\t"))); + }); QCOMPARE(QLocale::system().uiLanguages(), uiLanguages); + reporter.dismiss(); } QCOMPARE(QLocale(), originalLocale);