diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 20a984fafe..5b53b8b338 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -334,33 +334,17 @@ QByteArray QLocalePrivate::bcp47Name(char separator) const return localeId.withLikelySubtagsRemoved().name(separator); } -const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLocale::Script script, QLocale::Country country) +static const QLocaleData *findLocaleDataById(const QLocaleId &localeId) { - QLocaleId localeId = QLocaleId::fromIds(language, script, country); - localeId = localeId.withLikelySubtagsAdded(); - - uint idx = locale_index[localeId.language_id]; + const uint idx = locale_index[localeId.language_id]; const QLocaleData *data = locale_data + idx; - if (idx == 0) // default language has no associated country + if (idx == 0) // default language has no associated script or country return data; Q_ASSERT(data->m_language_id == localeId.language_id); - if (localeId.script_id != QLocale::AnyScript && localeId.country_id != QLocale::AnyCountry) { - // both script and country are explicitly specified - do { - if (data->m_script_id == localeId.script_id && data->m_country_id == localeId.country_id) - return data; - ++data; - } while (data->m_language_id == localeId.language_id); - - // no match; try again with default script - localeId.script_id = QLocale::AnyScript; - data = locale_data + idx; - } - if (localeId.script_id == QLocale::AnyScript && localeId.country_id == QLocale::AnyCountry) return data; @@ -369,15 +353,72 @@ const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLoca if (data->m_country_id == localeId.country_id) return data; ++data; - } while (data->m_language_id == localeId.language_id); + } while (data->m_language_id && data->m_language_id == localeId.language_id); } else if (localeId.country_id == QLocale::AnyCountry) { do { if (data->m_script_id == localeId.script_id) return data; ++data; - } while (data->m_language_id == localeId.language_id); + } while (data->m_language_id && data->m_language_id == localeId.language_id); + } else { + do { + if (data->m_script_id == localeId.script_id && data->m_country_id == localeId.country_id) + return data; + ++data; + } while (data->m_language_id && data->m_language_id == localeId.language_id); } + return 0; +} + +const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLocale::Script script, QLocale::Country country) +{ + QLocaleId localeId = QLocaleId::fromIds(language, script, country); + localeId = localeId.withLikelySubtagsAdded(); + + const uint idx = locale_index[localeId.language_id]; + + // Try a straight match + if (const QLocaleData *const data = findLocaleDataById(localeId)) + return data; + QList tried; + tried.push_back(localeId); + + // No match; try again with likely country + localeId = QLocaleId::fromIds(language, script, QLocale::AnyCountry); + localeId = localeId.withLikelySubtagsAdded(); + if (!tried.contains(localeId)) { + if (const QLocaleData *const data = findLocaleDataById(localeId)) + return data; + tried.push_back(localeId); + } + + // No match; try again with any country + localeId = QLocaleId::fromIds(language, script, QLocale::AnyCountry); + if (!tried.contains(localeId)) { + if (const QLocaleData *const data = findLocaleDataById(localeId)) + return data; + tried.push_back(localeId); + } + + // No match; try again with likely script + localeId = QLocaleId::fromIds(language, QLocale::AnyScript, country); + localeId = localeId.withLikelySubtagsAdded(); + if (!tried.contains(localeId)) { + if (const QLocaleData *const data = findLocaleDataById(localeId)) + return data; + tried.push_back(localeId); + } + + // No match; try again with any script + localeId = QLocaleId::fromIds(language, QLocale::AnyScript, country); + if (!tried.contains(localeId)) { + if (const QLocaleData *const data = findLocaleDataById(localeId)) + return data; + tried.push_back(localeId); + } + + // No match; return data at original index return locale_data + idx; } diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 8d9a789507..42bfb3603d 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -186,12 +186,50 @@ void tst_QLocale::ctor() QVERIFY(l.country() == default_country); } +#define TEST_CTOR(req_lang, req_script, req_country, exp_lang, exp_script, exp_country) \ + { \ + QLocale l(QLocale::req_lang, QLocale::req_script, QLocale::req_country); \ + QCOMPARE((int)l.language(), (int)exp_lang); \ + QCOMPARE((int)l.script(), (int)exp_script); \ + QCOMPARE((int)l.country(), (int)exp_country); \ + } + + // Exact matches + TEST_CTOR(Chinese, SimplifiedHanScript, China, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + TEST_CTOR(Chinese, TraditionalHanScript, Taiwan, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::Taiwan); + TEST_CTOR(Chinese, TraditionalHanScript, HongKong, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::HongKong); + + // Best match for AnyCountry + TEST_CTOR(Chinese, SimplifiedHanScript, AnyCountry, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + TEST_CTOR(Chinese, TraditionalHanScript, AnyCountry, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::Taiwan); + + // Best match for AnyScript (and change country to supported one, if necessary) + TEST_CTOR(Chinese, AnyScript, China, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + TEST_CTOR(Chinese, AnyScript, Taiwan, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::Taiwan); + TEST_CTOR(Chinese, AnyScript, HongKong, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::HongKong); + TEST_CTOR(Chinese, AnyScript, UnitedStates, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + + // Fully-specified not found; find best alternate country + TEST_CTOR(Chinese, SimplifiedHanScript, Taiwan, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + TEST_CTOR(Chinese, SimplifiedHanScript, UnitedStates, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + TEST_CTOR(Chinese, TraditionalHanScript, China, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::Taiwan); + TEST_CTOR(Chinese, TraditionalHanScript, UnitedStates, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::Taiwan); + + // Fully-specified not found; find best alternate script + TEST_CTOR(Chinese, LatinScript, China, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + TEST_CTOR(Chinese, LatinScript, Taiwan, QLocale::Chinese, QLocale::TraditionalHanScript, QLocale::Taiwan); + + // Fully-specified not found; find best alternate country and script + TEST_CTOR(Chinese, LatinScript, UnitedStates, QLocale::Chinese, QLocale::SimplifiedHanScript, QLocale::China); + +#undef TEST_CTOR #define TEST_CTOR(req_lang, req_country, exp_lang, exp_country) \ { \ QLocale l(QLocale::req_lang, QLocale::req_country); \ QCOMPARE((int)l.language(), (int)exp_lang); \ QCOMPARE((int)l.country(), (int)exp_country); \ } + { QLocale l(QLocale::C, QLocale::AnyCountry); QCOMPARE(l.language(), QLocale::C); @@ -295,7 +333,6 @@ void tst_QLocale::ctor() TEST_CTOR(Uzbek, AnyCountry, QLocale::Uzbek, QLocale::Uzbekistan) #undef TEST_CTOR - #define TEST_CTOR(req_lc, exp_lang, exp_country) \ { \ QLocale l(req_lc); \