Android: use BCP 47 tag to create a correct Locale for QTimeZone::displayName()

Before the patch we tried to create a java Locale object by passing the
human-readable language, territory and variant strings. However, the
Locale constructor accepts ISO-defined codes.

Fix it by using a factory method Locale.forLanguageTag() [0] that
constructs a Java Locale object based on BCP 47 tag.

[0]: https://developer.android.com/reference/java/util/Locale#forLanguageTag(java.lang.String)

Fixes: QTBUG-101460
Change-Id: If414c66cf0e5b7e8299ffc3a6038b6f9eb79d5ec
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
(cherry picked from commit 44f3fe1cf4e2319e012207eba3afe7adfe09cad6)
This commit is contained in:
Ivan Solovev 2022-04-05 10:53:06 +02:00
parent 4cb27786be
commit a2704c3421
2 changed files with 55 additions and 11 deletions

View File

@ -88,17 +88,10 @@ QAndroidTimeZonePrivate::~QAndroidTimeZonePrivate()
static QString getDisplayName(QJniObject zone, jint style, jboolean dst,
const QLocale &locale)
{
QJniObject jlanguage
= QJniObject::fromString(QLocale::languageToString(locale.language()));
QJniObject jterritory
= QJniObject::fromString(QLocale::territoryToString(locale.territory()));
QJniObject
jvariant = QJniObject::fromString(QLocale::scriptToString(locale.script()));
QJniObject jlocale("java.util.Locale",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
jlanguage.object<jstring>(),
jterritory.object<jstring>(),
jvariant.object<jstring>());
QJniObject jbcpTag = QJniObject::fromString(locale.bcp47Name());
QJniObject jlocale = QJniObject::callStaticObjectMethod(
"java/util/Locale", "forLanguageTag", "(Ljava/lang/String;)Ljava/util/Locale;",
jbcpTag.object<jstring>());
return zone.callObjectMethod("getDisplayName",
"(ZILjava/util/Locale;)Ljava/lang/String;",

View File

@ -75,6 +75,8 @@ private Q_SLOTS:
void macTest();
void darwinTypes();
void winTest();
void localeSpecificDisplayName_data();
void localeSpecificDisplayName();
private:
void printTimeZone(const QTimeZone &tz);
@ -1450,6 +1452,55 @@ void tst_QTimeZone::winTest()
#endif // QT_BUILD_INTERNAL && USING_WIN_TZ
}
void tst_QTimeZone::localeSpecificDisplayName_data()
{
#ifdef USING_WIN_TZ
QSKIP("MS backend does not use locale parameter");
#endif
QTest::addColumn<QByteArray>("zoneName");
QTest::addColumn<QLocale>("locale");
QTest::addColumn<QTimeZone::TimeType>("timeType");
QTest::addColumn<QString>("expectedName");
QStringList names;
QLocale locale;
// Pick a non-system locale; German or French
if (QLocale::system().language() != QLocale::German) {
locale = QLocale(QLocale::German);
names << QString("Mitteleurop\u00e4ische Normalzeit")
<< QString("Mitteleurop\u00e4ische Sommerzeit");
} else {
locale = QLocale(QLocale::French);
names << QString("heure normale d\u2019Europe centrale")
<< QString("heure d\u2019\u00E9t\u00E9 d\u2019Europe centrale");
}
qsizetype index = 0;
QTest::newRow("Berlin, standard time")
<< QByteArray("Europe/Berlin") << locale << QTimeZone::StandardTime
<< names.at(index++);
QTest::newRow("Berlin, summer time")
<< QByteArray("Europe/Berlin") << locale << QTimeZone::DaylightTime
<< names.at(index++);
}
void tst_QTimeZone::localeSpecificDisplayName()
{
// This test checks that QTimeZone::displayName() correctly uses the
// specified locale, NOT the system locale (see QTBUG-101460).
QFETCH(QByteArray, zoneName);
QFETCH(QLocale, locale);
QFETCH(QTimeZone::TimeType, timeType);
QFETCH(QString, expectedName);
QTimeZone zone(zoneName);
QVERIFY(zone.isValid());
const QString localeName = zone.displayName(timeType, QTimeZone::LongName, locale);
QCOMPARE(localeName, expectedName);
}
#ifdef QT_BUILD_INTERNAL
// Test each private produces the same basic results for CET
void tst_QTimeZone::testCetPrivate(const QTimeZonePrivate &tzp)