mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-03-24 03:13:13 +08:00
Support more aspects in wxUILocale and wxNumberFormatter
Add support for currency amounts, including functions for retrieving currency symbol and currency code for the current locale and the possibility to format such amounts according to the locale rules. Allow retrieving more information about numeric values formatting, for both numbers and currency amounts, including grouping information when group separator is used and number of digits after decimal separator and also use them when formatting numbers. Finally add function to retrieve the measurement system (metric or imperial) used by the current locale. See #1781. Closes #25765.
This commit is contained in:
committed by
Vadim Zeitlin
parent
9469d6d4c8
commit
8c46e47ecf
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "wx/defs.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxLayoutDirection: used by wxWindow, wxDC etc
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -122,6 +124,53 @@ enum wxLocaleForm
|
||||
wxLOCALE_FORM_ENGLISH
|
||||
};
|
||||
|
||||
enum class wxMeasurementSystem
|
||||
{
|
||||
Unknown,
|
||||
Metric,
|
||||
NonMetric
|
||||
};
|
||||
|
||||
enum class wxCurrencySymbolPosition
|
||||
{
|
||||
PrefixNoSep,
|
||||
PrefixWithSep,
|
||||
SuffixNoSep,
|
||||
SuffixWithSep
|
||||
};
|
||||
|
||||
struct wxLocaleNumberFormatting
|
||||
{
|
||||
wxLocaleNumberFormatting() = default;
|
||||
wxLocaleNumberFormatting(const wxString& groupSeparator_, const std::vector<int>& grouping_,
|
||||
const wxString& decimalSeparator_, int fractionalDigits_)
|
||||
: groupSeparator(groupSeparator_), grouping(grouping_),
|
||||
decimalSeparator(decimalSeparator_), fractionalDigits(fractionalDigits_)
|
||||
{
|
||||
}
|
||||
wxString groupSeparator;
|
||||
std::vector<int> grouping;
|
||||
wxString decimalSeparator;
|
||||
int fractionalDigits = 0;
|
||||
};
|
||||
|
||||
struct wxLocaleCurrencyInfo
|
||||
{
|
||||
wxLocaleCurrencyInfo() = default;
|
||||
wxLocaleCurrencyInfo(const wxString& symbol_, const wxString& code_,
|
||||
const wxCurrencySymbolPosition currencySymbolPos_,
|
||||
const wxLocaleNumberFormatting currencyFormat_)
|
||||
: currencySymbol(symbol_), currencyCode(code_),
|
||||
currencySymbolPos(currencySymbolPos_),
|
||||
currencyFormat(currencyFormat_)
|
||||
{
|
||||
}
|
||||
wxString currencySymbol; // the currency symbol (for example "$")
|
||||
wxString currencyCode; // the currency ISO code (for example "USD")
|
||||
wxCurrencySymbolPosition currencySymbolPos = wxCurrencySymbolPosition::PrefixWithSep;
|
||||
wxLocaleNumberFormatting currencyFormat;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxLanguageInfo: encapsulates wxLanguage to OS native lang.desc.
|
||||
// translation information
|
||||
|
||||
@@ -25,6 +25,9 @@ public:
|
||||
Style_NoTrailingZeroes = 0x02, // Only for floating point numbers
|
||||
Style_SignPlus = 0x04,
|
||||
Style_SignSpace = 0x08,
|
||||
Style_Currency = 0x10, // Currency, without currency symbol
|
||||
Style_CurrencySymbol = 0x20, // Currency with currency symbol
|
||||
Style_CurrencyCode = 0x40, // Currency with ISO 4217 code
|
||||
};
|
||||
|
||||
// Format a number as a string. By default, the thousands separator is
|
||||
@@ -75,18 +78,24 @@ public:
|
||||
// number. Also used by ToString().
|
||||
static void RemoveTrailingZeroes(wxString& s);
|
||||
|
||||
// Remove currency symbol or code
|
||||
static wxString RemoveCurrencySymbolOrCode(wxString s, int style);
|
||||
|
||||
private:
|
||||
// Post-process the string representing an integer.
|
||||
static wxString PostProcessIntString(wxString s, int style);
|
||||
|
||||
// Add the thousands separators to a string representing a number without
|
||||
// the separators. This is used by ToString(Style_WithThousandsSep).
|
||||
static void AddThousandsSeparators(wxString& s);
|
||||
static void AddThousandsSeparators(wxString& s, int style);
|
||||
|
||||
// Add the sign prefix to a string representing a number without
|
||||
// the prefix. This is used by ToString().
|
||||
static void AddSignPrefix(wxString& s, int style);
|
||||
|
||||
// Add currency symbol or code depending on style
|
||||
static void AddCurrency(wxString& s, int style);
|
||||
|
||||
// Remove all thousands separators from a string representing a number.
|
||||
static void RemoveThousandsSeparators(wxString& s);
|
||||
};
|
||||
|
||||
@@ -96,6 +96,14 @@ public:
|
||||
#endif // wxUSE_DATETIME
|
||||
|
||||
virtual wxLayoutDirection GetLayoutDirection() const = 0;
|
||||
|
||||
virtual wxLocaleNumberFormatting GetNumberFormatting() const = 0;
|
||||
virtual wxString GetCurrencySymbol() const = 0;
|
||||
virtual wxString GetCurrencyCode() const = 0;
|
||||
virtual wxCurrencySymbolPosition GetCurrencySymbolPosition() const = 0;
|
||||
virtual wxLocaleCurrencyInfo GetCurrencyInfo() const = 0;
|
||||
virtual wxMeasurementSystem UsesMetricSystem() const = 0;
|
||||
|
||||
virtual int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int flags) const = 0;
|
||||
|
||||
|
||||
@@ -186,6 +186,27 @@ public:
|
||||
// Query the layout direction of the current locale.
|
||||
wxLayoutDirection GetLayoutDirection() const;
|
||||
|
||||
// Query infos about number formatting of the current locale
|
||||
wxLocaleNumberFormatting GetNumberFormatting() const;
|
||||
|
||||
// Query the curreny symbol of the current locale
|
||||
wxString GetCurrencySymbol() const;
|
||||
|
||||
// Query the currency code of the current locale
|
||||
wxString GetCurrencyCode() const;
|
||||
|
||||
// Query the currency symbol position of the current locale
|
||||
wxCurrencySymbolPosition GetCurrencySymbolPosition() const;
|
||||
|
||||
// Query the currency infos of the current locale
|
||||
wxLocaleCurrencyInfo GetCurrencyInfo() const;
|
||||
|
||||
// Query whether the current locale uses the metric system
|
||||
wxMeasurementSystem UsesMetricSystem() const;
|
||||
|
||||
// Guess from the region whether the current locale uses the metric system
|
||||
static wxMeasurementSystem GuessMetricSystemFromRegion(const wxLocaleIdent& idLocale);
|
||||
|
||||
// Compares two strings in the order defined by this locale.
|
||||
int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int flags = wxCompare_CaseSensitive) const;
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
/**
|
||||
If this flag is given, thousands separators will be inserted in the
|
||||
number string representation as defined by the current UI locale.
|
||||
Thousands separators will be applied according to the grouping rules
|
||||
of the current UI locale.
|
||||
*/
|
||||
Style_WithThousandsSep = 0x01,
|
||||
|
||||
@@ -74,6 +76,40 @@ public:
|
||||
@since 3.3.1
|
||||
*/
|
||||
Style_SignSpace = 0x08,
|
||||
|
||||
/**
|
||||
If this flag is given, the number will be interpreted
|
||||
as a currency value and formatted according to the rules
|
||||
of the current UI locale.
|
||||
|
||||
@since 3.3.2
|
||||
*/
|
||||
Style_Currency = 0x10,
|
||||
|
||||
/**
|
||||
If this flag is given, the currency symbol of the current
|
||||
UI locale will be prepended or appended to the currency value
|
||||
according to the rules of the current locale.
|
||||
|
||||
The style will only take effect, if it is combined with Style_Currency.
|
||||
The style should not be combined with Style_CurrencyCode.
|
||||
|
||||
@since 3.3.2
|
||||
*/
|
||||
Style_CurrencySymbol = 0x20, // Currency with currency symbol
|
||||
|
||||
/**
|
||||
If this flag is given, the ISO 42127 currency code of the current
|
||||
UI locale will be prepended to the currency value. It will be separated
|
||||
from the currency value by a space character.
|
||||
|
||||
The style will only take effect, if it is combined with Style_Currency.
|
||||
The style should not be combined with Style_CurrencySymbol.
|
||||
|
||||
@since 3.3.2
|
||||
*/
|
||||
Style_CurrencyCode = 0x40, // Currency with ISO 4217 code
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -180,4 +216,22 @@ public:
|
||||
*/
|
||||
static void RemoveTrailingZeroes(wxString& str);
|
||||
|
||||
/**
|
||||
Remove currency symbol or code, and grouping separators,
|
||||
according to the given style flags.
|
||||
|
||||
@note This function allows to remove the currency symbol or code
|
||||
from a string with a formatted currency value, so that
|
||||
FromString() can be used afterwards to retrieve the numerical value.
|
||||
Additionally, grouping separators are removed, if necessary.
|
||||
|
||||
@param[in] str
|
||||
The string to remove the currency symbol or code or grouping separators from.
|
||||
@param flags
|
||||
Combination of values from the Style enumeration.
|
||||
|
||||
@since 3.3.2
|
||||
*/
|
||||
static wxString RemoveCurrencySymbolOrCode(wxString str, int flags);
|
||||
|
||||
};
|
||||
|
||||
@@ -296,6 +296,106 @@ public:
|
||||
*/
|
||||
wxLayoutDirection GetLayoutDirection() const;
|
||||
|
||||
/**
|
||||
Return all settings related to number formatting for the current locale.
|
||||
The information includes:
|
||||
- the grouping separator
|
||||
- the grouping specification
|
||||
- the decimal separator
|
||||
- the number of fractional digits
|
||||
|
||||
@return
|
||||
The wxLocaleNumberFormatting structure with the number formatting details.
|
||||
@since 3.3.2
|
||||
*/
|
||||
wxLocaleNumberFormatting GetNumberFormatting() const;
|
||||
|
||||
/**
|
||||
Query the currency symbol of the current locale.
|
||||
|
||||
@return
|
||||
The currency symbol that is typically used locally for currency values.
|
||||
If no currency symbol could be determined, an empty string will be returned.
|
||||
@since 3.3.2
|
||||
*/
|
||||
wxString GetCurrencySymbol() const;
|
||||
|
||||
/**
|
||||
Query the ISO 4217 currency code of the current locale.
|
||||
|
||||
@return
|
||||
The 3-letter ISO 4217 currency code.
|
||||
If no currency code could be determined, an empty string will be returned.
|
||||
@since 3.3.2
|
||||
*/
|
||||
wxString GetCurrencyCode() const;
|
||||
|
||||
/**
|
||||
Query the currency symbol position of the current locale.
|
||||
|
||||
The currency symbol can be positioned in one of 4 ways:
|
||||
as a prefix or suffix to the currency value, either separated from the value
|
||||
by a space character or not. Accordingly, one of the following values is returned:
|
||||
- wxCurrencySymbolPosition::PrefixWithSep
|
||||
- wxCurrencySymbolPosition::PrefixNoSep
|
||||
- wxCurrencySymbolPosition::SuffixWithSep
|
||||
- wxCurrencySymbolPosition::SuffixNoSep
|
||||
|
||||
@note The position of the currency symbol does not affect the representation
|
||||
with the currency code. The currency code is always placed before the
|
||||
currency value and separated by a space.
|
||||
|
||||
@return
|
||||
The currency symbol position.
|
||||
@since 3.3.2
|
||||
*/
|
||||
wxCurrencySymbolPosition GetCurrencySymbolPosition() const;
|
||||
|
||||
/**
|
||||
Return all settings related to currency formatting for the current locale.
|
||||
|
||||
The currency information includes the following items:
|
||||
- the currency symbol
|
||||
- the currency code
|
||||
- the currency symbol position
|
||||
- the currency value formatting information
|
||||
|
||||
@return
|
||||
The wxLocaleCurrencyInfo structure.
|
||||
@since 3.3.2
|
||||
*/
|
||||
wxLocaleCurrencyInfo GetCurrencyInfo() const;
|
||||
|
||||
/**
|
||||
Query whether the current locale uses the metric system
|
||||
|
||||
@note If wxMeasurementSystem::Unknown is returned,
|
||||
GuessMetricSystemFromRegion() can be used as a fallback
|
||||
|
||||
@return
|
||||
The measurement system, one of the values
|
||||
wxMeasurementSystem::Metric, wxMeasurementSystem::NonMetric,
|
||||
or wxMeasurementSystem::Unknown.
|
||||
@since 3.3.2
|
||||
|
||||
@see GuessMetricSystemFromRegion()
|
||||
*/
|
||||
wxMeasurementSystem UsesMetricSystem() const;
|
||||
|
||||
/**
|
||||
Guess whether the current locale uses the metric system
|
||||
base on from the region part of the locale identification.
|
||||
|
||||
@param idLocale
|
||||
The id of the locale for which the measurement system should be guessed.
|
||||
@return
|
||||
The guessed measurement system, one of the values
|
||||
wxMeasurementSystem::Metric, wxMeasurementSystem::NonMetric,
|
||||
or wxMeasurementSystem::Unknown.
|
||||
@since 3.3.2
|
||||
*/
|
||||
static wxMeasurementSystem GuessMetricSystemFromRegion(const wxLocaleIdent& idLocale);
|
||||
|
||||
/**
|
||||
Return true if locale is supported on the current system.
|
||||
|
||||
|
||||
@@ -83,13 +83,15 @@ void ReplaceSeparatorIfNecessary(wxString& s, wxChar sepOld, wxChar sepNew)
|
||||
wxString wxNumberFormatter::PostProcessIntString(wxString s, int style)
|
||||
{
|
||||
if ( style & Style_WithThousandsSep )
|
||||
AddThousandsSeparators(s);
|
||||
AddThousandsSeparators(s, style);
|
||||
|
||||
wxASSERT_MSG( !(style & Style_NoTrailingZeroes),
|
||||
"Style_NoTrailingZeroes can't be used with integer values" );
|
||||
|
||||
AddSignPrefix(s, style);
|
||||
|
||||
AddCurrency(s, style);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -121,13 +123,15 @@ wxString wxNumberFormatter::ToString(double val, int precision, int style)
|
||||
ReplaceSeparatorIfNecessary(s, '.', GetDecimalSeparator());
|
||||
|
||||
if ( style & Style_WithThousandsSep )
|
||||
AddThousandsSeparators(s);
|
||||
AddThousandsSeparators(s, style);
|
||||
|
||||
if ( style & Style_NoTrailingZeroes )
|
||||
RemoveTrailingZeroes(s);
|
||||
|
||||
AddSignPrefix(s, style);
|
||||
|
||||
AddCurrency(s, style);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -148,17 +152,33 @@ wxString wxNumberFormatter::Format(const wxString& format, double val)
|
||||
return s;
|
||||
}
|
||||
|
||||
void wxNumberFormatter::AddThousandsSeparators(wxString& s)
|
||||
void wxNumberFormatter::AddThousandsSeparators(wxString& s, int style)
|
||||
{
|
||||
// Thousands separators for numbers in scientific format are not relevant.
|
||||
if ( s.find_first_of("eE") != wxString::npos )
|
||||
return;
|
||||
|
||||
wxChar thousandsSep;
|
||||
if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
|
||||
wxString groupingSeparator;
|
||||
std::vector<int> grouping;
|
||||
wxString decimalSeparator = GetDecimalSeparator();
|
||||
#if wxUSE_INTL
|
||||
wxLocaleNumberFormatting numForm;
|
||||
if (style & Style_Currency)
|
||||
numForm = wxUILocale::GetCurrent().GetCurrencyInfo().currencyFormat;
|
||||
else
|
||||
numForm = wxUILocale::GetCurrent().GetNumberFormatting();
|
||||
if (!numForm.groupSeparator.empty())
|
||||
{
|
||||
groupingSeparator = numForm.groupSeparator;
|
||||
grouping = numForm.grouping;
|
||||
decimalSeparator = numForm.decimalSeparator;
|
||||
}
|
||||
#endif // wxUSE_INTL
|
||||
|
||||
if (groupingSeparator.empty() )
|
||||
return;
|
||||
|
||||
size_t pos = s.find(GetDecimalSeparator());
|
||||
size_t pos = s.find(decimalSeparator);
|
||||
if ( pos == wxString::npos )
|
||||
{
|
||||
// Start grouping at the end of an integer number.
|
||||
@@ -169,17 +189,47 @@ void wxNumberFormatter::AddThousandsSeparators(wxString& s)
|
||||
// before their start.
|
||||
const size_t start = s.find_first_of("0123456789");
|
||||
|
||||
// We currently group digits by 3 independently of the locale. This is not
|
||||
// the right thing to do and we should use lconv::grouping (under POSIX)
|
||||
// and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about
|
||||
// the correct grouping to use. This is something that needs to be done at
|
||||
// wxLocale level first and then used here in the future (TODO).
|
||||
const size_t GROUP_LEN = 3;
|
||||
if (grouping.empty())
|
||||
return;
|
||||
|
||||
while ( pos > start + GROUP_LEN )
|
||||
// The vector grouping conatins a list of group length.
|
||||
// Beginning from the right, each group length is applied once
|
||||
// to determine the next position of a group separator,
|
||||
// unless the last entry entry is a zero, in which case
|
||||
// the last group length is applied repeatedly.
|
||||
size_t groupIndex = 0;
|
||||
size_t groupLen = grouping[0];
|
||||
size_t nextGroupLen = groupLen;
|
||||
|
||||
// Repeat while the group length is valid (i.e. > 0)
|
||||
// and the potential group separator position lies
|
||||
// within the number.
|
||||
while (groupLen > 0 && pos > start)
|
||||
{
|
||||
pos -= GROUP_LEN;
|
||||
s.insert(pos, thousandsSep);
|
||||
// Determine next group separator position
|
||||
pos = (pos >= groupLen) ? pos - groupLen : 0;
|
||||
|
||||
// Apply group separator if it is within the number
|
||||
if (pos > start)
|
||||
s.insert(pos, groupingSeparator);
|
||||
|
||||
// Select next group length
|
||||
if (++groupIndex < grouping.size())
|
||||
{
|
||||
// Set the group length to the next group length entry
|
||||
// unless the next group length is zero,
|
||||
// in which case the last group length remains in effect.
|
||||
nextGroupLen = grouping[groupIndex];
|
||||
if (nextGroupLen != 0)
|
||||
groupLen = nextGroupLen;
|
||||
}
|
||||
else if (nextGroupLen != 0)
|
||||
{
|
||||
// If the next group length is not zero,
|
||||
// the last group length was already applied once, and
|
||||
// no further group is to be applied.
|
||||
groupLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +282,101 @@ void wxNumberFormatter::AddSignPrefix(wxString& s, int style)
|
||||
}
|
||||
}
|
||||
|
||||
void wxNumberFormatter::AddCurrency(wxString& s, int style)
|
||||
{
|
||||
#if wxUSE_INTL
|
||||
if (style & Style_Currency)
|
||||
{
|
||||
auto currencyInfo = wxUILocale::GetCurrent().GetCurrencyInfo();
|
||||
wxString currencyStr;
|
||||
wxCurrencySymbolPosition currencyPos{ wxCurrencySymbolPosition::PrefixWithSep };
|
||||
if (style & Style_CurrencySymbol)
|
||||
{
|
||||
currencyStr = currencyInfo.currencySymbol;
|
||||
currencyPos = currencyInfo.currencySymbolPos;
|
||||
}
|
||||
else if (style & Style_CurrencyCode)
|
||||
{
|
||||
currencyStr = currencyInfo.currencyCode;
|
||||
}
|
||||
|
||||
if (!currencyStr.empty())
|
||||
{
|
||||
switch (currencyPos)
|
||||
{
|
||||
case wxCurrencySymbolPosition::PrefixWithSep:
|
||||
s = currencyStr + wxString(" ") + s;
|
||||
break;
|
||||
case wxCurrencySymbolPosition::PrefixNoSep:
|
||||
s = currencyStr + s;
|
||||
break;
|
||||
case wxCurrencySymbolPosition::SuffixWithSep:
|
||||
s = s + wxString(" ") + currencyStr;
|
||||
break;
|
||||
case wxCurrencySymbolPosition::SuffixNoSep:
|
||||
s = s + currencyStr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
wxUnused(s);
|
||||
wxUnused(style);
|
||||
#endif // wxUSE_INTL
|
||||
}
|
||||
|
||||
wxString wxNumberFormatter::RemoveCurrencySymbolOrCode(wxString s, int style)
|
||||
{
|
||||
#if wxUSE_INTL
|
||||
if (style & Style_Currency)
|
||||
{
|
||||
auto currencyInfo = wxUILocale::GetCurrent().GetCurrencyInfo();
|
||||
wxString thousandsSep = currencyInfo.currencyFormat.groupSeparator;
|
||||
wxString currencyStr;
|
||||
wxCurrencySymbolPosition currencyPos{ wxCurrencySymbolPosition::PrefixWithSep };
|
||||
if (style & Style_CurrencySymbol)
|
||||
{
|
||||
currencyStr = currencyInfo.currencySymbol;
|
||||
currencyPos = currencyInfo.currencySymbolPos;
|
||||
}
|
||||
else if (style & Style_CurrencyCode)
|
||||
{
|
||||
currencyStr = currencyInfo.currencyCode;
|
||||
}
|
||||
|
||||
if (!currencyStr.empty())
|
||||
{
|
||||
wxString valueStr;
|
||||
switch (currencyPos)
|
||||
{
|
||||
case wxCurrencySymbolPosition::PrefixWithSep:
|
||||
currencyStr += wxString(" ");
|
||||
// Fall through to case without separator
|
||||
case wxCurrencySymbolPosition::PrefixNoSep:
|
||||
if (s.StartsWith(currencyStr, &valueStr))
|
||||
s = valueStr;
|
||||
break;
|
||||
case wxCurrencySymbolPosition::SuffixWithSep:
|
||||
currencyStr = wxString(" ") + currencyStr;
|
||||
// Fall through to case without separator
|
||||
case wxCurrencySymbolPosition::SuffixNoSep:
|
||||
if (s.EndsWith(currencyStr, &valueStr))
|
||||
s = valueStr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (style & Style_WithThousandsSep && !thousandsSep.empty())
|
||||
{
|
||||
s.Replace(thousandsSep, wxString());
|
||||
}
|
||||
}
|
||||
return s;
|
||||
#else
|
||||
wxUnused(style);
|
||||
return s;
|
||||
#endif // wxUSE_INTL
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Conversion from strings
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -994,6 +994,70 @@ wxLayoutDirection wxUILocale::GetLayoutDirection() const
|
||||
return dir;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting wxUILocale::GetNumberFormatting() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return wxLocaleNumberFormatting();
|
||||
|
||||
return m_impl->GetNumberFormatting();
|
||||
}
|
||||
|
||||
wxString wxUILocale::GetCurrencySymbol() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return wxString();
|
||||
|
||||
return m_impl->GetCurrencySymbol();
|
||||
}
|
||||
|
||||
wxString wxUILocale::GetCurrencyCode() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return wxString();
|
||||
|
||||
return m_impl->GetCurrencyCode();
|
||||
}
|
||||
|
||||
wxCurrencySymbolPosition wxUILocale::GetCurrencySymbolPosition() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return wxCurrencySymbolPosition::PrefixWithSep;
|
||||
|
||||
return m_impl->GetCurrencySymbolPosition();
|
||||
}
|
||||
|
||||
wxLocaleCurrencyInfo wxUILocale::GetCurrencyInfo() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return wxLocaleCurrencyInfo();
|
||||
|
||||
return m_impl->GetCurrencyInfo();
|
||||
}
|
||||
|
||||
wxMeasurementSystem wxUILocale::UsesMetricSystem() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return wxMeasurementSystem::Unknown;
|
||||
|
||||
return m_impl->UsesMetricSystem();
|
||||
}
|
||||
|
||||
wxMeasurementSystem wxUILocale::GuessMetricSystemFromRegion(const wxLocaleIdent& idLocale)
|
||||
{
|
||||
wxString region = idLocale.GetRegion();
|
||||
// In 2025 only in the United States, Liberia, and Myanmar
|
||||
// the metric system is not the default measurement system.
|
||||
if (!region.empty())
|
||||
{
|
||||
if (region == "US" || region == "LR" || region == "MM")
|
||||
return wxMeasurementSystem::NonMetric;
|
||||
else
|
||||
return wxMeasurementSystem::Metric;
|
||||
}
|
||||
else
|
||||
return wxMeasurementSystem::Unknown;
|
||||
}
|
||||
|
||||
int
|
||||
wxUILocale::CompareStrings(const wxString& lhs,
|
||||
const wxString& rhs,
|
||||
|
||||
@@ -28,8 +28,12 @@
|
||||
|
||||
#include "wx/scopedarray.h"
|
||||
#include "wx/dynlib.h"
|
||||
#include "wx/tokenzr.h"
|
||||
#include "wx/wxcrt.h"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#ifndef LOCALE_NAME_USER_DEFAULT
|
||||
#define LOCALE_NAME_USER_DEFAULT nullptr
|
||||
#endif
|
||||
@@ -304,6 +308,45 @@ public:
|
||||
return wxLayout_Default;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting GetNumberFormatting() const override
|
||||
{
|
||||
wxLocaleNumberFormatting numForm;
|
||||
numForm.decimalSeparator = ".";
|
||||
numForm.groupSeparator = "";
|
||||
numForm.grouping = {};
|
||||
numForm.fractionalDigits = 2;
|
||||
return numForm;
|
||||
}
|
||||
|
||||
wxString GetCurrencySymbol() const override
|
||||
{
|
||||
return "$";
|
||||
}
|
||||
|
||||
wxString GetCurrencyCode() const override
|
||||
{
|
||||
return "USD";
|
||||
}
|
||||
|
||||
wxCurrencySymbolPosition GetCurrencySymbolPosition() const override
|
||||
{
|
||||
return wxCurrencySymbolPosition::PrefixWithSep;
|
||||
}
|
||||
|
||||
wxLocaleCurrencyInfo GetCurrencyInfo() const override
|
||||
{
|
||||
return wxLocaleCurrencyInfo(
|
||||
GetCurrencySymbol(),
|
||||
GetCurrencyCode(),
|
||||
GetCurrencySymbolPosition(),
|
||||
GetNumberFormatting());
|
||||
}
|
||||
|
||||
wxMeasurementSystem UsesMetricSystem() const override
|
||||
{
|
||||
return wxMeasurementSystem::Metric;
|
||||
}
|
||||
|
||||
int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int flags) const override
|
||||
{
|
||||
@@ -472,13 +515,15 @@ public:
|
||||
switch ( index )
|
||||
{
|
||||
case wxLOCALE_THOUSANDS_SEP:
|
||||
str = DoGetInfo(LOCALE_STHOUSAND);
|
||||
str = DoGetInfo(cat == wxLOCALE_CAT_MONEY
|
||||
? LOCALE_SMONTHOUSANDSEP
|
||||
: LOCALE_STHOUSAND);
|
||||
break;
|
||||
|
||||
case wxLOCALE_DECIMAL_POINT:
|
||||
str = DoGetInfo(cat == wxLOCALE_CAT_MONEY
|
||||
? LOCALE_SMONDECIMALSEP
|
||||
: LOCALE_SDECIMAL);
|
||||
? LOCALE_SMONDECIMALSEP
|
||||
: LOCALE_SDECIMAL);
|
||||
break;
|
||||
|
||||
case wxLOCALE_SHORT_DATE_FMT:
|
||||
@@ -642,6 +687,53 @@ public:
|
||||
return m_layoutDir;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting GetNumberFormatting() const override
|
||||
{
|
||||
return DoGetNumberFormatting(wxLOCALE_CAT_NUMBER);
|
||||
}
|
||||
|
||||
wxString GetCurrencySymbol() const override
|
||||
{
|
||||
return DoGetInfo(LOCALE_SCURRENCY);
|
||||
}
|
||||
|
||||
wxString GetCurrencyCode() const override
|
||||
{
|
||||
return wxString(DoGetInfo(LOCALE_SINTLSYMBOL)).Left(3);
|
||||
}
|
||||
|
||||
wxCurrencySymbolPosition GetCurrencySymbolPosition() const override
|
||||
{
|
||||
static std::array<wxCurrencySymbolPosition, 4> symPos = {
|
||||
wxCurrencySymbolPosition::PrefixNoSep, wxCurrencySymbolPosition::SuffixNoSep,
|
||||
wxCurrencySymbolPosition::PrefixWithSep, wxCurrencySymbolPosition::SuffixWithSep };
|
||||
wxString posStr = wxString(DoGetInfo(LOCALE_ICURRENCY));
|
||||
unsigned int posIdx;
|
||||
return posStr.ToUInt(&posIdx) && posIdx < symPos.size()
|
||||
? symPos[posIdx]
|
||||
: wxCurrencySymbolPosition::PrefixWithSep;
|
||||
}
|
||||
|
||||
wxLocaleCurrencyInfo GetCurrencyInfo() const override
|
||||
{
|
||||
wxLocaleNumberFormatting currencyFormatting = DoGetNumberFormatting(wxLOCALE_CAT_MONEY);
|
||||
return wxLocaleCurrencyInfo(
|
||||
GetCurrencySymbol(),
|
||||
GetCurrencyCode(),
|
||||
GetCurrencySymbolPosition(),
|
||||
currencyFormatting);
|
||||
}
|
||||
|
||||
wxMeasurementSystem UsesMetricSystem() const override
|
||||
{
|
||||
wxString str = DoGetInfo(LOCALE_IMEASURE);
|
||||
if (!str.empty())
|
||||
{
|
||||
return (str.IsSameAs("0")) ? wxMeasurementSystem::Metric : wxMeasurementSystem::NonMetric;
|
||||
}
|
||||
return wxMeasurementSystem::Unknown;
|
||||
}
|
||||
|
||||
int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int flags) const override
|
||||
{
|
||||
@@ -696,6 +788,36 @@ private:
|
||||
return buf;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting DoGetNumberFormatting(wxLocaleCategory cat) const
|
||||
{
|
||||
wxString groupSeparator = DoGetInfo(cat == wxLOCALE_CAT_MONEY
|
||||
? LOCALE_SMONTHOUSANDSEP
|
||||
: LOCALE_STHOUSAND);
|
||||
wxString groupingInfo = DoGetInfo(cat == wxLOCALE_CAT_MONEY
|
||||
? LOCALE_SMONGROUPING
|
||||
: LOCALE_SGROUPING);
|
||||
wxString decimalSeparator = DoGetInfo(cat == wxLOCALE_CAT_MONEY
|
||||
? LOCALE_SMONDECIMALSEP
|
||||
: LOCALE_SDECIMAL);
|
||||
wxString digits = DoGetInfo(cat == wxLOCALE_CAT_MONEY
|
||||
? LOCALE_ICURRDIGITS
|
||||
: LOCALE_IDIGITS);
|
||||
int fractionalDigits;
|
||||
if (digits.empty() || !digits.ToInt(&fractionalDigits))
|
||||
fractionalDigits = 0;
|
||||
|
||||
// Extract grouping lengths from groupingInfo
|
||||
std::vector<int> grouping;
|
||||
for (wxStringTokenizer tokenizer(groupingInfo, ";"); tokenizer.HasMoreTokens();)
|
||||
{
|
||||
int value = 0;
|
||||
if (tokenizer.GetNextToken().ToInt(&value))
|
||||
grouping.push_back(value);
|
||||
}
|
||||
|
||||
return wxLocaleNumberFormatting(groupSeparator, grouping, decimalSeparator, fractionalDigits);
|
||||
}
|
||||
|
||||
const wchar_t* const m_name;
|
||||
|
||||
mutable wxLayoutDirection m_layoutDir = wxLayout_Default;
|
||||
|
||||
@@ -27,13 +27,12 @@
|
||||
#include "wx/osx/core/cfref.h"
|
||||
#include "wx/osx/core/cfstring.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSLocale.h>
|
||||
#import <Foundation/NSDateFormatter.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "wx/osx/private/uilocale.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
extern wxString
|
||||
wxGetInfoFromCFLocale(CFLocaleRef cfloc, wxLocaleInfo index, wxLocaleCategory cat);
|
||||
|
||||
@@ -165,10 +164,20 @@ public:
|
||||
#endif // wxUSE_DATETIME
|
||||
|
||||
wxLayoutDirection GetLayoutDirection() const override;
|
||||
|
||||
wxLocaleNumberFormatting GetNumberFormatting() const override;
|
||||
wxString GetCurrencySymbol() const override;
|
||||
wxString GetCurrencyCode() const override;
|
||||
wxCurrencySymbolPosition GetCurrencySymbolPosition() const override;
|
||||
wxLocaleCurrencyInfo GetCurrencyInfo() const override;
|
||||
wxMeasurementSystem UsesMetricSystem() const override;
|
||||
|
||||
int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int flags) const override;
|
||||
|
||||
private:
|
||||
wxLocaleNumberFormatting DoGetNumberFormatting(wxLocaleCategory cat) const;
|
||||
|
||||
NSLocale* const m_nsloc;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxUILocaleImplCF);
|
||||
@@ -349,6 +358,132 @@ wxUILocaleImplCF::GetLayoutDirection() const
|
||||
return wxLayout_Default;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting
|
||||
wxUILocaleImplCF::GetNumberFormatting() const
|
||||
{
|
||||
return DoGetNumberFormatting(wxLOCALE_CAT_NUMBER);
|
||||
}
|
||||
|
||||
wxString
|
||||
wxUILocaleImplCF::GetCurrencySymbol() const
|
||||
{
|
||||
NSString* str = [m_nsloc currencySymbol];
|
||||
return wxCFStringRef::AsString(str);
|
||||
}
|
||||
|
||||
wxString
|
||||
wxUILocaleImplCF::GetCurrencyCode() const
|
||||
{
|
||||
NSString* str = [m_nsloc currencyCode];
|
||||
return wxCFStringRef::AsString(str);
|
||||
}
|
||||
|
||||
wxCurrencySymbolPosition
|
||||
wxUILocaleImplCF::GetCurrencySymbolPosition() const
|
||||
{
|
||||
wxCFRef<NSNumberFormatter*> cfRefFormatter = [[NSNumberFormatter alloc] init];
|
||||
NSNumberFormatter* formatter = cfRefFormatter.get();
|
||||
formatter.locale = m_nsloc;
|
||||
formatter.numberStyle = NSNumberFormatterCurrencyStyle;
|
||||
|
||||
NSString* formatted = [formatter stringFromNumber:@123];
|
||||
NSString* symbol = formatter.currencySymbol;
|
||||
|
||||
NSRange symbolRange = [formatted rangeOfString:symbol];
|
||||
BOOL symbolBefore = (symbolRange.location == 0);
|
||||
|
||||
wxCurrencySymbolPosition symbolPos = wxCurrencySymbolPosition::PrefixWithSep;
|
||||
BOOL hasSpace = NO;
|
||||
if (symbolRange.location != NSNotFound)
|
||||
{
|
||||
if (symbolBefore)
|
||||
{
|
||||
// Check character succeeding the currency symbol
|
||||
NSUInteger idx = NSMaxRange(symbolRange);
|
||||
if (idx < formatted.length)
|
||||
{
|
||||
unichar after = [formatted characterAtIndex:idx];
|
||||
hasSpace = [[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:after];
|
||||
}
|
||||
symbolPos = (hasSpace)
|
||||
? wxCurrencySymbolPosition::PrefixWithSep
|
||||
: wxCurrencySymbolPosition::PrefixNoSep;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check character preceding the currency symbol
|
||||
if (symbolRange.location > 0)
|
||||
{
|
||||
unichar before = [formatted characterAtIndex:symbolRange.location - 1];
|
||||
hasSpace = [[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:before];
|
||||
}
|
||||
symbolPos = (hasSpace)
|
||||
? wxCurrencySymbolPosition::SuffixWithSep
|
||||
: wxCurrencySymbolPosition::SuffixNoSep;
|
||||
}
|
||||
}
|
||||
|
||||
return symbolPos;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting
|
||||
wxUILocaleImplCF::DoGetNumberFormatting(wxLocaleCategory cat) const
|
||||
{
|
||||
wxCFRef<NSNumberFormatter*> cfRefFormatter = [[NSNumberFormatter alloc] init];
|
||||
NSNumberFormatter* formatter = cfRefFormatter.get();
|
||||
formatter.locale = m_nsloc;
|
||||
formatter.numberStyle = (cat == wxLOCALE_CAT_MONEY)
|
||||
? NSNumberFormatterCurrencyStyle
|
||||
: NSNumberFormatterDecimalStyle;
|
||||
|
||||
wxString groupSeparator = wxCFStringRef::AsString(formatter.groupingSeparator);
|
||||
|
||||
std::vector<int> grouping;
|
||||
int groupingSize = (int) formatter.groupingSize;
|
||||
int secondaryGroupingSize = (int) formatter.secondaryGroupingSize;
|
||||
if (groupingSize > 0)
|
||||
{
|
||||
if (secondaryGroupingSize > 0 && secondaryGroupingSize != groupingSize)
|
||||
{
|
||||
grouping.push_back(groupingSize);
|
||||
grouping.push_back(secondaryGroupingSize);
|
||||
grouping.push_back(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
grouping.push_back(groupingSize);
|
||||
grouping.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
wxString decimalSeparator = wxCFStringRef::AsString(formatter.decimalSeparator);
|
||||
int fractionalDigits = (int) formatter.minimumFractionDigits;
|
||||
|
||||
return wxLocaleNumberFormatting(groupSeparator, grouping, decimalSeparator, fractionalDigits);
|
||||
}
|
||||
|
||||
wxLocaleCurrencyInfo
|
||||
wxUILocaleImplCF::GetCurrencyInfo() const
|
||||
{
|
||||
wxLocaleNumberFormatting currencyFormatting = DoGetNumberFormatting(wxLOCALE_CAT_MONEY);
|
||||
return wxLocaleCurrencyInfo(
|
||||
GetCurrencySymbol(),
|
||||
GetCurrencyCode(),
|
||||
GetCurrencySymbolPosition(),
|
||||
currencyFormatting);
|
||||
}
|
||||
|
||||
wxMeasurementSystem
|
||||
wxUILocaleImplCF::UsesMetricSystem() const
|
||||
{
|
||||
if ([m_nsloc respondsToSelector:@selector(usesMetricSystem)])
|
||||
{
|
||||
BOOL isMetric = [m_nsloc usesMetricSystem];
|
||||
return (isMetric) ? wxMeasurementSystem::Metric : wxMeasurementSystem::NonMetric;
|
||||
}
|
||||
return wxMeasurementSystem::Unknown;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxUILocaleImpl* wxUILocaleImpl::CreateStdC()
|
||||
{
|
||||
|
||||
@@ -41,11 +41,27 @@
|
||||
#include "wx/tokenzr.h"
|
||||
#include "wx/utils.h"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#define TRACE_I18N wxS("i18n")
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Enumeration for accessing member variables of the localeconv structure
|
||||
// used as fallback, if nl_langinfo_l or nl_langinfo are not available
|
||||
enum wxLocaleConvAttr
|
||||
{
|
||||
LOCALE_CONV_THOUSANDS_SEP,
|
||||
LOCALE_CONV_DECIMAL_POINT,
|
||||
LOCALE_CONV_GROUPING,
|
||||
LOCALE_CONV_DIGITS,
|
||||
LOCALE_CONV_CURRENCY_SYMBOL,
|
||||
LOCALE_CONV_CURRENCY_CODE,
|
||||
LOCALE_CONV_CURRENCY_SYM_POS
|
||||
};
|
||||
|
||||
// Small helper function: get the value of the given environment variable and
|
||||
// return true only if the variable was found and has non-empty value.
|
||||
inline bool wxGetNonEmptyEnvVar(const wxString& name, wxString* value)
|
||||
@@ -191,6 +207,13 @@ public:
|
||||
#endif // wxUSE_DATETIME
|
||||
wxLayoutDirection GetLayoutDirection() const override;
|
||||
|
||||
wxLocaleNumberFormatting GetNumberFormatting() const override;
|
||||
wxString GetCurrencySymbol() const override;
|
||||
wxString GetCurrencyCode() const override;
|
||||
wxCurrencySymbolPosition GetCurrencySymbolPosition() const override;
|
||||
wxLocaleCurrencyInfo GetCurrencyInfo() const override;
|
||||
wxMeasurementSystem UsesMetricSystem() const override;
|
||||
|
||||
int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int flags) const override;
|
||||
|
||||
@@ -214,6 +237,11 @@ private:
|
||||
|
||||
const wxString& GetCodeSet() const;
|
||||
|
||||
wxLocaleNumberFormatting DoGetNumberFormatting(wxLocaleCategory cat) const;
|
||||
|
||||
#if !(defined(HAVE_LANGINFO_H) && defined(__GLIBC__))
|
||||
wxString DoGetInfoFromLocaleConv(wxLocaleConvAttr index, wxLocaleCategory cat) const;
|
||||
#endif
|
||||
|
||||
wxLocaleIdent m_locId;
|
||||
|
||||
@@ -520,7 +548,7 @@ wxUILocaleImplUnix::GetLangInfo(nl_item item) const
|
||||
if ( m_locale )
|
||||
return nl_langinfo_l(item, m_locale);
|
||||
#else
|
||||
TempLocaleSetter setThisLocale(LC_CTYPE, m_locId.GetName());
|
||||
TempLocaleSetter setThisLocale(LC_ALL, m_locId.GetName());
|
||||
#endif // HAVE_LOCALE_T
|
||||
|
||||
return nl_langinfo(item);
|
||||
@@ -534,7 +562,7 @@ wxUILocaleImplUnix::GetLangInfoWide(nl_item item) const
|
||||
if ( m_locale )
|
||||
return (wchar_t*) nl_langinfo_l(item, m_locale);
|
||||
#else
|
||||
TempLocaleSetter setThisLocale(LC_CTYPE, m_locId.GetName());
|
||||
TempLocaleSetter setThisLocale(LC_ALL, m_locId.GetName());
|
||||
#endif // HAVE_LOCALE_T
|
||||
|
||||
return (wchar_t*) nl_langinfo(item);
|
||||
@@ -591,7 +619,6 @@ wxUILocaleImplUnix::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const
|
||||
#else
|
||||
wxUnusedVar(cat);
|
||||
#endif
|
||||
|
||||
return GetLangInfo(RADIXCHAR);
|
||||
|
||||
case wxLOCALE_SHORT_DATE_FMT:
|
||||
@@ -832,6 +859,88 @@ wxUILocaleImplUnix::GetLayoutDirection() const
|
||||
return wxLayout_Default;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting
|
||||
wxUILocaleImplUnix::GetNumberFormatting() const
|
||||
{
|
||||
return DoGetNumberFormatting(wxLOCALE_CAT_NUMBER);
|
||||
}
|
||||
|
||||
wxString
|
||||
wxUILocaleImplUnix::GetCurrencySymbol() const
|
||||
{
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
wxString currencyStr = wxString(GetLangInfo(CURRENCY_SYMBOL), wxCSConv(GetCodeSet()));
|
||||
if (!currencyStr.empty() &&
|
||||
(currencyStr[0] == '+' ||
|
||||
currencyStr[0] == '-' ||
|
||||
currencyStr[0] == '.'))
|
||||
{
|
||||
currencyStr.erase(0, 1);
|
||||
}
|
||||
return currencyStr;
|
||||
#else
|
||||
return DoGetInfoFromLocaleConv(LOCALE_CONV_CURRENCY_SYMBOL, wxLOCALE_CAT_DEFAULT);
|
||||
#endif
|
||||
}
|
||||
|
||||
wxString
|
||||
wxUILocaleImplUnix::GetCurrencyCode() const
|
||||
{
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
wxString currencyCode = wxString(GetLangInfo(INT_CURR_SYMBOL), wxCSConv(GetCodeSet()));
|
||||
return currencyCode.Left(3);
|
||||
#else
|
||||
return DoGetInfoFromLocaleConv(LOCALE_CONV_CURRENCY_CODE, wxLOCALE_CAT_DEFAULT);
|
||||
#endif
|
||||
}
|
||||
|
||||
wxCurrencySymbolPosition
|
||||
wxUILocaleImplUnix::GetCurrencySymbolPosition() const
|
||||
{
|
||||
static std::array<wxCurrencySymbolPosition, 4> symPos = {
|
||||
wxCurrencySymbolPosition::PrefixNoSep, wxCurrencySymbolPosition::SuffixNoSep,
|
||||
wxCurrencySymbolPosition::PrefixWithSep, wxCurrencySymbolPosition::SuffixWithSep };
|
||||
|
||||
wxUint32 posIdx = 0;
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
const char* csPrecedes = GetLangInfo(P_CS_PRECEDES);
|
||||
const char* sepBySpace = GetLangInfo(P_SEP_BY_SPACE);
|
||||
posIdx += (csPrecedes[0] == 0) ? 1 : 0;
|
||||
posIdx += (sepBySpace[0] == 0) ? 0 : 2;
|
||||
#else
|
||||
wxString symbolPosition = DoGetInfoFromLocaleConv(LOCALE_CONV_CURRENCY_SYM_POS, wxLOCALE_CAT_DEFAULT);
|
||||
posIdx = symbolPosition.GetChar(0).GetValue();
|
||||
#endif
|
||||
return (posIdx < symPos.size()) ? symPos[posIdx] : wxCurrencySymbolPosition::PrefixWithSep;
|
||||
}
|
||||
|
||||
wxLocaleCurrencyInfo
|
||||
wxUILocaleImplUnix::GetCurrencyInfo() const
|
||||
{
|
||||
wxLocaleNumberFormatting currencyFormatting = DoGetNumberFormatting(wxLOCALE_CAT_MONEY);
|
||||
return wxLocaleCurrencyInfo(
|
||||
GetCurrencySymbol(),
|
||||
GetCurrencyCode(),
|
||||
GetCurrencySymbolPosition(),
|
||||
currencyFormatting);
|
||||
}
|
||||
|
||||
wxMeasurementSystem
|
||||
wxUILocaleImplUnix::UsesMetricSystem() const
|
||||
{
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
wxString measureStr = GetLangInfo(_NL_MEASUREMENT_MEASUREMENT);
|
||||
if (!measureStr.empty() && measureStr[0].GetValue() == 1)
|
||||
return wxMeasurementSystem::Metric;
|
||||
else if (!measureStr.empty() && measureStr[0].GetValue() == 2)
|
||||
return wxMeasurementSystem::NonMetric;
|
||||
else
|
||||
return wxMeasurementSystem::Unknown;
|
||||
#else
|
||||
return wxUILocale::GuessMetricSystemFromRegion(GetLocaleId());
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
wxUILocaleImplUnix::CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
int WXUNUSED(flags)) const
|
||||
@@ -854,6 +963,166 @@ wxUILocaleImplUnix::CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
wxLocaleNumberFormatting
|
||||
wxUILocaleImplUnix::DoGetNumberFormatting(wxLocaleCategory cat) const
|
||||
{
|
||||
wxString groupSeparator;
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
const char* groupSep =
|
||||
#ifdef MON_THOUSANDS_SEP
|
||||
(cat == wxLOCALE_CAT_MONEY)
|
||||
? GetLangInfo(MON_THOUSANDS_SEP)
|
||||
: GetLangInfo(THOUSEP);
|
||||
#else
|
||||
GetLangInfo(THOUSEP);
|
||||
#endif
|
||||
groupSeparator = wxString(groupSep, wxCSConv(GetCodeSet()));
|
||||
#else
|
||||
groupSeparator = DoGetInfoFromLocaleConv(LOCALE_CONV_THOUSANDS_SEP, cat);
|
||||
#endif
|
||||
|
||||
std::vector<int> grouping;
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
const char* groupingInfo =
|
||||
#ifdef MON_GROUPING
|
||||
(cat == wxLOCALE_CAT_MONEY)
|
||||
? GetLangInfo(MON_GROUPING)
|
||||
: GetLangInfo(GROUPING);
|
||||
#else
|
||||
GetLangInfo(GROUPING);
|
||||
#endif
|
||||
|
||||
// Include the terminating '\0' in total length
|
||||
size_t groupLen = strlen(groupingInfo) + 1;
|
||||
for (size_t j = 0; j < groupLen; ++j)
|
||||
{
|
||||
auto val = groupingInfo[j];
|
||||
if (val == CHAR_MAX)
|
||||
break;
|
||||
grouping.push_back(static_cast<int>(val));
|
||||
}
|
||||
#else
|
||||
wxString groupingStr = DoGetInfoFromLocaleConv(LOCALE_CONV_GROUPING, cat);
|
||||
for (auto ch : groupingStr)
|
||||
{
|
||||
auto val = ch.GetValue();
|
||||
if (val == CHAR_MAX)
|
||||
break;
|
||||
grouping.push_back(static_cast<int>(val));
|
||||
}
|
||||
#endif
|
||||
|
||||
wxString decimalSeparator;
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
const char* decimalSep =
|
||||
#ifdef MON_DECIMAL_POINT
|
||||
(cat == wxLOCALE_CAT_MONEY)
|
||||
? GetLangInfo(MON_DECIMAL_POINT)
|
||||
: GetLangInfo(RADIXCHAR);
|
||||
#else
|
||||
GetLangInfo(RADIXCHAR);
|
||||
#endif
|
||||
decimalSeparator = wxString(decimalSep, wxCSConv(GetCodeSet()));
|
||||
#else
|
||||
decimalSeparator = DoGetInfoFromLocaleConv(LOCALE_CONV_DECIMAL_POINT, cat);
|
||||
#endif
|
||||
|
||||
int fractionalDigits = 0;
|
||||
#if defined(HAVE_LANGINFO_H) && defined(__GLIBC__)
|
||||
const char* fracDigits = GetLangInfo(FRAC_DIGITS);
|
||||
fractionalDigits = (fracDigits) ? fracDigits[0] : 0;
|
||||
#else
|
||||
wxString fracDigits = DoGetInfoFromLocaleConv(LOCALE_CONV_DIGITS, cat);
|
||||
fractionalDigits = (!fracDigits.empty()) ? fracDigits.GetChar(0).GetValue() : 0;
|
||||
#endif
|
||||
|
||||
return wxLocaleNumberFormatting(groupSeparator, grouping, decimalSeparator, fractionalDigits);
|
||||
}
|
||||
|
||||
#if !(defined(HAVE_LANGINFO_H) && defined(__GLIBC__))
|
||||
|
||||
wxString
|
||||
wxUILocaleImplUnix::DoGetInfoFromLocaleConv(wxLocaleConvAttr index, wxLocaleCategory cat) const
|
||||
{
|
||||
// localeconv accesses only the global locale
|
||||
// temporarily set this locale
|
||||
TempLocaleSetter setThisLocale(LC_ALL, m_locId.GetName());
|
||||
|
||||
lconv* const lc = localeconv();
|
||||
if (!lc)
|
||||
return wxString();
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case LOCALE_CONV_THOUSANDS_SEP:
|
||||
{
|
||||
if (cat == wxLOCALE_CAT_MONEY)
|
||||
return wxString(lc->mon_thousands_sep, wxConvLibc);
|
||||
else
|
||||
return wxString(lc->thousands_sep, wxConvLibc);
|
||||
}
|
||||
|
||||
case LOCALE_CONV_DECIMAL_POINT:
|
||||
{
|
||||
if (cat == wxLOCALE_CAT_MONEY)
|
||||
return wxString(lc->mon_decimal_point, wxConvLibc);
|
||||
else
|
||||
return wxString(lc->decimal_point, wxConvLibc);
|
||||
}
|
||||
|
||||
case LOCALE_CONV_GROUPING:
|
||||
{
|
||||
wxString groupingStr;
|
||||
const char* grouping;
|
||||
if (cat == wxLOCALE_CAT_MONEY)
|
||||
grouping = lc->mon_grouping;
|
||||
else
|
||||
grouping = lc->grouping;
|
||||
|
||||
size_t groupLen = strlen(grouping);
|
||||
for (size_t j = 0; j < groupLen; ++j)
|
||||
groupingStr.Append(wxUniChar(grouping[j]));
|
||||
groupingStr.Append(wxUniChar(0));
|
||||
return groupingStr;
|
||||
}
|
||||
|
||||
case LOCALE_CONV_CURRENCY_SYMBOL:
|
||||
{
|
||||
return wxString(lc->currency_symbol, wxConvLibc);
|
||||
}
|
||||
|
||||
case LOCALE_CONV_CURRENCY_CODE:
|
||||
{
|
||||
return wxString(lc->int_curr_symbol, wxConvLibc).Left(3);
|
||||
}
|
||||
|
||||
case LOCALE_CONV_DIGITS:
|
||||
{
|
||||
wxString currencyDigitsStr(wxUniChar(lc->frac_digits));
|
||||
return currencyDigitsStr;
|
||||
}
|
||||
|
||||
case LOCALE_CONV_CURRENCY_SYM_POS:
|
||||
{
|
||||
char csPrecedes = lc->p_cs_precedes;
|
||||
char sepBySpace = lc->p_sep_by_space;
|
||||
wxUint32 posIdx = 0;
|
||||
posIdx += (csPrecedes == 0) ? 1 : 0;
|
||||
posIdx += (sepBySpace == 0) ? 0 : 2;
|
||||
wxString symbolPosition;
|
||||
symbolPosition.Append(wxUniChar(posIdx));
|
||||
return symbolPosition;
|
||||
}
|
||||
|
||||
default:
|
||||
wxFAIL_MSG("unknown localeconv value");
|
||||
}
|
||||
|
||||
return wxString();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
wxUILocaleImpl* wxUILocaleImpl::CreateStdC()
|
||||
{
|
||||
|
||||
@@ -417,11 +417,35 @@ TEST_CASE("wxUILocale::IsSupported", "[uilocale]")
|
||||
|
||||
TEST_CASE("wxUILocale::GetInfo", "[uilocale]")
|
||||
{
|
||||
CHECK( wxUILocale::FromTag("en").GetInfo(wxLOCALE_DECIMAL_POINT) == "." );
|
||||
const wxUILocale locEN(wxUILocale::FromTag("en-US"));
|
||||
CHECK( locEN.GetInfo(wxLOCALE_DECIMAL_POINT) == "." );
|
||||
CHECK( locEN.GetCurrencySymbol() == "$");
|
||||
CHECK( locEN.GetCurrencyCode() == "USD");
|
||||
CHECK( locEN.GetCurrencyInfo().currencyFormat.fractionalDigits == 2);
|
||||
CHECK( locEN.GetCurrencySymbolPosition() == wxCurrencySymbolPosition::PrefixNoSep );
|
||||
CHECK( locEN.UsesMetricSystem() == wxMeasurementSystem::NonMetric);
|
||||
|
||||
const wxUILocale locDE(wxUILocale::FromTag("de"));
|
||||
if ( CheckSupported(locDE, "German") )
|
||||
CHECK( locDE.GetInfo(wxLOCALE_DECIMAL_POINT) == "," );
|
||||
const wxUILocale locDE(wxUILocale::FromTag("de-DE"));
|
||||
if (CheckSupported(locDE, "German"))
|
||||
{
|
||||
CHECK( locDE.GetInfo(wxLOCALE_DECIMAL_POINT) == ",");
|
||||
CHECK( locDE.GetCurrencySymbol() == L"\u20AC");
|
||||
CHECK( locDE.GetCurrencyCode() == "EUR");
|
||||
CHECK( locDE.GetCurrencyInfo().currencyFormat.fractionalDigits == 2);
|
||||
CHECK( locDE.GetCurrencySymbolPosition() == wxCurrencySymbolPosition::SuffixWithSep);
|
||||
CHECK( locDE.UsesMetricSystem() == wxMeasurementSystem::Metric);
|
||||
}
|
||||
|
||||
const wxUILocale locFR(wxUILocale::FromTag("fr-FR"));
|
||||
if (CheckSupported(locFR, "French"))
|
||||
{
|
||||
CHECK( locFR.GetInfo(wxLOCALE_DECIMAL_POINT) == ",");
|
||||
CHECK( locFR.GetCurrencySymbol() == L"\u20AC");
|
||||
CHECK( locFR.GetCurrencyCode() == "EUR");
|
||||
CHECK( locFR.GetCurrencyInfo().currencyFormat.fractionalDigits == 2);
|
||||
CHECK( locFR.GetCurrencySymbolPosition() == wxCurrencySymbolPosition::SuffixWithSep);
|
||||
CHECK( locFR.UsesMetricSystem() == wxMeasurementSystem::Metric);
|
||||
}
|
||||
|
||||
// This one shows that "Swiss High German" locale (de_CH) correctly uses
|
||||
// dot, and not comma, as decimal separator, even under macOS, where POSIX
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user