ICU-13634 Centralizing data loading for pattern strings.
X-SVN-Rev: 41230
This commit is contained in:
parent
cbae6dfbaa
commit
e0df2775ea
@ -34,6 +34,16 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
|
||||
|
||||
DecimalFormat::DecimalFormat(UErrorCode& status)
|
||||
: DecimalFormat(nullptr, status) {
|
||||
// Use the default locale and decimal pattern.
|
||||
const char* localeName = Locale::getDefault().getName();
|
||||
LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(status));
|
||||
UnicodeString patternString = utils::getPatternForStyle(
|
||||
localeName,
|
||||
ns->getName(),
|
||||
CLDR_PATTERN_STYLE_DECIMAL,
|
||||
status);
|
||||
setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status);
|
||||
refreshFormatter(status);
|
||||
}
|
||||
|
||||
DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
|
||||
|
@ -26,70 +26,6 @@ using namespace icu::number::impl;
|
||||
|
||||
namespace {
|
||||
|
||||
// NOTE: In Java, the method to get a pattern from the resource bundle exists in NumberFormat.
|
||||
// In C++, we have to implement that logic here.
|
||||
// TODO: Make Java and C++ consistent?
|
||||
|
||||
enum CldrPatternStyle {
|
||||
CLDR_PATTERN_STYLE_DECIMAL,
|
||||
CLDR_PATTERN_STYLE_CURRENCY,
|
||||
CLDR_PATTERN_STYLE_ACCOUNTING,
|
||||
CLDR_PATTERN_STYLE_PERCENT
|
||||
// TODO: Consider scientific format.
|
||||
};
|
||||
|
||||
const char16_t*
|
||||
doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
|
||||
UErrorCode& localStatus) {
|
||||
// Construct the path into the resource bundle
|
||||
CharString key;
|
||||
key.append("NumberElements/", publicStatus);
|
||||
key.append(nsName, publicStatus);
|
||||
key.append("/patterns/", publicStatus);
|
||||
key.append(patternKey, publicStatus);
|
||||
if (U_FAILURE(publicStatus)) {
|
||||
return u"";
|
||||
}
|
||||
return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus);
|
||||
}
|
||||
|
||||
const char16_t* getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
|
||||
UErrorCode& status) {
|
||||
const char* patternKey;
|
||||
switch (style) {
|
||||
case CLDR_PATTERN_STYLE_DECIMAL:
|
||||
patternKey = "decimalFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_CURRENCY:
|
||||
patternKey = "currencyFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_ACCOUNTING:
|
||||
patternKey = "accountingFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_PERCENT:
|
||||
default:
|
||||
patternKey = "percentFormat";
|
||||
break;
|
||||
}
|
||||
LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status));
|
||||
if (U_FAILURE(status)) { return u""; }
|
||||
|
||||
// Attempt to get the pattern with the native numbering system.
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
const char16_t* pattern;
|
||||
pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus);
|
||||
if (U_FAILURE(status)) { return u""; }
|
||||
|
||||
// Fall back to latn if native numbering system does not have the right pattern
|
||||
if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) {
|
||||
localStatus = U_ZERO_ERROR;
|
||||
pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus);
|
||||
if (U_FAILURE(status)) { return u""; }
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
struct CurrencyFormatInfoResult {
|
||||
bool exists;
|
||||
const char16_t* pattern;
|
||||
@ -195,10 +131,10 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
// TODO: Accept currency symbols from DecimalFormatSymbols?
|
||||
|
||||
// Pre-compute a few values for efficiency.
|
||||
bool isCurrency = unitIsCurrency(macros.unit);
|
||||
bool isNoUnit = unitIsNoUnit(macros.unit);
|
||||
bool isPercent = isNoUnit && unitIsPercent(macros.unit);
|
||||
bool isPermille = isNoUnit && unitIsPermille(macros.unit);
|
||||
bool isCurrency = utils::unitIsCurrency(macros.unit);
|
||||
bool isNoUnit = utils::unitIsNoUnit(macros.unit);
|
||||
bool isPercent = isNoUnit && utils::unitIsPercent(macros.unit);
|
||||
bool isPermille = isNoUnit && utils::unitIsPermille(macros.unit);
|
||||
bool isCldrUnit = !isCurrency && !isNoUnit;
|
||||
bool isAccounting =
|
||||
macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
|
||||
@ -277,7 +213,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
|
||||
} else {
|
||||
patternStyle = CLDR_PATTERN_STYLE_CURRENCY;
|
||||
}
|
||||
pattern = getPatternForStyle(macros.locale, nsName, patternStyle, status);
|
||||
pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status);
|
||||
}
|
||||
auto patternInfo = new ParsedPatternInfo();
|
||||
fPatternInfo.adoptInstead(patternInfo);
|
||||
@ -522,7 +458,7 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
|
||||
|
||||
// Get and append the next digit value
|
||||
int8_t nextDigit = quantity.getDigit(i);
|
||||
length += insertDigitFromSymbols(
|
||||
length += utils::insertDigitFromSymbols(
|
||||
string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
|
||||
}
|
||||
return length;
|
||||
@ -535,7 +471,7 @@ int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, Decim
|
||||
for (int i = 0; i < fractionCount; i++) {
|
||||
// Get and append the next digit value
|
||||
int8_t nextDigit = quantity.getDigit(-i - 1);
|
||||
length += insertDigitFromSymbols(
|
||||
length += utils::insertDigitFromSymbols(
|
||||
string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
|
||||
}
|
||||
return length;
|
||||
|
@ -64,7 +64,13 @@ int32_t ScientificModifier::apply(NumberStringBuilder &output, int32_t /*leftInd
|
||||
int32_t disp = std::abs(fExponent);
|
||||
for (int j = 0; j < fHandler->fSettings.fMinExponentDigits || disp > 0; j++, disp /= 10) {
|
||||
auto d = static_cast<int8_t>(disp % 10);
|
||||
i += insertDigitFromSymbols(output, i - j, d, *fHandler->fSymbols, UNUM_EXPONENT_FIELD, status);
|
||||
i += utils::insertDigitFromSymbols(
|
||||
output,
|
||||
i - j,
|
||||
d,
|
||||
*fHandler->fSymbols,
|
||||
UNUM_EXPONENT_FIELD,
|
||||
status);
|
||||
}
|
||||
return i - rightIndex;
|
||||
}
|
||||
|
@ -1256,15 +1256,15 @@ bool GeneratorHelpers::notation(const MacroProps& macros, UnicodeString& sb, UEr
|
||||
}
|
||||
|
||||
bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
|
||||
if (unitIsCurrency(macros.unit)) {
|
||||
if (utils::unitIsCurrency(macros.unit)) {
|
||||
sb.append(u"currency/", -1);
|
||||
blueprint_helpers::generateCurrencyOption({macros.unit, status}, sb, status);
|
||||
return true;
|
||||
} else if (unitIsNoUnit(macros.unit)) {
|
||||
if (unitIsPercent(macros.unit)) {
|
||||
} else if (utils::unitIsNoUnit(macros.unit)) {
|
||||
if (utils::unitIsPercent(macros.unit)) {
|
||||
sb.append(u"percent", -1);
|
||||
return true;
|
||||
} else if (unitIsPermille(macros.unit)) {
|
||||
} else if (utils::unitIsPermille(macros.unit)) {
|
||||
sb.append(u"permille", -1);
|
||||
return true;
|
||||
} else {
|
||||
@ -1280,15 +1280,15 @@ bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorC
|
||||
|
||||
bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
|
||||
// Per-units are currently expected to be only MeasureUnits.
|
||||
if (unitIsNoUnit(macros.perUnit)) {
|
||||
if (unitIsPercent(macros.perUnit) || unitIsPermille(macros.perUnit)) {
|
||||
if (utils::unitIsNoUnit(macros.perUnit)) {
|
||||
if (utils::unitIsPercent(macros.perUnit) || utils::unitIsPermille(macros.perUnit)) {
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return false;
|
||||
} else {
|
||||
// Default value: ok to ignore
|
||||
return false;
|
||||
}
|
||||
} else if (unitIsCurrency(macros.perUnit)) {
|
||||
} else if (utils::unitIsCurrency(macros.perUnit)) {
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return false;
|
||||
} else {
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "decContext.h"
|
||||
#include "decNumber.h"
|
||||
#include "double-conversion.h"
|
||||
#include "uresimp.h"
|
||||
#include "ureslocs.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
@ -25,6 +27,68 @@ using namespace icu::number::impl;
|
||||
using icu::double_conversion::DoubleToStringConverter;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
const char16_t*
|
||||
doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
|
||||
UErrorCode& localStatus) {
|
||||
// Construct the path into the resource bundle
|
||||
CharString key;
|
||||
key.append("NumberElements/", publicStatus);
|
||||
key.append(nsName, publicStatus);
|
||||
key.append("/patterns/", publicStatus);
|
||||
key.append(patternKey, publicStatus);
|
||||
if (U_FAILURE(publicStatus)) {
|
||||
return u"";
|
||||
}
|
||||
return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const char16_t* utils::getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
|
||||
UErrorCode& status) {
|
||||
const char* patternKey;
|
||||
switch (style) {
|
||||
case CLDR_PATTERN_STYLE_DECIMAL:
|
||||
patternKey = "decimalFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_CURRENCY:
|
||||
patternKey = "currencyFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_ACCOUNTING:
|
||||
patternKey = "accountingFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_PERCENT:
|
||||
patternKey = "percentFormat";
|
||||
break;
|
||||
case CLDR_PATTERN_STYLE_SCIENTIFIC:
|
||||
patternKey = "scientificFormat";
|
||||
break;
|
||||
default:
|
||||
U_ASSERT(false);
|
||||
}
|
||||
LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status));
|
||||
if (U_FAILURE(status)) { return u""; }
|
||||
|
||||
// Attempt to get the pattern with the native numbering system.
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
const char16_t* pattern;
|
||||
pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus);
|
||||
if (U_FAILURE(status)) { return u""; }
|
||||
|
||||
// Fall back to latn if native numbering system does not have the right pattern
|
||||
if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) {
|
||||
localStatus = U_ZERO_ERROR;
|
||||
pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus);
|
||||
if (U_FAILURE(status)) { return u""; }
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
|
||||
DecNum::DecNum() {
|
||||
uprv_decContextDefault(&fContext, DEC_INIT_BASE);
|
||||
uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
|
||||
|
@ -105,6 +105,18 @@ struct MicroProps : public MicroPropsGenerator {
|
||||
bool exhausted = false;
|
||||
};
|
||||
|
||||
enum CldrPatternStyle {
|
||||
CLDR_PATTERN_STYLE_DECIMAL,
|
||||
CLDR_PATTERN_STYLE_CURRENCY,
|
||||
CLDR_PATTERN_STYLE_ACCOUNTING,
|
||||
CLDR_PATTERN_STYLE_PERCENT,
|
||||
CLDR_PATTERN_STYLE_SCIENTIFIC,
|
||||
CLDR_PATTERN_STYLE_COUNT,
|
||||
};
|
||||
|
||||
// Namespace for naked functions
|
||||
namespace utils {
|
||||
|
||||
inline int32_t insertDigitFromSymbols(NumberStringBuilder& output, int32_t index, int8_t digit,
|
||||
const DecimalFormatSymbols& symbols, Field field,
|
||||
UErrorCode& status) {
|
||||
@ -130,6 +142,12 @@ inline bool unitIsPermille(const MeasureUnit& unit) {
|
||||
return uprv_strcmp("permille", unit.getSubtype()) == 0;
|
||||
}
|
||||
|
||||
// NOTE: In Java, this method is in NumberFormat.java
|
||||
const char16_t*
|
||||
getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
|
||||
/** A very thin C++ wrapper around decNumber.h */
|
||||
class DecNum : public UMemory {
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "sharednumberformat.h"
|
||||
#include "unifiedcache.h"
|
||||
#include "number_decimalquantity.h"
|
||||
#include "number_utils.h"
|
||||
|
||||
//#define FMT_DEBUG
|
||||
|
||||
@ -129,31 +130,28 @@ static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] =
|
||||
|
||||
// Keys used for accessing resource bundles
|
||||
|
||||
static const char *gNumberElements = "NumberElements";
|
||||
static const char *gLatn = "latn";
|
||||
static const char *gPatterns = "patterns";
|
||||
static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = {
|
||||
NULL, // UNUM_PATTERN_DECIMAL
|
||||
"decimalFormat", // UNUM_DECIMAL
|
||||
"currencyFormat", // UNUM_CURRENCY
|
||||
"percentFormat", // UNUM_PERCENT
|
||||
"scientificFormat", // UNUM_SCIENTIFIC
|
||||
NULL, // UNUM_SPELLOUT
|
||||
NULL, // UNUM_ORDINAL
|
||||
NULL, // UNUM_DURATION
|
||||
NULL, // UNUM_NUMBERING_SYSTEM
|
||||
NULL, // UNUM_PATTERN_RULEBASED
|
||||
static const icu::number::impl::CldrPatternStyle gFormatCldrStyles[UNUM_FORMAT_STYLE_COUNT] = {
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_PATTERN_DECIMAL
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_DECIMAL, // UNUM_DECIMAL
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_PERCENT, // UNUM_PERCENT
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_SCIENTIFIC, // UNUM_SCIENTIFIC
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_SPELLOUT
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_ORDINAL
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DURATION
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_NUMBERING_SYSTEM
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_PATTERN_RULEBASED
|
||||
// For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL,
|
||||
// the pattern is the same as the pattern of UNUM_CURRENCY
|
||||
// except for replacing the single currency sign with
|
||||
// double currency sign or triple currency sign.
|
||||
"currencyFormat", // UNUM_CURRENCY_ISO
|
||||
"currencyFormat", // UNUM_CURRENCY_PLURAL
|
||||
"accountingFormat", // UNUM_CURRENCY_ACCOUNTING
|
||||
"currencyFormat", // UNUM_CASH_CURRENCY
|
||||
NULL, // UNUM_DECIMAL_COMPACT_SHORT
|
||||
NULL, // UNUM_DECIMAL_COMPACT_LONG
|
||||
"currencyFormat", // UNUM_CURRENCY_STANDARD
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_ISO
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_PLURAL
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_ACCOUNTING, // UNUM_CURRENCY_ACCOUNTING
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CASH_CURRENCY
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DECIMAL_COMPACT_SHORT
|
||||
/* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DECIMAL_COMPACT_LONG
|
||||
icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_STANDARD
|
||||
};
|
||||
|
||||
// Static hashtable cache of NumberingSystem objects used by NumberFormat
|
||||
@ -1400,27 +1398,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UResourceBundle *resource = ownedResource.orphan();
|
||||
UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status);
|
||||
resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status);
|
||||
resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
|
||||
ownedResource.adoptInstead(resource);
|
||||
|
||||
int32_t patLen = 0;
|
||||
const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
|
||||
|
||||
// Didn't find a pattern specific to the numbering system, so fall back to "latn"
|
||||
if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) {
|
||||
status = U_ZERO_ERROR;
|
||||
resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status);
|
||||
resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
|
||||
patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
|
||||
}
|
||||
|
||||
ures_close(numElements);
|
||||
|
||||
// Creates the specified decimal format style of the desired locale.
|
||||
pattern.setTo(TRUE, patResStr, patLen);
|
||||
// Load the pattern from data using the common library function
|
||||
const char16_t* patternPtr = number::impl::utils::getPatternForStyle(
|
||||
desiredLocale,
|
||||
ns->getName(),
|
||||
gFormatCldrStyles[style],
|
||||
status);
|
||||
pattern = UnicodeString(TRUE, patternPtr, -1);
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user