// Initializes this with the decimal format symbols in the default locale.
DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
- : UObject(),
- locale()
-{
+ : UObject(), locale() {
initialize(locale, status, TRUE);
}
// Initializes this with the decimal format symbols in the desired locale.
DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
- : UObject(),
- locale(loc)
-{
+ : UObject(), locale(loc) {
initialize(locale, status);
}
+DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status)
+ : UObject(), locale(loc) {
+ initialize(locale, status, FALSE, &ns);
+}
+
DecimalFormatSymbols::DecimalFormatSymbols()
- : UObject(),
- locale(Locale::getRoot()),
- currPattern(NULL) {
+ : UObject(), locale(Locale::getRoot()), currPattern(NULL) {
*validLocale = *actualLocale = 0;
initialize();
}
} // namespace
void
-DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UBool useLastResortData)
+DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
+ UBool useLastResortData, const NumberingSystem* ns)
{
if (U_FAILURE(status)) { return; }
*validLocale = *actualLocale = 0;
// Next get the numbering system for this locale and set zero digit
// and the digit string based on the numbering system for the locale
//
- LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(loc, status));
+ LocalPointer<NumberingSystem> nsLocal;
+ if (ns == nullptr) {
+ // Use the numbering system according to the locale.
+ // Save it into a LocalPointer so it gets cleaned up.
+ nsLocal.adoptInstead(NumberingSystem::createInstance(loc, status));
+ ns = nsLocal.getAlias();
+ }
const char *nsName;
if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) {
nsName = ns->getName();
#include "unicode/uobject.h"
#include "unicode/locid.h"
+#include "unicode/numsys.h"
#include "unicode/unum.h"
#include "unicode/unistr.h"
*/
DecimalFormatSymbols(const Locale& locale, UErrorCode& status);
+ /**
+ * Creates a DecimalFormatSymbols instance for the given locale with digits and symbols
+ * corresponding to the given NumberingSystem.
+ *
+ * This constructor behaves equivalently to the normal constructor called with a locale having a
+ * "numbers=xxxx" keyword specifying the numbering system by name.
+ *
+ * In this constructor, the NumberingSystem argument will be used even if the locale has its own
+ * "numbers=xxxx" keyword.
+ *
+ * @param locale The locale to get symbols for.
+ * @param ns The numbering system.
+ * @param status Input/output parameter, set to success or
+ * failure code upon return.
+ * @draft ICU 60
+ */
+ DecimalFormatSymbols(const Locale& locale, const NumberingSystem& ns, UErrorCode& status);
+
/**
* Create a DecimalFormatSymbols object for the default locale.
* This constructor will not fail. If the resource file data is
* @param success Input/output parameter, set to success or
* failure code upon return.
* @param useLastResortData determine if use last resort data
+ * @param ns The NumberingSystem to use; otherwise, fall
+ * back to the locale.
*/
- void initialize(const Locale& locale, UErrorCode& success, UBool useLastResortData = FALSE);
+ void initialize(const Locale& locale, UErrorCode& success,
+ UBool useLastResortData = FALSE, const NumberingSystem* ns = nullptr);
/**
* Initialize the symbols with default values.
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(testSymbols);
TESTCASE_AUTO(testLastResortData);
+ TESTCASE_AUTO(testNumberingSystem);
TESTCASE_AUTO_END;
}
Verify(1234567.25, "#,##0.##", *lastResort, "1,234,567.25");
}
+void IntlTestDecimalFormatSymbols::testNumberingSystem() {
+ IcuTestErrorCode errorCode(*this, "testNumberingSystem");
+ struct testcase {
+ const char* locid;
+ const char* nsname;
+ const char16_t* expected1; // Expected number format string
+ const char16_t* expected2; // Expected pattern separator
+ };
+ static const testcase cases[9] = {
+ {"en", "latn", u"1,234.56", u";"},
+ {"en", "arab", u"١٬٢٣٤٫٥٦", u"؛"},
+ {"en", "mathsanb", u"𝟭,𝟮𝟯𝟰.𝟱𝟲", u";"},
+ {"en", "mymr", u"၁,၂၃၄.၅၆", u";"},
+ {"my", "latn", u"1,234.56", u";"},
+ {"my", "arab", u"١٬٢٣٤٫٥٦", u"؛"},
+ {"my", "mathsanb", u"𝟭,𝟮𝟯𝟰.𝟱𝟲", u";"},
+ {"my", "mymr", u"၁,၂၃၄.၅၆", u"၊"},
+ {"en@numbers=thai", "mymr", u"၁,၂၃၄.၅၆", u";"}, // conflicting numbering system
+ };
+
+ for (int i=0; i<8; i++) {
+ testcase cas = cases[i];
+ Locale loc(cas.locid);
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstanceByName(cas.nsname, errorCode));
+ if (errorCode.logDataIfFailureAndReset("NumberingSystem failed")) {
+ return;
+ }
+ UnicodeString expected1(cas.expected1);
+ UnicodeString expected2(cas.expected2);
+ DecimalFormatSymbols dfs(loc, *ns, errorCode);
+ if (errorCode.logDataIfFailureAndReset("DecimalFormatSymbols failed")) {
+ return;
+ }
+ Verify(1234.56, "#,##0.##", dfs, expected1);
+ // The pattern separator is something that differs by numbering system in my@numbers=mymr.
+ UnicodeString actual2 = dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
+ if (expected2 != actual2) {
+ errln((UnicodeString)"ERROR: DecimalFormatSymbols returned pattern separator " + actual2
+ + " but we expected " + expected2);
+ }
+ }
+}
+
void IntlTestDecimalFormatSymbols::Verify(double value, const UnicodeString& pattern,
const DecimalFormatSymbols &sym, const UnicodeString& expected){
UErrorCode status = U_ZERO_ERROR;
*/
void testSymbols(/*char *par*/);
void testLastResortData();
+ void testNumberingSystem();
/** helper functions**/
void Verify(double value, const UnicodeString& pattern,
* @stable ICU 2.0
*/
public DecimalFormatSymbols() {
- initialize(ULocale.getDefault(Category.FORMAT));
+ this(ULocale.getDefault(Category.FORMAT));
}
/**
* @stable ICU 2.0
*/
public DecimalFormatSymbols(Locale locale) {
- initialize(ULocale.forLocale(locale));
+ this(ULocale.forLocale(locale));
}
/**
* @stable ICU 3.2
*/
public DecimalFormatSymbols(ULocale locale) {
- initialize(locale);
+ initialize(locale, null);
+ }
+
+ private DecimalFormatSymbols(Locale locale, NumberingSystem ns) {
+ this(ULocale.forLocale(locale), ns);
+ }
+
+ private DecimalFormatSymbols(ULocale locale, NumberingSystem ns) {
+ initialize(locale, ns);
}
/**
return new DecimalFormatSymbols(locale);
}
+ /**
+ * {@icu} Returns a DecimalFormatSymbols instance for the given locale with digits and symbols
+ * corresponding to the given {@link NumberingSystem}.
+ *
+ * <p>This method behaves equivalently to {@link #getInstance} called with a locale having a
+ * "numbers=xxxx" keyword specifying the numbering system by name.
+ *
+ * <p>In this method, the NumberingSystem argument will be used even if the locale has its own
+ * "numbers=xxxx" keyword.
+ *
+ * @param locale the locale.
+ * @param ns the numbering system.
+ * @return A DecimalFormatSymbols instance.
+ * @provisional This API might change or be removed in a future release.
+ * @draft ICU 60
+ */
+ public static DecimalFormatSymbols forNumberingSystem(Locale locale, NumberingSystem ns) {
+ return new DecimalFormatSymbols(locale, ns);
+ }
+
+ /**
+ * {@icu} Returns a DecimalFormatSymbols instance for the given locale with digits and symbols
+ * corresponding to the given {@link NumberingSystem}.
+ *
+ * <p>This method behaves equivalently to {@link #getInstance} called with a locale having a
+ * "numbers=xxxx" keyword specifying the numbering system by name.
+ *
+ * <p>In this method, the NumberingSystem argument will be used even if the locale has its own
+ * "numbers=xxxx" keyword.
+ *
+ * @param locale the locale.
+ * @param ns the numbering system.
+ * @return A DecimalFormatSymbols instance.
+ * @provisional This API might change or be removed in a future release.
+ * @draft ICU 60
+ */
+ public static DecimalFormatSymbols forNumberingSystem(ULocale locale, NumberingSystem ns) {
+ return new DecimalFormatSymbols(locale, ns);
+ }
+
/**
* Returns an array of all locales for which the <code>getInstance</code> methods of
* this class can return localized instances.
/**
* Initializes the symbols from the locale data.
*/
- private void initialize( ULocale locale ) {
+ private void initialize(ULocale locale, NumberingSystem ns) {
this.requestedLocale = locale.toLocale();
this.ulocale = locale;
- CacheData data = cachedLocaleData.getInstance(locale, null /* unused */);
+
+ // TODO: The cache requires a single key, so we just save the NumberingSystem into the
+ // locale string. NumberingSystem is then decoded again in the loadData() method. It would
+ // be more efficient if we didn't have to serialize and deserialize the NumberingSystem.
+ ULocale keyLocale = (ns == null) ? locale : locale.setKeywordValue("numbers", ns.getName());
+ CacheData data = cachedLocaleData.getInstance(keyLocale, null /* unused */);
+
setLocale(data.validLocale, data.validLocale);
setDigitStrings(data.digits);
String[] numberElements = data.numberElements;
import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.DecimalFormatSymbols;
+import com.ibm.icu.text.NumberingSystem;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.ULocale;
errln("ERROR: Latin digits should be set" + symbols.getDigitStrings()[0]);
}
}
+
+ @Test
+ public void testNumberingSystem() {
+ Object[][] cases = {
+ {"en", "latn", "1,234.56", ';'},
+ {"en", "arab", "١٬٢٣٤٫٥٦", '؛'},
+ {"en", "mathsanb", "𝟭,𝟮𝟯𝟰.𝟱𝟲", ';'},
+ {"en", "mymr", "၁,၂၃၄.၅၆", ';'},
+ {"my", "latn", "1,234.56", ';'},
+ {"my", "arab", "١٬٢٣٤٫٥٦", '؛'},
+ {"my", "mathsanb", "𝟭,𝟮𝟯𝟰.𝟱𝟲", ';'},
+ {"my", "mymr", "၁,၂၃၄.၅၆", '၊'},
+ {"en@numbers=thai", "mymr", "၁,၂၃၄.၅၆", ';'}, // conflicting numbering system
+ };
+
+ for (Object[] cas : cases) {
+ ULocale loc = new ULocale((String) cas[0]);
+ NumberingSystem ns = NumberingSystem.getInstanceByName((String) cas[1]);
+ String expectedFormattedNumberString = (String) cas[2];
+ char expectedPatternSeparator = (Character) cas[3];
+
+ DecimalFormatSymbols dfs = DecimalFormatSymbols.forNumberingSystem(loc, ns);
+ DecimalFormat df = new DecimalFormat("#,##0.##", dfs);
+ String actual1 = df.format(1234.56);
+ assertEquals("1234.56 with " + loc + " and " + ns.getName(),
+ expectedFormattedNumberString, actual1);
+ // The pattern separator is something that differs by numbering system in my@numbers=mymr.
+ char actual2 = dfs.getPatternSeparator();
+ assertEquals("Pattern separator with " + loc + " and " + ns.getName(),
+ expectedPatternSeparator, actual2);
+
+ // Coverage for JDK Locale overload
+ DecimalFormatSymbols dfs2 = DecimalFormatSymbols.forNumberingSystem(loc.toLocale(), ns);
+ assertEquals("JDK Locale and ICU Locale should produce the same object", dfs, dfs2);
+ }
+ }
}