QLocale: Report RTL text direction for pa_Arab and uz_Arab
[profile/ivi/qtbase.git] / src / corelib / tools / qlocale.cpp
index 1dc3849..582ae9e 100644 (file)
@@ -1,38 +1,38 @@
 /****************************************************************************
 **
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the QtCore module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
 ** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
 ** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
 **
 **
 ** $QT_END_LICENSE$
 
 #include "qglobal.h"
 
-#ifndef QT_NO_SYSTEMLOCALE
-QT_BEGIN_NAMESPACE
-class QSystemLocale;
-static QSystemLocale *QSystemLocale_globalSystemLocale();
-QT_END_NAMESPACE
-#endif
-
 #include "qplatformdefs.h"
 
 #include "qdatastream.h"
@@ -67,31 +60,26 @@ QT_END_NAMESPACE
 #include "qstringlist.h"
 #include "qvariant.h"
 #include "qstringbuilder.h"
-#if defined(Q_OS_WIN)
-#   include "qt_windows.h"
-#   include <time.h>
-#endif
 #include "private/qnumeric_p.h"
 #include "private/qsystemlibrary_p.h"
+#ifdef Q_OS_WIN
+#   include <qt_windows.h>
+#   include <time.h>
+#endif
 
 QT_BEGIN_NAMESPACE
 
-#if defined(Q_OS_SYMBIAN)
-void qt_symbianUpdateSystemPrivate();
-void qt_symbianInitSystemLocale();
-#endif
-
 #ifndef QT_NO_SYSTEMLOCALE
 static QSystemLocale *_systemLocale = 0;
-Q_GLOBAL_STATIC_WITH_ARGS(QSystemLocale, QSystemLocale_globalSystemLocale, (true))
-static QLocalePrivate *system_lp = 0;
-Q_GLOBAL_STATIC(QLocalePrivate, globalLocalePrivate)
-#endif
+class QSystemLocaleSingleton: public QSystemLocale
+{
+public:
+    QSystemLocaleSingleton() : QSystemLocale(true) {}
+};
 
-#ifdef QT_USE_ICU
-extern bool qt_initIcu(const QString &localeName);
-extern bool qt_u_strToUpper(const QString &str, QString *out, const QLocale &locale);
-extern bool qt_u_strToLower(const QString &str, QString *out, const QLocale &locale);
+Q_GLOBAL_STATIC(QSystemLocaleSingleton, QSystemLocale_globalSystemLocale)
+static QLocaleData *system_data = 0;
+Q_GLOBAL_STATIC(QLocaleData, globalLocaleData)
 #endif
 
 /******************************************************************************
@@ -111,15 +99,30 @@ QLocale::Language QLocalePrivate::codeToLanguage(const QString &code)
     ushort uc2 = len-- > 0 ? code[1].toLower().unicode() : 0;
     ushort uc3 = len-- > 0 ? code[2].toLower().unicode() : 0;
 
-    if (uc1 == 'n' && uc2 == 'o' && uc3 == 0)
-        uc2 = 'b';
-
     const unsigned char *c = language_code_list;
     for (; *c != 0; c += 3) {
         if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2])
             return QLocale::Language((c - language_code_list)/3);
     }
 
+    // legacy codes
+    if (uc1 == 'n' && uc2 == 'o' && uc3 == 0) { // no -> nb
+        Q_STATIC_ASSERT(QLocale::Norwegian == QLocale::NorwegianBokmal);
+        return QLocale::Norwegian;
+    }
+    if (uc1 == 't' && uc2 == 'l' && uc3 == 0) { // tl -> fil
+        Q_STATIC_ASSERT(QLocale::Tagalog == QLocale::Filipino);
+        return QLocale::Tagalog;
+    }
+    if (uc1 == 's' && uc2 == 'h' && uc3 == 0) { // sh -> sr[_Latn]
+        Q_STATIC_ASSERT(QLocale::SerboCroatian == QLocale::Serbian);
+        return QLocale::SerboCroatian;
+    }
+    if (uc1 == 'm' && uc2 == 'o' && uc3 == 0) { // mo -> ro
+        Q_STATIC_ASSERT(QLocale::Moldavian == QLocale::Romanian);
+        return QLocale::Moldavian;
+    }
+
     return QLocale::C;
 }
 
@@ -163,12 +166,12 @@ QLocale::Country QLocalePrivate::codeToCountry(const QString &code)
 
 QString QLocalePrivate::languageCode() const
 {
-    if (m_language_id == QLocale::AnyLanguage)
+    if (m_data->m_language_id == QLocale::AnyLanguage)
         return QString();
-    if (m_language_id == QLocale::C)
+    if (m_data->m_language_id == QLocale::C)
         return QLatin1String("C");
 
-    const unsigned char *c = language_code_list + 3*(uint(m_language_id));
+    const unsigned char *c = language_code_list + 3*(uint(m_data->m_language_id));
 
     QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized);
 
@@ -182,18 +185,18 @@ QString QLocalePrivate::languageCode() const
 
 QString QLocalePrivate::scriptCode() const
 {
-    if (m_script_id == QLocale::AnyScript || m_script_id > QLocale::LastScript)
+    if (m_data->m_script_id == QLocale::AnyScript || m_data->m_script_id > QLocale::LastScript)
         return QString();
-    const unsigned char *c = script_code_list + 4*(uint(m_script_id));
+    const unsigned char *c = script_code_list + 4*(uint(m_data->m_script_id));
     return QString::fromLatin1((const char *)c, 4);
 }
 
 QString QLocalePrivate::countryCode() const
 {
-    if (m_country_id == QLocale::AnyCountry)
+    if (m_data->m_country_id == QLocale::AnyCountry)
         return QString();
 
-    const unsigned char *c = country_code_list + 3*(uint(m_country_id));
+    const unsigned char *c = country_code_list + 3*(uint(m_data->m_country_id));
 
     QString code(c[2] == 0 ? 2 : 3, Qt::Uninitialized);
 
@@ -205,17 +208,94 @@ QString QLocalePrivate::countryCode() const
     return code;
 }
 
-QString QLocalePrivate::bcp47Name() const
+// http://www.unicode.org/reports/tr35/#Likely_Subtags
+static bool addLikelySubtags(QLocaleId &localeId)
+{
+    // ### optimize with bsearch
+    const int likely_subtags_count = sizeof(likely_subtags) / sizeof(likely_subtags[0]);
+    const QLocaleId *p = likely_subtags;
+    const QLocaleId *const e = p + likely_subtags_count;
+    for ( ; p < e; p += 2) {
+        if (localeId == p[0]) {
+            localeId = p[1];
+            return true;
+        }
+    }
+    return false;
+}
+
+QLocaleId QLocaleId::withLikelySubtagsAdded() const
 {
-    if (m_language_id == QLocale::AnyLanguage)
+    // language_script_region
+    if (language_id || script_id || country_id) {
+        QLocaleId id = QLocaleId::fromIds(language_id, script_id, country_id);
+        if (addLikelySubtags(id))
+            return id;
+    }
+    // language_script
+    if (country_id) {
+        QLocaleId id = QLocaleId::fromIds(language_id, script_id, 0);
+        if (addLikelySubtags(id)) {
+            id.country_id = country_id;
+            return id;
+        }
+    }
+    // language_region
+    if (script_id) {
+        QLocaleId id = QLocaleId::fromIds(language_id, 0, country_id);
+        if (addLikelySubtags(id)) {
+            id.script_id = script_id;
+            return id;
+        }
+    }
+    // language
+    if (script_id && country_id) {
+        QLocaleId id = QLocaleId::fromIds(language_id, 0, 0);
+        if (addLikelySubtags(id)) {
+            id.script_id = script_id;
+            id.country_id = country_id;
+            return id;
+        }
+    }
+    return *this;
+}
+
+QLocaleId QLocaleId::withLikelySubtagsRemoved() const
+{
+    QLocaleId max = withLikelySubtagsAdded();
+    // language
+    {
+        QLocaleId id = QLocaleId::fromIds(language_id, 0, 0);
+        if (id.withLikelySubtagsAdded() == max)
+            return id;
+    }
+    // language_region
+    if (country_id) {
+        QLocaleId id = QLocaleId::fromIds(language_id, 0, country_id);
+        if (id.withLikelySubtagsAdded() == max)
+            return id;
+    }
+    // language_script
+    if (script_id) {
+        QLocaleId id = QLocaleId::fromIds(language_id, script_id, 0);
+        if (id.withLikelySubtagsAdded() == max)
+            return id;
+    }
+    return max;
+}
+
+QString QLocaleId::bcp47Name() const
+{
+    if (language_id == QLocale::AnyLanguage)
         return QString();
-    if (m_language_id == QLocale::C)
-        return QLatin1String("C");
-    const unsigned char *lang = language_code_list + 3*(uint(m_language_id));
+    if (language_id == QLocale::C)
+        return QStringLiteral("C");
+
+    const unsigned char *lang = language_code_list + 3*uint(language_id);
     const unsigned char *script =
-            (m_script_id != QLocale::AnyScript ? script_code_list + 4*(uint(m_script_id)) : 0);
+            (script_id != QLocale::AnyScript ? script_code_list + 4*uint(script_id) : 0);
     const unsigned char *country =
-            (m_country_id != QLocale::AnyCountry  ? country_code_list + 3*(uint(m_country_id)) : 0);
+            (country_id != QLocale::AnyCountry  ? country_code_list + 3*uint(country_id) : 0);
     char len = (lang[2] != 0 ? 3 : 2) + (script ? 4+1 : 0) + (country ? (country[2] != 0 ? 3 : 2)+1 : 0);
     QString name(len, Qt::Uninitialized);
     QChar *uc = name.data();
@@ -240,42 +320,59 @@ QString QLocalePrivate::bcp47Name() const
     return name;
 }
 
-const QLocalePrivate *QLocalePrivate::findLocale(QLocale::Language language, QLocale::Script script, QLocale::Country country)
+QString QLocalePrivate::bcp47Name() const
 {
-    const unsigned language_id = language;
-    const unsigned script_id = script;
-    const unsigned country_id = country;
+    if (m_data->m_language_id == QLocale::AnyLanguage)
+        return QString();
+    if (m_data->m_language_id == QLocale::C)
+        return QStringLiteral("C");
+
+    QLocaleId localeId = QLocaleId::fromIds(m_data->m_language_id, m_data->m_script_id, m_data->m_country_id);
+    return localeId.withLikelySubtagsRemoved().bcp47Name();
+}
 
-    uint idx = locale_index[language_id];
+const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLocale::Script script, QLocale::Country country)
+{
+    QLocaleId localeId = QLocaleId::fromIds(language, script, country);
+    localeId = localeId.withLikelySubtagsAdded();
 
-    const QLocalePrivate *d = locale_data + idx;
+    uint idx = locale_index[localeId.language_id];
+
+    const QLocaleData *data = locale_data + idx;
 
     if (idx == 0) // default language has no associated country
-        return d;
-
-    if (script == QLocale::AnyScript && country == QLocale::AnyCountry)
-        return d;
-
-    Q_ASSERT(d->languageId() == language_id);
-
-    if (country == QLocale::AnyCountry) {
-        while (d->m_language_id == language_id && d->m_script_id != script_id)
-            ++d;
-        if (d->m_language_id == language_id && d->m_script_id == script_id)
-            return d;
-    } else if (script == QLocale::AnyScript) {
-        while (d->m_language_id == language_id) {
-            if (d->m_script_id == script_id && d->m_country_id == country_id)
-                return d;
-            ++d;
-        }
-    } else {
+        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
-        while (d->m_language_id == language_id) {
-            if (d->m_script_id == script_id && d->m_country_id == country_id)
-                return d;
-            ++d;
-        }
+        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;
+
+    if (localeId.script_id == QLocale::AnyScript) {
+        do {
+            if (data->m_country_id == localeId.country_id)
+                return data;
+            ++data;
+        } while (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);
     }
 
     return locale_data + idx;
@@ -307,7 +404,7 @@ bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QSt
 
     lang = script = cntry = QString();
 
-    const QString separators = QLatin1String("_-.@");
+    const QString separators = QStringLiteral("_-.@");
     enum ParserState { NoState, LangState, ScriptState, CountryState };
     ParserState state = LangState;
     for (int i = 0; i < length && state != NoState; ) {
@@ -376,14 +473,14 @@ void QLocalePrivate::getLangAndCountry(const QString &name, QLocale::Language &l
     cntry = QLocalePrivate::codeToCountry(cntry_code);
 }
 
-static const QLocalePrivate *findLocale(const QString &name)
+static const QLocaleData *findLocaleData(const QString &name)
 {
     QLocale::Language lang;
     QLocale::Script script;
     QLocale::Country cntry;
     QLocalePrivate::getLangAndCountry(name, lang, script, cntry);
 
-    return QLocalePrivate::findLocale(lang, script, cntry);
+    return QLocaleData::findLocaleData(lang, script, cntry);
 }
 
 QString qt_readEscapedFormatString(const QString &format, int *idx)
@@ -429,7 +526,7 @@ int qt_repeatCount(const QString &s, int i)
     return j - i;
 }
 
-static const QLocalePrivate *default_lp = 0;
+static const QLocaleData *default_data = 0;
 static uint default_number_options = 0;
 
 #ifndef QT_NO_SYSTEMLOCALE
@@ -449,11 +546,13 @@ QSystemLocale::QSystemLocale()
     delete _systemLocale;
     _systemLocale = this;
 
-    if (system_lp)
-        system_lp->m_language_id = 0;
+    if (system_data)
+        system_data->m_language_id = 0;
 }
 
-/*! \internal */
+/*!
+    \internal
+*/
 QSystemLocale::QSystemLocale(bool)
 { }
 
@@ -465,8 +564,8 @@ QSystemLocale::~QSystemLocale()
     if (_systemLocale == this) {
         _systemLocale = 0;
 
-        if (system_lp)
-            system_lp->m_language_id = 0;
+        if (system_data)
+            system_data->m_language_id = 0;
     }
 }
 
@@ -474,87 +573,74 @@ static const QSystemLocale *systemLocale()
 {
     if (_systemLocale)
         return _systemLocale;
-#if defined(Q_OS_SYMBIAN)
-    qt_symbianInitSystemLocale();
-#endif
     return QSystemLocale_globalSystemLocale();
 }
 
 void QLocalePrivate::updateSystemPrivate()
 {
     const QSystemLocale *sys_locale = systemLocale();
-    if (!system_lp)
-        system_lp = globalLocalePrivate();
+    if (!system_data)
+        system_data = globalLocaleData();
 
     // tell the object that the system locale has changed.
     sys_locale->query(QSystemLocale::LocaleChanged, QVariant());
 
-    *system_lp = *sys_locale->fallbackLocale().d();
-
-#if defined(Q_OS_SYMBIAN)
-    qt_symbianUpdateSystemPrivate();
-#endif
+    *system_data = *sys_locale->fallbackUiLocale().d->m_data;
 
     QVariant res = sys_locale->query(QSystemLocale::LanguageId, QVariant());
     if (!res.isNull()) {
-        system_lp->m_language_id = res.toInt();
-        system_lp->m_script_id = QLocale::AnyScript; // default for compatibility
+        system_data->m_language_id = res.toInt();
+        system_data->m_script_id = QLocale::AnyScript; // default for compatibility
     }
     res = sys_locale->query(QSystemLocale::CountryId, QVariant());
     if (!res.isNull()) {
-        system_lp->m_country_id = res.toInt();
-        system_lp->m_script_id = QLocale::AnyScript; // default for compatibility
+        system_data->m_country_id = res.toInt();
+        system_data->m_script_id = QLocale::AnyScript; // default for compatibility
     }
     res = sys_locale->query(QSystemLocale::ScriptId, QVariant());
     if (!res.isNull())
-        system_lp->m_script_id = res.toInt();
+        system_data->m_script_id = res.toInt();
 
     res = sys_locale->query(QSystemLocale::DecimalPoint, QVariant());
     if (!res.isNull())
-        system_lp->m_decimal = res.toString().at(0).unicode();
+        system_data->m_decimal = res.toString().at(0).unicode();
 
     res = sys_locale->query(QSystemLocale::GroupSeparator, QVariant());
     if (!res.isNull())
-        system_lp->m_group = res.toString().at(0).unicode();
+        system_data->m_group = res.toString().at(0).unicode();
 
     res = sys_locale->query(QSystemLocale::ZeroDigit, QVariant());
     if (!res.isNull())
-        system_lp->m_zero = res.toString().at(0).unicode();
+        system_data->m_zero = res.toString().at(0).unicode();
 
     res = sys_locale->query(QSystemLocale::NegativeSign, QVariant());
     if (!res.isNull())
-        system_lp->m_minus = res.toString().at(0).unicode();
+        system_data->m_minus = res.toString().at(0).unicode();
 
     res = sys_locale->query(QSystemLocale::PositiveSign, QVariant());
     if (!res.isNull())
-        system_lp->m_plus = res.toString().at(0).unicode();
-
-#ifdef QT_USE_ICU
-    if (!default_lp)
-        qt_initIcu(system_lp->bcp47Name());
-#endif
-
+        system_data->m_plus = res.toString().at(0).unicode();
 }
 #endif
 
-static const QLocalePrivate *systemPrivate()
+static const QLocaleData *systemData()
 {
 #ifndef QT_NO_SYSTEMLOCALE
     // copy over the information from the fallback locale and modify
-    if (!system_lp || system_lp->m_language_id == 0)
+    if (!system_data || system_data->m_language_id == 0)
         QLocalePrivate::updateSystemPrivate();
 
-    return system_lp;
+    return system_data;
 #else
     return locale_data;
 #endif
 }
 
-static const QLocalePrivate *defaultPrivate()
+static const QLocaleData *defaultData()
 {
-    if (!default_lp)
-        default_lp = systemPrivate();
-    return default_lp;
+    if (!default_data)
+        default_data = systemData();
+    return default_data;
 }
 
 static QString getLocaleListData(const ushort *data, int size, int index)
@@ -598,14 +684,14 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
 #endif // QT_NO_DATASTREAM
 
 
-static const int locale_data_size = sizeof(locale_data)/sizeof(QLocalePrivate) - 1;
+static const int locale_data_size = sizeof(locale_data)/sizeof(QLocaleData) - 1;
 
-static const QLocalePrivate *dataPointerHelper(quint16 index)
+const QLocaleData *QLocalePrivate::dataPointerForIndex(quint16 index)
 {
 #ifndef QT_NO_SYSTEMLOCALE
     Q_ASSERT(index <= locale_data_size);
     if (index == locale_data_size)
-        return system_lp;
+        return system_data;
 #else
     Q_ASSERT(index < locale_data_size);
 #endif
@@ -613,12 +699,12 @@ static const QLocalePrivate *dataPointerHelper(quint16 index)
     return &locale_data[index];
 }
 
-static quint16 localePrivateIndex(const QLocalePrivate *p)
+static quint16 localeDataIndex(const QLocaleData *p)
 {
 #ifndef QT_NO_SYSTEMLOCALE
     Q_ASSERT((p >= locale_data && p - locale_data < locale_data_size)
-             || (p != 0 && p == system_lp));
-    quint16 index = p == system_lp ? locale_data_size : p - locale_data;
+             || (p != 0 && p == system_data));
+    quint16 index = p == system_data ? locale_data_size : p - locale_data;
 #else
     Q_ASSERT(p >= locale_data && p - locale_data < locale_data_size);
     quint16 index = p - locale_data;
@@ -628,15 +714,23 @@ static quint16 localePrivateIndex(const QLocalePrivate *p)
 }
 
 /*!
+ \internal
+*/
+QLocale::QLocale(QLocalePrivate &dd)
+    : d(&dd)
+{}
+
+
+/*!
     Constructs a QLocale object with the specified \a name,
     which has the format
     "language[_script][_country][.codeset][@modifier]" or "C", where:
 
     \list
-    \i language is a lowercase, two-letter, ISO 639 language code,
-    \i script is a titlecase, four-letter, ISO 15924 script code,
-    \i country is an uppercase, two- or three-letter, ISO 3166 country code (also "419" as defined by United Nations),
-    \i and codeset and modifier are ignored.
+    \li language is a lowercase, two-letter, ISO 639 language code (also some three-letter codes),
+    \li script is a titlecase, four-letter, ISO 15924 script code,
+    \li country is an uppercase, two-letter, ISO 3166 country code (also "419" as defined by United Nations),
+    \li and codeset and modifier are ignored.
     \endlist
 
     The separator can be either underscore or a minus sign.
@@ -657,25 +751,21 @@ static quint16 localePrivateIndex(const QLocalePrivate *p)
 */
 
 QLocale::QLocale(const QString &name)
-    : v(0)
+    : d(new QLocalePrivate(localeDataIndex(findLocaleData(name))))
 {
-    p.numberOptions = 0;
-    p.index = localePrivateIndex(findLocale(name));
 }
 
 /*!
     Constructs a QLocale object initialized with the default locale. If
-    no default locale was set using setDefaultLocale(), this locale will
+    no default locale was set using setDefault(), this locale will
     be the same as the one returned by system().
 
     \sa setDefault()
 */
 
 QLocale::QLocale()
-    : v(0)
+    : d(new QLocalePrivate(localeDataIndex(defaultData()), default_number_options))
 {
-    p.numberOptions = default_number_options;
-    p.index = localePrivateIndex(defaultPrivate());
 }
 
 /*!
@@ -683,33 +773,34 @@ QLocale::QLocale()
     country.
 
     \list
-    \i If the language/country pair is found in the database, it is used.
-    \i If the language is found but the country is not, or if the country
+    \li If the language/country pair is found in the database, it is used.
+    \li If the language is found but the country is not, or if the country
        is \c AnyCountry, the language is used with the most
        appropriate available country (for example, Germany for German),
-    \i If neither the language nor the country are found, QLocale
+    \li If neither the language nor the country are found, QLocale
        defaults to the default locale (see setDefault()).
     \endlist
 
     The language and country that are actually used can be queried
     using language() and country().
 
-    \sa setDefault() language() country()
+    \sa setDefault(), language(), country()
 */
 
 QLocale::QLocale(Language language, Country country)
-    : v(0)
 {
-    const QLocalePrivate *d = QLocalePrivate::findLocale(language, QLocale::AnyScript, country);
+    const QLocaleData *data = QLocaleData::findLocaleData(language, QLocale::AnyScript, country);
+    int index;
+    int numberOptions = 0;
 
     // If not found, should default to system
-    if (d->languageId() == QLocale::C && language != QLocale::C) {
-        p.numberOptions = default_number_options;
-        p.index = localePrivateIndex(defaultPrivate());
+    if (data->m_language_id == QLocale::C && language != QLocale::C) {
+        numberOptions = default_number_options;
+        index = localeDataIndex(defaultData());
     } else {
-        p.numberOptions = 0;
-        p.index = localePrivateIndex(d);
+        index = localeDataIndex(data);
     }
+    d = new QLocalePrivate(index, numberOptions);
 }
 \
 /*!
@@ -719,36 +810,37 @@ QLocale::QLocale(Language language, Country country)
     \a country.
 
     \list
-    \i If the language/script/country is found in the database, it is used.
-    \i If both \a script is AnyScript and \a country is AnyCountry, the
+    \li If the language/script/country is found in the database, it is used.
+    \li If both \a script is AnyScript and \a country is AnyCountry, the
        language is used with the most appropriate available script and country
        (for example, Germany for German),
-    \i If either \a script is AnyScript or \a country is AnyCountry, the
+    \li If either \a script is AnyScript or \a country is AnyCountry, the
        language is used with the first locale that matches the given \a script
        and \a country.
-    \i If neither the language nor the country are found, QLocale
+    \li If neither the language nor the country are found, QLocale
        defaults to the default locale (see setDefault()).
     \endlist
 
     The language, script and country that are actually used can be queried
     using language(), script() and country().
 
-    \sa setDefault() language() script() country()
+    \sa setDefault(), language(), script(), country()
 */
 
 QLocale::QLocale(Language language, Script script, Country country)
-    : v(0)
 {
-    const QLocalePrivate *d = QLocalePrivate::findLocale(language, script, country);
+    const QLocaleData *data = QLocaleData::findLocaleData(language, script, country);
+    int index;
+    int numberOptions = 0;
 
     // If not found, should default to system
-    if (d->languageId() == QLocale::C && language != QLocale::C) {
-        p.numberOptions = default_number_options;
-        p.index = localePrivateIndex(defaultPrivate());
+    if (data->m_language_id == QLocale::C && language != QLocale::C) {
+        numberOptions = default_number_options;
+        index = localeDataIndex(defaultData());
     } else {
-        p.numberOptions = 0;
-        p.index = localePrivateIndex(d);
+        index = localeDataIndex(data);
     }
+    d = new QLocalePrivate(index, numberOptions);
 }
 
 /*!
@@ -757,12 +849,15 @@ QLocale::QLocale(Language language, Script script, Country country)
 
 QLocale::QLocale(const QLocale &other)
 {
-    v = other.v;
+    d = other.d;
 }
 
-const QLocalePrivate *QLocale::d() const
+/*!
+    Destructor
+*/
+
+QLocale::~QLocale()
 {
-    return dataPointerHelper(p.index);
 }
 
 /*!
@@ -772,18 +867,18 @@ const QLocalePrivate *QLocale::d() const
 
 QLocale &QLocale::operator=(const QLocale &other)
 {
-    v = other.v;
+    d = other.d;
     return *this;
 }
 
 bool QLocale::operator==(const QLocale &other) const
 {
-    return d() == other.d() && numberOptions() == other.numberOptions();
+    return d->m_data == other.d->m_data && d->m_numberOptions == other.d->m_numberOptions;
 }
 
 bool QLocale::operator!=(const QLocale &other) const
 {
-    return d() != other.d() || numberOptions() != other.numberOptions();
+    return d->m_data != other.d->m_data || d->m_numberOptions != other.d->m_numberOptions;
 }
 
 /*!
@@ -794,7 +889,7 @@ bool QLocale::operator!=(const QLocale &other) const
 */
 void QLocale::setNumberOptions(NumberOptions options)
 {
-    p.numberOptions = options;
+    d->m_numberOptions = options;
 }
 
 /*!
@@ -807,7 +902,7 @@ void QLocale::setNumberOptions(NumberOptions options)
 */
 QLocale::NumberOptions QLocale::numberOptions() const
 {
-    return static_cast<NumberOption>(p.numberOptions);
+    return static_cast<NumberOption>(d->m_numberOptions);
 }
 
 /*!
@@ -829,7 +924,7 @@ QString QLocale::quoteString(const QString &str, QuotationStyle style) const
 QString QLocale::quoteString(const QStringRef &str, QuotationStyle style) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res;
         if (style == QLocale::AlternateQuotation)
             res = systemLocale()->query(QSystemLocale::StringToAlternateQuotation, QVariant::fromValue(str));
@@ -841,9 +936,9 @@ QString QLocale::quoteString(const QStringRef &str, QuotationStyle style) const
 #endif
 
     if (style == QLocale::StandardQuotation)
-        return QChar(d()->m_quotation_start) % str % QChar(d()->m_quotation_end);
+        return QChar(d->m_data->m_quotation_start) % str % QChar(d->m_data->m_quotation_end);
     else
-        return QChar(d()->m_alternate_quotation_start) % str % QChar(d()->m_alternate_quotation_end);
+        return QChar(d->m_data->m_alternate_quotation_start) % str % QChar(d->m_data->m_alternate_quotation_end);
 }
 
 /*!
@@ -855,7 +950,7 @@ QString QLocale::quoteString(const QStringRef &str, QuotationStyle style) const
 QString QLocale::createSeparatedList(const QStringList &list) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res;
         res = systemLocale()->query(QSystemLocale::ListToSeparatedString, QVariant::fromValue(list));
 
@@ -868,12 +963,12 @@ QString QLocale::createSeparatedList(const QStringList &list) const
     if (size == 1) {
         return list.at(0);
     } else if (size == 2) {
-        QString format = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_two_idx, d()->m_list_pattern_part_two_size);
+        QString format = getLocaleData(list_pattern_part_data + d->m_data->m_list_pattern_part_two_idx, d->m_data->m_list_pattern_part_two_size);
         return format.arg(list.at(0), list.at(1));
     } else if (size > 2) {
-        QString formatStart = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_start_idx, d()->m_list_pattern_part_start_size);
-        QString formatMid = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_mid_idx, d()->m_list_pattern_part_mid_size);
-        QString formatEnd = getLocaleData(list_pattern_part_data + d()->m_list_pattern_part_end_idx, d()->m_list_pattern_part_end_size);
+        QString formatStart = getLocaleData(list_pattern_part_data + d->m_data->m_list_pattern_part_start_idx, d->m_data->m_list_pattern_part_start_size);
+        QString formatMid = getLocaleData(list_pattern_part_data + d->m_data->m_list_pattern_part_mid_idx, d->m_data->m_list_pattern_part_mid_size);
+        QString formatEnd = getLocaleData(list_pattern_part_data + d->m_data->m_list_pattern_part_end_idx, d->m_data->m_list_pattern_part_end_size);
         QString result = formatStart.arg(list.at(0), list.at(1));
         for (int i = 2; i < size - 1; ++i)
             result = formatMid.arg(result, list.at(i));
@@ -896,17 +991,13 @@ QString QLocale::createSeparatedList(const QStringList &list) const
     should be set at application startup, before any non-GUI threads
     are created.
 
-    \sa system() c()
+    \sa system(), c()
 */
 
 void QLocale::setDefault(const QLocale &locale)
 {
-    default_lp = locale.d();
+    default_data = locale.d->m_data;
     default_number_options = locale.numberOptions();
-
-#ifdef QT_USE_ICU
-    qt_initIcu(locale.bcp47Name());
-#endif
 }
 
 /*!
@@ -916,7 +1007,7 @@ void QLocale::setDefault(const QLocale &locale)
 */
 QLocale::Language QLocale::language() const
 {
-    return Language(d()->languageId());
+    return Language(d->languageId());
 }
 
 /*!
@@ -928,7 +1019,7 @@ QLocale::Language QLocale::language() const
 */
 QLocale::Script QLocale::script() const
 {
-    return Script(d()->m_script_id);
+    return Script(d->m_data->m_script_id);
 }
 
 /*!
@@ -938,7 +1029,7 @@ QLocale::Script QLocale::script() const
 */
 QLocale::Country QLocale::country() const
 {
-    return Country(d()->countryId());
+    return Country(d->countryId());
 }
 
 /*!
@@ -958,7 +1049,7 @@ QString QLocale::name() const
 {
     Language l = language();
 
-    QString result = d()->languageCode();
+    QString result = d->languageCode();
 
     if (l == C)
         return result;
@@ -968,7 +1059,7 @@ QString QLocale::name() const
         return result;
 
     result.append(QLatin1Char('_'));
-    result.append(d()->countryCode());
+    result.append(d->countryCode());
 
     return result;
 }
@@ -989,7 +1080,7 @@ QString QLocale::name() const
 */
 QString QLocale::bcp47Name() const
 {
-    return d()->bcp47Name();
+    return d->bcp47Name();
 }
 
 /*!
@@ -1033,11 +1124,7 @@ QString QLocale::scriptToString(QLocale::Script script)
 }
 
 /*!
-    Returns the short int represented by the localized string \a s,
-    using base \a base. If \a base is 0 the base is determined
-    automatically using the following rules: If the string begins with
-    "0x", it is assumed to be hexadecimal; if it begins with "0", it
-    is assumed to be octal; otherwise it is assumed to be decimal.
+    Returns the short int represented by the localized string \a s.
 
     If the conversion fails the function returns 0.
 
@@ -1049,9 +1136,9 @@ QString QLocale::scriptToString(QLocale::Script script)
     \sa toUShort(), toString()
 */
 
-short QLocale::toShort(const QString &s, bool *ok, int base) const
+short QLocale::toShort(const QString &s, bool *ok) const
 {
-    qlonglong i = toLongLong(s, ok, base);
+    qlonglong i = toLongLong(s, ok);
     if (i < SHRT_MIN || i > SHRT_MAX) {
         if (ok != 0)
             *ok = false;
@@ -1061,11 +1148,7 @@ short QLocale::toShort(const QString &s, bool *ok, int base) const
 }
 
 /*!
-    Returns the unsigned short int represented by the localized string
-    \a s, using base \a base. If \a base is 0 the base is determined
-    automatically using the following rules: If the string begins with
-    "0x", it is assumed to be hexadecimal; if it begins with "0", it
-    is assumed to be octal; otherwise it is assumed to be decimal.
+    Returns the unsigned short int represented by the localized string \a s.
 
     If the conversion fails the function returns 0.
 
@@ -1077,9 +1160,9 @@ short QLocale::toShort(const QString &s, bool *ok, int base) const
     \sa toShort(), toString()
 */
 
-ushort QLocale::toUShort(const QString &s, bool *ok, int base) const
+ushort QLocale::toUShort(const QString &s, bool *ok) const
 {
-    qulonglong i = toULongLong(s, ok, base);
+    qulonglong i = toULongLong(s, ok);
     if (i > USHRT_MAX) {
         if (ok != 0)
             *ok = false;
@@ -1089,11 +1172,7 @@ ushort QLocale::toUShort(const QString &s, bool *ok, int base) const
 }
 
 /*!
-    Returns the int represented by the localized string \a s, using
-    base \a base. If \a base is 0 the base is determined automatically
-    using the following rules: If the string begins with "0x", it is
-    assumed to be hexadecimal; if it begins with "0", it is assumed to
-    be octal; otherwise it is assumed to be decimal.
+    Returns the int represented by the localized string \a s.
 
     If the conversion fails the function returns 0.
 
@@ -1105,9 +1184,9 @@ ushort QLocale::toUShort(const QString &s, bool *ok, int base) const
     \sa toUInt(), toString()
 */
 
-int QLocale::toInt(const QString &s, bool *ok, int base) const
+int QLocale::toInt(const QString &s, bool *ok) const
 {
-    qlonglong i = toLongLong(s, ok, base);
+    qlonglong i = toLongLong(s, ok);
     if (i < INT_MIN || i > INT_MAX) {
         if (ok != 0)
             *ok = false;
@@ -1117,11 +1196,7 @@ int QLocale::toInt(const QString &s, bool *ok, int base) const
 }
 
 /*!
-    Returns the unsigned int represented by the localized string \a s,
-    using base \a base. If \a base is 0 the base is determined
-    automatically using the following rules: If the string begins with
-    "0x", it is assumed to be hexadecimal; if it begins with "0", it
-    is assumed to be octal; otherwise it is assumed to be decimal.
+    Returns the unsigned int represented by the localized string \a s.
 
     If the conversion fails the function returns 0.
 
@@ -1133,9 +1208,9 @@ int QLocale::toInt(const QString &s, bool *ok, int base) const
     \sa toInt(), toString()
 */
 
-uint QLocale::toUInt(const QString &s, bool *ok, int base) const
+uint QLocale::toUInt(const QString &s, bool *ok) const
 {
-    qulonglong i = toULongLong(s, ok, base);
+    qulonglong i = toULongLong(s, ok);
     if (i > UINT_MAX) {
         if (ok != 0)
             *ok = false;
@@ -1145,11 +1220,7 @@ uint QLocale::toUInt(const QString &s, bool *ok, int base) const
 }
 
 /*!
-    Returns the long long int represented by the localized string \a
-    s, using base \a base. If \a base is 0 the base is determined
-    automatically using the following rules: If the string begins with
-    "0x", it is assumed to be hexadecimal; if it begins with "0", it
-    is assumed to be octal; otherwise it is assumed to be decimal.
+    Returns the long long int represented by the localized string \a s.
 
     If the conversion fails the function returns 0.
 
@@ -1162,25 +1233,19 @@ uint QLocale::toUInt(const QString &s, bool *ok, int base) const
 */
 
 
-qlonglong QLocale::toLongLong(const QString &s, bool *ok, int base) const
+qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
 {
     QLocalePrivate::GroupSeparatorMode mode
-        = p.numberOptions & RejectGroupSeparator
+        = d->m_numberOptions & RejectGroupSeparator
             ? QLocalePrivate::FailOnGroupSeparators
             : QLocalePrivate::ParseGroupSeparators;
 
-    return d()->stringToLongLong(s, base, ok, mode);
+    return d->stringToLongLong(s, 10, ok, mode);
 }
 
-// ### Qt5: make the return type for toULongLong() qulonglong.
-
 /*!
     Returns the unsigned long long int represented by the localized
-    string \a s, using base \a base. If \a base is 0 the base is
-    determined automatically using the following rules: If the string
-    begins with "0x", it is assumed to be hexadecimal; if it begins
-    with "0", it is assumed to be octal; otherwise it is assumed to be
-    decimal.
+    string \a s.
 
     If the conversion fails the function returns 0.
 
@@ -1192,14 +1257,14 @@ qlonglong QLocale::toLongLong(const QString &s, bool *ok, int base) const
     \sa toLongLong(), toInt(), toDouble(), toString()
 */
 
-qlonglong QLocale::toULongLong(const QString &s, bool *ok, int base) const
+qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
 {
     QLocalePrivate::GroupSeparatorMode mode
-        = p.numberOptions & RejectGroupSeparator
+        = d->m_numberOptions & RejectGroupSeparator
             ? QLocalePrivate::FailOnGroupSeparators
             : QLocalePrivate::ParseGroupSeparators;
 
-    return d()->stringToUnsLongLong(s, base, ok, mode);
+    return d->stringToUnsLongLong(s, 10, ok, mode);
 }
 
 /*!
@@ -1241,7 +1306,7 @@ float QLocale::toFloat(const QString &s, bool *ok) const
     the "C" locale if the string cannot be interpreted in this
     locale.
 
-    \snippet doc/src/snippets/code/src_corelib_tools_qlocale.cpp 3
+    \snippet code/src_corelib_tools_qlocale.cpp 3
 
     Notice that the last conversion returns 1234.0, because '.' is the
     thousands group separator in the German locale.
@@ -1254,11 +1319,11 @@ float QLocale::toFloat(const QString &s, bool *ok) const
 double QLocale::toDouble(const QString &s, bool *ok) const
 {
     QLocalePrivate::GroupSeparatorMode mode
-        = p.numberOptions & RejectGroupSeparator
+        = d->m_numberOptions & RejectGroupSeparator
             ? QLocalePrivate::FailOnGroupSeparators
             : QLocalePrivate::ParseGroupSeparators;
 
-    return d()->stringToDouble(s, ok, mode);
+    return d->stringToDouble(s, ok, mode);
 }
 
 /*!
@@ -1269,11 +1334,11 @@ double QLocale::toDouble(const QString &s, bool *ok) const
 
 QString QLocale::toString(qlonglong i) const
 {
-    int flags = p.numberOptions & OmitGroupSeparator
+    int flags = d->m_numberOptions & OmitGroupSeparator
                     ? 0
                     : QLocalePrivate::ThousandsGroup;
 
-    return d()->longLongToString(i, -1, 10, -1, flags);
+    return d->longLongToString(i, -1, 10, -1, flags);
 }
 
 /*!
@@ -1284,11 +1349,11 @@ QString QLocale::toString(qlonglong i) const
 
 QString QLocale::toString(qulonglong i) const
 {
-    int flags = p.numberOptions & OmitGroupSeparator
+    int flags = d->m_numberOptions & OmitGroupSeparator
                     ? 0
                     : QLocalePrivate::ThousandsGroup;
 
-    return d()->unsLongLongToString(i, -1, 10, -1, flags);
+    return d->unsLongLongToString(i, -1, 10, -1, flags);
 }
 
 /*!
@@ -1299,7 +1364,7 @@ QString QLocale::toString(qulonglong i) const
 
 QString QLocale::toString(const QDate &date, const QString &format) const
 {
-    return d()->dateTimeToString(format, &date, 0, this);
+    return d->dateTimeToString(format, &date, 0, this);
 }
 
 /*!
@@ -1313,7 +1378,7 @@ QString QLocale::toString(const QDate &date, FormatType format) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(format == LongFormat
                                              ? QSystemLocale::DateToStringLong : QSystemLocale::DateToStringShort,
                                              date);
@@ -1377,7 +1442,7 @@ static QString timeZone()
 */
 QString QLocale::toString(const QTime &time, const QString &format) const
 {
-    return d()->dateTimeToString(format, 0, &time, this);
+    return d->dateTimeToString(format, 0, &time, this);
 }
 
 /*!
@@ -1392,7 +1457,7 @@ QString QLocale::toString(const QDateTime &dateTime, const QString &format) cons
 {
     const QDate dt = dateTime.date();
     const QTime tm = dateTime.time();
-    return d()->dateTimeToString(format, &dt, &tm, this);
+    return d->dateTimeToString(format, &dt, &tm, this);
 }
 
 /*!
@@ -1408,7 +1473,7 @@ QString QLocale::toString(const QDateTime &dateTime, FormatType format) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(format == LongFormat
                                              ? QSystemLocale::DateTimeToStringLong
                                              : QSystemLocale::DateTimeToStringShort,
@@ -1434,7 +1499,7 @@ QString QLocale::toString(const QTime &time, FormatType format) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(format == LongFormat
                                              ? QSystemLocale::TimeToStringLong : QSystemLocale::TimeToStringShort,
                                              time);
@@ -1461,7 +1526,7 @@ QString QLocale::toString(const QTime &time, FormatType format) const
 QString QLocale::dateFormat(FormatType format) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(format == LongFormat
                                              ? QSystemLocale::DateFormatLong : QSystemLocale::DateFormatShort,
                                              QVariant());
@@ -1473,12 +1538,12 @@ QString QLocale::dateFormat(FormatType format) const
     quint32 idx, size;
     switch (format) {
     case LongFormat:
-        idx = d()->m_long_date_format_idx;
-        size = d()->m_long_date_format_size;
+        idx = d->m_data->m_long_date_format_idx;
+        size = d->m_data->m_long_date_format_size;
         break;
     default:
-        idx = d()->m_short_date_format_idx;
-        size = d()->m_short_date_format_size;
+        idx = d->m_data->m_short_date_format_idx;
+        size = d->m_data->m_short_date_format_size;
         break;
     }
     return getLocaleData(date_format_data + idx, size);
@@ -1498,7 +1563,7 @@ QString QLocale::dateFormat(FormatType format) const
 QString QLocale::timeFormat(FormatType format) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(format == LongFormat
                                              ? QSystemLocale::TimeFormatLong : QSystemLocale::TimeFormatShort,
                                              QVariant());
@@ -1510,12 +1575,12 @@ QString QLocale::timeFormat(FormatType format) const
     quint32 idx, size;
     switch (format) {
     case LongFormat:
-        idx = d()->m_long_time_format_idx;
-        size = d()->m_long_time_format_size;
+        idx = d->m_data->m_long_time_format_idx;
+        size = d->m_data->m_long_time_format_size;
         break;
     default:
-        idx = d()->m_short_time_format_idx;
-        size = d()->m_short_time_format_size;
+        idx = d->m_data->m_short_time_format_idx;
+        size = d->m_data->m_short_time_format_size;
         break;
     }
     return getLocaleData(time_format_data + idx, size);
@@ -1535,7 +1600,7 @@ QString QLocale::timeFormat(FormatType format) const
 QString QLocale::dateTimeFormat(FormatType format) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(format == LongFormat
                                              ? QSystemLocale::DateTimeFormatLong
                                              : QSystemLocale::DateTimeFormatShort,
@@ -1703,7 +1768,7 @@ QDateTime QLocale::toDateTime(const QString &string, const QString &format) cons
 */
 QChar QLocale::decimalPoint() const
 {
-    return d()->decimal();
+    return d->decimal();
 }
 
 /*!
@@ -1713,7 +1778,7 @@ QChar QLocale::decimalPoint() const
 */
 QChar QLocale::groupSeparator() const
 {
-    return d()->group();
+    return d->group();
 }
 
 /*!
@@ -1723,7 +1788,7 @@ QChar QLocale::groupSeparator() const
 */
 QChar QLocale::percent() const
 {
-    return d()->percent();
+    return d->percent();
 }
 
 /*!
@@ -1733,7 +1798,7 @@ QChar QLocale::percent() const
 */
 QChar QLocale::zeroDigit() const
 {
-    return d()->zero();
+    return d->zero();
 }
 
 /*!
@@ -1743,7 +1808,7 @@ QChar QLocale::zeroDigit() const
 */
 QChar QLocale::negativeSign() const
 {
-    return d()->minus();
+    return d->minus();
 }
 
 /*!
@@ -1753,7 +1818,7 @@ QChar QLocale::negativeSign() const
 */
 QChar QLocale::positiveSign() const
 {
-    return d()->plus();
+    return d->plus();
 }
 
 /*!
@@ -1763,7 +1828,7 @@ QChar QLocale::positiveSign() const
 */
 QChar QLocale::exponential() const
 {
-    return d()->exponential();
+    return d->exponential();
 }
 
 static bool qIsUpper(char c)
@@ -1810,9 +1875,9 @@ QString QLocale::toString(double i, char f, int prec) const
             break;
     }
 
-    if (!(p.numberOptions & OmitGroupSeparator))
+    if (!(d->m_numberOptions & OmitGroupSeparator))
         flags |= QLocalePrivate::ThousandsGroup;
-    return d()->doubleToString(i, prec, form, -1, flags);
+    return d->doubleToString(i, prec, form, -1, flags);
 }
 
 /*!
@@ -1834,9 +1899,7 @@ QString QLocale::toString(double i, char f, int prec) const
 
 QLocale QLocale::system()
 {
-    QLocale result(C);
-    result.p.index = localePrivateIndex(systemPrivate());
-    return result;
+    return QLocale(*new QLocalePrivate(localeDataIndex(systemData())));
 }
 
 
@@ -1848,6 +1911,9 @@ QLocale QLocale::system()
 
     Getting a list of all locales:
     QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
+
+    Getting a list of locales suitable for Russia:
+    QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::Russia);
 */
 QList<QLocale> QLocale::matchingLocales(QLocale::Language language,
                                         QLocale::Script script,
@@ -1857,18 +1923,21 @@ QList<QLocale> QLocale::matchingLocales(QLocale::Language language,
             uint(country) > QLocale::LastCountry)
         return QList<QLocale>();
 
+    if (language == QLocale::C)
+        return QList<QLocale>() << QLocale(QLocale::C);
+
     QList<QLocale> result;
-    const QLocalePrivate *d = locale_data;
     if (language == QLocale::AnyLanguage && script == QLocale::AnyScript && country == QLocale::AnyCountry)
         result.reserve(locale_data_size);
-    if (language != QLocale::C)
-        d += locale_index[language];
-    while ( (d != locale_data + locale_data_size)
-            && (language == QLocale::AnyLanguage || d->m_language_id == uint(language))) {
-        QLocale locale(QLocale::C);
-        locale.p.index = localePrivateIndex(d);
-        result.append(locale);
-        ++d;
+    const QLocaleData *data = locale_data + locale_index[language];
+    while ( (data != locale_data + locale_data_size)
+            && (language == QLocale::AnyLanguage || data->m_language_id == uint(language))) {
+        if ((script == QLocale::AnyScript || data->m_script_id == uint(script))
+            && (country == QLocale::AnyCountry || data->m_country_id == uint(country))) {
+            QLocale locale(*new QLocalePrivate(localeDataIndex(data)));
+            result.append(locale);
+        }
+        ++data;
     }
     return result;
 }
@@ -1877,7 +1946,7 @@ QList<QLocale> QLocale::matchingLocales(QLocale::Language language,
     \obsolete
     \since 4.3
 
-    Returns the list of countries that have entires for \a language in Qt's locale
+    Returns the list of countries that have entries for \a language in Qt's locale
     database. If the result is an empty list, then \a language is not represented in
     Qt's locale database.
 
@@ -1886,20 +1955,18 @@ QList<QLocale> QLocale::matchingLocales(QLocale::Language language,
 QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
 {
     QList<Country> result;
-
-    unsigned language_id = language;
-    uint idx = locale_index[language_id];
-
     if (language == C) {
         result << AnyCountry;
         return result;
     }
 
-    const QLocalePrivate *d = locale_data + idx;
-
-    while (d->languageId() == language_id) {
-        result << static_cast<Country>(d->countryId());
-        ++d;
+    unsigned language_id = language;
+    const QLocaleData *data = locale_data + locale_index[language_id];
+    while (data->m_language_id == language_id) {
+        const QLocale::Country country = static_cast<Country>(data->m_country_id);
+        if (!result.contains(country))
+            result.append(country);
+        ++data;
     }
 
     return result;
@@ -1919,7 +1986,7 @@ QString QLocale::monthName(int month, FormatType type) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(type == LongFormat
                                              ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort,
                                              month);
@@ -1931,16 +1998,16 @@ QString QLocale::monthName(int month, FormatType type) const
     quint32 idx, size;
     switch (type) {
     case QLocale::LongFormat:
-        idx = d()->m_long_month_names_idx;
-        size = d()->m_long_month_names_size;
+        idx = d->m_data->m_long_month_names_idx;
+        size = d->m_data->m_long_month_names_size;
         break;
     case QLocale::ShortFormat:
-        idx = d()->m_short_month_names_idx;
-        size = d()->m_short_month_names_size;
+        idx = d->m_data->m_short_month_names_idx;
+        size = d->m_data->m_short_month_names_size;
         break;
     case QLocale::NarrowFormat:
-        idx = d()->m_narrow_month_names_idx;
-        size = d()->m_narrow_month_names_size;
+        idx = d->m_data->m_narrow_month_names_idx;
+        size = d->m_data->m_narrow_month_names_size;
         break;
     default:
         return QString();
@@ -1965,7 +2032,7 @@ QString QLocale::standaloneMonthName(int month, FormatType type) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(type == LongFormat
                                              ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort,
                                              month);
@@ -1977,21 +2044,21 @@ QString QLocale::standaloneMonthName(int month, FormatType type) const
     quint32 idx, size;
     switch (type) {
     case QLocale::LongFormat:
-        idx = d()->m_standalone_long_month_names_idx;
-        size = d()->m_standalone_long_month_names_size;
+        idx = d->m_data->m_standalone_long_month_names_idx;
+        size = d->m_data->m_standalone_long_month_names_size;
         break;
     case QLocale::ShortFormat:
-        idx = d()->m_standalone_short_month_names_idx;
-        size = d()->m_standalone_short_month_names_size;
+        idx = d->m_data->m_standalone_short_month_names_idx;
+        size = d->m_data->m_standalone_short_month_names_size;
         break;
     case QLocale::NarrowFormat:
-        idx = d()->m_standalone_narrow_month_names_idx;
-        size = d()->m_standalone_narrow_month_names_size;
+        idx = d->m_data->m_standalone_narrow_month_names_idx;
+        size = d->m_data->m_standalone_narrow_month_names_size;
         break;
     default:
         return QString();
     }
-    QString name = getLocaleListData(standalone_months_data + idx, size, month - 1);
+    QString name = getLocaleListData(months_data + idx, size, month - 1);
     if (name.isEmpty())
         return monthName(month, type);
     return name;
@@ -2012,7 +2079,7 @@ QString QLocale::dayName(int day, FormatType type) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(type == LongFormat
                                              ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort,
                                              day);
@@ -2026,16 +2093,16 @@ QString QLocale::dayName(int day, FormatType type) const
     quint32 idx, size;
     switch (type) {
     case QLocale::LongFormat:
-        idx = d()->m_long_day_names_idx;
-        size = d()->m_long_day_names_size;
+        idx = d->m_data->m_long_day_names_idx;
+        size = d->m_data->m_long_day_names_size;
         break;
     case QLocale::ShortFormat:
-        idx = d()->m_short_day_names_idx;
-        size = d()->m_short_day_names_size;
+        idx = d->m_data->m_short_day_names_idx;
+        size = d->m_data->m_short_day_names_size;
         break;
     case QLocale::NarrowFormat:
-        idx = d()->m_narrow_day_names_idx;
-        size = d()->m_narrow_day_names_size;
+        idx = d->m_data->m_narrow_day_names_idx;
+        size = d->m_data->m_narrow_day_names_size;
         break;
     default:
         return QString();
@@ -2061,7 +2128,7 @@ QString QLocale::standaloneDayName(int day, FormatType type) const
         return QString();
 
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(type == LongFormat
                                              ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort,
                                              day);
@@ -2075,16 +2142,16 @@ QString QLocale::standaloneDayName(int day, FormatType type) const
     quint32 idx, size;
     switch (type) {
     case QLocale::LongFormat:
-        idx = d()->m_standalone_long_day_names_idx;
-        size = d()->m_standalone_long_day_names_size;
+        idx = d->m_data->m_standalone_long_day_names_idx;
+        size = d->m_data->m_standalone_long_day_names_size;
         break;
     case QLocale::ShortFormat:
-        idx = d()->m_standalone_short_day_names_idx;
-        size = d()->m_standalone_short_day_names_size;
+        idx = d->m_data->m_standalone_short_day_names_idx;
+        size = d->m_data->m_standalone_short_day_names_size;
         break;
     case QLocale::NarrowFormat:
-        idx = d()->m_standalone_narrow_day_names_idx;
-        size = d()->m_standalone_narrow_day_names_size;
+        idx = d->m_data->m_standalone_narrow_day_names_idx;
+        size = d->m_data->m_standalone_narrow_day_names_size;
         break;
     default:
         return QString();
@@ -2103,21 +2170,21 @@ QString QLocale::standaloneDayName(int day, FormatType type) const
 Qt::DayOfWeek QLocale::firstDayOfWeek() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::FirstDayOfWeek, QVariant());
         if (!res.isNull())
             return static_cast<Qt::DayOfWeek>(res.toUInt());
     }
 #endif
-    return static_cast<Qt::DayOfWeek>(d()->m_first_day_of_week);
+    return static_cast<Qt::DayOfWeek>(d->m_data->m_first_day_of_week);
 }
 
 QLocale::MeasurementSystem QLocalePrivate::measurementSystem() const
 {
     for (int i = 0; i < ImperialMeasurementSystemsCount; ++i) {
-        if (ImperialMeasurementSystems[i].languageId == m_language_id
-            && ImperialMeasurementSystems[i].countryId == m_country_id) {
-            return QLocale::ImperialSystem;
+        if (ImperialMeasurementSystems[i].languageId == m_data->m_language_id
+            && ImperialMeasurementSystems[i].countryId == m_data->m_country_id) {
+            return ImperialMeasurementSystems[i].system;
         }
     }
     return QLocale::MetricSystem;
@@ -2131,15 +2198,15 @@ QLocale::MeasurementSystem QLocalePrivate::measurementSystem() const
 QList<Qt::DayOfWeek> QLocale::weekdays() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::Weekdays, QVariant());
         if (!res.isNull())
             return static_cast<QList<Qt::DayOfWeek> >(res.value<QList<Qt::DayOfWeek> >());
     }
 #endif
     QList<Qt::DayOfWeek> weekdays;
-    quint16 weekendStart = d()->m_weekend_start;
-    quint16 weekendEnd = d()->m_weekend_end;
+    quint16 weekendStart = d->m_data->m_weekend_start;
+    quint16 weekendEnd = d->m_data->m_weekend_end;
     for (int day = Qt::Monday; day <= Qt::Sunday; day++) {
         if ((weekendEnd >= weekendStart && (day < weekendStart || day > weekendEnd)) ||
             (weekendEnd < weekendStart && (day > weekendEnd && day < weekendStart)))
@@ -2156,14 +2223,14 @@ QList<Qt::DayOfWeek> QLocale::weekdays() const
 QLocale::MeasurementSystem QLocale::measurementSystem() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::MeasurementSystem, QVariant());
         if (!res.isNull())
             return MeasurementSystem(res.toInt());
     }
 #endif
 
-    return d()->measurementSystem();
+    return d->measurementSystem();
 }
 
 /*!
@@ -2173,14 +2240,23 @@ QLocale::MeasurementSystem QLocale::measurementSystem() const
 */
 Qt::LayoutDirection QLocale::textDirection() const
 {
-    Language lang = language();
-    if (lang == QLocale::Arabic ||
-        lang == QLocale::Hebrew ||
-        lang == QLocale::Persian ||
-        lang == QLocale::Urdu ||
-        lang == QLocale::Syriac)
+    switch (language()) {
+    case QLocale::Arabic:
+    case QLocale::Hebrew:
+    case QLocale::Persian:
+    case QLocale::Pashto:
+    case QLocale::Urdu:
+    case QLocale::Syriac:
+    case QLocale::Divehi:
         return Qt::RightToLeft;
-
+    case QLocale::Punjabi:
+    case QLocale::Uzbek:
+        if (script() == QLocale::ArabicScript)
+            return Qt::RightToLeft;
+        // fall through
+    default:
+        break;
+    }
     return Qt::LeftToRight;
 }
 
@@ -2192,12 +2268,11 @@ Qt::LayoutDirection QLocale::textDirection() const
 QString QLocale::toUpper(const QString &str) const
 {
 #ifdef QT_USE_ICU
-    {
-        QString result;
-        if (qt_u_strToUpper(str, &result, *this))
-            return result;
-        // else fall through and use Qt's toUpper
-    }
+    bool ok = true;
+    QString result = QIcu::toUpper(d->m_localeID, str, &ok);
+    if (ok)
+        return result;
+    // else fall through and use Qt's toUpper
 #endif
     return str.toUpper();
 }
@@ -2210,12 +2285,11 @@ QString QLocale::toUpper(const QString &str) const
 QString QLocale::toLower(const QString &str) const
 {
 #ifdef QT_USE_ICU
-    {
-        QString result;
-        if (qt_u_strToLower(str, &result, *this))
-            return result;
-        // else fall through and use Qt's toUpper
-    }
+    bool ok = true;
+    QString result = QIcu::toLower(d->m_localeID, str, &ok);
+    if (ok)
+        return result;
+    // else fall through and use Qt's toUpper
 #endif
     return str.toLower();
 }
@@ -2232,13 +2306,13 @@ QString QLocale::toLower(const QString &str) const
 QString QLocale::amText() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::AMText, QVariant());
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    return getLocaleData(am_data + d()->m_am_idx, d()->m_am_size);
+    return getLocaleData(am_data + d->m_data->m_am_idx, d->m_data->m_am_size);
 }
 
 /*!
@@ -2252,13 +2326,13 @@ QString QLocale::amText() const
 QString QLocale::pmText() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::PMText, QVariant());
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    return getLocaleData(pm_data + d()->m_pm_idx, d()->m_pm_size);
+    return getLocaleData(pm_data + d->m_data->m_pm_idx, d->m_data->m_pm_size);
 }
 
 
@@ -2309,7 +2383,7 @@ QString QLocalePrivate::dateTimeToString(const QString &format, const QDate *dat
 
                 switch (repeat) {
                 case 4:
-                    result.append(longLongToString(date->year()));
+                    result.append(longLongToString(date->year(), -1, 10, 4, QLocalePrivate::ZeroPadded));
                     break;
                 case 2:
                     result.append(longLongToString(date->year() % 100, -1, 10, 2,
@@ -2833,7 +2907,7 @@ bool QLocalePrivate::numberToCLocale(const QString &num,
         return false;
 
     while (idx < l) {
-        const QChar &in = uc[idx];
+        const QChar in = uc[idx];
 
         char out = digitToCLocale(in);
         if (out == 0) {
@@ -3137,7 +3211,7 @@ qulonglong QLocalePrivate::bytearrayToUnsLongLong(const char *num, int base, boo
 QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::CurrencySymbol, format);
         if (!res.isNull())
             return res.toString();
@@ -3146,20 +3220,20 @@ QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
     quint32 idx, size;
     switch (format) {
     case CurrencySymbol:
-        idx = d()->m_currency_symbol_idx;
-        size = d()->m_currency_symbol_size;
+        idx = d->m_data->m_currency_symbol_idx;
+        size = d->m_data->m_currency_symbol_size;
         return getLocaleData(currency_symbol_data + idx, size);
     case CurrencyDisplayName:
-        idx = d()->m_currency_display_name_idx;
-        size = d()->m_currency_display_name_size;
+        idx = d->m_data->m_currency_display_name_idx;
+        size = d->m_data->m_currency_display_name_size;
         return getLocaleListData(currency_display_name_data + idx, size, 0);
     case CurrencyIsoCode: {
         int len = 0;
-        const QLocalePrivate *d = this->d();
+        const QLocaleData *data = this->d->m_data;
         for (; len < 3; ++len)
-            if (!d->m_currency_iso_code[len])
+            if (!data->m_currency_iso_code[len])
                 break;
-        return len ? QString::fromLatin1(d->m_currency_iso_code, len) : QString();
+        return len ? QString::fromLatin1(data->m_currency_iso_code, len) : QString();
     }
     }
     return QString();
@@ -3176,22 +3250,22 @@ QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
 QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QSystemLocale::CurrencyToStringArgument arg(value, symbol);
         QVariant res = systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg));
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    const QLocalePrivate *d = this->d();
-    quint8 idx = d->m_currency_format_idx;
-    quint8 size = d->m_currency_format_size;
-    if (d->m_currency_negative_format_size && value < 0) {
-        idx = d->m_currency_negative_format_idx;
-        size = d->m_currency_negative_format_size;
+    const QLocalePrivate *d = this->d;
+    quint8 idx = d->m_data->m_currency_format_idx;
+    quint8 size = d->m_data->m_currency_format_size;
+    if (d->m_data->m_currency_negative_format_size && value < 0) {
+        idx = d->m_data->m_currency_negative_format_idx;
+        size = d->m_data->m_currency_negative_format_size;
         value = -value;
     }
-    QString str = d->longLongToString(value);
+    QString str = toString(value);
     QString sym = symbol.isNull() ? currencySymbol() : symbol;
     if (sym.isEmpty())
         sym = currencySymbol(QLocale::CurrencyIsoCode);
@@ -3206,17 +3280,17 @@ QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
 QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QSystemLocale::CurrencyToStringArgument arg(value, symbol);
         QVariant res = systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg));
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    const QLocalePrivate *d = this->d();
-    quint8 idx = d->m_currency_format_idx;
-    quint8 size = d->m_currency_format_size;
-    QString str = d->unsLongLongToString(value);
+    const QLocaleData *data = this->d->m_data;
+    quint8 idx = data->m_currency_format_idx;
+    quint8 size = data->m_currency_format_size;
+    QString str = toString(value);
     QString sym = symbol.isNull() ? currencySymbol() : symbol;
     if (sym.isEmpty())
         sym = currencySymbol(QLocale::CurrencyIsoCode);
@@ -3231,23 +3305,22 @@ QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
 QString QLocale::toCurrencyString(double value, const QString &symbol) const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QSystemLocale::CurrencyToStringArgument arg(value, symbol);
         QVariant res = systemLocale()->query(QSystemLocale::CurrencyToString, QVariant::fromValue(arg));
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    const QLocalePrivate *d = this->d();
-    quint8 idx = d->m_currency_format_idx;
-    quint8 size = d->m_currency_format_size;
-    if (d->m_currency_negative_format_size && value < 0) {
-        idx = d->m_currency_negative_format_idx;
-        size = d->m_currency_negative_format_size;
+    const QLocaleData *data = this->d->m_data;
+    quint8 idx = data->m_currency_format_idx;
+    quint8 size = data->m_currency_format_size;
+    if (data->m_currency_negative_format_size && value < 0) {
+        idx = data->m_currency_negative_format_idx;
+        size = data->m_currency_negative_format_size;
         value = -value;
     }
-    QString str = d->doubleToString(value, d->m_currency_digits,
-                                    QLocalePrivate::DFDecimal);
+    QString str = toString(value, 'f', d->m_data->m_currency_digits);
     QString sym = symbol.isNull() ? currencySymbol() : symbol;
     if (sym.isEmpty())
         sym = currencySymbol(QLocale::CurrencyIsoCode);
@@ -3259,7 +3332,7 @@ QString QLocale::toCurrencyString(double value, const QString &symbol) const
     \since 4.8
 
     Returns an ordered list of locale names for translation purposes in
-    preference order.
+    preference order (like "en", "en-US", "en-Latn-US").
 
     The return value represents locale names that the user expects to see the
     UI translation in.
@@ -3274,7 +3347,7 @@ QString QLocale::toCurrencyString(double value, const QString &symbol) const
 QStringList QLocale::uiLanguages() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::UILanguages, QVariant());
         if (!res.isNull()) {
             QStringList result = res.toStringList();
@@ -3283,7 +3356,20 @@ QStringList QLocale::uiLanguages() const
         }
     }
 #endif
-    return QStringList(bcp47Name());
+    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(min.bcp47Name());
+    if (id.script_id) {
+        id.script_id = 0;
+        if (id != min && id.withLikelySubtagsAdded() == max)
+            uiLanguages.append(id.bcp47Name());
+    }
+    if (max != min && max != id)
+        uiLanguages.append(max.bcp47Name());
+    return uiLanguages;
 }
 
 /*!
@@ -3297,13 +3383,13 @@ QStringList QLocale::uiLanguages() const
 QString QLocale::nativeLanguageName() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::NativeLanguageName, QVariant());
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    return getLocaleData(endonyms_data + d()->m_language_endonym_idx, d()->m_language_endonym_size);
+    return getLocaleData(endonyms_data + d->m_data->m_language_endonym_idx, d->m_data->m_language_endonym_size);
 }
 
 /*!
@@ -3317,13 +3403,13 @@ QString QLocale::nativeLanguageName() const
 QString QLocale::nativeCountryName() const
 {
 #ifndef QT_NO_SYSTEMLOCALE
-    if (d() == systemPrivate()) {
+    if (d->m_data == systemData()) {
         QVariant res = systemLocale()->query(QSystemLocale::NativeCountryName, QVariant());
         if (!res.isNull())
             return res.toString();
     }
 #endif
-    return getLocaleData(endonyms_data + d()->m_country_endonym_idx, d()->m_country_endonym_size);
+    return getLocaleData(endonyms_data + d->m_data->m_country_endonym_idx, d->m_data->m_country_endonym_size);
 }
 
 #ifndef QT_NO_DEBUG_STREAM