summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qlocale_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qlocale_win.cpp')
-rw-r--r--src/corelib/tools/qlocale_win.cpp988
1 files changed, 988 insertions, 0 deletions
diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp
new file mode 100644
index 0000000000..4a215614d2
--- /dev/null
+++ b/src/corelib/tools/qlocale_win.cpp
@@ -0,0 +1,988 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlocale_p.h"
+#include "qlocale_tools_p.h"
+
+#include "qstringlist.h"
+#include "qvariant.h"
+#include "qdatetime.h"
+
+#include "private/qsystemlibrary_p.h"
+
+#include "qdebug.h"
+
+#if defined(Q_OS_WIN)
+# include "qt_windows.h"
+# include <time.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT);
+static const char *winLangCodeToIsoName(int code);
+static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT);
+static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT);
+
+#ifndef QT_NO_SYSTEMLOCALE
+
+#ifndef MUI_LANGUAGE_NAME
+#define MUI_LANGUAGE_NAME 0x8
+#endif
+#ifndef LOCALE_SSHORTESTDAYNAME1
+# define LOCALE_SSHORTESTDAYNAME1 0x0060
+# define LOCALE_SSHORTESTDAYNAME2 0x0061
+# define LOCALE_SSHORTESTDAYNAME3 0x0062
+# define LOCALE_SSHORTESTDAYNAME4 0x0063
+# define LOCALE_SSHORTESTDAYNAME5 0x0064
+# define LOCALE_SSHORTESTDAYNAME6 0x0065
+# define LOCALE_SSHORTESTDAYNAME7 0x0066
+#endif
+#ifndef LOCALE_SNATIVELANGUAGENAME
+# define LOCALE_SNATIVELANGUAGENAME 0x00000004
+#endif
+#ifndef LOCALE_SNATIVECOUNTRYNAME
+# define LOCALE_SNATIVECOUNTRYNAME 0x00000008
+#endif
+
+struct QSystemLocalePrivate
+{
+ QSystemLocalePrivate();
+
+ QChar zeroDigit();
+ QChar decimalPoint();
+ QChar groupSeparator();
+ QChar negativeSign();
+ QChar positiveSign();
+ QVariant dateFormat(QLocale::FormatType);
+ QVariant timeFormat(QLocale::FormatType);
+ QVariant dateTimeFormat(QLocale::FormatType);
+ QVariant dayName(int, QLocale::FormatType);
+ QVariant monthName(int, QLocale::FormatType);
+ QVariant toString(const QDate &, QLocale::FormatType);
+ QVariant toString(const QTime &, QLocale::FormatType);
+ QVariant toString(const QDateTime &, QLocale::FormatType);
+ QVariant measurementSystem();
+ QVariant amText();
+ QVariant pmText();
+ QVariant firstDayOfWeek();
+ QVariant currencySymbol(QLocale::CurrencySymbolFormat);
+ QVariant toCurrencyString(const QSystemLocale::CurrencyToStringArgument &);
+ QVariant uiLanguages();
+ QVariant nativeLanguageName();
+ QVariant nativeCountryName();
+
+ void update();
+
+private:
+ QByteArray langEnvVar;
+
+ enum SubstitutionType {
+ SUnknown,
+ SContext,
+ SAlways,
+ SNever
+ };
+
+ // cached values:
+ LCID lcid;
+ SubstitutionType substitutionType;
+ QChar zero;
+
+ QString getLocaleInfo(LCTYPE type, int maxlen = 0);
+ int getLocaleInfo_int(LCTYPE type, int maxlen = 0);
+ QChar getLocaleInfo_qchar(LCTYPE type);
+
+ SubstitutionType substitution();
+ QString &substituteDigits(QString &string);
+
+ static QString winToQtFormat(const QString &sys_fmt);
+
+};
+Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate)
+
+QSystemLocalePrivate::QSystemLocalePrivate()
+ : substitutionType(SUnknown)
+{
+ langEnvVar = qgetenv("LANG");
+ lcid = GetUserDefaultLCID();
+}
+
+QString QSystemLocalePrivate::getLocaleInfo(LCTYPE type, int maxlen)
+{
+ QVarLengthArray<wchar_t, 64> buf(maxlen ? maxlen : 64);
+ if (!GetLocaleInfo(lcid, type, buf.data(), buf.size()))
+ return QString();
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ int cnt = GetLocaleInfo(lcid, type, 0, 0);
+ if (cnt == 0)
+ return QString();
+ buf.resize(cnt);
+ if (!GetLocaleInfo(lcid, type, buf.data(), buf.size()))
+ return QString();
+ }
+ return QString::fromWCharArray(buf.data());
+}
+
+int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type, int maxlen)
+{
+ QString str = getLocaleInfo(type, maxlen);
+ bool ok = false;
+ int v = str.toInt(&ok);
+ return ok ? v : 0;
+}
+
+QChar QSystemLocalePrivate::getLocaleInfo_qchar(LCTYPE type)
+{
+ QString str = getLocaleInfo(type);
+ return str.isEmpty() ? QChar() : str.at(0);
+}
+
+QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
+{
+ if (substitutionType == SUnknown) {
+ wchar_t buf[8];
+ if (!GetLocaleInfo(lcid, LOCALE_IDIGITSUBSTITUTION, buf, 8)) {
+ substitutionType = QSystemLocalePrivate::SNever;
+ return substitutionType;
+ }
+ if (buf[0] == '1')
+ substitutionType = QSystemLocalePrivate::SNever;
+ else if (buf[0] == '0')
+ substitutionType = QSystemLocalePrivate::SContext;
+ else if (buf[0] == '2')
+ substitutionType = QSystemLocalePrivate::SAlways;
+ else {
+ wchar_t digits[11];
+ if (!GetLocaleInfo(lcid, LOCALE_SNATIVEDIGITS, digits, 11)) {
+ substitutionType = QSystemLocalePrivate::SNever;
+ return substitutionType;
+ }
+ const wchar_t zero = digits[0];
+ if (buf[0] == zero + 2)
+ substitutionType = QSystemLocalePrivate::SAlways;
+ else
+ substitutionType = QSystemLocalePrivate::SNever;
+ }
+ }
+ return substitutionType;
+}
+
+QString &QSystemLocalePrivate::substituteDigits(QString &string)
+{
+ ushort zero = zeroDigit().unicode();
+ ushort *qch = (ushort *)string.data();
+ for (ushort *end = qch + string.size(); qch != end; ++qch) {
+ if (*qch >= '0' && *qch <= '9')
+ *qch = zero + (*qch - '0');
+ }
+ return string;
+}
+
+QChar QSystemLocalePrivate::zeroDigit()
+{
+ if (zero.isNull())
+ zero = getLocaleInfo_qchar(LOCALE_SNATIVEDIGITS);
+ return zero;
+}
+
+QChar QSystemLocalePrivate::decimalPoint()
+{
+ return getLocaleInfo_qchar(LOCALE_SDECIMAL);
+}
+
+QChar QSystemLocalePrivate::groupSeparator()
+{
+ return getLocaleInfo_qchar(LOCALE_STHOUSAND);
+}
+
+QChar QSystemLocalePrivate::negativeSign()
+{
+ return getLocaleInfo_qchar(LOCALE_SNEGATIVESIGN);
+}
+
+QChar QSystemLocalePrivate::positiveSign()
+{
+ return getLocaleInfo_qchar(LOCALE_SPOSITIVESIGN);
+}
+
+QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type)
+{
+ switch (type) {
+ case QLocale::ShortFormat:
+ return winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE));
+ case QLocale::LongFormat:
+ return winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE));
+ case QLocale::NarrowFormat:
+ break;
+ }
+ return QVariant();
+}
+
+QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type)
+{
+ switch (type) {
+ case QLocale::ShortFormat:
+ return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT)); //###
+ case QLocale::LongFormat:
+ return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT));
+ case QLocale::NarrowFormat:
+ break;
+ }
+ return QVariant();
+}
+
+QVariant QSystemLocalePrivate::dateTimeFormat(QLocale::FormatType type)
+{
+ return QString(dateFormat(type).toString() + QLatin1Char(' ') + timeFormat(type).toString());
+}
+
+QVariant QSystemLocalePrivate::dayName(int day, QLocale::FormatType type)
+{
+ static const LCTYPE short_day_map[]
+ = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
+ LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
+ LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 };
+
+ static const LCTYPE long_day_map[]
+ = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2,
+ LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5,
+ LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 };
+
+ static const LCTYPE narrow_day_map[]
+ = { LOCALE_SSHORTESTDAYNAME1, LOCALE_SSHORTESTDAYNAME2,
+ LOCALE_SSHORTESTDAYNAME3, LOCALE_SSHORTESTDAYNAME4,
+ LOCALE_SSHORTESTDAYNAME5, LOCALE_SSHORTESTDAYNAME6,
+ LOCALE_SSHORTESTDAYNAME7 };
+
+ day -= 1;
+
+ if (type == QLocale::LongFormat)
+ return getLocaleInfo(long_day_map[day]);
+ else if (type == QLocale::NarrowFormat && QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
+ return getLocaleInfo(narrow_day_map[day]);
+ return getLocaleInfo(short_day_map[day]);
+}
+
+QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type)
+{
+ static const LCTYPE short_month_map[]
+ = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
+ LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
+ LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
+ LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
+
+ static const LCTYPE long_month_map[]
+ = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
+ LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
+ LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
+ LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 };
+
+ month -= 1;
+ if (month < 0 || month > 11)
+ return QString();
+
+ LCTYPE lctype = (type == QLocale::ShortFormat || type == QLocale::NarrowFormat)
+ ? short_month_map[month] : long_month_map[month];
+ return getLocaleInfo(lctype);
+}
+
+QVariant QSystemLocalePrivate::toString(const QDate &date, QLocale::FormatType type)
+{
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ st.wYear = date.year();
+ st.wMonth = date.month();
+ st.wDay = date.day();
+
+ DWORD flags = (type == QLocale::LongFormat ? DATE_LONGDATE : DATE_SHORTDATE);
+ wchar_t buf[255];
+ if (GetDateFormat(lcid, flags, &st, NULL, buf, 255)) {
+ QString format = QString::fromWCharArray(buf);
+ if (substitution() == SAlways)
+ substituteDigits(format);
+ return format;
+ }
+ return QString();
+}
+
+QVariant QSystemLocalePrivate::toString(const QTime &time, QLocale::FormatType)
+{
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ st.wHour = time.hour();
+ st.wMinute = time.minute();
+ st.wSecond = time.second();
+ st.wMilliseconds = 0;
+
+ DWORD flags = 0;
+
+ wchar_t buf[255];
+ if (GetTimeFormat(lcid, flags, &st, NULL, buf, 255)) {
+ QString format = QString::fromWCharArray(buf);
+ if (substitution() == SAlways)
+ substituteDigits(format);
+ return format;
+ }
+ return QString();
+}
+
+QVariant QSystemLocalePrivate::toString(const QDateTime &dt, QLocale::FormatType type)
+{
+ return QString(toString(dt.date(), type).toString() + QLatin1Char(' ') + toString(dt.time(), type).toString());
+}
+
+QVariant QSystemLocalePrivate::measurementSystem()
+{
+ wchar_t output[2];
+
+ if (GetLocaleInfo(lcid, LOCALE_IMEASURE, output, 2)) {
+ QString iMeasure = QString::fromWCharArray(output);
+ if (iMeasure == QLatin1String("1")) {
+ return QLocale::ImperialSystem;
+ }
+ }
+
+ return QLocale::MetricSystem;
+}
+
+QVariant QSystemLocalePrivate::amText()
+{
+ wchar_t output[15]; // maximum length including terminating zero character for Win2003+
+
+ if (GetLocaleInfo(lcid, LOCALE_S1159, output, 15)) {
+ return QString::fromWCharArray(output);
+ }
+
+ return QVariant();
+}
+
+QVariant QSystemLocalePrivate::pmText()
+{
+ wchar_t output[15]; // maximum length including terminating zero character for Win2003+
+
+ if (GetLocaleInfo(lcid, LOCALE_S2359, output, 15)) {
+ return QString::fromWCharArray(output);
+ }
+
+ return QVariant();
+}
+
+QVariant QSystemLocalePrivate::firstDayOfWeek()
+{
+ wchar_t output[4]; // maximum length including terminating zero character for Win2003+
+
+ if (GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, output, 4))
+ return QString::fromWCharArray(output).toUInt()+1;
+
+ return 1;
+}
+
+QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat format)
+{
+ wchar_t buf[13];
+ switch (format) {
+ case QLocale::CurrencySymbol:
+ if (GetLocaleInfo(lcid, LOCALE_SCURRENCY, buf, 13))
+ return QString::fromWCharArray(buf);
+ break;
+ case QLocale::CurrencyIsoCode:
+ if (GetLocaleInfo(lcid, LOCALE_SINTLSYMBOL, buf, 9))
+ return QString::fromWCharArray(buf);
+ break;
+ case QLocale::CurrencyDisplayName: {
+ QVarLengthArray<wchar_t, 64> buf(64);
+ if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ break;
+ buf.resize(255); // should be large enough, right?
+ if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size()))
+ break;
+ }
+ return QString::fromWCharArray(buf.data());
+ }
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+QVariant QSystemLocalePrivate::toCurrencyString(const QSystemLocale::CurrencyToStringArgument &arg)
+{
+ QString value;
+ switch (arg.value.type()) {
+ case QVariant::Int:
+ value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
+ arg.value.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::UInt:
+ value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
+ arg.value.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::Double:
+ value = QLocalePrivate::doubleToString(QLatin1Char('0'), QLatin1Char('+'), QLatin1Char('-'),
+ QLatin1Char(' '), QLatin1Char(','), QLatin1Char('.'),
+ arg.value.toDouble(), -1, QLocalePrivate::DFDecimal, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::LongLong:
+ value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
+ arg.value.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::ULongLong:
+ value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
+ arg.value.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ default:
+ return QVariant();
+ }
+
+ QVarLengthArray<wchar_t, 64> out(64);
+
+ QString decimalSep;
+ QString thousandSep;
+ CURRENCYFMT format;
+ CURRENCYFMT *pformat = NULL;
+ if (!arg.symbol.isEmpty()) {
+ format.NumDigits = getLocaleInfo_int(lcid, LOCALE_ICURRDIGITS);
+ format.LeadingZero = getLocaleInfo_int(lcid, LOCALE_ILZERO);
+ decimalSep = getLocaleInfo(lcid, LOCALE_SMONDECIMALSEP);
+ format.lpDecimalSep = (wchar_t *)decimalSep.utf16();
+ thousandSep = getLocaleInfo(lcid, LOCALE_SMONTHOUSANDSEP);
+ format.lpThousandSep = (wchar_t *)thousandSep.utf16();
+ format.NegativeOrder = getLocaleInfo_int(lcid, LOCALE_INEGCURR);
+ format.PositiveOrder = getLocaleInfo_int(lcid, LOCALE_ICURRENCY);
+ format.lpCurrencySymbol = (wchar_t *)arg.symbol.utf16();
+
+ // grouping is complicated and ugly:
+ // int(0) == "123456789.00" == string("0")
+ // int(3) == "123,456,789.00" == string("3;0")
+ // int(30) == "123456,789.00" == string("3;0;0")
+ // int(32) == "12,34,56,789.00" == string("3;2;0")
+ // int(320)== "1234,56,789.00" == string("3;2")
+ QString groupingStr = getLocaleInfo(lcid, LOCALE_SMONGROUPING);
+ format.Grouping = groupingStr.remove(QLatin1Char(';')).toInt();
+ if (format.Grouping % 10 == 0) // magic
+ format.Grouping /= 10;
+ else
+ format.Grouping *= 10;
+ pformat = &format;
+ }
+
+ int ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
+ pformat, out.data(), out.size());
+ if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
+ pformat, out.data(), 0);
+ out.resize(ret);
+ ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
+ pformat, out.data(), out.size());
+ }
+
+ value = QString::fromWCharArray(out.data());
+ if (substitution() == SAlways)
+ substituteDigits( value);
+ return value;
+}
+
+QVariant QSystemLocalePrivate::uiLanguages()
+{
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) {
+ typedef BOOL (*GetUserPreferredUILanguagesFunc) (
+ DWORD dwFlags,
+ PULONG pulNumLanguages,
+ PWSTR pwszLanguagesBuffer,
+ PULONG pcchLanguagesBuffer);
+ static GetUserPreferredUILanguagesFunc GetUserPreferredUILanguages_ptr = 0;
+ if (!GetUserPreferredUILanguages_ptr) {
+ QSystemLibrary lib(QLatin1String("kernel32"));
+ if (lib.load())
+ GetUserPreferredUILanguages_ptr = (GetUserPreferredUILanguagesFunc)lib.resolve("GetUserPreferredUILanguages");
+ }
+ if (GetUserPreferredUILanguages_ptr) {
+ unsigned long cnt = 0;
+ QVarLengthArray<wchar_t, 64> buf(64);
+ unsigned long size = buf.size();
+ if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) {
+ size = 0;
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
+ GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) {
+ buf.resize(size);
+ if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size))
+ return QStringList();
+ }
+ }
+ QStringList result;
+ result.reserve(cnt);
+ const wchar_t *str = buf.constData();
+ for (; cnt > 0; --cnt) {
+ QString s = QString::fromWCharArray(str);
+ if (s.isEmpty())
+ break; // something is wrong
+ result.append(s);
+ str += s.size()+1;
+ }
+ return result;
+ }
+ }
+
+ // old Windows before Vista
+ return QStringList(QString::fromLatin1(winLangCodeToIsoName(GetUserDefaultUILanguage())));
+}
+
+QVariant QSystemLocalePrivate::nativeLanguageName()
+{
+ if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
+ return getLocaleInfo(LOCALE_SNATIVELANGNAME);
+ return getLocaleInfo(LOCALE_SNATIVELANGUAGENAME);
+}
+
+QVariant QSystemLocalePrivate::nativeCountryName()
+{
+ if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
+ return getLocaleInfo(LOCALE_SNATIVECTRYNAME);
+ return getLocaleInfo(LOCALE_SNATIVECOUNTRYNAME);
+}
+
+
+void QSystemLocalePrivate::update()
+{
+ lcid = GetUserDefaultLCID();
+ substitutionType = SUnknown;
+ zero = QChar();
+}
+
+QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
+{
+ QString result;
+ int i = 0;
+
+ while (i < sys_fmt.size()) {
+ if (sys_fmt.at(i).unicode() == QLatin1Char('\'')) {
+ QString text = qt_readEscapedFormatString(sys_fmt, &i);
+ if (text == QLatin1String("'"))
+ result += QLatin1String("''");
+ else
+ result += QString(QLatin1Char('\'') + text + QLatin1Char('\''));
+ continue;
+ }
+
+ QChar c = sys_fmt.at(i);
+ int repeat = qt_repeatCount(sys_fmt, i);
+
+ switch (c.unicode()) {
+ // Date
+ case 'y':
+ if (repeat > 5)
+ repeat = 5;
+ else if (repeat == 3)
+ repeat = 2;
+ switch (repeat) {
+ case 1:
+ result += QLatin1String("yy"); // "y" unsupported by Qt, use "yy"
+ break;
+ case 5:
+ result += QLatin1String("yyyy"); // "yyyyy" same as "yyyy" on Windows
+ break;
+ default:
+ result += QString(repeat, QLatin1Char('y'));
+ break;
+ }
+ break;
+ case 'g':
+ if (repeat > 2)
+ repeat = 2;
+ switch (repeat) {
+ case 2:
+ break; // no equivalent of "gg" in Qt
+ default:
+ result += QLatin1Char('g');
+ break;
+ }
+ break;
+ case 't':
+ if (repeat > 2)
+ repeat = 2;
+ result += QLatin1String("AP"); // "t" unsupported, use "AP"
+ break;
+ default:
+ result += QString(repeat, c);
+ break;
+ }
+
+ i += repeat;
+ }
+
+ return result;
+}
+
+QLocale QSystemLocale::fallbackLocale() const
+{
+ return QLocale(QString::fromLatin1(getWinLocaleName()));
+}
+
+QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
+{
+ QSystemLocalePrivate *d = systemLocalePrivate();
+ switch(type) {
+ case DecimalPoint:
+ return d->decimalPoint();
+ case GroupSeparator:
+ return d->groupSeparator();
+ case NegativeSign:
+ return d->negativeSign();
+ case PositiveSign:
+ return d->positiveSign();
+ case DateFormatLong:
+ return d->dateFormat(QLocale::LongFormat);
+ case DateFormatShort:
+ return d->dateFormat(QLocale::ShortFormat);
+ case TimeFormatLong:
+ return d->timeFormat(QLocale::LongFormat);
+ case TimeFormatShort:
+ return d->timeFormat(QLocale::ShortFormat);
+ case DateTimeFormatLong:
+ return d->dateTimeFormat(QLocale::LongFormat);
+ case DateTimeFormatShort:
+ return d->dateTimeFormat(QLocale::ShortFormat);
+ case DayNameLong:
+ return d->dayName(in.toInt(), QLocale::LongFormat);
+ case DayNameShort:
+ return d->dayName(in.toInt(), QLocale::ShortFormat);
+ case MonthNameLong:
+ return d->monthName(in.toInt(), QLocale::LongFormat);
+ case MonthNameShort:
+ return d->monthName(in.toInt(), QLocale::ShortFormat);
+ case DateToStringShort:
+ return d->toString(in.toDate(), QLocale::ShortFormat);
+ case DateToStringLong:
+ return d->toString(in.toDate(), QLocale::LongFormat);
+ case TimeToStringShort:
+ return d->toString(in.toTime(), QLocale::ShortFormat);
+ case TimeToStringLong:
+ return d->toString(in.toTime(), QLocale::LongFormat);
+ case DateTimeToStringShort:
+ return d->toString(in.toDateTime(), QLocale::ShortFormat);
+ case DateTimeToStringLong:
+ return d->toString(in.toDateTime(), QLocale::LongFormat);
+ case ZeroDigit:
+ return d->zeroDigit();
+ case LanguageId:
+ case CountryId: {
+ QString locale = QString::fromLatin1(getWinLocaleName());
+ QLocale::Language lang;
+ QLocale::Script script;
+ QLocale::Country cntry;
+ QLocalePrivate::getLangAndCountry(locale, lang, script, cntry);
+ if (type == LanguageId)
+ return lang;
+ if (cntry == QLocale::AnyCountry)
+ return fallbackLocale().country();
+ return cntry;
+ }
+ case ScriptId:
+ return QVariant(QLocale::AnyScript);
+ case MeasurementSystem:
+ return d->measurementSystem();
+ case AMText:
+ return d->amText();
+ case PMText:
+ return d->pmText();
+ case FirstDayOfWeek:
+ return d->firstDayOfWeek();
+ case CurrencySymbol:
+ return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
+ case CurrencyToString:
+ return d->toCurrencyString(in.value<QSystemLocale::CurrencyToStringArgument>());
+ case UILanguages:
+ return d->uiLanguages();
+ case LocaleChanged:
+ d->update();
+ break;
+ case NativeLanguageName:
+ return d->nativeLanguageName();
+ case NativeCountryName:
+ return d->nativeCountryName();
+ default:
+ break;
+ }
+ return QVariant();
+}
+#endif // QT_NO_SYSTEMLOCALE
+
+struct WindowsToISOListElt {
+ ushort windows_code;
+ char iso_name[6];
+};
+
+/* NOTE: This array should be sorted by the first column! */
+static const WindowsToISOListElt windows_to_iso_list[] = {
+ { 0x0401, "ar_SA" },
+ { 0x0402, "bg\0 " },
+ { 0x0403, "ca\0 " },
+ { 0x0404, "zh_TW" },
+ { 0x0405, "cs\0 " },
+ { 0x0406, "da\0 " },
+ { 0x0407, "de\0 " },
+ { 0x0408, "el\0 " },
+ { 0x0409, "en_US" },
+ { 0x040a, "es\0 " },
+ { 0x040b, "fi\0 " },
+ { 0x040c, "fr\0 " },
+ { 0x040d, "he\0 " },
+ { 0x040e, "hu\0 " },
+ { 0x040f, "is\0 " },
+ { 0x0410, "it\0 " },
+ { 0x0411, "ja\0 " },
+ { 0x0412, "ko\0 " },
+ { 0x0413, "nl\0 " },
+ { 0x0414, "no\0 " },
+ { 0x0415, "pl\0 " },
+ { 0x0416, "pt_BR" },
+ { 0x0418, "ro\0 " },
+ { 0x0419, "ru\0 " },
+ { 0x041a, "hr\0 " },
+ { 0x041c, "sq\0 " },
+ { 0x041d, "sv\0 " },
+ { 0x041e, "th\0 " },
+ { 0x041f, "tr\0 " },
+ { 0x0420, "ur\0 " },
+ { 0x0421, "in\0 " },
+ { 0x0422, "uk\0 " },
+ { 0x0423, "be\0 " },
+ { 0x0425, "et\0 " },
+ { 0x0426, "lv\0 " },
+ { 0x0427, "lt\0 " },
+ { 0x0429, "fa\0 " },
+ { 0x042a, "vi\0 " },
+ { 0x042d, "eu\0 " },
+ { 0x042f, "mk\0 " },
+ { 0x0436, "af\0 " },
+ { 0x0438, "fo\0 " },
+ { 0x0439, "hi\0 " },
+ { 0x043e, "ms\0 " },
+ { 0x0458, "mt\0 " },
+ { 0x0801, "ar_IQ" },
+ { 0x0804, "zh_CN" },
+ { 0x0807, "de_CH" },
+ { 0x0809, "en_GB" },
+ { 0x080a, "es_MX" },
+ { 0x080c, "fr_BE" },
+ { 0x0810, "it_CH" },
+ { 0x0812, "ko\0 " },
+ { 0x0813, "nl_BE" },
+ { 0x0814, "no\0 " },
+ { 0x0816, "pt\0 " },
+ { 0x081a, "sr\0 " },
+ { 0x081d, "sv_FI" },
+ { 0x0c01, "ar_EG" },
+ { 0x0c04, "zh_HK" },
+ { 0x0c07, "de_AT" },
+ { 0x0c09, "en_AU" },
+ { 0x0c0a, "es\0 " },
+ { 0x0c0c, "fr_CA" },
+ { 0x0c1a, "sr\0 " },
+ { 0x1001, "ar_LY" },
+ { 0x1004, "zh_SG" },
+ { 0x1007, "de_LU" },
+ { 0x1009, "en_CA" },
+ { 0x100a, "es_GT" },
+ { 0x100c, "fr_CH" },
+ { 0x1401, "ar_DZ" },
+ { 0x1407, "de_LI" },
+ { 0x1409, "en_NZ" },
+ { 0x140a, "es_CR" },
+ { 0x140c, "fr_LU" },
+ { 0x1801, "ar_MA" },
+ { 0x1809, "en_IE" },
+ { 0x180a, "es_PA" },
+ { 0x1c01, "ar_TN" },
+ { 0x1c09, "en_ZA" },
+ { 0x1c0a, "es_DO" },
+ { 0x2001, "ar_OM" },
+ { 0x2009, "en_JM" },
+ { 0x200a, "es_VE" },
+ { 0x2401, "ar_YE" },
+ { 0x2409, "en\0 " },
+ { 0x240a, "es_CO" },
+ { 0x2801, "ar_SY" },
+ { 0x2809, "en_BZ" },
+ { 0x280a, "es_PE" },
+ { 0x2c01, "ar_JO" },
+ { 0x2c09, "en_TT" },
+ { 0x2c0a, "es_AR" },
+ { 0x3001, "ar_LB" },
+ { 0x300a, "es_EC" },
+ { 0x3401, "ar_KW" },
+ { 0x340a, "es_CL" },
+ { 0x3801, "ar_AE" },
+ { 0x380a, "es_UY" },
+ { 0x3c01, "ar_BH" },
+ { 0x3c0a, "es_PY" },
+ { 0x4001, "ar_QA" },
+ { 0x400a, "es_BO" },
+ { 0x440a, "es_SV" },
+ { 0x480a, "es_HN" },
+ { 0x4c0a, "es_NI" },
+ { 0x500a, "es_PR" }
+};
+
+static const int windows_to_iso_count
+ = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt);
+
+static const char *winLangCodeToIsoName(int code)
+{
+ int cmp = code - windows_to_iso_list[0].windows_code;
+ if (cmp < 0)
+ return 0;
+
+ if (cmp == 0)
+ return windows_to_iso_list[0].iso_name;
+
+ int begin = 0;
+ int end = windows_to_iso_count;
+
+ while (end - begin > 1) {
+ uint mid = (begin + end)/2;
+
+ const WindowsToISOListElt *elt = windows_to_iso_list + mid;
+ int cmp = code - elt->windows_code;
+ if (cmp < 0)
+ end = mid;
+ else if (cmp > 0)
+ begin = mid;
+ else
+ return elt->iso_name;
+ }
+
+ return 0;
+
+}
+
+static QString winIso639LangName(LCID id)
+{
+ QString result;
+
+ // Windows returns the wrong ISO639 for some languages, we need to detect them here using
+ // the language code
+ QString lang_code;
+ wchar_t out[256];
+ if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255)) // ### shouldn't use them according to msdn
+ lang_code = QString::fromWCharArray(out);
+
+ if (!lang_code.isEmpty()) {
+ const char *endptr;
+ bool ok;
+ QByteArray latin1_lang_code = lang_code.toLatin1();
+ int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok);
+ if (ok && *endptr == '\0') {
+ switch (i) {
+ case 0x814:
+ result = QLatin1String("nn"); // Nynorsk
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!result.isEmpty())
+ return result;
+
+ // not one of the problematic languages - do the usual lookup
+ if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME , out, 255))
+ result = QString::fromWCharArray(out);
+
+ return result;
+}
+
+static QString winIso3116CtryName(LCID id)
+{
+ QString result;
+
+ wchar_t out[256];
+ if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255))
+ result = QString::fromWCharArray(out);
+
+ return result;
+}
+
+static QByteArray getWinLocaleName(LCID id)
+{
+ QByteArray result;
+ if (id == LOCALE_USER_DEFAULT) {
+ static QByteArray langEnvVar = qgetenv("LANG");
+ result = langEnvVar;
+ QString lang, script, cntry;
+ if ( result == "C" || (!result.isEmpty()
+ && qt_splitLocaleName(QString::fromLocal8Bit(result), lang, script, cntry)) ) {
+ long id = 0;
+ bool ok = false;
+ id = qstrtoll(result.data(), 0, 0, &ok);
+ if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX )
+ return result;
+ else
+ return winLangCodeToIsoName( (int)id );
+ }
+ }
+
+#if defined(Q_OS_WINCE)
+ result = winLangCodeToIsoName(id != LOCALE_USER_DEFAULT ? id : GetUserDefaultLCID());
+#else
+ if (id == LOCALE_USER_DEFAULT)
+ id = GetUserDefaultLCID();
+ QString resultuage = winIso639LangName(id);
+ QString country = winIso3116CtryName(id);
+ result = resultuage.toLatin1();
+ if (!country.isEmpty()) {
+ result += '_';
+ result += country.toLatin1();
+ }
+#endif
+
+ return result;
+}
+
+Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
+{
+ return QLocale(QString::fromLatin1(getWinLocaleName(id)));
+}
+
+QT_END_NAMESPACE