1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "qlocale_p.h"
42 #include "qlocale_tools_p.h"
43
44 #include "qstringlist.h"
45 #include "qvariant.h"
46 #include "qdatetime.h"
47 #include "qdebug.h"
48
49 #ifdef Q_OS_WIN
50 # include <qt_windows.h>
51 # include <time.h>
52 #endif
53
54 #ifdef Q_OS_WINRT
55 #include <qfunctions_winrt.h>
56
57 #include <wrl.h>
58 #include <windows.foundation.h>
59 #include <windows.foundation.collections.h>
60 #include <windows.system.userprofile.h>
61 #endif // Q_OS_WINRT
62
63 QT_BEGIN_NAMESPACE
64
65 #ifndef Q_OS_WINRT
66 static QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT);
67 static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT);
68 static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT);
69 #else // !Q_OS_WINRT
70 using namespace Microsoft::WRL;
71 using namespace Microsoft::WRL::Wrappers;
72 using namespace ABI::Windows::Foundation;
73 using namespace ABI::Windows::System::UserProfile;
74
75 static QByteArray getWinLocaleName(LPWSTR id = LOCALE_NAME_USER_DEFAULT);
76 static const char *winLangCodeToIsoName(int code);
77 static QString winIso639LangName(LPWSTR id = LOCALE_NAME_USER_DEFAULT);
78 static QString winIso3116CtryName(LPWSTR id = LOCALE_NAME_USER_DEFAULT);
79 #endif // Q_OS_WINRT
80
81 #ifndef QT_NO_SYSTEMLOCALE
82
83 #ifndef MUI_LANGUAGE_NAME
84 #define MUI_LANGUAGE_NAME 0x8
85 #endif
86 #ifndef LOCALE_SSHORTESTDAYNAME1
87 # define LOCALE_SSHORTESTDAYNAME1 0x0060
88 # define LOCALE_SSHORTESTDAYNAME2 0x0061
89 # define LOCALE_SSHORTESTDAYNAME3 0x0062
90 # define LOCALE_SSHORTESTDAYNAME4 0x0063
91 # define LOCALE_SSHORTESTDAYNAME5 0x0064
92 # define LOCALE_SSHORTESTDAYNAME6 0x0065
93 # define LOCALE_SSHORTESTDAYNAME7 0x0066
94 #endif
95 #ifndef LOCALE_SNATIVELANGUAGENAME
96 # define LOCALE_SNATIVELANGUAGENAME 0x00000004
97 #endif
98 #ifndef LOCALE_SNATIVECOUNTRYNAME
99 # define LOCALE_SNATIVECOUNTRYNAME 0x00000008
100 #endif
101 #ifndef LOCALE_SSHORTTIME
102 # define LOCALE_SSHORTTIME 0x00000079
103 #endif
104
105 struct QSystemLocalePrivate
106 {
107 QSystemLocalePrivate();
108
109 QVariant zeroDigit();
110 QVariant decimalPoint();
111 QVariant groupSeparator();
112 QVariant negativeSign();
113 QVariant positiveSign();
114 QVariant dateFormat(QLocale::FormatType);
115 QVariant timeFormat(QLocale::FormatType);
116 QVariant dateTimeFormat(QLocale::FormatType);
117 QVariant dayName(int, QLocale::FormatType);
118 QVariant monthName(int, QLocale::FormatType);
119 QVariant toString(QDate, QLocale::FormatType);
120 QVariant toString(QTime, QLocale::FormatType);
121 QVariant toString(const QDateTime &, QLocale::FormatType);
122 QVariant measurementSystem();
123 QVariant collation();
124 QVariant amText();
125 QVariant pmText();
126 QVariant firstDayOfWeek();
127 QVariant currencySymbol(QLocale::CurrencySymbolFormat);
128 QVariant toCurrencyString(const QSystemLocale::CurrencyToStringArgument &);
129 QVariant uiLanguages();
130 QVariant nativeLanguageName();
131 QVariant nativeCountryName();
132
133 void update();
134
135 private:
136 enum SubstitutionType {
137 SUnknown,
138 SContext,
139 SAlways,
140 SNever
141 };
142
143 // cached values:
144 #ifndef Q_OS_WINRT
145 LCID lcid;
146 #else
147 WCHAR lcName[LOCALE_NAME_MAX_LENGTH];
148 #endif
149 SubstitutionType substitutionType;
150 QString zero; // cached value for zeroDigit()
151
152 int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
153 // Need to distinguish empty QString packaged as (non-null) QVariant from null QVariant:
154 template <typename T = QString>
155 T getLocaleInfo(LCTYPE type, int maxlen = 0);
156 int getLocaleInfo_int(LCTYPE type, int maxlen = 0);
157
158 int getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size);
159 int getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size);
160 int getTimeFormat(DWORD flags, const SYSTEMTIME *date, LPCWSTR format, LPWSTR data, int size);
161
162 SubstitutionType substitution();
163 QString &substituteDigits(QString &string);
164
165 static QString winToQtFormat(QStringView sys_fmt);
166
167 };
Q_GLOBAL_STATIC(QSystemLocalePrivate,systemLocalePrivate)168 Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate)
169
170 QSystemLocalePrivate::QSystemLocalePrivate()
171 : substitutionType(SUnknown)
172 {
173 #ifndef Q_OS_WINRT
174 lcid = GetUserDefaultLCID();
175 #else
176 GetUserDefaultLocaleName(lcName, LOCALE_NAME_MAX_LENGTH);
177 #endif
178 }
179
getCurrencyFormat(DWORD flags,LPCWSTR value,const CURRENCYFMTW * format,LPWSTR data,int size)180 inline int QSystemLocalePrivate::getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size)
181 {
182 #ifndef Q_OS_WINRT
183 return GetCurrencyFormat(lcid, flags, value, format, data, size);
184 #else
185 return GetCurrencyFormatEx(lcName, flags, value, format, data, size);
186 #endif
187 }
188
getDateFormat(DWORD flags,const SYSTEMTIME * date,LPCWSTR format,LPWSTR data,int size)189 inline int QSystemLocalePrivate::getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size)
190 {
191 #ifndef Q_OS_WINRT
192 return GetDateFormat(lcid, flags, date, format, data, size);
193 #else
194 return GetDateFormatEx(lcName, flags, date, format, data, size, NULL);
195 #endif
196 }
197
getTimeFormat(DWORD flags,const SYSTEMTIME * date,LPCWSTR format,LPWSTR data,int size)198 inline int QSystemLocalePrivate::getTimeFormat(DWORD flags, const SYSTEMTIME *date, LPCWSTR format, LPWSTR data, int size)
199 {
200 #ifndef Q_OS_WINRT
201 return GetTimeFormat(lcid, flags, date, format, data, size);
202 #else
203 return GetTimeFormatEx(lcName, flags, date, format, data, size);
204 #endif
205 }
206
getLocaleInfo(LCTYPE type,LPWSTR data,int size)207 inline int QSystemLocalePrivate::getLocaleInfo(LCTYPE type, LPWSTR data, int size)
208 {
209 #ifndef Q_OS_WINRT
210 return GetLocaleInfo(lcid, type, data, size);
211 #else
212 return GetLocaleInfoEx(lcName, type, data, size);
213 #endif
214 }
215
216 template<typename T>
getLocaleInfo(LCTYPE type,int maxlen)217 T QSystemLocalePrivate::getLocaleInfo(LCTYPE type, int maxlen)
218 {
219 // https://docs.microsoft.com/en-us/windows/win32/intl/locale-spositivesign
220 // says empty for LOCALE_SPOSITIVESIGN means "+", although GetLocaleInfo()
221 // is documented to return 0 only on failure, so it's not clear how it
222 // returns empty to mean this; hence the two checks for it below.
223 const QString plus = QStringLiteral("+");
224 QVarLengthArray<wchar_t, 64> buf(maxlen ? maxlen : 64);
225 if (!getLocaleInfo(type, buf.data(), buf.size())) {
226 const auto lastError = GetLastError();
227 if (type == LOCALE_SPOSITIVESIGN && lastError == ERROR_SUCCESS)
228 return plus;
229 if (lastError != ERROR_INSUFFICIENT_BUFFER)
230 return {};
231 int cnt = getLocaleInfo(type, 0, 0);
232 if (cnt == 0)
233 return {};
234 buf.resize(cnt);
235 if (!getLocaleInfo(type, buf.data(), buf.size()))
236 return {};
237 }
238 if (type == LOCALE_SPOSITIVESIGN && !buf[0])
239 return plus;
240 return QString::fromWCharArray(buf.data());
241 }
242
getLocaleInfo_int(LCTYPE type,int maxlen)243 int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type, int maxlen)
244 {
245 QString str = getLocaleInfo(type, maxlen);
246 bool ok = false;
247 int v = str.toInt(&ok);
248 return ok ? v : 0;
249 }
250
substitution()251 QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
252 {
253 if (substitutionType == SUnknown) {
254 wchar_t buf[8];
255 if (!getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, buf, 8)) {
256 substitutionType = QSystemLocalePrivate::SNever;
257 return substitutionType;
258 }
259 if (buf[0] == '1')
260 substitutionType = QSystemLocalePrivate::SNever;
261 else if (buf[0] == '0')
262 substitutionType = QSystemLocalePrivate::SContext;
263 else if (buf[0] == '2')
264 substitutionType = QSystemLocalePrivate::SAlways;
265 else {
266 wchar_t digits[11]; // See zeroDigit() for why 11.
267 if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
268 substitutionType = QSystemLocalePrivate::SNever;
269 return substitutionType;
270 }
271 if (buf[0] == digits[0] + 2)
272 substitutionType = QSystemLocalePrivate::SAlways;
273 else
274 substitutionType = QSystemLocalePrivate::SNever;
275 }
276 }
277 return substitutionType;
278 }
279
substituteDigits(QString & string)280 QString &QSystemLocalePrivate::substituteDigits(QString &string)
281 {
282 zeroDigit(); // Ensure zero is set.
283 switch (zero.size()) {
284 case 1: {
285 const ushort offset = zero.at(0).unicode() - '0';
286 if (!offset) // Nothing to do
287 break;
288 Q_ASSERT(offset > 9);
289 ushort *const qch = reinterpret_cast<ushort *>(string.data());
290 for (int i = 0, stop = string.size(); i < stop; ++i) {
291 ushort &ch = qch[i];
292 if (ch >= '0' && ch <= '9')
293 ch += offset;
294 }
295 break;
296 }
297 case 2: {
298 // Surrogate pair (high, low):
299 uint digit = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
300 for (int i = 0; i < 10; i++) {
301 const QChar s[2] = { QChar::highSurrogate(digit + i), QChar::lowSurrogate(digit + i) };
302 string.replace(QString(QLatin1Char('0' + i)), QString(s, 2));
303 }
304 break;
305 }
306 default:
307 Q_ASSERT(!"Expected zero digit to be a single UCS2 code-point or a surrogate pair");
308 case 0: // Apparently this locale info was not available.
309 break;
310 }
311 return string;
312 }
313
zeroDigit()314 QVariant QSystemLocalePrivate::zeroDigit()
315 {
316 if (zero.isEmpty()) {
317 /* Ten digits plus a terminator.
318
319 https://docs.microsoft.com/en-us/windows/win32/intl/locale-snative-constants
320 "Native equivalents of ASCII 0 through 9. The maximum number of
321 characters allowed for this string is eleven, including a terminating
322 null character."
323 */
324 wchar_t digits[11];
325 if (getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
326 // assert all(digits[i] == i + digits[0] for i in range(1, 10)), assumed above
327 zero = QString::fromWCharArray(digits, 1);
328 }
329 }
330 return zero;
331 }
332
decimalPoint()333 QVariant QSystemLocalePrivate::decimalPoint()
334 {
335 return getLocaleInfo<QVariant>(LOCALE_SDECIMAL);
336 }
337
groupSeparator()338 QVariant QSystemLocalePrivate::groupSeparator()
339 {
340 return getLocaleInfo<QVariant>(LOCALE_STHOUSAND);
341 }
342
negativeSign()343 QVariant QSystemLocalePrivate::negativeSign()
344 {
345 return getLocaleInfo<QVariant>(LOCALE_SNEGATIVESIGN);
346 }
347
positiveSign()348 QVariant QSystemLocalePrivate::positiveSign()
349 {
350 return getLocaleInfo<QVariant>(LOCALE_SPOSITIVESIGN);
351 }
352
dateFormat(QLocale::FormatType type)353 QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type)
354 {
355 switch (type) {
356 case QLocale::ShortFormat:
357 return winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE));
358 case QLocale::LongFormat:
359 return winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE));
360 case QLocale::NarrowFormat:
361 break;
362 }
363 return QVariant();
364 }
365
timeFormat(QLocale::FormatType type)366 QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type)
367 {
368 switch (type) {
369 case QLocale::ShortFormat:
370 return winToQtFormat(getLocaleInfo(LOCALE_SSHORTTIME));
371 case QLocale::LongFormat:
372 return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT));
373 case QLocale::NarrowFormat:
374 break;
375 }
376 return QVariant();
377 }
378
dateTimeFormat(QLocale::FormatType type)379 QVariant QSystemLocalePrivate::dateTimeFormat(QLocale::FormatType type)
380 {
381 return QString(dateFormat(type).toString() + QLatin1Char(' ') + timeFormat(type).toString());
382 }
383
dayName(int day,QLocale::FormatType type)384 QVariant QSystemLocalePrivate::dayName(int day, QLocale::FormatType type)
385 {
386 if (day < 1 || day > 7)
387 return QString();
388
389 static const LCTYPE short_day_map[]
390 = { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
391 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
392 LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 };
393
394 static const LCTYPE long_day_map[]
395 = { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2,
396 LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5,
397 LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 };
398
399 static const LCTYPE narrow_day_map[]
400 = { LOCALE_SSHORTESTDAYNAME1, LOCALE_SSHORTESTDAYNAME2,
401 LOCALE_SSHORTESTDAYNAME3, LOCALE_SSHORTESTDAYNAME4,
402 LOCALE_SSHORTESTDAYNAME5, LOCALE_SSHORTESTDAYNAME6,
403 LOCALE_SSHORTESTDAYNAME7 };
404
405 day -= 1;
406
407 if (type == QLocale::LongFormat)
408 return getLocaleInfo<QVariant>(long_day_map[day]);
409 if (type == QLocale::NarrowFormat)
410 return getLocaleInfo<QVariant>(narrow_day_map[day]);
411 return getLocaleInfo<QVariant>(short_day_map[day]);
412 }
413
monthName(int month,QLocale::FormatType type)414 QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type)
415 {
416 static const LCTYPE short_month_map[]
417 = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
418 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
419 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
420 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
421
422 static const LCTYPE long_month_map[]
423 = { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
424 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
425 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
426 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 };
427
428 month -= 1;
429 if (month < 0 || month > 11)
430 return QString();
431
432 LCTYPE lctype = (type == QLocale::ShortFormat || type == QLocale::NarrowFormat)
433 ? short_month_map[month] : long_month_map[month];
434 return getLocaleInfo<QVariant>(lctype);
435 }
436
toString(QDate date,QLocale::FormatType type)437 QVariant QSystemLocalePrivate::toString(QDate date, QLocale::FormatType type)
438 {
439 SYSTEMTIME st;
440 memset(&st, 0, sizeof(SYSTEMTIME));
441 st.wYear = date.year();
442 st.wMonth = date.month();
443 st.wDay = date.day();
444
445 DWORD flags = (type == QLocale::LongFormat ? DATE_LONGDATE : DATE_SHORTDATE);
446 wchar_t buf[255];
447 if (getDateFormat(flags, &st, NULL, buf, 255)) {
448 QString format = QString::fromWCharArray(buf);
449 if (substitution() == SAlways)
450 substituteDigits(format);
451 return format;
452 }
453 return QString();
454 }
455
toString(QTime time,QLocale::FormatType type)456 QVariant QSystemLocalePrivate::toString(QTime time, QLocale::FormatType type)
457 {
458 SYSTEMTIME st;
459 memset(&st, 0, sizeof(SYSTEMTIME));
460 st.wHour = time.hour();
461 st.wMinute = time.minute();
462 st.wSecond = time.second();
463 st.wMilliseconds = 0;
464
465 DWORD flags = 0;
466 // keep the same conditional as timeFormat() above
467 if (type == QLocale::ShortFormat)
468 flags = TIME_NOSECONDS;
469
470 wchar_t buf[255];
471 if (getTimeFormat(flags, &st, NULL, buf, 255)) {
472 QString format = QString::fromWCharArray(buf);
473 if (substitution() == SAlways)
474 substituteDigits(format);
475 return format;
476 }
477 return QString();
478 }
479
toString(const QDateTime & dt,QLocale::FormatType type)480 QVariant QSystemLocalePrivate::toString(const QDateTime &dt, QLocale::FormatType type)
481 {
482 return QString(toString(dt.date(), type).toString() + QLatin1Char(' ') + toString(dt.time(), type).toString());
483 }
484
measurementSystem()485 QVariant QSystemLocalePrivate::measurementSystem()
486 {
487 wchar_t output[2];
488
489 if (getLocaleInfo(LOCALE_IMEASURE, output, 2)) {
490 QString iMeasure = QString::fromWCharArray(output);
491 if (iMeasure == QLatin1String("1")) {
492 return QLocale::ImperialSystem;
493 }
494 }
495
496 return QLocale::MetricSystem;
497 }
498
collation()499 QVariant QSystemLocalePrivate::collation()
500 {
501 return getLocaleInfo<QVariant>(LOCALE_SSORTLOCALE);
502 }
503
amText()504 QVariant QSystemLocalePrivate::amText()
505 {
506 wchar_t output[15]; // maximum length including terminating zero character for Win2003+
507
508 if (getLocaleInfo(LOCALE_S1159, output, 15)) {
509 return QString::fromWCharArray(output);
510 }
511
512 return QVariant();
513 }
514
pmText()515 QVariant QSystemLocalePrivate::pmText()
516 {
517 wchar_t output[15]; // maximum length including terminating zero character for Win2003+
518
519 if (getLocaleInfo(LOCALE_S2359, output, 15)) {
520 return QString::fromWCharArray(output);
521 }
522
523 return QVariant();
524 }
525
firstDayOfWeek()526 QVariant QSystemLocalePrivate::firstDayOfWeek()
527 {
528 wchar_t output[4]; // maximum length including terminating zero character for Win2003+
529
530 if (getLocaleInfo(LOCALE_IFIRSTDAYOFWEEK, output, 4))
531 return QString::fromWCharArray(output).toUInt()+1;
532
533 return 1;
534 }
535
currencySymbol(QLocale::CurrencySymbolFormat format)536 QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat format)
537 {
538 wchar_t buf[13];
539 switch (format) {
540 case QLocale::CurrencySymbol:
541 if (getLocaleInfo(LOCALE_SCURRENCY, buf, 13))
542 return QString::fromWCharArray(buf);
543 break;
544 case QLocale::CurrencyIsoCode:
545 if (getLocaleInfo(LOCALE_SINTLSYMBOL, buf, 9))
546 return QString::fromWCharArray(buf);
547 break;
548 case QLocale::CurrencyDisplayName: {
549 QVarLengthArray<wchar_t, 64> buf(64);
550 if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size())) {
551 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
552 break;
553 buf.resize(255); // should be large enough, right?
554 if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size()))
555 break;
556 }
557 return QString::fromWCharArray(buf.data());
558 }
559 default:
560 break;
561 }
562 return QVariant();
563 }
564
toCurrencyString(const QSystemLocale::CurrencyToStringArgument & arg)565 QVariant QSystemLocalePrivate::toCurrencyString(const QSystemLocale::CurrencyToStringArgument &arg)
566 {
567 QString value;
568 switch (arg.value.type()) {
569 case QVariant::Int:
570 value = QLocaleData::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
571 arg.value.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
572 break;
573 case QVariant::UInt:
574 value = QLocaleData::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
575 arg.value.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
576 break;
577 case QVariant::Double:
578 value = QLocaleData::doubleToString(QLatin1Char('0'), QLatin1Char('+'), QLatin1Char('-'),
579 QLatin1Char(' '), QLatin1Char(','), QLatin1Char('.'),
580 arg.value.toDouble(), -1, QLocaleData::DFDecimal, -1, QLocale::OmitGroupSeparator);
581 break;
582 case QVariant::LongLong:
583 value = QLocaleData::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
584 arg.value.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
585 break;
586 case QVariant::ULongLong:
587 value = QLocaleData::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
588 arg.value.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
589 break;
590 default:
591 return QVariant();
592 }
593
594 QVarLengthArray<wchar_t, 64> out(64);
595
596 QString decimalSep;
597 QString thousandSep;
598 CURRENCYFMT format;
599 CURRENCYFMT *pformat = NULL;
600 if (!arg.symbol.isEmpty()) {
601 format.NumDigits = getLocaleInfo_int(LOCALE_ICURRDIGITS);
602 format.LeadingZero = getLocaleInfo_int(LOCALE_ILZERO);
603 decimalSep = getLocaleInfo(LOCALE_SMONDECIMALSEP);
604 format.lpDecimalSep = (wchar_t *)decimalSep.utf16();
605 thousandSep = getLocaleInfo(LOCALE_SMONTHOUSANDSEP);
606 format.lpThousandSep = (wchar_t *)thousandSep.utf16();
607 format.NegativeOrder = getLocaleInfo_int(LOCALE_INEGCURR);
608 format.PositiveOrder = getLocaleInfo_int(LOCALE_ICURRENCY);
609 format.lpCurrencySymbol = (wchar_t *)arg.symbol.utf16();
610
611 // grouping is complicated and ugly:
612 // int(0) == "123456789.00" == string("0")
613 // int(3) == "123,456,789.00" == string("3;0")
614 // int(30) == "123456,789.00" == string("3;0;0")
615 // int(32) == "12,34,56,789.00" == string("3;2;0")
616 // int(320)== "1234,56,789.00" == string("3;2")
617 QString groupingStr = getLocaleInfo(LOCALE_SMONGROUPING);
618 format.Grouping = groupingStr.remove(QLatin1Char(';')).toInt();
619 if (format.Grouping % 10 == 0) // magic
620 format.Grouping /= 10;
621 else
622 format.Grouping *= 10;
623 pformat = &format;
624 }
625
626 int ret = getCurrencyFormat(0, reinterpret_cast<const wchar_t *>(value.utf16()),
627 pformat, out.data(), out.size());
628 if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
629 ret = getCurrencyFormat(0, reinterpret_cast<const wchar_t *>(value.utf16()),
630 pformat, out.data(), 0);
631 out.resize(ret);
632 getCurrencyFormat(0, reinterpret_cast<const wchar_t *>(value.utf16()),
633 pformat, out.data(), out.size());
634 }
635
636 value = QString::fromWCharArray(out.data());
637 if (substitution() == SAlways)
638 substituteDigits( value);
639 return value;
640 }
641
uiLanguages()642 QVariant QSystemLocalePrivate::uiLanguages()
643 {
644 #ifndef Q_OS_WINRT
645 unsigned long cnt = 0;
646 QVarLengthArray<wchar_t, 64> buf(64);
647 # if !defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE) // Not present in MinGW 4.9/bootstrap builds.
648 unsigned long size = buf.size();
649 if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size)) {
650 size = 0;
651 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
652 GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) {
653 buf.resize(size);
654 if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size))
655 return QStringList();
656 }
657 }
658 # endif // !QT_BOOTSTRAPPED && !QT_BUILD_QMAKE
659 QStringList result;
660 result.reserve(cnt);
661 const wchar_t *str = buf.constData();
662 for (; cnt > 0; --cnt) {
663 QString s = QString::fromWCharArray(str);
664 if (s.isEmpty())
665 break; // something is wrong
666 result.append(s);
667 str += s.size() + 1;
668 }
669 return result;
670 #else // !Q_OS_WINRT
671 QStringList result;
672
673 ComPtr<IGlobalizationPreferencesStatics> preferences;
674 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_UserProfile_GlobalizationPreferences).Get(), &preferences);
675 if (FAILED(hr)) {
676 qWarning("Could not obtain ApplicationLanguagesStatic");
677 return QStringList();
678 }
679
680 ComPtr<ABI::Windows::Foundation::Collections::IVectorView<HSTRING> > languageList;
681 // Languages is a ranked list of "long names" (e.g. en-US) of preferred languages
682 hr = preferences->get_Languages(&languageList);
683 Q_ASSERT_SUCCEEDED(hr);
684 unsigned int size;
685 hr = languageList->get_Size(&size);
686 Q_ASSERT_SUCCEEDED(hr);
687 result.reserve(size);
688 for (unsigned int i = 0; i < size; ++i) {
689 HString language;
690 hr = languageList->GetAt(i, language.GetAddressOf());
691 Q_ASSERT_SUCCEEDED(hr);
692 UINT32 length;
693 PCWSTR rawString = language.GetRawBuffer(&length);
694 result << QString::fromWCharArray(rawString, length);
695 }
696
697 return result;
698 #endif // Q_OS_WINRT
699 }
700
nativeLanguageName()701 QVariant QSystemLocalePrivate::nativeLanguageName()
702 {
703 return getLocaleInfo<QVariant>(LOCALE_SNATIVELANGUAGENAME);
704 }
705
nativeCountryName()706 QVariant QSystemLocalePrivate::nativeCountryName()
707 {
708 return getLocaleInfo<QVariant>(LOCALE_SNATIVECOUNTRYNAME);
709 }
710
711
update()712 void QSystemLocalePrivate::update()
713 {
714 #ifndef Q_OS_WINRT
715 lcid = GetUserDefaultLCID();
716 #else
717 GetUserDefaultLocaleName(lcName, LOCALE_NAME_MAX_LENGTH);
718 #endif
719 substitutionType = SUnknown;
720 zero.resize(0);
721 }
722
winToQtFormat(QStringView sys_fmt)723 QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt)
724 {
725 QString result;
726 int i = 0;
727
728 while (i < sys_fmt.size()) {
729 if (sys_fmt.at(i).unicode() == QLatin1Char('\'')) {
730 QString text = qt_readEscapedFormatString(sys_fmt, &i);
731 if (text == QLatin1String("'"))
732 result += QLatin1String("''");
733 else
734 result += QLatin1Char('\'') + text + QLatin1Char('\'');
735 continue;
736 }
737
738 QChar c = sys_fmt.at(i);
739 int repeat = qt_repeatCount(sys_fmt.mid(i));
740
741 switch (c.unicode()) {
742 // Date
743 case 'y':
744 if (repeat > 5)
745 repeat = 5;
746 else if (repeat == 3)
747 repeat = 2;
748 switch (repeat) {
749 case 1:
750 result += QLatin1String("yy"); // "y" unsupported by Qt, use "yy"
751 break;
752 case 5:
753 result += QLatin1String("yyyy"); // "yyyyy" same as "yyyy" on Windows
754 break;
755 default:
756 result += QString(repeat, QLatin1Char('y'));
757 break;
758 }
759 break;
760 case 'g':
761 if (repeat > 2)
762 repeat = 2;
763 switch (repeat) {
764 case 2:
765 break; // no equivalent of "gg" in Qt
766 default:
767 result += QLatin1Char('g');
768 break;
769 }
770 break;
771 case 't':
772 if (repeat > 2)
773 repeat = 2;
774 result += QLatin1String("AP"); // "t" unsupported, use "AP"
775 break;
776 default:
777 result += QString(repeat, c);
778 break;
779 }
780
781 i += repeat;
782 }
783
784 return result;
785 }
786
fallbackUiLocale() const787 QLocale QSystemLocale::fallbackUiLocale() const
788 {
789 return QLocale(QString::fromLatin1(getWinLocaleName()));
790 }
791
query(QueryType type,QVariant in) const792 QVariant QSystemLocale::query(QueryType type, QVariant in) const
793 {
794 QSystemLocalePrivate *d = systemLocalePrivate();
795 switch(type) {
796 case DecimalPoint:
797 return d->decimalPoint();
798 case GroupSeparator:
799 return d->groupSeparator();
800 case NegativeSign:
801 return d->negativeSign();
802 case PositiveSign:
803 return d->positiveSign();
804 case DateFormatLong:
805 return d->dateFormat(QLocale::LongFormat);
806 case DateFormatShort:
807 return d->dateFormat(QLocale::ShortFormat);
808 case TimeFormatLong:
809 return d->timeFormat(QLocale::LongFormat);
810 case TimeFormatShort:
811 return d->timeFormat(QLocale::ShortFormat);
812 case DateTimeFormatLong:
813 return d->dateTimeFormat(QLocale::LongFormat);
814 case DateTimeFormatShort:
815 return d->dateTimeFormat(QLocale::ShortFormat);
816 case DayNameLong:
817 return d->dayName(in.toInt(), QLocale::LongFormat);
818 case DayNameShort:
819 return d->dayName(in.toInt(), QLocale::ShortFormat);
820 case MonthNameLong:
821 case StandaloneMonthNameLong:
822 return d->monthName(in.toInt(), QLocale::LongFormat);
823 case MonthNameShort:
824 case StandaloneMonthNameShort:
825 return d->monthName(in.toInt(), QLocale::ShortFormat);
826 case DateToStringShort:
827 return d->toString(in.toDate(), QLocale::ShortFormat);
828 case DateToStringLong:
829 return d->toString(in.toDate(), QLocale::LongFormat);
830 case TimeToStringShort:
831 return d->toString(in.toTime(), QLocale::ShortFormat);
832 case TimeToStringLong:
833 return d->toString(in.toTime(), QLocale::LongFormat);
834 case DateTimeToStringShort:
835 return d->toString(in.toDateTime(), QLocale::ShortFormat);
836 case DateTimeToStringLong:
837 return d->toString(in.toDateTime(), QLocale::LongFormat);
838 case ZeroDigit:
839 return d->zeroDigit();
840 case LanguageId:
841 case ScriptId:
842 case CountryId: {
843 QString locale = QString::fromLatin1(getWinLocaleName());
844 QLocale::Language lang;
845 QLocale::Script script;
846 QLocale::Country cntry;
847 QLocalePrivate::getLangAndCountry(locale, lang, script, cntry);
848 if (type == LanguageId)
849 return lang;
850 if (type == ScriptId)
851 return script == QLocale::AnyScript ? fallbackUiLocale().script() : script;
852 if (cntry == QLocale::AnyCountry)
853 return fallbackUiLocale().country();
854 return cntry;
855 }
856 case MeasurementSystem:
857 return d->measurementSystem();
858 case Collation:
859 return d->collation();
860 case AMText:
861 return d->amText();
862 case PMText:
863 return d->pmText();
864 case FirstDayOfWeek:
865 return d->firstDayOfWeek();
866 case CurrencySymbol:
867 return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
868 case CurrencyToString:
869 return d->toCurrencyString(in.value<QSystemLocale::CurrencyToStringArgument>());
870 case UILanguages:
871 return d->uiLanguages();
872 case LocaleChanged:
873 d->update();
874 break;
875 case NativeLanguageName:
876 return d->nativeLanguageName();
877 case NativeCountryName:
878 return d->nativeCountryName();
879 default:
880 break;
881 }
882 return QVariant();
883 }
884 #endif // QT_NO_SYSTEMLOCALE
885
886 struct WindowsToISOListElt {
887 ushort windows_code;
888 char iso_name[6];
889 };
890
891 /* NOTE: This array should be sorted by the first column! */
892 static const WindowsToISOListElt windows_to_iso_list[] = {
893 { 0x0401, "ar_SA" },
894 { 0x0402, "bg\0 " },
895 { 0x0403, "ca\0 " },
896 { 0x0404, "zh_TW" },
897 { 0x0405, "cs\0 " },
898 { 0x0406, "da\0 " },
899 { 0x0407, "de\0 " },
900 { 0x0408, "el\0 " },
901 { 0x0409, "en_US" },
902 { 0x040a, "es\0 " },
903 { 0x040b, "fi\0 " },
904 { 0x040c, "fr\0 " },
905 { 0x040d, "he\0 " },
906 { 0x040e, "hu\0 " },
907 { 0x040f, "is\0 " },
908 { 0x0410, "it\0 " },
909 { 0x0411, "ja\0 " },
910 { 0x0412, "ko\0 " },
911 { 0x0413, "nl\0 " },
912 { 0x0414, "no\0 " },
913 { 0x0415, "pl\0 " },
914 { 0x0416, "pt_BR" },
915 { 0x0418, "ro\0 " },
916 { 0x0419, "ru\0 " },
917 { 0x041a, "hr\0 " },
918 { 0x041c, "sq\0 " },
919 { 0x041d, "sv\0 " },
920 { 0x041e, "th\0 " },
921 { 0x041f, "tr\0 " },
922 { 0x0420, "ur\0 " },
923 { 0x0421, "in\0 " },
924 { 0x0422, "uk\0 " },
925 { 0x0423, "be\0 " },
926 { 0x0425, "et\0 " },
927 { 0x0426, "lv\0 " },
928 { 0x0427, "lt\0 " },
929 { 0x0429, "fa\0 " },
930 { 0x042a, "vi\0 " },
931 { 0x042d, "eu\0 " },
932 { 0x042f, "mk\0 " },
933 { 0x0436, "af\0 " },
934 { 0x0438, "fo\0 " },
935 { 0x0439, "hi\0 " },
936 { 0x043e, "ms\0 " },
937 { 0x0458, "mt\0 " },
938 { 0x0801, "ar_IQ" },
939 { 0x0804, "zh_CN" },
940 { 0x0807, "de_CH" },
941 { 0x0809, "en_GB" },
942 { 0x080a, "es_MX" },
943 { 0x080c, "fr_BE" },
944 { 0x0810, "it_CH" },
945 { 0x0812, "ko\0 " },
946 { 0x0813, "nl_BE" },
947 { 0x0814, "no\0 " },
948 { 0x0816, "pt\0 " },
949 { 0x081a, "sr\0 " },
950 { 0x081d, "sv_FI" },
951 { 0x0c01, "ar_EG" },
952 { 0x0c04, "zh_HK" },
953 { 0x0c07, "de_AT" },
954 { 0x0c09, "en_AU" },
955 { 0x0c0a, "es\0 " },
956 { 0x0c0c, "fr_CA" },
957 { 0x0c1a, "sr\0 " },
958 { 0x1001, "ar_LY" },
959 { 0x1004, "zh_SG" },
960 { 0x1007, "de_LU" },
961 { 0x1009, "en_CA" },
962 { 0x100a, "es_GT" },
963 { 0x100c, "fr_CH" },
964 { 0x1401, "ar_DZ" },
965 { 0x1407, "de_LI" },
966 { 0x1409, "en_NZ" },
967 { 0x140a, "es_CR" },
968 { 0x140c, "fr_LU" },
969 { 0x1801, "ar_MA" },
970 { 0x1809, "en_IE" },
971 { 0x180a, "es_PA" },
972 { 0x1c01, "ar_TN" },
973 { 0x1c09, "en_ZA" },
974 { 0x1c0a, "es_DO" },
975 { 0x2001, "ar_OM" },
976 { 0x2009, "en_JM" },
977 { 0x200a, "es_VE" },
978 { 0x2401, "ar_YE" },
979 { 0x2409, "en\0 " },
980 { 0x240a, "es_CO" },
981 { 0x2801, "ar_SY" },
982 { 0x2809, "en_BZ" },
983 { 0x280a, "es_PE" },
984 { 0x2c01, "ar_JO" },
985 { 0x2c09, "en_TT" },
986 { 0x2c0a, "es_AR" },
987 { 0x3001, "ar_LB" },
988 { 0x300a, "es_EC" },
989 { 0x3401, "ar_KW" },
990 { 0x340a, "es_CL" },
991 { 0x3801, "ar_AE" },
992 { 0x380a, "es_UY" },
993 { 0x3c01, "ar_BH" },
994 { 0x3c0a, "es_PY" },
995 { 0x4001, "ar_QA" },
996 { 0x400a, "es_BO" },
997 { 0x440a, "es_SV" },
998 { 0x480a, "es_HN" },
999 { 0x4c0a, "es_NI" },
1000 { 0x500a, "es_PR" }
1001 };
1002
1003 static const int windows_to_iso_count
1004 = sizeof(windows_to_iso_list)/sizeof(WindowsToISOListElt);
1005
winLangCodeToIsoName(int code)1006 static const char *winLangCodeToIsoName(int code)
1007 {
1008 int cmp = code - windows_to_iso_list[0].windows_code;
1009 if (cmp < 0)
1010 return 0;
1011
1012 if (cmp == 0)
1013 return windows_to_iso_list[0].iso_name;
1014
1015 int begin = 0;
1016 int end = windows_to_iso_count;
1017
1018 while (end - begin > 1) {
1019 uint mid = (begin + end)/2;
1020
1021 const WindowsToISOListElt *elt = windows_to_iso_list + mid;
1022 int cmp = code - elt->windows_code;
1023 if (cmp < 0)
1024 end = mid;
1025 else if (cmp > 0)
1026 begin = mid;
1027 else
1028 return elt->iso_name;
1029 }
1030
1031 return 0;
1032
1033 }
1034
qt_inIsoNametoLCID(const char * name)1035 LCID qt_inIsoNametoLCID(const char *name)
1036 {
1037 // handle norwegian manually, the list above will fail
1038 if (!strncmp(name, "nb", 2))
1039 return 0x0414;
1040 if (!strncmp(name, "nn", 2))
1041 return 0x0814;
1042
1043 char n[64];
1044 strncpy(n, name, sizeof(n));
1045 n[sizeof(n)-1] = 0;
1046 char *c = n;
1047 while (*c) {
1048 if (*c == '-')
1049 *c = '_';
1050 ++c;
1051 }
1052
1053 for (const WindowsToISOListElt &i : windows_to_iso_list) {
1054 if (!strcmp(n, i.iso_name))
1055 return i.windows_code;
1056 }
1057 return LOCALE_USER_DEFAULT;
1058 }
1059
1060
1061 #ifndef Q_OS_WINRT
winIso639LangName(LCID id)1062 static QString winIso639LangName(LCID id)
1063 #else
1064 static QString winIso639LangName(LPWSTR id)
1065 #endif
1066 {
1067 QString result;
1068
1069 // Windows returns the wrong ISO639 for some languages, we need to detect them here using
1070 // the language code
1071 QString lang_code;
1072 wchar_t out[256];
1073 #ifndef Q_OS_WINRT
1074 if (GetLocaleInfo(id, LOCALE_ILANGUAGE, out, 255))
1075 #else
1076 if (GetLocaleInfoEx(id, LOCALE_ILANGUAGE, out, 255))
1077 #endif
1078 lang_code = QString::fromWCharArray(out);
1079
1080 if (!lang_code.isEmpty()) {
1081 const char *endptr;
1082 bool ok;
1083 QByteArray latin1_lang_code = std::move(lang_code).toLatin1();
1084 int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok);
1085 if (ok && *endptr == '\0') {
1086 switch (i) {
1087 case 0x814:
1088 result = QLatin1String("nn"); // Nynorsk
1089 break;
1090 default:
1091 break;
1092 }
1093 }
1094 }
1095
1096 if (!result.isEmpty())
1097 return result;
1098
1099 // not one of the problematic languages - do the usual lookup
1100 #ifndef Q_OS_WINRT
1101 if (GetLocaleInfo(id, LOCALE_SISO639LANGNAME, out, 255))
1102 #else
1103 if (GetLocaleInfoEx(id, LOCALE_SISO639LANGNAME, out, 255))
1104 #endif
1105 result = QString::fromWCharArray(out);
1106
1107 return result;
1108 }
1109
1110 #ifndef Q_OS_WINRT
winIso3116CtryName(LCID id)1111 static QString winIso3116CtryName(LCID id)
1112 #else
1113 static QString winIso3116CtryName(LPWSTR id)
1114 #endif
1115 {
1116 QString result;
1117
1118 wchar_t out[256];
1119 #ifndef Q_OS_WINRT
1120 if (GetLocaleInfo(id, LOCALE_SISO3166CTRYNAME, out, 255))
1121 #else
1122 if (GetLocaleInfoEx(id, LOCALE_SISO3166CTRYNAME, out, 255))
1123 #endif
1124 result = QString::fromWCharArray(out);
1125
1126 return result;
1127 }
1128
1129 #ifndef Q_OS_WINRT
getWinLocaleName(LCID id)1130 static QByteArray getWinLocaleName(LCID id)
1131 #else
1132 static QByteArray getWinLocaleName(LPWSTR id)
1133 #endif
1134 {
1135 QByteArray result;
1136 #ifndef Q_OS_WINRT
1137 if (id == LOCALE_USER_DEFAULT) {
1138 #else
1139 if (QString::fromWCharArray(id) == QString::fromWCharArray(LOCALE_NAME_USER_DEFAULT)) {
1140 #endif
1141 static QByteArray langEnvVar = qgetenv("LANG");
1142 result = langEnvVar;
1143 QString lang, script, cntry;
1144 if ( result == "C" || (!result.isEmpty()
1145 && qt_splitLocaleName(QString::fromLocal8Bit(result), lang, script, cntry)) ) {
1146 long id = 0;
1147 bool ok = false;
1148 id = qstrtoll(result.data(), 0, 0, &ok);
1149 if ( !ok || id == 0 || id < INT_MIN || id > INT_MAX )
1150 return result;
1151 return winLangCodeToIsoName(int(id));
1152 }
1153 }
1154
1155 #ifndef Q_OS_WINRT
1156 if (id == LOCALE_USER_DEFAULT)
1157 id = GetUserDefaultLCID();
1158 #else // !Q_OS_WINRT
1159 WCHAR lcName[LOCALE_NAME_MAX_LENGTH];
1160 if (QString::fromWCharArray(id) == QString::fromWCharArray(LOCALE_NAME_USER_DEFAULT)) {
1161 GetUserDefaultLocaleName(lcName, LOCALE_NAME_MAX_LENGTH);
1162 id = lcName;
1163 }
1164 #endif // Q_OS_WINRT
1165 QString resultusage = winIso639LangName(id);
1166 QString country = winIso3116CtryName(id);
1167 if (!country.isEmpty())
1168 resultusage += QLatin1Char('_') + country;
1169
1170 return std::move(resultusage).toLatin1();
1171 }
1172
1173 Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
1174 {
1175 #ifndef Q_OS_WINRT
1176 return QLocale(QString::fromLatin1(getWinLocaleName(id)));
1177 #else // !Q_OS_WINRT
1178 WCHAR name[LOCALE_NAME_MAX_LENGTH];
1179 LCIDToLocaleName(id, name, LOCALE_NAME_MAX_LENGTH, 0);
1180 return QLocale(QString::fromLatin1(getWinLocaleName(name)));
1181 #endif // Q_OS_WINRT
1182 }
1183
1184 QT_END_NAMESPACE
1185