summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qlocale.cpp426
-rw-r--r--src/corelib/tools/qlocale.h31
-rw-r--r--src/corelib/tools/qlocale_p.h25
-rw-r--r--tests/auto/qlocale/tst_qlocale.cpp27
-rwxr-xr-xutil/local_database/cldr2qlocalexml.py92
-rwxr-xr-xutil/local_database/qlocalexml2cpp.py49
-rw-r--r--util/local_database/xpathlite.py42
7 files changed, 636 insertions, 56 deletions
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 5debabb..fea96a7 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -658,6 +658,80 @@ static quint8 winSystemFirstDayOfWeek()
return 1;
}
+QString winCurrencySymbol(QLocale::CurrencySymbolFormat format)
+{
+ LCID lcid = GetUserDefaultLCID();
+ 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 QString();
+}
+
+static QString winFormatCurrency(const QVariant &in)
+{
+ QString value;
+ switch (in.type()) {
+ case QVariant::Int:
+ value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
+ in.toInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::UInt:
+ value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
+ in.toUInt(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::Double:
+ value = QLocalePrivate::doubleToString(QLatin1Char('0'), QLatin1Char('+'), QLatin1Char('-'),
+ QLatin1Char(' '), QLatin1Char(','), QLatin1Char('.'),
+ in.toDouble(), -1, QLocalePrivate::DFDecimal, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::LongLong:
+ value = QLocalePrivate::longLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'), QLatin1Char('-'),
+ in.toLongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ case QVariant::ULongLong:
+ value = QLocalePrivate::unsLongLongToString(QLatin1Char('0'), QLatin1Char(','), QLatin1Char('+'),
+ in.toULongLong(), -1, 10, -1, QLocale::OmitGroupSeparator);
+ break;
+ default:
+ return QString();
+ }
+
+ QVarLengthArray<wchar_t, 64> out(64);
+ LCID lcid = GetUserDefaultLCID();
+ int ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
+ NULL, out.data(), out.size());
+ if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ ret = ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
+ NULL, out.data(), 0);
+ out.resize(ret);
+ ::GetCurrencyFormat(lcid, 0, reinterpret_cast<const wchar_t *>(value.utf16()),
+ NULL, out.data(), out.size());
+ }
+
+ return QString::fromWCharArray(out.data());
+}
+
/*!
\since 4.6
Returns the fallback locale obtained from the system.
@@ -749,6 +823,10 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
return QVariant(winSystemPMText());
case FirstDayOfWeek:
return QVariant(winSystemFirstDayOfWeek());
+ case CurrencySymbol:
+ return QVariant(winCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())));
+ case FormatCurrency:
+ return QVariant(winFormatCurrency(in));
default:
break;
}
@@ -1184,6 +1262,57 @@ static quint8 macFirstDayOfWeek()
return day;
}
+static QString macCurrencySymbol(QLocale::CurrencySymbolFormat format)
+{
+ QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
+ switch (format) {
+ case QLocale::CurrencyIsoCode:
+ return QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleCurrencyCode)));
+ case QLocale::CurrencySymbol:
+ return QCFString::toQString(static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleCurrencySymbol)));
+ case QLocale::CurrencyDisplayName: {
+ CFStringRef code = static_cast<CFStringRef>(CFLocaleGetValue(locale, kCFLocaleCurrencyCode));
+ QCFType<CFStringRef> value = CFLocaleCopyDisplayNameForPropertyValue(locale, kCFLocaleCurrencyCode, code);
+ return QCFString::toQString(value);
+ }
+ default:
+ break;
+ }
+ return QString();
+}
+
+static QString macFormatCurrency(const QVariant &in)
+{
+ QCFType<CFNumberRef> value;
+ switch (in.type()) {
+ case QVariant::Int:
+ case QVariant::UInt: {
+ int v = in.toInt();
+ value = CFNumberCreate(NULL, kCFNumberIntType, &v);
+ break;
+ }
+ case QVariant::Double: {
+ double v = in.toInt();
+ value = CFNumberCreate(NULL, kCFNumberDoubleType, &v);
+ break;
+ }
+ case QVariant::LongLong:
+ case QVariant::ULongLong: {
+ qint64 v = in.toLongLong();
+ value = CFNumberCreate(NULL, kCFNumberLongLongType, &v);
+ break;
+ }
+ default:
+ return QString();
+ }
+
+ QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
+ QCFType<CFNumberFormatterRef> currencyFormatter =
+ CFNumberFormatterCreate(NULL, locale, kCFNumberFormatterCurrencyStyle);
+ QCFType<CFStringRef> result = CFNumberFormatterCreateStringWithNumber(NULL, currencyFormatter, value);
+ return QCFString::toQString(result);
+}
+
static void getMacPreferredLanguageAndCountry(QString *language, QString *country)
{
QCFType<CFArrayRef> languages = (CFArrayRef)CFPreferencesCopyValue(
@@ -1267,6 +1396,10 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
break;
case FirstDayOfWeek:
return QVariant(macFirstDayOfWeek());
+ case CurrencySymbol:
+ return QVariant(macCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())));
+ case FormatCurrency:
+ return macFormatCurrency(in);
default:
break;
}
@@ -1406,6 +1539,8 @@ Q_GLOBAL_STATIC(QLocalePrivate, globalLocalePrivate)
\value MeasurementSystem a QLocale::MeasurementSystem enum specifying the measurement system
\value AMText a string that represents the system AM designator associated with a 12-hour clock.
\value PMText a string that represents the system PM designator associated with a 12-hour clock.
+ \value CurrencySymbol a string that represents a currency in a format QLocale::CurrencyFormat.
+ \value FormatCurrency a localized string representation of a number with a currency symbol.
*/
/*!
@@ -3638,11 +3773,10 @@ QString QLocale::pmText() const
*/
-static QString qulltoa(qulonglong l, int base, const QLocalePrivate &locale)
+static QString qulltoa(qulonglong l, int base, const QChar _zero)
{
ushort buff[65]; // length of MAX_ULLONG in base 2
ushort *p = buff + 65;
- const QChar _zero = locale.zero();
if (base != 10 || _zero.unicode() == '0') {
while (l != 0) {
@@ -3671,9 +3805,9 @@ static QString qulltoa(qulonglong l, int base, const QLocalePrivate &locale)
return QString(reinterpret_cast<QChar *>(p), 65 - (p - buff));
}
-static QString qlltoa(qlonglong l, int base, const QLocalePrivate &locale)
+static QString qlltoa(qlonglong l, int base, const QChar zero)
{
- return qulltoa(l < 0 ? -l : l, base, locale);
+ return qulltoa(l < 0 ? -l : l, base, zero);
}
enum PrecisionMode {
@@ -3682,72 +3816,73 @@ enum PrecisionMode {
PMChopTrailingZeros = 0x03
};
-static QString &decimalForm(QString &digits, int decpt, uint precision,
+static QString &decimalForm(QChar zero, QChar decimal, QChar group,
+ QString &digits, int decpt, uint precision,
PrecisionMode pm,
bool always_show_decpt,
- bool thousands_group,
- const QLocalePrivate &locale)
+ bool thousands_group)
{
if (decpt < 0) {
for (int i = 0; i < -decpt; ++i)
- digits.prepend(locale.zero());
+ digits.prepend(zero);
decpt = 0;
}
else if (decpt > digits.length()) {
for (int i = digits.length(); i < decpt; ++i)
- digits.append(locale.zero());
+ digits.append(zero);
}
if (pm == PMDecimalDigits) {
uint decimal_digits = digits.length() - decpt;
for (uint i = decimal_digits; i < precision; ++i)
- digits.append(locale.zero());
+ digits.append(zero);
}
else if (pm == PMSignificantDigits) {
for (uint i = digits.length(); i < precision; ++i)
- digits.append(locale.zero());
+ digits.append(zero);
}
else { // pm == PMChopTrailingZeros
}
if (always_show_decpt || decpt < digits.length())
- digits.insert(decpt, locale.decimal());
+ digits.insert(decpt, decimal);
if (thousands_group) {
for (int i = decpt - 3; i > 0; i -= 3)
- digits.insert(i, locale.group());
+ digits.insert(i, group);
}
if (decpt == 0)
- digits.prepend(locale.zero());
+ digits.prepend(zero);
return digits;
}
-static QString &exponentForm(QString &digits, int decpt, uint precision,
- PrecisionMode pm,
- bool always_show_decpt,
- const QLocalePrivate &locale)
+static QString &exponentForm(QChar zero, QChar decimal, QChar exponential,
+ QChar group, QChar plus, QChar minus,
+ QString &digits, int decpt, uint precision,
+ PrecisionMode pm,
+ bool always_show_decpt)
{
int exp = decpt - 1;
if (pm == PMDecimalDigits) {
for (uint i = digits.length(); i < precision + 1; ++i)
- digits.append(locale.zero());
+ digits.append(zero);
}
else if (pm == PMSignificantDigits) {
for (uint i = digits.length(); i < precision; ++i)
- digits.append(locale.zero());
+ digits.append(zero);
}
else { // pm == PMChopTrailingZeros
}
if (always_show_decpt || digits.length() > 1)
- digits.insert(1, locale.decimal());
+ digits.insert(1, decimal);
- digits.append(locale.exponential());
- digits.append(locale.longLongToString(exp, 2, 10,
- -1, QLocalePrivate::AlwaysShowSign));
+ digits.append(exponential);
+ digits.append(QLocalePrivate::longLongToString(zero, group, plus, minus,
+ exp, 2, 10, -1, QLocalePrivate::AlwaysShowSign));
return digits;
}
@@ -3985,6 +4120,19 @@ QString QLocalePrivate::doubleToString(double d,
int width,
unsigned flags) const
{
+ return QLocalePrivate::doubleToString(zero(), plus(), minus(), exponential(),
+ group(), decimal(),
+ d, precision, form, width, flags);
+}
+
+QString QLocalePrivate::doubleToString(const QChar _zero, const QChar plus, const QChar minus,
+ const QChar exponential, const QChar group, const QChar decimal,
+ double d,
+ int precision,
+ DoubleForm form,
+ int width,
+ unsigned flags)
+{
if (precision == -1)
precision = 6;
if (width == -1)
@@ -4062,8 +4210,6 @@ QString QLocalePrivate::doubleToString(double d,
free(buff);
#endif // QT_QLOCALE_USES_FCVT
- const QChar _zero = zero();
-
if (_zero.unicode() != '0') {
ushort z = _zero.unicode() - '0';
for (int i = 0; i < digits.length(); ++i)
@@ -4073,14 +4219,15 @@ QString QLocalePrivate::doubleToString(double d,
bool always_show_decpt = (flags & Alternate || flags & ForcePoint);
switch (form) {
case DFExponent: {
- num_str = exponentForm(digits, decpt, precision, PMDecimalDigits,
- always_show_decpt, *this);
+ num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
+ digits, decpt, precision, PMDecimalDigits,
+ always_show_decpt);
break;
}
case DFDecimal: {
- num_str = decimalForm(digits, decpt, precision, PMDecimalDigits,
- always_show_decpt, flags & ThousandsGroup,
- *this);
+ num_str = decimalForm(_zero, decimal, group,
+ digits, decpt, precision, PMDecimalDigits,
+ always_show_decpt, flags & ThousandsGroup);
break;
}
case DFSignificantDigits: {
@@ -4088,12 +4235,13 @@ QString QLocalePrivate::doubleToString(double d,
PMSignificantDigits : PMChopTrailingZeros;
if (decpt != digits.length() && (decpt <= -4 || decpt > precision))
- num_str = exponentForm(digits, decpt, precision, mode,
- always_show_decpt, *this);
+ num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
+ digits, decpt, precision, mode,
+ always_show_decpt);
else
- num_str = decimalForm(digits, decpt, precision, mode,
- always_show_decpt, flags & ThousandsGroup,
- *this);
+ num_str = decimalForm(_zero, decimal, group,
+ digits, decpt, precision, mode,
+ always_show_decpt, flags & ThousandsGroup);
break;
}
}
@@ -4114,14 +4262,14 @@ QString QLocalePrivate::doubleToString(double d,
--num_pad_chars;
for (int i = 0; i < num_pad_chars; ++i)
- num_str.prepend(zero());
+ num_str.prepend(_zero);
}
// add sign
if (negative)
- num_str.prepend(minus());
+ num_str.prepend(minus);
else if (flags & QLocalePrivate::AlwaysShowSign)
- num_str.prepend(plus());
+ num_str.prepend(plus);
else if (flags & QLocalePrivate::BlankBeforePositive)
num_str.prepend(QLatin1Char(' '));
@@ -4135,6 +4283,16 @@ QString QLocalePrivate::longLongToString(qlonglong l, int precision,
int base, int width,
unsigned flags) const
{
+ return QLocalePrivate::longLongToString(zero(), group(), plus(), minus(),
+ l, precision, base, width, flags);
+}
+
+QString QLocalePrivate::longLongToString(const QChar zero, const QChar group,
+ const QChar plus, const QChar minus,
+ qlonglong l, int precision,
+ int base, int width,
+ unsigned flags)
+{
bool precision_not_specified = false;
if (precision == -1) {
precision_not_specified = true;
@@ -4151,20 +4309,20 @@ QString QLocalePrivate::longLongToString(qlonglong l, int precision,
QString num_str;
if (base == 10)
- num_str = qlltoa(l, base, *this);
+ num_str = qlltoa(l, base, zero);
else
- num_str = qulltoa(l, base, *this);
+ num_str = qulltoa(l, base, zero);
uint cnt_thousand_sep = 0;
if (flags & ThousandsGroup && base == 10) {
for (int i = num_str.length() - 3; i > 0; i -= 3) {
- num_str.insert(i, group());
+ num_str.insert(i, group);
++cnt_thousand_sep;
}
}
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
- num_str.prepend(base == 10 ? zero() : QChar::fromLatin1('0'));
+ num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
if ((flags & Alternate || flags & ShowBase)
&& base == 8
@@ -4194,7 +4352,7 @@ QString QLocalePrivate::longLongToString(qlonglong l, int precision,
num_pad_chars -= 2;
for (int i = 0; i < num_pad_chars; ++i)
- num_str.prepend(base == 10 ? zero() : QChar::fromLatin1('0'));
+ num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
}
if (flags & CapitalEorX)
@@ -4207,9 +4365,9 @@ QString QLocalePrivate::longLongToString(qlonglong l, int precision,
// add sign
if (negative)
- num_str.prepend(minus());
+ num_str.prepend(minus);
else if (flags & AlwaysShowSign)
- num_str.prepend(plus());
+ num_str.prepend(plus);
else if (flags & BlankBeforePositive)
num_str.prepend(QLatin1Char(' '));
@@ -4220,24 +4378,34 @@ QString QLocalePrivate::unsLongLongToString(qulonglong l, int precision,
int base, int width,
unsigned flags) const
{
+ return QLocalePrivate::unsLongLongToString(zero(), group(), plus(),
+ l, precision, base, width, flags);
+}
+
+QString QLocalePrivate::unsLongLongToString(const QChar zero, const QChar group,
+ const QChar plus,
+ qulonglong l, int precision,
+ int base, int width,
+ unsigned flags)
+{
bool precision_not_specified = false;
if (precision == -1) {
precision_not_specified = true;
precision = 1;
}
- QString num_str = qulltoa(l, base, *this);
+ QString num_str = qulltoa(l, base, zero);
uint cnt_thousand_sep = 0;
if (flags & ThousandsGroup && base == 10) {
for (int i = num_str.length() - 3; i > 0; i -=3) {
- num_str.insert(i, group());
+ num_str.insert(i, group);
++cnt_thousand_sep;
}
}
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
- num_str.prepend(base == 10 ? zero() : QChar::fromLatin1('0'));
+ num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
if ((flags & Alternate || flags & ShowBase)
&& base == 8
@@ -4261,7 +4429,7 @@ QString QLocalePrivate::unsLongLongToString(qulonglong l, int precision,
num_pad_chars -= 2;
for (int i = 0; i < num_pad_chars; ++i)
- num_str.prepend(base == 10 ? zero() : QChar::fromLatin1('0'));
+ num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
}
if (flags & CapitalEorX)
@@ -4274,7 +4442,7 @@ QString QLocalePrivate::unsLongLongToString(qulonglong l, int precision,
// add sign
if (flags & AlwaysShowSign)
- num_str.prepend(plus());
+ num_str.prepend(plus);
else if (flags & BlankBeforePositive)
num_str.prepend(QLatin1Char(' '));
@@ -4665,6 +4833,162 @@ qulonglong QLocalePrivate::bytearrayToUnsLongLong(const char *num, int base, boo
return l;
}
+/*!
+ \since 4.8
+
+ \enum QLocale::CurrencyFormat
+
+ Specifies the format of the currency symbol.
+
+ \value CurrencyIsoCode a ISO-4217 code of the currency.
+ \value CurrencySymbol a currency symbol.
+ \value CurrencyDisplayName a user readable name of the currency.
+*/
+
+/*!
+ \since 4.8
+ Returns a currency symbol according to the \a format.
+*/
+QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
+{
+#ifndef QT_NO_SYSTEMLOCALE
+ if (d() == systemPrivate()) {
+ QVariant res = systemLocale()->query(QSystemLocale::CurrencySymbol, format);
+ if (!res.isNull())
+ return res.toString();
+ }
+#endif
+ quint32 idx, size;
+ switch (format) {
+ case CurrencySymbol:
+ idx = d()->m_currency_symbol_idx;
+ size = d()->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;
+ return getLocaleListData(currency_display_name_data + idx, size, 0);
+ case CurrencyIsoCode: {
+ int len = 0;
+ const QLocalePrivate *d = this->d();
+ for (; len < 3; ++len)
+ if (!d->m_currency_iso_code[len])
+ break;
+ return len ? QString::fromLatin1(d->m_currency_iso_code, len) : QString();
+ }
+ }
+ return QString();
+}
+
+/*!
+ \fn QString QLocale::toCurrencyString(short) const
+ \since 4.8
+ \overload
+*/
+
+/*!
+ \fn QString QLocale::toCurrencyString(ushort) const
+ \since 4.8
+ \overload
+*/
+
+/*!
+ \fn QString QLocale::toCurrencyString(int) const
+ \since 4.8
+ \overload
+*/
+
+/*!
+ \fn QString QLocale::toCurrencyString(uint) const
+ \since 4.8
+ \overload
+*/
+/*!
+ \fn QString QLocale::toCurrencyString(float) const
+ \since 4.8
+ \overload
+*/
+
+/*!
+ \since 4.8
+
+ Returns a localized string representation of \a value as a currency.
+*/
+QString QLocale::toCurrencyString(qlonglong value) const
+{
+#ifndef QT_NO_SYSTEMLOCALE
+ if (d() == systemPrivate()) {
+ QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value);
+ 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;
+ value = -value;
+ }
+ QString str = d->longLongToString(value);
+ QString symbol = currencySymbol();
+ if (symbol.isEmpty())
+ symbol = currencySymbol(QLocale::CurrencyIsoCode);
+ QString format = getLocaleData(currency_format_data + idx, size);
+ return format.arg(str, symbol);
+}
+
+/*!
+ \since 4.8
+ \overload
+*/
+QString QLocale::toCurrencyString(qulonglong value) const
+{
+#ifndef QT_NO_SYSTEMLOCALE
+ if (d() == systemPrivate()) {
+ QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value);
+ 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);
+ QString symbol = currencySymbol();
+ if (symbol.isEmpty())
+ symbol = currencySymbol(QLocale::CurrencyIsoCode);
+ QString format = getLocaleData(currency_format_data + idx, size);
+ return format.arg(str, symbol);
+}
+
+QString QLocale::toCurrencyString(double value) const
+{
+#ifndef QT_NO_SYSTEMLOCALE
+ if (d() == systemPrivate()) {
+ QVariant res = systemLocale()->query(QSystemLocale::FormatCurrency, value);
+ 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;
+ value = -value;
+ }
+ QString str = d->doubleToString(value, d->m_currency_digits,
+ QLocalePrivate::DFDecimal);
+ QString symbol = currencySymbol();
+ if (symbol.isEmpty())
+ symbol = currencySymbol(QLocale::CurrencyIsoCode);
+ QString format = getLocaleData(currency_format_data + idx, size);
+ return format.arg(str, symbol);
+}
+
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index be58faf..af545f7 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -95,7 +95,9 @@ public:
PositiveSign, // QString
AMText, // QString
PMText, // QString
- FirstDayOfWeek // Qt::DayOfWeek
+ FirstDayOfWeek, // Qt::DayOfWeek
+ CurrencySymbol, // QString in: format
+ FormatCurrency // QString in: qlonglong, qulonglong or double
};
virtual QVariant query(QueryType type, QVariant in) const;
virtual QLocale fallbackLocale() const;
@@ -600,6 +602,12 @@ public:
};
Q_DECLARE_FLAGS(NumberOptions, NumberOption)
+ enum CurrencySymbolFormat {
+ CurrencyIsoCode,
+ CurrencySymbol,
+ CurrencyDisplayName
+ };
+
QLocale();
QLocale(const QString &name);
QLocale(Language language, Country country = AnyCountry);
@@ -671,6 +679,16 @@ public:
Qt::LayoutDirection textDirection() const;
+ QString currencySymbol(CurrencySymbolFormat = CurrencySymbol) const;
+ QString toCurrencyString(qlonglong) const;
+ QString toCurrencyString(qulonglong) const;
+ inline QString toCurrencyString(short) const;
+ inline QString toCurrencyString(ushort) const;
+ inline QString toCurrencyString(int) const;
+ inline QString toCurrencyString(uint) const;
+ QString toCurrencyString(double) const;
+ inline QString toCurrencyString(float) const;
+
inline bool operator==(const QLocale &other) const;
inline bool operator!=(const QLocale &other) const;
@@ -719,6 +737,17 @@ inline bool QLocale::operator==(const QLocale &other) const
inline bool QLocale::operator!=(const QLocale &other) const
{ return d() != other.d() || numberOptions() != other.numberOptions(); }
+inline QString QLocale::toCurrencyString(short i) const
+ { return toCurrencyString(qlonglong(i)); }
+inline QString QLocale::toCurrencyString(ushort i) const
+ { return toCurrencyString(qulonglong(i)); }
+inline QString QLocale::toCurrencyString(int i) const
+{ return toCurrencyString(qlonglong(i)); }
+inline QString QLocale::toCurrencyString(uint i) const
+{ return toCurrencyString(qulonglong(i)); }
+inline QString QLocale::toCurrencyString(float i) const
+{ return toCurrencyString(double(i)); }
+
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QLocale &);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QLocale &);
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index b2c86d8..283f722 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -108,6 +108,22 @@ public:
ParseGroupSeparators
};
+ static QString doubleToString(const QChar zero, const QChar plus,
+ const QChar minus, const QChar exponent,
+ const QChar group, const QChar decimal,
+ double d, int precision,
+ DoubleForm form,
+ int width, unsigned flags);
+ static QString longLongToString(const QChar zero, const QChar group,
+ const QChar plus, const QChar minus,
+ qint64 l, int precision, int base,
+ int width, unsigned flags);
+ static QString unsLongLongToString(const QChar zero, const QChar group,
+ const QChar plus,
+ quint64 l, int precision,
+ int base, int width,
+ unsigned flags);
+
QString doubleToString(double d,
int precision = -1,
DoubleForm form = DFSignificantDigits,
@@ -167,7 +183,14 @@ public:
quint16 m_narrow_day_names_idx, m_narrow_day_names_size;
quint16 m_am_idx, m_am_size;
quint16 m_pm_idx, m_pm_size;
- quint8 m_first_day_of_week : 3;
+ char m_currency_iso_code[3];
+ quint16 m_currency_symbol_idx, m_currency_symbol_size;
+ quint16 m_currency_display_name_idx, m_currency_display_name_size;
+ quint8 m_currency_format_idx, m_currency_format_size;
+ quint8 m_currency_negative_format_idx, m_currency_negative_format_size;
+ quint16 m_currency_digits : 2;
+ quint16 m_currency_rounding : 3;
+ quint16 m_first_day_of_week : 3;
};
inline char QLocalePrivate::digitToCLocale(const QChar &in) const
diff --git a/tests/auto/qlocale/tst_qlocale.cpp b/tests/auto/qlocale/tst_qlocale.cpp
index 16846de..08c96a0 100644
--- a/tests/auto/qlocale/tst_qlocale.cpp
+++ b/tests/auto/qlocale/tst_qlocale.cpp
@@ -140,6 +140,7 @@ private slots:
#endif
void ampm();
+ void currency();
private:
QString m_decimal, m_thousand, m_sdate, m_ldate, m_time;
@@ -1095,6 +1096,11 @@ void tst_QLocale::macDefaultLocale()
const QString timeString = locale.toString(QTime(1,2,3), QLocale::LongFormat);
QVERIFY(timeString.contains(QString("1:02:03")));
+ QCOMPARE(locale.toCurrencyString(qulonglong(1234)), QString("$1,234"));
+ QCOMPARE(locale.toCurrencyString(qlonglong(-1234)), QString("$-1,234"));
+ QCOMPARE(locale.toCurrencyString(double(1234.56)), QString("$1,234.56"));
+ QCOMPARE(locale.toCurrencyString(double(-1234.56)), QString("$-1,234.56"));
+
// Depending on the configured time zone, the time string might not
// contain a GMT specifier. (Sometimes it just names the zone, like "CEST")
if (timeString.contains(QString("GMT"))) {
@@ -2123,5 +2129,26 @@ void tst_QLocale::symbianSystemLocale()
}
#endif
+void tst_QLocale::currency()
+{
+ const QLocale c(QLocale::C);
+ QCOMPARE(c.toCurrencyString(qulonglong(1234)), QString("1234"));
+ QCOMPARE(c.toCurrencyString(qlonglong(-1234)), QString("-1234"));
+ QCOMPARE(c.toCurrencyString(double(1234.56)), QString("1234.56"));
+ QCOMPARE(c.toCurrencyString(double(-1234.56)), QString("-1234.56"));
+
+ const QLocale ru_RU("ru_RU");
+ QCOMPARE(ru_RU.toCurrencyString(qulonglong(1234)), QString::fromUtf8("1234\xc2\xa0\xd1\x80\xd1\x83\xd0\xb1."));
+ QCOMPARE(ru_RU.toCurrencyString(qlonglong(-1234)), QString::fromUtf8("-1234\xc2\xa0\xd1\x80\xd1\x83\xd0\xb1."));
+ QCOMPARE(ru_RU.toCurrencyString(double(1234.56)), QString::fromUtf8("1234,56\xc2\xa0\xd1\x80\xd1\x83\xd0\xb1."));
+ QCOMPARE(ru_RU.toCurrencyString(double(-1234.56)), QString::fromUtf8("-1234,56\xc2\xa0\xd1\x80\xd1\x83\xd0\xb1."));
+
+ const QLocale de_DE("de_DE");
+ QCOMPARE(de_DE.toCurrencyString(qulonglong(1234)), QString::fromUtf8("1234""\xc2\xa0\xe2\x82\xac"));
+ QCOMPARE(de_DE.toCurrencyString(qlonglong(-1234)), QString::fromUtf8("-1234""\xc2\xa0\xe2\x82\xac"));
+ QCOMPARE(de_DE.toCurrencyString(double(1234.56)), QString::fromUtf8("1234,56""\xc2\xa0\xe2\x82\xac"));
+ QCOMPARE(de_DE.toCurrencyString(double(-1234.56)), QString::fromUtf8("-1234,56""\xc2\xa0\xe2\x82\xac"));
+}
+
QTEST_APPLESS_MAIN(tst_QLocale)
#include "tst_qlocale.moc"
diff --git a/util/local_database/cldr2qlocalexml.py b/util/local_database/cldr2qlocalexml.py
index 8b5ec16..311cf4e 100755
--- a/util/local_database/cldr2qlocalexml.py
+++ b/util/local_database/cldr2qlocalexml.py
@@ -50,6 +50,37 @@ import re
findEntry = xpathlite.findEntry
findEntryInFile = xpathlite._findEntryInFile
+findTagsInFile = xpathlite.findTagsInFile
+
+def parse_number_format(patterns, data):
+ # this is a very limited parsing of the number format for currency only.
+ def skip_repeating_pattern(x):
+ p = x.replace('0', '#').replace(',', '').replace('.', '')
+ seen = False
+ result = ''
+ for c in p:
+ if c == '#':
+ if seen:
+ continue
+ seen = True
+ else:
+ seen = False
+ result = result + c
+ return result
+ patterns = patterns.split(';')
+ result = []
+ for pattern in patterns:
+ pattern = skip_repeating_pattern(pattern)
+ pattern = pattern.replace('#', "%1")
+ # according to http://www.unicode.org/reports/tr35/#Number_Format_Patterns
+ # there can be doubled or trippled currency sign, however none of the
+ # locales use that.
+ pattern = pattern.replace(u'\xa4', "%2")
+ pattern = pattern.replace("''", "###").replace("'", '').replace("###", "'")
+ pattern = pattern.replace('-', data['minus'])
+ pattern = pattern.replace('+', data['plus'])
+ result.append(pattern)
+ return result
def ordStr(c):
if len(c) == 1:
@@ -123,11 +154,36 @@ def generateLocaleInfo(path):
result['language_id'] = language_id
result['country_id'] = country_id
+ supplementalPath = dir_name + "/../supplemental/supplementalData.xml"
+ currencies = findTagsInFile(supplementalPath, "currencyData/region[iso3166=%s]"%country_code);
+ result['currencyIsoCode'] = ''
+ result['currencyDigits'] = 2
+ result['currencyRounding'] = 1
+ if currencies:
+ for e in currencies:
+ if e[0] == 'currency':
+ tender = True
+ t = filter(lambda x: x[0] == 'tender', e[1])
+ if t and t[0][1] == 'false':
+ tender = False;
+ if tender and not filter(lambda x: x[0] == 'to', e[1]):
+ result['currencyIsoCode'] = filter(lambda x: x[0] == 'iso4217', e[1])[0][1]
+ break
+ if result['currencyIsoCode']:
+ t = findTagsInFile(supplementalPath, "currencyData/fractions/info[iso4217=%s]"%result['currencyIsoCode']);
+ if t and t[0][0] == 'info':
+ result['currencyDigits'] = int(filter(lambda x: x[0] == 'digits', t[0][1])[0][1])
+ result['currencyRounding'] = int(filter(lambda x: x[0] == 'rounding', t[0][1])[0][1])
numbering_system = None
try:
numbering_system = findEntry(path, "numbers/defaultNumberingSystem")
except:
pass
+ def findEntryDef(path, xpath, value=''):
+ try:
+ return findEntry(path, xpath)
+ except xpathlite.Error:
+ return value
def get_number_in_system(path, xpath, numbering_system):
if numbering_system:
try:
@@ -150,6 +206,27 @@ def generateLocaleInfo(path):
result['longTimeFormat'] = convert_date(findEntry(path, "dates/calendars/calendar[gregorian]/timeFormats/timeFormatLength[full]/timeFormat/pattern"))
result['shortTimeFormat'] = convert_date(findEntry(path, "dates/calendars/calendar[gregorian]/timeFormats/timeFormatLength[short]/timeFormat/pattern"))
+ currency_format = get_number_in_system(path, "numbers/currencyFormats/currencyFormatLength/currencyFormat/pattern", numbering_system)
+ currency_format = parse_number_format(currency_format, result)
+ result['currencyFormat'] = currency_format[0]
+ result['currencyNegativeFormat'] = ''
+ if len(currency_format) > 1:
+ result['currencyNegativeFormat'] = currency_format[1]
+
+ result['currencySymbol'] = ''
+ result['currencyDisplayName'] = ''
+ if result['currencyIsoCode']:
+ result['currencySymbol'] = findEntryDef(path, "numbers/currencies/currency[%s]/symbol" % result['currencyIsoCode'])
+ display_name_path = "numbers/currencies/currency[%s]/displayName" % result['currencyIsoCode']
+ result['currencyDisplayName'] \
+ = findEntryDef(path, display_name_path) + ";" \
+ + findEntryDef(path, display_name_path + "[count=zero]") + ";" \
+ + findEntryDef(path, display_name_path + "[count=one]") + ";" \
+ + findEntryDef(path, display_name_path + "[count=two]") + ";" \
+ + findEntryDef(path, display_name_path + "[count=few]") + ";" \
+ + findEntryDef(path, display_name_path + "[count=many]") + ";" \
+ + findEntryDef(path, display_name_path + "[count=other]") + ";"
+
standalone_long_month_path = "dates/calendars/calendar[gregorian]/months/monthContext[stand-alone]/monthWidth[wide]/month"
result['standaloneLongMonths'] \
= findEntry(path, standalone_long_month_path + "[1]") + ";" \
@@ -300,7 +377,6 @@ def generateLocaleInfo(path):
+ findEntry(path, standalone_narrow_day_path + "[fri]") + ";" \
+ findEntry(path, standalone_narrow_day_path + "[sat]") + ";"
-
return result
def addEscapes(s):
@@ -536,6 +612,13 @@ print \
<standaloneLongDays>Sunday;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday;</standaloneLongDays>\n\
<standaloneShortDays>Sun;Mon;Tue;Wed;Thu;Fri;Sat;</standaloneShortDays>\n\
<standaloneNarrowDays>S;M;T;W;T;F;S;</standaloneNarrowDays>\n\
+ <currencyIsoCode></currencyIsoCode>\n\
+ <currencySymbol></currencySymbol>\n\
+ <currencyDisplayName>;;;;;;;</currencyDisplayName>\n\
+ <currencyDigits>2</currencyDigits>\n\
+ <currencyRounding>1</currencyRounding>\n\
+ <currencyFormat>%1%2</currencyFormat>\n\
+ <currencyNegativeFormat></currencyNegativeFormat>\n\
</locale>"
for key in locale_keys:
@@ -573,6 +656,13 @@ for key in locale_keys:
print " <standaloneLongDays>" + l['standaloneLongDays'].encode('utf-8') + "</standaloneLongDays>"
print " <standaloneShortDays>" + l['standaloneShortDays'].encode('utf-8') + "</standaloneShortDays>"
print " <standaloneNarrowDays>" + l['standaloneNarrowDays'].encode('utf-8') + "</standaloneNarrowDays>"
+ print " <currencyIsoCode>" + l['currencyIsoCode'].encode('utf-8') + "</currencyIsoCode>"
+ print " <currencySymbol>" + l['currencySymbol'].encode('utf-8') + "</currencySymbol>"
+ print " <currencyDisplayName>" + l['currencyDisplayName'].encode('utf-8') + "</currencyDisplayName>"
+ print " <currencyDigits>" + str(l['currencyDigits']) + "</currencyDigits>"
+ print " <currencyRounding>" + str(l['currencyRounding']) + "</currencyRounding>"
+ print " <currencyFormat>" + l['currencyFormat'].encode('utf-8') + "</currencyFormat>"
+ print " <currencyNegativeFormat>" + l['currencyNegativeFormat'].encode('utf-8') + "</currencyNegativeFormat>"
print " </locale>"
print " </localeList>"
print "</localeDatabase>"
diff --git a/util/local_database/qlocalexml2cpp.py b/util/local_database/qlocalexml2cpp.py
index 9bc3c7e..494daf2 100755
--- a/util/local_database/qlocalexml2cpp.py
+++ b/util/local_database/qlocalexml2cpp.py
@@ -223,6 +223,13 @@ class Locale:
self.longDays = eltText(firstChildElt(elt, "longDays"))
self.shortDays = eltText(firstChildElt(elt, "shortDays"))
self.narrowDays = eltText(firstChildElt(elt, "narrowDays"))
+ self.currencyIsoCode = eltText(firstChildElt(elt, "currencyIsoCode"))
+ self.currencySymbol = eltText(firstChildElt(elt, "currencySymbol"))
+ self.currencyDisplayName = eltText(firstChildElt(elt, "currencyDisplayName"))
+ self.currencyDigits = int(eltText(firstChildElt(elt, "currencyDigits")))
+ self.currencyRounding = int(eltText(firstChildElt(elt, "currencyRounding")))
+ self.currencyFormat = eltText(firstChildElt(elt, "currencyFormat"))
+ self.currencyNegativeFormat = eltText(firstChildElt(elt, "currencyNegativeFormat"))
def loadLocaleMap(doc, language_map, country_map):
result = {}
@@ -336,6 +343,11 @@ def printEscapedString(s):
print escapedString(s);
+def currencyIsoCodeData(s):
+ if s:
+ return ",".join(map(lambda x: str(ord(x)), s))
+ return "0,0,0"
+
def main():
doc = xml.dom.minidom.parse("locale.xml")
language_map = loadLanguageMap(doc)
@@ -389,6 +401,9 @@ def main():
days_data = StringData()
am_data = StringData()
pm_data = StringData()
+ currency_symbol_data = StringData()
+ currency_display_name_data = StringData()
+ currency_format_data = StringData()
# Locale data
print "static const QLocalePrivate locale_data[] = {"
@@ -402,7 +417,7 @@ def main():
for key in locale_keys:
l = locale_map[key]
- print " { %6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%6d }, // %s/%s" \
+ print " { %6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s, {%s}, %s,%s,%s,%s,%6d,%6d,%6d }, // %s/%s" \
% (key[0], key[1],
l.decimal,
l.group,
@@ -430,10 +445,17 @@ def main():
days_data.append(l.narrowDays),
am_data.append(l.am),
pm_data.append(l.pm),
+ currencyIsoCodeData(l.currencyIsoCode),
+ currency_symbol_data.append(l.currencySymbol),
+ currency_display_name_data.append(l.currencyDisplayName),
+ currency_format_data.append(l.currencyFormat),
+ currency_format_data.append(l.currencyNegativeFormat),
+ l.currencyDigits,
+ l.currencyRounding,
l.firstDayOfWeek,
l.language,
l.country)
- print " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0 } // trailing 0s"
+ print " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, {0,0,0}, 0,0, 0,0, 0,0, 0,0, 0, 0, 0 } // trailing 0s"
print "};"
print
@@ -494,6 +516,29 @@ def main():
print
+ # Currency symbol data
+ #check_static_char_array_length("currency_symbol", currency_symbol_data.data)
+ print "static const ushort currency_symbol_data[] = {"
+ print wrap_list(currency_symbol_data.data)
+ print "};"
+
+ print
+
+ # Currency display name data
+ #check_static_char_array_length("currency_display_name", currency_display_name_data.data)
+ print "static const ushort currency_display_name_data[] = {"
+ print wrap_list(currency_display_name_data.data)
+ print "};"
+
+ print
+
+ # Currency format data
+ #check_static_char_array_length("currency_format", currency_format_data.data)
+ print "static const ushort currency_format_data[] = {"
+ print wrap_list(currency_format_data.data)
+ print "};"
+
+ print
# Language name list
print "static const char language_name_list[] ="
print "\"Default\\0\""
diff --git a/util/local_database/xpathlite.py b/util/local_database/xpathlite.py
index 95e6711..502d85d 100644
--- a/util/local_database/xpathlite.py
+++ b/util/local_database/xpathlite.py
@@ -87,6 +87,48 @@ def findChild(parent, tag_name, arg_name=None, arg_value=None, draft=None):
return node
return False
+def findTagsInFile(file, path):
+ doc = False
+ if doc_cache.has_key(file):
+ doc = doc_cache[file]
+ else:
+ doc = xml.dom.minidom.parse(file)
+ doc_cache[file] = doc
+
+ elt = doc.documentElement
+ tag_spec_list = path.split("/")
+ last_entry = None
+ for i in range(len(tag_spec_list)):
+ tag_spec = tag_spec_list[i]
+ tag_name = tag_spec
+ arg_name = 'type'
+ arg_value = ''
+ left_bracket = tag_spec.find('[')
+ if left_bracket != -1:
+ tag_name = tag_spec[:left_bracket]
+ arg_value = tag_spec[left_bracket+1:-1].split("=")
+ if len(arg_value) == 2:
+ arg_name = arg_value[0]
+ arg_value = arg_value[1]
+ else:
+ arg_value = arg_value[0]
+ elt = findChild(elt, tag_name, arg_name, arg_value)
+ if not elt:
+ return None
+ ret = []
+ if elt.childNodes:
+ for node in elt.childNodes:
+ if node.attributes:
+ element = [node.nodeName, None]
+ element[1] = node.attributes.items()
+ ret.append(element)
+ else:
+ if elt.attributes:
+ element = [elt.nodeName, None]
+ element[1] = elt.attributes.items()
+ ret.append(element)
+ return ret
+
def _findEntryInFile(file, path, draft=None, attribute=None):
doc = False
if doc_cache.has_key(file):