QSystemLocale: add group size query
Add a GroupSizes struct and a corresponding query type to QSystemLocale that would return a struct of form struct { int first, higher, least; } by consulting suitable platform-specific APIs. Fixes: QTBUG-109955 Change-Id: I2deee814f161ac914f810080866eea1cc432acbe Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
a317b28d87
commit
5465e4723d
@ -1108,6 +1108,29 @@ QString QLocaleData::exponentSeparator() const
|
|||||||
return exponential().getData(single_character_data);
|
return exponential().getData(single_character_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QLocaleData::GroupSizes QLocaleData::groupSizes() const
|
||||||
|
{
|
||||||
|
#ifndef QT_NO_SYSTEMLOCALE
|
||||||
|
if (this == &systemLocaleData) {
|
||||||
|
QVariant queryResult = systemLocale()->query(QSystemLocale::Grouping);
|
||||||
|
if (!queryResult.isNull()) {
|
||||||
|
QLocaleData::GroupSizes sysGroupSizes =
|
||||||
|
queryResult.value<QLocaleData::GroupSizes>();
|
||||||
|
if (sysGroupSizes.first <= 0)
|
||||||
|
sysGroupSizes.first = m_grouping_first;
|
||||||
|
if (sysGroupSizes.higher <= 0)
|
||||||
|
sysGroupSizes.higher = m_grouping_higher;
|
||||||
|
if (sysGroupSizes.least <= 0)
|
||||||
|
sysGroupSizes.least = m_grouping_least;
|
||||||
|
return sysGroupSizes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return { m_grouping_first,
|
||||||
|
m_grouping_higher,
|
||||||
|
m_grouping_least };
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -3992,11 +4015,12 @@ QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
|
|||||||
// Set bias to everything added to exponent form but not
|
// Set bias to everything added to exponent form but not
|
||||||
// decimal, minus the converse.
|
// decimal, minus the converse.
|
||||||
|
|
||||||
|
const QLocaleData::GroupSizes grouping = groupSizes();
|
||||||
// Exponent adds separator, sign and digits:
|
// Exponent adds separator, sign and digits:
|
||||||
int bias = 2 + minExponentDigits;
|
int bias = 2 + minExponentDigits;
|
||||||
// Decimal form may get grouping separators inserted:
|
// Decimal form may get grouping separators inserted:
|
||||||
if (groupDigits && decpt >= m_grouping_top + m_grouping_least)
|
if (groupDigits && decpt >= grouping.first + grouping.least)
|
||||||
bias -= (decpt - m_grouping_least) / m_grouping_higher + 1;
|
bias -= (decpt - grouping.least) / grouping.higher + 1;
|
||||||
// X = decpt - 1 needs two digits if decpt > 10:
|
// X = decpt - 1 needs two digits if decpt > 10:
|
||||||
if (decpt > 10 && minExponentDigits == 1)
|
if (decpt > 10 && minExponentDigits == 1)
|
||||||
++bias;
|
++bias;
|
||||||
@ -4081,11 +4105,12 @@ QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision,
|
|||||||
digits.insert(decpt * digitWidth, decimalPoint());
|
digits.insert(decpt * digitWidth, decimalPoint());
|
||||||
|
|
||||||
if (groupDigits) {
|
if (groupDigits) {
|
||||||
|
const QLocaleData::GroupSizes grouping = groupSizes();
|
||||||
const QString group = groupSeparator();
|
const QString group = groupSeparator();
|
||||||
qsizetype i = decpt - m_grouping_least;
|
qsizetype i = decpt - grouping.least;
|
||||||
if (i >= m_grouping_top) {
|
if (i >= grouping.first) {
|
||||||
digits.insert(i * digitWidth, group);
|
digits.insert(i * digitWidth, group);
|
||||||
while ((i -= m_grouping_higher) > 0)
|
while ((i -= grouping.higher) > 0)
|
||||||
digits.insert(i * digitWidth, group);
|
digits.insert(i * digitWidth, group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4188,12 +4213,13 @@ QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int
|
|||||||
qsizetype usedWidth = digitCount + prefix.size();
|
qsizetype usedWidth = digitCount + prefix.size();
|
||||||
|
|
||||||
if (base == 10 && flags & GroupDigits) {
|
if (base == 10 && flags & GroupDigits) {
|
||||||
|
const QLocaleData::GroupSizes grouping = groupSizes();
|
||||||
const QString group = groupSeparator();
|
const QString group = groupSeparator();
|
||||||
qsizetype i = digitCount - m_grouping_least;
|
qsizetype i = digitCount - grouping.least;
|
||||||
if (i >= m_grouping_top) {
|
if (i >= grouping.first) {
|
||||||
numStr.insert(i * digitWidth, group);
|
numStr.insert(i * digitWidth, group);
|
||||||
++usedWidth;
|
++usedWidth;
|
||||||
while ((i -= m_grouping_higher) > 0) {
|
while ((i -= grouping.higher) > 0) {
|
||||||
numStr.insert(i * digitWidth, group);
|
numStr.insert(i * digitWidth, group);
|
||||||
++usedWidth;
|
++usedWidth;
|
||||||
}
|
}
|
||||||
@ -4462,6 +4488,7 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
|
|||||||
qsizetype digitsInGroup = 0;
|
qsizetype digitsInGroup = 0;
|
||||||
qsizetype last_separator_idx = -1;
|
qsizetype last_separator_idx = -1;
|
||||||
qsizetype start_of_digits_idx = -1;
|
qsizetype start_of_digits_idx = -1;
|
||||||
|
const QLocaleData::GroupSizes grouping = groupSizes();
|
||||||
|
|
||||||
// Floating-point details (non-integer modes):
|
// Floating-point details (non-integer modes):
|
||||||
qsizetype decpt_idx = -1;
|
qsizetype decpt_idx = -1;
|
||||||
@ -4511,13 +4538,13 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
|
|||||||
|
|
||||||
if (last_separator_idx == -1) {
|
if (last_separator_idx == -1) {
|
||||||
// Check distance from the beginning of the digits:
|
// Check distance from the beginning of the digits:
|
||||||
if (start_of_digits_idx == -1 || m_grouping_top > digitsInGroup
|
if (start_of_digits_idx == -1 || grouping.first > digitsInGroup
|
||||||
|| digitsInGroup >= m_grouping_least + m_grouping_top) {
|
|| digitsInGroup >= grouping.least + grouping.first) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check distance from the last separator:
|
// Check distance from the last separator:
|
||||||
if (digitsInGroup != m_grouping_higher)
|
if (digitsInGroup != grouping.higher)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4526,7 +4553,7 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
|
|||||||
} else if (mode != IntegerMode && (out == '.' || idx == exponent_idx)
|
} else if (mode != IntegerMode && (out == '.' || idx == exponent_idx)
|
||||||
&& last_separator_idx != -1) {
|
&& last_separator_idx != -1) {
|
||||||
// Were there enough digits since the last group separator?
|
// Were there enough digits since the last group separator?
|
||||||
if (digitsInGroup != m_grouping_least)
|
if (digitsInGroup != grouping.least)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// stop processing separators
|
// stop processing separators
|
||||||
@ -4543,7 +4570,7 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
|
|||||||
|
|
||||||
if (!number_options.testFlag(QLocale::RejectGroupSeparator) && last_separator_idx != -1) {
|
if (!number_options.testFlag(QLocale::RejectGroupSeparator) && last_separator_idx != -1) {
|
||||||
// Were there enough digits since the last group separator?
|
// Were there enough digits since the last group separator?
|
||||||
if (digitsInGroup != m_grouping_least)
|
if (digitsInGroup != grouping.least)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,6 +432,28 @@ static QVariant macToQtFormat(QStringView sys_fmt)
|
|||||||
return !result.isEmpty() ? QVariant::fromValue(result) : QVariant();
|
return !result.isEmpty() ? QVariant::fromValue(result) : QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QVariant getGroupingSizes()
|
||||||
|
{
|
||||||
|
// It does not seem like you can directly query the group sizes from CFLocale as there
|
||||||
|
// is no key that corresponds to it, see:
|
||||||
|
// https://developer.apple.com/documentation/corefoundation/cflocalekey
|
||||||
|
// We have to create a number formatter for the locale and query the data from there.
|
||||||
|
// see: https://developer.apple.com/documentation/corefoundation/1390801-cfnumberformattercopyproperty
|
||||||
|
QLocaleData::GroupSizes sizes;
|
||||||
|
QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
|
||||||
|
QCFType<CFNumberFormatterRef> numberFormatter =
|
||||||
|
CFNumberFormatterCreate(NULL, locale, kCFNumberFormatterDecimalStyle);
|
||||||
|
CFTypeRef numTref =
|
||||||
|
CFNumberFormatterCopyProperty(numberFormatter, kCFNumberFormatterGroupingSize);
|
||||||
|
CFNumberRef num = static_cast<CFNumberRef>(numTref);
|
||||||
|
int value;
|
||||||
|
if (CFNumberGetValue(num, kCFNumberIntType, &value) && value > 0) {
|
||||||
|
sizes.least = value;
|
||||||
|
sizes.higher = value;
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
static QVariant getMacDateFormat(CFDateFormatterStyle style)
|
static QVariant getMacDateFormat(CFDateFormatterStyle style)
|
||||||
{
|
{
|
||||||
QCFType<CFLocaleRef> l = CFLocaleCopyCurrent();
|
QCFType<CFLocaleRef> l = CFLocaleCopyCurrent();
|
||||||
@ -594,6 +616,8 @@ QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
|
|||||||
return getLocaleValue<QLocalePrivate::codeToScript>(kCFLocaleScriptCode);
|
return getLocaleValue<QLocalePrivate::codeToScript>(kCFLocaleScriptCode);
|
||||||
case DecimalPoint:
|
case DecimalPoint:
|
||||||
return getCFLocaleValue(kCFLocaleDecimalSeparator);
|
return getCFLocaleValue(kCFLocaleDecimalSeparator);
|
||||||
|
case Grouping:
|
||||||
|
return getGroupingSizes();
|
||||||
case GroupSeparator:
|
case GroupSeparator:
|
||||||
return getCFLocaleValue(kCFLocaleGroupingSeparator);
|
return getCFLocaleValue(kCFLocaleGroupingSeparator);
|
||||||
case DateFormatLong:
|
case DateFormatLong:
|
||||||
|
@ -125,6 +125,7 @@ public:
|
|||||||
LanguageId, // uint
|
LanguageId, // uint
|
||||||
TerritoryId, // uint
|
TerritoryId, // uint
|
||||||
DecimalPoint, // QString
|
DecimalPoint, // QString
|
||||||
|
Grouping, // QLocaleData::GroupSizes
|
||||||
GroupSeparator, // QString (empty QString means: don't group digits)
|
GroupSeparator, // QString (empty QString means: don't group digits)
|
||||||
ZeroDigit, // QString
|
ZeroDigit, // QString
|
||||||
NegativeSign, // QString
|
NegativeSign, // QString
|
||||||
@ -174,6 +175,12 @@ public:
|
|||||||
|
|
||||||
virtual QLocale fallbackLocale() const;
|
virtual QLocale fallbackLocale() const;
|
||||||
inline qsizetype fallbackLocaleIndex() const;
|
inline qsizetype fallbackLocaleIndex() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline const QSharedDataPointer<QLocalePrivate> localeData(const QLocale &locale) const
|
||||||
|
{
|
||||||
|
return locale.d;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Q_DECLARE_TYPEINFO(QSystemLocale::QueryType, Q_PRIMITIVE_TYPE);
|
Q_DECLARE_TYPEINFO(QSystemLocale::QueryType, Q_PRIMITIVE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QSystemLocale::CurrencyToStringArgument, Q_RELOCATABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QSystemLocale::CurrencyToStringArgument, Q_RELOCATABLE_TYPE);
|
||||||
@ -274,6 +281,14 @@ public:
|
|||||||
|
|
||||||
enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
|
enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
|
||||||
|
|
||||||
|
struct GroupSizes
|
||||||
|
{
|
||||||
|
int first = 0;
|
||||||
|
int higher = 0;
|
||||||
|
int least = 0;
|
||||||
|
bool isValid() const { return least > 0 && higher > first && first > 0; }
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum PrecisionMode {
|
enum PrecisionMode {
|
||||||
PMDecimalDigits = 0x01,
|
PMDecimalDigits = 0x01,
|
||||||
@ -397,6 +412,7 @@ public:
|
|||||||
[[nodiscard]] QString positiveSign() const;
|
[[nodiscard]] QString positiveSign() const;
|
||||||
[[nodiscard]] QString negativeSign() const;
|
[[nodiscard]] QString negativeSign() const;
|
||||||
[[nodiscard]] QString exponentSeparator() const;
|
[[nodiscard]] QString exponentSeparator() const;
|
||||||
|
[[nodiscard]] Q_CORE_EXPORT GroupSizes groupSizes() const;
|
||||||
|
|
||||||
struct DataRange
|
struct DataRange
|
||||||
{
|
{
|
||||||
@ -498,11 +514,13 @@ public:
|
|||||||
quint8 m_first_day_of_week : 3;
|
quint8 m_first_day_of_week : 3;
|
||||||
quint8 m_weekend_start : 3;
|
quint8 m_weekend_start : 3;
|
||||||
quint8 m_weekend_end : 3;
|
quint8 m_weekend_end : 3;
|
||||||
quint8 m_grouping_top : 2; // Don't group until more significant group has this many digits.
|
quint8 m_grouping_first : 2; // Don't group until more significant group has this many digits.
|
||||||
quint8 m_grouping_higher : 3; // Number of digits between grouping separators
|
quint8 m_grouping_higher : 3; // Number of digits between grouping separators
|
||||||
quint8 m_grouping_least : 3; // Number of digits after last grouping separator (before decimal).
|
quint8 m_grouping_least : 3; // Number of digits after last grouping separator (before decimal).
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_TYPEINFO(QLocaleData::GroupSizes, Q_PRIMITIVE_TYPE);
|
||||||
|
|
||||||
class QLocalePrivate
|
class QLocalePrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -143,6 +143,8 @@ QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case DecimalPoint:
|
case DecimalPoint:
|
||||||
return lc_numeric.decimalPoint();
|
return lc_numeric.decimalPoint();
|
||||||
|
case Grouping:
|
||||||
|
return QVariant::fromValue(lc_numeric.d->m_data->groupSizes());
|
||||||
case GroupSeparator:
|
case GroupSeparator:
|
||||||
return lc_numeric.groupSeparator();
|
return lc_numeric.groupSeparator();
|
||||||
case ZeroDigit:
|
case ZeroDigit:
|
||||||
|
@ -108,6 +108,7 @@ struct QSystemLocalePrivate
|
|||||||
|
|
||||||
QVariant zeroDigit();
|
QVariant zeroDigit();
|
||||||
QVariant decimalPoint();
|
QVariant decimalPoint();
|
||||||
|
QVariant groupingSizes();
|
||||||
QVariant groupSeparator();
|
QVariant groupSeparator();
|
||||||
QVariant negativeSign();
|
QVariant negativeSign();
|
||||||
QVariant positiveSign();
|
QVariant positiveSign();
|
||||||
@ -145,6 +146,7 @@ private:
|
|||||||
LCID lcid;
|
LCID lcid;
|
||||||
SubstitutionType substitutionType = SUnknown;
|
SubstitutionType substitutionType = SUnknown;
|
||||||
QString zero; // cached value for zeroDigit()
|
QString zero; // cached value for zeroDigit()
|
||||||
|
QLocaleData::GroupSizes sizes; // cached value for groupingSizes()
|
||||||
|
|
||||||
int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
|
int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
|
||||||
QVariant getLocaleInfo(LCTYPE type);
|
QVariant getLocaleInfo(LCTYPE type);
|
||||||
@ -319,6 +321,46 @@ QVariant QSystemLocalePrivate::decimalPoint()
|
|||||||
return nullIfEmpty(getLocaleInfo(LOCALE_SDECIMAL).toString());
|
return nullIfEmpty(getLocaleInfo(LOCALE_SDECIMAL).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant QSystemLocalePrivate::groupingSizes()
|
||||||
|
{
|
||||||
|
if (sizes.higher == 0) {
|
||||||
|
wchar_t grouping[10];
|
||||||
|
/*
|
||||||
|
* Nine digits/semicolons plus a terminator.
|
||||||
|
|
||||||
|
* https://learn.microsoft.com/en-us/windows/win32/intl/locale-sgrouping
|
||||||
|
* "Sizes for each group of digits to the left of the decimal. The maximum
|
||||||
|
* number of characters allowed for this string is ten, including a
|
||||||
|
* terminating null character."
|
||||||
|
*/
|
||||||
|
int dataSize = getLocaleInfo(LOCALE_SGROUPING, grouping, int(std::size(grouping)));
|
||||||
|
if (dataSize) {
|
||||||
|
// MS does not seem to include {first} so it will always be NAN.
|
||||||
|
QString sysGroupingStr = QString::fromWCharArray(grouping, dataSize);
|
||||||
|
auto tokenized = sysGroupingStr.tokenize(u";");
|
||||||
|
int width[2] = {0, 0};
|
||||||
|
int index = 0;
|
||||||
|
for (const auto tok : tokenized) {
|
||||||
|
bool ok = false;
|
||||||
|
int value = tok.toInt(&ok);
|
||||||
|
if (!ok || !value || index >= 2)
|
||||||
|
break;
|
||||||
|
width[index++] = value;
|
||||||
|
}
|
||||||
|
// The MS docs allow patterns Qt doesn't support, so we treat "X;Y" as "X;Y;0"
|
||||||
|
// and "X" as "X;0" and ignore all but the first two widths. The MS API does
|
||||||
|
// not support an equivalent of sizes.first.
|
||||||
|
if (index > 1) {
|
||||||
|
sizes.least = width[0];
|
||||||
|
sizes.higher = width[1];
|
||||||
|
} else if (index) {
|
||||||
|
sizes.least = sizes.higher = width[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
QVariant QSystemLocalePrivate::groupSeparator()
|
QVariant QSystemLocalePrivate::groupSeparator()
|
||||||
{
|
{
|
||||||
return getLocaleInfo(LOCALE_STHOUSAND); // Empty means don't group digits.
|
return getLocaleInfo(LOCALE_STHOUSAND); // Empty means don't group digits.
|
||||||
@ -831,6 +873,8 @@ QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
|
|||||||
switch(type) {
|
switch(type) {
|
||||||
case DecimalPoint:
|
case DecimalPoint:
|
||||||
return d->decimalPoint();
|
return d->decimalPoint();
|
||||||
|
case Grouping:
|
||||||
|
return d->groupingSizes();
|
||||||
case GroupSeparator:
|
case GroupSeparator:
|
||||||
return d->groupSeparator();
|
return d->groupSeparator();
|
||||||
case NegativeSign:
|
case NegativeSign:
|
||||||
|
@ -110,6 +110,8 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant &&in) const
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case DecimalPoint:
|
case DecimalPoint:
|
||||||
return m_locale.decimalPoint();
|
return m_locale.decimalPoint();
|
||||||
|
case Grouping:
|
||||||
|
return QVariant::fromValue(localeData(m_locale)->m_data->groupSizes());
|
||||||
case GroupSeparator:
|
case GroupSeparator:
|
||||||
return m_locale.groupSeparator();
|
return m_locale.groupSeparator();
|
||||||
case ZeroDigit:
|
case ZeroDigit:
|
||||||
|
@ -145,6 +145,8 @@ private slots:
|
|||||||
# ifdef QT_BUILD_INTERNAL
|
# ifdef QT_BUILD_INTERNAL
|
||||||
void mySystemLocale_data();
|
void mySystemLocale_data();
|
||||||
void mySystemLocale();
|
void mySystemLocale();
|
||||||
|
void systemGrouping_data();
|
||||||
|
void systemGrouping();
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
void systemLocaleDayAndMonthNames_data();
|
void systemLocaleDayAndMonthNames_data();
|
||||||
@ -4103,7 +4105,18 @@ public:
|
|||||||
return m_id.territory_id;
|
return m_id.territory_id;
|
||||||
case ScriptId:
|
case ScriptId:
|
||||||
return m_id.script_id;
|
return m_id.script_id;
|
||||||
|
case Grouping:
|
||||||
|
if (m_name == u"en-ES") // CLDR: 1,3,3
|
||||||
|
return QVariant::fromValue(QLocaleData::GroupSizes{2,3,3});
|
||||||
|
if (m_name == u"en-BD") // CLDR: 1,3,3
|
||||||
|
return QVariant::fromValue(QLocaleData::GroupSizes{1,2,3});
|
||||||
|
if (m_name == u"ccp") // CLDR: 1,3,3
|
||||||
|
return QVariant::fromValue(QLocaleData::GroupSizes{2,2,3});
|
||||||
|
if (m_name == u"en-BT") // CLDR: 1,3,3
|
||||||
|
return QVariant::fromValue(QLocaleData::GroupSizes{0,2,3});
|
||||||
|
if (m_name == u"en-NP") // CLDR: 1,3,3
|
||||||
|
return QVariant::fromValue(QLocaleData::GroupSizes{0,2,0});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4255,6 +4268,75 @@ void tst_QLocale::mySystemLocale()
|
|||||||
QT_TEST_EQUALITY_OPS(QLocale(), originalLocale, true);
|
QT_TEST_EQUALITY_OPS(QLocale(), originalLocale, true);
|
||||||
QT_TEST_EQUALITY_OPS(QLocale::system(), originalSystemLocale, true);
|
QT_TEST_EQUALITY_OPS(QLocale::system(), originalSystemLocale, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QLocale::systemGrouping_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("name");
|
||||||
|
QTest::addColumn<QString>("separator");
|
||||||
|
QTest::addColumn<QString>("zeroDigit");
|
||||||
|
QTest::addColumn<int>("number");
|
||||||
|
QTest::addColumn<QString>("formattedString");
|
||||||
|
|
||||||
|
// Testing locales with non {1, 3, 3} groupe sizes, plus some locales
|
||||||
|
// that return invalid group sizes to test that we fallbakc to CLDR data.
|
||||||
|
QTest::newRow("en-ES") // {2,3,3}
|
||||||
|
<< u"en-ES"_s << u","_s << u"0"_s << 1234 << u"1234"_s;
|
||||||
|
QTest::newRow("en-ES-grouped") // {2,3,3}
|
||||||
|
<< u"en-ES"_s << u","_s << u"0"_s << 12345 << u"12,345"_s;
|
||||||
|
QTest::newRow("en-BD") // {1,2,3}
|
||||||
|
<< u"en-BD"_s << u","_s << u"0"_s << 123456789 << u"12,34,56,789"_s;
|
||||||
|
QTest::newRow("en-BT") // {1,2,3}
|
||||||
|
<< u"en-BT"_s << u","_s << u"0"_s << 123456789 << u"12,34,56,789"_s;
|
||||||
|
QTest::newRow("en-NP") // {1,2,3}
|
||||||
|
<< u"en-NP"_s << u","_s << u"0"_s << 123456789 << u"12,34,56,789"_s;
|
||||||
|
|
||||||
|
// Testing with Chakma locale
|
||||||
|
const char32_t zeroVal = 0x11136; // Chakma zero
|
||||||
|
const QChar data[] = {
|
||||||
|
QChar::highSurrogate(zeroVal), QChar::lowSurrogate(zeroVal),
|
||||||
|
QChar::highSurrogate(zeroVal + 1), QChar::lowSurrogate(zeroVal + 1),
|
||||||
|
QChar::highSurrogate(zeroVal + 2), QChar::lowSurrogate(zeroVal + 2),
|
||||||
|
QChar::highSurrogate(zeroVal + 3), QChar::lowSurrogate(zeroVal + 3),
|
||||||
|
QChar::highSurrogate(zeroVal + 4), QChar::lowSurrogate(zeroVal + 4),
|
||||||
|
QChar::highSurrogate(zeroVal + 5), QChar::lowSurrogate(zeroVal + 5),
|
||||||
|
};
|
||||||
|
const QChar separator(QLatin1Char(',')); // Separator for the Chakma locale
|
||||||
|
const QString
|
||||||
|
// Copy zero so it persists through QFETCH(), after data falls off the stack.
|
||||||
|
zero = QString(data, 2),
|
||||||
|
one = QString::fromRawData(data + 2, 2),
|
||||||
|
two = QString::fromRawData(data + 4, 2),
|
||||||
|
three = QString::fromRawData(data + 6, 2),
|
||||||
|
four = QString::fromRawData(data + 8, 2),
|
||||||
|
five = QString::fromRawData(data + 10, 2);
|
||||||
|
QString fourDigit = one + two + three + four;
|
||||||
|
QString fiveDigit = one + two + separator + three + four + five;
|
||||||
|
|
||||||
|
QTest::newRow("Chakma-short") // {2,2,3}
|
||||||
|
<< u"ccp"_s << QString(separator)
|
||||||
|
<< zero << 1234 << fourDigit;
|
||||||
|
QTest::newRow("Chakma") // {2,2,3}
|
||||||
|
<< u"ccp"_s << QString(separator)
|
||||||
|
<< zero << 12345 << fiveDigit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QLocale::systemGrouping()
|
||||||
|
{
|
||||||
|
QFETCH(QString, name);
|
||||||
|
QFETCH(QString, separator);
|
||||||
|
QFETCH(QString, zeroDigit);
|
||||||
|
QFETCH(int, number);
|
||||||
|
QFETCH(QString, formattedString);
|
||||||
|
|
||||||
|
{
|
||||||
|
MySystemLocale sLocale(name);
|
||||||
|
QLocale sys = QLocale::system();
|
||||||
|
QCOMPARE(sys.groupSeparator(), separator);
|
||||||
|
QCOMPARE(sys.zeroDigit(), zeroDigit);
|
||||||
|
QCOMPARE(sys.toString(number), formattedString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# endif // QT_BUILD_INTERNAL
|
# endif // QT_BUILD_INTERNAL
|
||||||
|
|
||||||
void tst_QLocale::systemLocaleDayAndMonthNames_data()
|
void tst_QLocale::systemLocaleDayAndMonthNames_data()
|
||||||
|
@ -684,12 +684,12 @@ class LocaleScanner (object):
|
|||||||
def __numberGrouping(self, system: str) -> tuple[int, int, int]:
|
def __numberGrouping(self, system: str) -> tuple[int, int, int]:
|
||||||
"""Sizes of groups of digits within a number.
|
"""Sizes of groups of digits within a number.
|
||||||
|
|
||||||
Returns a triple (least, higher, top) for which:
|
Returns a triple (least, higher, fist) for which:
|
||||||
* least is the number of digits after the last grouping
|
* least is the number of digits after the last grouping
|
||||||
separator;
|
separator;
|
||||||
* higher is the number of digits between grouping
|
* higher is the number of digits between grouping
|
||||||
separators;
|
separators;
|
||||||
* top is the fewest digits that can appear before the first
|
* first is the fewest digits that can appear before the first
|
||||||
grouping separator.
|
grouping separator.
|
||||||
|
|
||||||
Thus (4, 3, 2) would want 1e7 as 1000,0000 but 1e8 as 10,000,0000.
|
Thus (4, 3, 2) would want 1e7 as 1000,0000 but 1e8 as 10,000,0000.
|
||||||
@ -699,17 +699,17 @@ class LocaleScanner (object):
|
|||||||
is placement of the sign character anywhere but at the start
|
is placement of the sign character anywhere but at the start
|
||||||
of the number (some formats may place it at the end, possibly
|
of the number (some formats may place it at the end, possibly
|
||||||
elsewhere)."""
|
elsewhere)."""
|
||||||
top = int(self.find('numbers/minimumGroupingDigits'))
|
first = int(self.find('numbers/minimumGroupingDigits'))
|
||||||
assert top < 4, top # We store it in a 2-bit field
|
assert first < 4, first # We store it in a 2-bit field
|
||||||
grouping: str | None = self.find(f'numbers/decimalFormats[numberSystem={system}]/'
|
grouping: str | None = self.find(f'numbers/decimalFormats[numberSystem={system}]/'
|
||||||
'decimalFormatLength/decimalFormat/pattern')
|
'decimalFormatLength/decimalFormat/pattern')
|
||||||
groups: list[str] = grouping.split('.')[0].split(',')[-3:]
|
groups: list[str] = grouping.split('.')[0].split(',')[-3:]
|
||||||
assert all(len(x) < 8 for x in groups[-2:]), grouping # we store them in 3-bit fields
|
assert all(len(x) < 8 for x in groups[-2:]), grouping # we store them in 3-bit fields
|
||||||
if len(groups) > 2:
|
if len(groups) > 2:
|
||||||
return len(groups[-1]), len(groups[-2]), top
|
return len(groups[-1]), len(groups[-2]), first
|
||||||
|
|
||||||
size = len(groups[-1]) if len(groups) == 2 else 3
|
size = len(groups[-1]) if len(groups) == 2 else 3
|
||||||
return size, size, top
|
return size, size, first
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __currencyFormats(patterns: str, plus: str, minus: str) -> Iterator[str]:
|
def __currencyFormats(patterns: str, plus: str, minus: str) -> Iterator[str]:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user