1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtCore module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qlocale_p.h"
43 #include "qlocale_tools_p.h"
45 #include "qstringlist.h"
47 #include "qdatetime.h"
49 #include "private/qsystemlibrary_p.h"
54 # include <qt_windows.h>
60 static QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT);
61 static const char *winLangCodeToIsoName(int code);
62 static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT);
63 static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT);
65 #ifndef QT_NO_SYSTEMLOCALE
67 #ifndef MUI_LANGUAGE_NAME
68 #define MUI_LANGUAGE_NAME 0x8
70 #ifndef LOCALE_SSHORTESTDAYNAME1
71 # define LOCALE_SSHORTESTDAYNAME1 0x0060
72 # define LOCALE_SSHORTESTDAYNAME2 0x0061
73 # define LOCALE_SSHORTESTDAYNAME3 0x0062
74 # define LOCALE_SSHORTESTDAYNAME4 0x0063
75 # define LOCALE_SSHORTESTDAYNAME5 0x0064
76 # define LOCALE_SSHORTESTDAYNAME6 0x0065
77 # define LOCALE_SSHORTESTDAYNAME7 0x0066
79 #ifndef LOCALE_SNATIVELANGUAGENAME
80 # define LOCALE_SNATIVELANGUAGENAME 0x00000004
82 #ifndef LOCALE_SNATIVECOUNTRYNAME
83 # define LOCALE_SNATIVECOUNTRYNAME 0x00000008
86 struct QSystemLocalePrivate
88 QSystemLocalePrivate();
92 QChar groupSeparator();
95 QVariant dateFormat(QLocale::FormatType);
96 QVariant timeFormat(QLocale::FormatType);
97 QVariant dateTimeFormat(QLocale::FormatType);
98 QVariant dayName(int, QLocale::FormatType);
99 QVariant monthName(int, QLocale::FormatType);
100 QVariant toString(const QDate &, QLocale::FormatType);
101 QVariant toString(const QTime &, QLocale::FormatType);
102 QVariant toString(const QDateTime &, QLocale::FormatType);
103 QVariant measurementSystem();
106 QVariant firstDayOfWeek();
107 QVariant currencySymbol(QLocale::CurrencySymbolFormat);
108 QVariant toCurrencyString(const QSystemLocale::CurrencyToStringArgument &);
109 QVariant uiLanguages();
110 QVariant nativeLanguageName();
111 QVariant nativeCountryName();
116 QByteArray langEnvVar;
118 enum SubstitutionType {
127 SubstitutionType substitutionType;
130 QString getLocaleInfo(LCTYPE type, int maxlen = 0);
131 int getLocaleInfo_int(LCTYPE type, int maxlen = 0);
132 QChar getLocaleInfo_qchar(LCTYPE type);
134 SubstitutionType substitution();
135 QString &substituteDigits(QString &string);
137 static QString winToQtFormat(const QString &sys_fmt);
140 Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate)
142 QSystemLocalePrivate::QSystemLocalePrivate()
143 : substitutionType(SUnknown)
145 langEnvVar = qgetenv("LANG");
146 lcid = GetUserDefaultLCID();
149 QString QSystemLocalePrivate::getLocaleInfo(LCTYPE type, int maxlen)
151 QVarLengthArray<wchar_t, 64> buf(maxlen ? maxlen : 64);
152 if (!GetLocaleInfo(lcid, type, buf.data(), buf.size()))
154 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
155 int cnt = GetLocaleInfo(lcid, type, 0, 0);
159 if (!GetLocaleInfo(lcid, type, buf.data(), buf.size()))
162 return QString::fromWCharArray(buf.data());
165 int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type, int maxlen)
167 QString str = getLocaleInfo(type, maxlen);
169 int v = str.toInt(&ok);
173 QChar QSystemLocalePrivate::getLocaleInfo_qchar(LCTYPE type)
175 QString str = getLocaleInfo(type);
176 return str.isEmpty() ? QChar() : str.at(0);
179 QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
181 if (substitutionType == SUnknown) {
183 if (!GetLocaleInfo(lcid, LOCALE_IDIGITSUBSTITUTION, buf, 8)) {
184 substitutionType = QSystemLocalePrivate::SNever;
185 return substitutionType;
188 substitutionType = QSystemLocalePrivate::SNever;
189 else if (buf[0] == '0')
190 substitutionType = QSystemLocalePrivate::SContext;
191 else if (buf[0] == '2')
192 substitutionType = QSystemLocalePrivate::SAlways;
195 if (!GetLocaleInfo(lcid, LOCALE_SNATIVEDIGITS, digits, 11)) {
196 substitutionType = QSystemLocalePrivate::SNever;
197 return substitutionType;
199 const wchar_t zero = digits[0];
200 if (buf[0] == zero + 2)
201 substitutionType = QSystemLocalePrivate::SAlways;
203 substitutionType = QSystemLocalePrivate::SNever;
206 return substitutionType;
209 QString &QSystemLocalePrivate::substituteDigits(QString &string)
211 ushort zero = zeroDigit().unicode();
212 ushort *qch = (ushort *)string.data();
213 for (ushort *end = qch + string.size(); qch != end; ++qch) {
214 if (*qch >= '0' && *qch <= '9')
215 *qch = zero + (*qch - '0');
220 QChar QSystemLocalePrivate::zeroDigit()
223 zero = getLocaleInfo_qchar(LOCALE_SNATIVEDIGITS);
227 QChar QSystemLocalePrivate::decimalPoint()
229 return getLocaleInfo_qchar(LOCALE_SDECIMAL);
232 QChar QSystemLocalePrivate::groupSeparator()
234 return getLocaleInfo_qchar(LOCALE_STHOUSAND);
237 QChar QSystemLocalePrivate::negativeSign()
239 return getLocaleInfo_qchar(LOCALE_SNEGATIVESIGN);
242 QChar QSystemLocalePrivate::positiveSign()
244 return getLocaleInfo_qchar(LOCALE_SPOSITIVESIGN);
247 QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type)
250 case QLocale::ShortFormat:
251 return winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE));
252 case QLocale::LongFormat:
253 return winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE));
254 case QLocale::NarrowFormat:
260 QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type)
263 case QLocale::ShortFormat:
264 return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT)); //###
265 case QLocale::LongFormat:
266 return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT));
267 case QLocale::NarrowFormat:
273 QVariant QSystemLocalePrivate::dateTimeFormat(QLocale::FormatType type)
275 return QString(dateFormat(type).toString() + QLatin1Char(' ') + timeFormat(type).toString());
278 QVariant QSystemLocalePrivate::dayName(int day, QLocale::FormatType type)
280 static const LCTYPE short_day_map[]
281 = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
282 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
283 LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 };
285 static const LCTYPE long_day_map[]
286 = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2,
287 LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5,
288 LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 };
290 static const LCTYPE narrow_day_map[]
291 = { LOCALE_SSHORTESTDAYNAME1, LOCALE_SSHORTESTDAYNAME2,
292 LOCALE_SSHORTESTDAYNAME3, LOCALE_SSHORTESTDAYNAME4,
293 LOCALE_SSHORTESTDAYNAME5, LOCALE_SSHORTESTDAYNAME6,
294 LOCALE_SSHORTESTDAYNAME7 };
298 if (type == QLocale::LongFormat)
299 return getLocaleInfo(long_day_map[day]);
300 else if (type == QLocale::NarrowFormat && QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
301 return getLocaleInfo(narrow_day_map[day]);
302 return getLocaleInfo(short_day_map[day]);
305 QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type)
307 static const LCTYPE short_month_map[]
308 = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
309 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
310 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
311 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
313 static const LCTYPE long_month_map[]
314 = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
315 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
316 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
317 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 };
320 if (month < 0 || month > 11)
323 LCTYPE lctype = (type == QLocale::ShortFormat || type == QLocale::NarrowFormat)
324 ? short_month_map[month] : long_month_map[month];
325 return getLocaleInfo(lctype);
328 QVariant QSystemLocalePrivate::toString(const QDate &date, QLocale::FormatType type)
331 memset(&st, 0, sizeof(SYSTEMTIME));
332 st.wYear = date.year();
333 st.wMonth = date.month();
334 st.wDay = date.day();
336 DWORD flags = (type == QLocale::LongFormat ? DATE_LONGDATE : DATE_SHORTDATE);
338 if (GetDateFormat(lcid, flags, &st, NULL, buf, 255)) {
339 QString format = QString::fromWCharArray(buf);
340 if (substitution() == SAlways)
341 substituteDigits(format);
347 QVariant QSystemLocalePrivate::toString(const QTime &time, QLocale::FormatType)
350 memset(&st, 0, sizeof(SYSTEMTIME));
351 st.wHour = time.hour();
352 st.wMinute = time.minute();
353 st.wSecond = time.second();
354 st.wMilliseconds = 0;
359 if (GetTimeFormat(lcid, flags, &st, NULL, buf, 255)) {
360 QString format = QString::fromWCharArray(buf);
361 if (substitution() == SAlways)
362 substituteDigits(format);
368 QVariant QSystemLocalePrivate::toString(const QDateTime &dt, QLocale::FormatType type)
370 return QString(toString(dt.date(), type).toString() + QLatin1Char(' ') + toString(dt.time(), type).toString());
373 QVariant QSystemLocalePrivate::measurementSystem()
377 if (GetLocaleInfo(lcid, LOCALE_IMEASURE, output, 2)) {
378 QString iMeasure = QString::fromWCharArray(output);
379 if (iMeasure == QLatin1String("1")) {
380 return QLocale::ImperialSystem;
384 return QLocale::MetricSystem;
387 QVariant QSystemLocalePrivate::amText()
389 wchar_t output[15]; // maximum length including terminating zero character for Win2003+
391 if (GetLocaleInfo(lcid, LOCALE_S1159, output, 15)) {
392 return QString::fromWCharArray(output);
398 QVariant QSystemLocalePrivate::pmText()
400 wchar_t output[15]; // maximum length including terminating zero character for Win2003+
402 if (GetLocaleInfo(lcid, LOCALE_S2359, output, 15)) {
403 return QString::fromWCharArray(output);
409 QVariant QSystemLocalePrivate::firstDayOfWeek()
411 wchar_t output[4]; // maximum length including terminating zero character for Win2003+
413 if (GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, output, 4))
414 return QString::fromWCharArray(output).toUInt()+1;
419 QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat format)
423 case QLocale::CurrencySymbol:
424 if (GetLocaleInfo(lcid, LOCALE_SCURRENCY, buf, 13))
425 return QString::fromWCharArray(buf);
427 case QLocale::CurrencyIsoCode:
428 if (GetLocaleInfo(lcid, LOCALE_SINTLSYMBOL, buf, 9))
429 return QString::fromWCharArray(buf);
431 case QLocale::CurrencyDisplayName: {
432 QVarLengthArray<wchar_t, 64> buf(64);
433 if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) {
434 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
436 buf.resize(255); // should be large enough, right?
437 if (!GetLocaleInfo(lcid, LOCALE_SNATIVECURRNAME, buf.data(), buf.size()))
440 return QString::fromWCharArray(buf.data());
448 QVariant QSystemLocalePrivate::toCurrencyString(const QSystemLocale::CurrencyToStringArgument &arg)
451 switch (arg.value.type()) {
453 value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
454 arg.value.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
457 value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
458 arg.value.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
460 case QVariant::Double:
461 value = QLocalePrivate::doubleToString(QLatin1Char('0'), QLatin1Char('+'), QLatin1Char('-'),
462 QLatin1Char(' '), QLatin1Char(','), QLatin1Char('.'),
463 arg.value.toDouble(), -1, QLocalePrivate::DFDecimal, -1, QLocale::OmitGroupSeparator);
465 case QVariant::LongLong:
466 value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
467 arg.value.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
469 case QVariant::ULongLong:
470 value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
471 arg.value.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
477 QVarLengthArray<wchar_t, 64> out(64);
482 CURRENCYFMT *pformat = NULL;
483 if (!arg.symbol.isEmpty()) {
484 format.NumDigits = getLocaleInfo_int(lcid, LOCALE_ICURRDIGITS);
485 format.LeadingZero = getLocaleInfo_int(lcid, LOCALE_ILZERO);
486 decimalSep = getLocaleInfo(lcid, LOCALE_SMONDECIMALSEP);
487 format.lpDecimalSep = (wchar_t *)decimalSep.utf16();
488 thousandSep = getLocaleInfo(lcid, LOCALE_SMONTHOUSANDSEP);
489 format.lpThousandSep = (wchar_t *)thousandSep.utf16();
490 format.NegativeOrder = getLocaleInfo_int(lcid, LOCALE_INEGCURR);
491 format.PositiveOrder = getLocaleInfo_int(lcid, LOCALE_ICURRENCY);
492 format.lpCurrencySymbol = (wchar_t *)arg.symbol.utf16();
494 // grouping is complicated and ugly:
495 // int(0) == "123456789.00" == string("0")
496 // int(3) == "123,456,789.00" == string("3;0")
497 // int(30) == "123456,789.00" == string("3;0;0")
498 // int(32) == "12,34,56,789.00" == string("3;2;0")
499 // int(320)== "1234,56,789.00" == string("3;2")
500 QString groupingStr = getLocaleInfo(lcid, LOCALE_SMONGROUPING);
501 format.Grouping = groupingStr.remove(QLatin1Char(';')).toInt();
502 if (format.Grouping % 10 == 0) // magic
503 format.Grouping /= 10;
505 format.Grouping *= 10;
509 int ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
510 pformat, out.data(), out.size());
511 if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
512 ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
513 pformat, out.data(), 0);
515 ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
516 pformat, out.data(), out.size());
519 value = QString::fromWCharArray(out.data());
520 if (substitution() == SAlways)
521 substituteDigits( value);
525 QVariant QSystemLocalePrivate::uiLanguages()
527 if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) {
528 typedef BOOL (WINAPI *GetUserPreferredUILanguagesFunc) (
530 PULONG pulNumLanguages,
531 PWSTR pwszLanguagesBuffer,
532 PULONG pcchLanguagesBuffer);
533 static GetUserPreferredUILanguagesFunc GetUserPreferredUILanguages_ptr = 0;
534 if (!GetUserPreferredUILanguages_ptr) {
535 QSystemLibrary lib(QLatin1String("kernel32"));
537 GetUserPreferredUILanguages_ptr = (GetUserPreferredUILanguagesFunc)lib.resolve("GetUserPreferredUILanguages");
539 if (GetUserPreferredUILanguages_ptr) {
540 unsigned long cnt = 0;
541 QVarLengthArray<wchar_t, 64> buf(64);
542 unsigned long size = buf.size();
543 if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) {
545 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
546 GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) {
548 if (!GetUserPreferredUILanguages_ptr(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size))
549 return QStringList();
554 const wchar_t *str = buf.constData();
555 for (; cnt > 0; --cnt) {
556 QString s = QString::fromWCharArray(str);
558 break; // something is wrong
566 // old Windows before Vista
567 return QStringList(QString::fromLatin1(winLangCodeToIsoName(GetUserDefaultUILanguage())));
570 QVariant QSystemLocalePrivate::nativeLanguageName()
572 if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
573 return getLocaleInfo(LOCALE_SNATIVELANGNAME);
574 return getLocaleInfo(LOCALE_SNATIVELANGUAGENAME);
577 QVariant QSystemLocalePrivate::nativeCountryName()
579 if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7)
580 return getLocaleInfo(LOCALE_SNATIVECTRYNAME);
581 return getLocaleInfo(LOCALE_SNATIVECOUNTRYNAME);
585 void QSystemLocalePrivate::update()
587 lcid = GetUserDefaultLCID();
588 substitutionType = SUnknown;
592 QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
597 while (i < sys_fmt.size()) {
598 if (sys_fmt.at(i).unicode() == QLatin1Char('\'')) {
599 QString text = qt_readEscapedFormatString(sys_fmt, &i);
600 if (text == QLatin1String("'"))
601 result += QLatin1String("''");
603 result += QString(QLatin1Char('\'') + text + QLatin1Char('\''));
607 QChar c = sys_fmt.at(i);
608 int repeat = qt_repeatCount(sys_fmt, i);
610 switch (c.unicode()) {
615 else if (repeat == 3)
619 result += QLatin1String("yy"); // "y" unsupported by Qt, use "yy"
622 result += QLatin1String("yyyy"); // "yyyyy" same as "yyyy" on Windows
625 result += QString(repeat, QLatin1Char('y'));
634 break; // no equivalent of "gg" in Qt
636 result += QLatin1Char('g');
643 result += QLatin1String("AP"); // "t" unsupported, use "AP"
646 result += QString(repeat, c);
656 QLocale QSystemLocale::fallbackLocale() const
658 return QLocale(QString::fromLatin1(getWinLocaleName()));
661 QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
663 QSystemLocalePrivate *d = systemLocalePrivate();
666 return d->decimalPoint();
668 return d->groupSeparator();
670 return d->negativeSign();
672 return d->positiveSign();
674 return d->dateFormat(QLocale::LongFormat);
675 case DateFormatShort:
676 return d->dateFormat(QLocale::ShortFormat);
678 return d->timeFormat(QLocale::LongFormat);
679 case TimeFormatShort:
680 return d->timeFormat(QLocale::ShortFormat);
681 case DateTimeFormatLong:
682 return d->dateTimeFormat(QLocale::LongFormat);
683 case DateTimeFormatShort:
684 return d->dateTimeFormat(QLocale::ShortFormat);
686 return d->dayName(in.toInt(), QLocale::LongFormat);
688 return d->dayName(in.toInt(), QLocale::ShortFormat);
690 return d->monthName(in.toInt(), QLocale::LongFormat);
692 return d->monthName(in.toInt(), QLocale::ShortFormat);
693 case DateToStringShort:
694 return d->toString(in.toDate(), QLocale::ShortFormat);
695 case DateToStringLong:
696 return d->toString(in.toDate(), QLocale::LongFormat);
697 case TimeToStringShort:
698 return d->toString(in.toTime(), QLocale::ShortFormat);
699 case TimeToStringLong:
700 return d->toString(in.toTime(), QLocale::LongFormat);
701 case DateTimeToStringShort:
702 return d->toString(in.toDateTime(), QLocale::ShortFormat);
703 case DateTimeToStringLong:
704 return d->toString(in.toDateTime(), QLocale::LongFormat);
706 return d->zeroDigit();
709 QString locale = QString::fromLatin1(getWinLocaleName());
710 QLocale::Language lang;
711 QLocale::Script script;
712 QLocale::Country cntry;
713 QLocalePrivate::getLangAndCountry(locale, lang, script, cntry);
714 if (type == LanguageId)
716 if (cntry == QLocale::AnyCountry)
717 return fallbackLocale().country();
721 return QVariant(QLocale::AnyScript);
722 case MeasurementSystem:
723 return d->measurementSystem();
729 return d->firstDayOfWeek();
731 return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
732 case CurrencyToString:
733 return d->toCurrencyString(in.value<QSystemLocale::CurrencyToStringArgument>());
735 return d->uiLanguages();
739 case NativeLanguageName:
740 return d->nativeLanguageName();
741 case NativeCountryName:
742 return d->nativeCountryName();
748 #endif // QT_NO_SYSTEMLOCALE
750 struct WindowsToISOListElt {
755 /* NOTE: This array should be sorted by the first column! */
756 static const WindowsToISOListElt windows_to_iso_list[] = {
867 static const int windows_to_iso_count
868 = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt);
870 static const char *winLangCodeToIsoName(int code)
872 int cmp = code - windows_to_iso_list[0].windows_code;
877 return windows_to_iso_list[0].iso_name;
880 int end = windows_to_iso_count;
882 while (end - begin > 1) {
883 uint mid = (begin + end)/2;
885 const WindowsToISOListElt *elt = windows_to_iso_list + mid;
886 int cmp = code - elt->windows_code;
892 return elt->iso_name;
899 static QString winIso639LangName(LCID id)
903 // Windows returns the wrong ISO639 for some languages, we need to detect them here using
907 if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255)) // ### shouldn't use them according to msdn
908 lang_code = QString::fromWCharArray(out);
910 if (!lang_code.isEmpty()) {
913 QByteArray latin1_lang_code = lang_code.toLatin1();
914 int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok);
915 if (ok && *endptr == '\0') {
918 result = QLatin1String("nn"); // Nynorsk
926 if (!result.isEmpty())
929 // not one of the problematic languages - do the usual lookup
930 if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME , out, 255))
931 result = QString::fromWCharArray(out);
936 static QString winIso3116CtryName(LCID id)
941 if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255))
942 result = QString::fromWCharArray(out);
947 static QByteArray getWinLocaleName(LCID id)
950 if (id == LOCALE_USER_DEFAULT) {
951 static QByteArray langEnvVar = qgetenv("LANG");
953 QString lang, script, cntry;
954 if ( result == "C" || (!result.isEmpty()
955 && qt_splitLocaleName(QString::fromLocal8Bit(result), lang, script, cntry)) ) {
958 id = qstrtoll(result.data(), 0, 0, &ok);
959 if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX )
962 return winLangCodeToIsoName( (int)id );
966 #if defined(Q_OS_WINCE)
967 result = winLangCodeToIsoName(id != LOCALE_USER_DEFAULT ? id : GetUserDefaultLCID());
969 if (id == LOCALE_USER_DEFAULT)
970 id = GetUserDefaultLCID();
971 QString resultuage = winIso639LangName(id);
972 QString country = winIso3116CtryName(id);
973 result = resultuage.toLatin1();
974 if (!country.isEmpty()) {
976 result += country.toLatin1();
983 Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
985 return QLocale(QString::fromLatin1(getWinLocaleName(id)));