int32_t u_sprintf_spellout_handler(u_localized_string *output, const u_sprintf_spec_info *info, const ufmt_args *args) { double num = (double) (args[0].doubleValue); UNumberFormat *format; UChar result [USPRINTF_BUFFER_SIZE]; int32_t minDecimalDigits; int32_t maxDecimalDigits; UErrorCode status = U_ZERO_ERROR; /* mask off any necessary bits */ /* if(! info->fIsLongDouble) num &= DBL_MAX;*/ /* get the formatter */ format = u_locbund_getSpelloutFormat(output->fBundle); /* handle error */ if(format == 0) return 0; /* set the appropriate flags on the formatter */ /* clone the stream's bundle if it isn't owned */ if(! output->fOwnBundle) { output->fBundle = u_locbund_clone(output->fBundle); output->fOwnBundle = TRUE; format = u_locbund_getSpelloutFormat(output->fBundle); } /* set the number of decimal digits */ /* save the formatter's state */ minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); if(info->fPrecision != -1) { /* set the # of decimal digits */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); } else if(info->fPrecision == 0 && ! info->fAlt) { /* no decimal point in this case */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0); } else if(info->fAlt) { /* '#' means always show decimal point */ /* copy of printf behavior on Solaris - '#' shows 6 digits */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); } else { /* # of decimal digits is 6 if precision not specified */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); } /* set whether to show the sign */ u_sprintf_set_sign(format, info, &status); /* format the number */ unum_formatDouble(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status); /* restore the number format */ unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); return u_sprintf_pad_and_justify(output, info, result, u_strlen(result)); }
/* HSYS */ int32_t u_sprintf_integer_handler(u_localized_string *output, const u_sprintf_spec_info *info, const ufmt_args *args) { long num = (long) (args[0].intValue); UNumberFormat *format; UChar result [USPRINTF_BUFFER_SIZE]; int32_t minDigits = -1; UErrorCode status = U_ZERO_ERROR; /* mask off any necessary bits */ if(info->fIsShort) num &= UINT16_MAX; else if(! info->fIsLong || ! info->fIsLongLong) num &= UINT32_MAX; /* get the formatter */ format = u_locbund_getNumberFormat(output->fBundle); /* handle error */ if(format == 0) return 0; /* set the appropriate flags on the formatter */ /* set the minimum integer digits */ if(info->fPrecision != -1) { /* clone the stream's bundle if it isn't owned */ if(! output->fOwnBundle) { output->fBundle = u_locbund_clone(output->fBundle); output->fOwnBundle = TRUE; format = u_locbund_getNumberFormat(output->fBundle); } /* set the minimum # of digits */ minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS); unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision); } /* set whether to show the sign */ if(info->fShowSign) { /* clone the stream's bundle if it isn't owned */ if(! output->fOwnBundle) { output->fBundle = u_locbund_clone(output->fBundle); output->fOwnBundle = TRUE; format = u_locbund_getNumberFormat(output->fBundle); } u_sprintf_set_sign(format, info, &status); } /* format the number */ unum_format(format, num, result, USPRINTF_BUFFER_SIZE, 0, &status); /* restore the number format */ if(minDigits != -1) { unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits); } return u_sprintf_pad_and_justify(output, info, result, u_strlen(result)); }
static void TestRelDateFmt() { const RelDateTimeFormatTestItem *itemPtr; log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_format(), ureldatefmt_formatNumeric() with various parameters\n"); for (itemPtr = fmtTestItems; itemPtr->locale != NULL; itemPtr++) { URelativeDateTimeFormatter *reldatefmt = NULL; UNumberFormat* nfToAdopt = NULL; UErrorCode status = U_ZERO_ERROR; int32_t iOffset; if (itemPtr->decPlaces >= 0) { nfToAdopt = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status); if ( U_FAILURE(status) ) { log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr->locale, myErrorName(status)); continue; } unum_setAttribute(nfToAdopt, UNUM_MIN_FRACTION_DIGITS, itemPtr->decPlaces); unum_setAttribute(nfToAdopt, UNUM_MAX_FRACTION_DIGITS, itemPtr->decPlaces); unum_setAttribute(nfToAdopt, UNUM_ROUNDING_MODE, UNUM_ROUND_DOWN); } reldatefmt = ureldatefmt_open(itemPtr->locale, nfToAdopt, itemPtr->width, itemPtr->capContext, &status); if ( U_FAILURE(status) ) { log_data_err("FAIL: ureldatefmt_open() for locale %s, decPlaces %d, width %d, capContext %d: %s\n", itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); continue; } for (iOffset = 0; iOffset < kNumOffsets; iOffset++) { UChar ubufget[kUBufMax]; int32_t ulenget; if (itemPtr->unit >= UDAT_REL_UNIT_SUNDAY && offsets[iOffset] != -1.0 && offsets[iOffset] != 0.0 && offsets[iOffset] != 1.0) { continue; /* we do not currently have data for this */ } status = U_ZERO_ERROR; ulenget = ureldatefmt_format(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status); if ( U_FAILURE(status) ) { log_err("FAIL: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n", itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, offsets[iOffset], (int)itemPtr->unit, myErrorName(status) ); } else { UChar ubufexp[kUBufMax]; int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2], ubufexp, kUBufMax); if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { char bbufget[kBBufMax]; u_austrncpy(bbufget, ubufget, kUBufMax); log_err("ERROR: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d;\n expected %s\n get %s\n", itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2], bbufget ); } } if (itemPtr->unit >= UDAT_REL_UNIT_SUNDAY) { continue; /* we do not currently have numeric-style data for this */ } status = U_ZERO_ERROR; ulenget = ureldatefmt_formatNumeric(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status); if ( U_FAILURE(status) ) { log_err("FAIL: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n", itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, offsets[iOffset], (int)itemPtr->unit, myErrorName(status) ); } else { UChar ubufexp[kUBufMax]; int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2 + 1], ubufexp, kUBufMax); if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { char bbufget[kBBufMax]; u_austrncpy(bbufget, ubufget, kUBufMax); log_err("ERROR: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d;\n expected %s\n get %s\n", itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2 + 1], bbufget ); } } } ureldatefmt_close(reldatefmt); } }
/** * Test the functioning of the secondary grouping value. */ static void TestSecondaryGrouping(void) { UErrorCode status = U_ZERO_ERROR; UNumberFormat *f = NULL, *g= NULL; UNumberFormat *us = unum_open(UNUM_DECIMAL,NULL,0, "en_US", NULL,&status); UFieldPosition pos; UChar resultBuffer[512]; int32_t l = 1876543210L; UBool ok = TRUE; UChar buffer[512]; int32_t i; UBool expectGroup = FALSE, isGroup = FALSE; u_uastrcpy(buffer, "#,##,###"); f = unum_open(UNUM_IGNORE,buffer, -1, "en_US",NULL, &status); if (U_FAILURE(status)) { log_data_err("Error DecimalFormat ct -> %s (Are you missing data?)\n", u_errorName(status)); return; } pos.field = 0; unum_format(f, (int32_t)123456789L, resultBuffer, 512 , &pos, &status); u_uastrcpy(buffer, "12,34,56,789"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: Formatting \"#,##,###\" pattern with 123456789 got %s, expected %s\n", austrdup(resultBuffer), "12,34,56,789"); } if (pos.beginIndex != 0 && pos.endIndex != 12) { log_err("Fail: Formatting \"#,##,###\" pattern pos = (%d, %d) expected pos = (0, 12)\n", pos.beginIndex, pos.endIndex); } memset(resultBuffer,0, sizeof(UChar)*512); unum_toPattern(f, FALSE, resultBuffer, 512, &status); u_uastrcpy(buffer, "#,##,##0"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: toPattern() got %s, expected %s\n", austrdup(resultBuffer), "#,##,##0"); } memset(resultBuffer,0, sizeof(UChar)*512); u_uastrcpy(buffer, "#,###"); unum_applyPattern(f, FALSE, buffer, -1,NULL,NULL); if (U_FAILURE(status)) { log_err("Fail: applyPattern call failed\n"); } unum_setAttribute(f, UNUM_SECONDARY_GROUPING_SIZE, 4); unum_format(f, (int32_t)123456789L, resultBuffer, 512 , &pos, &status); u_uastrcpy(buffer, "12,3456,789"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: Formatting \"#,###\" pattern with 123456789 got %s, expected %s\n", austrdup(resultBuffer), "12,3456,789"); } memset(resultBuffer,0, sizeof(UChar)*512); unum_toPattern(f, FALSE, resultBuffer, 512, &status); u_uastrcpy(buffer, "#,####,##0"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: toPattern() got %s, expected %s\n", austrdup(resultBuffer), "#,####,##0"); } memset(resultBuffer,0, sizeof(UChar)*512); g = unum_open(UNUM_DECIMAL, NULL,0,"hi_IN",NULL, &status); if (U_FAILURE(status)) { log_err("Fail: Cannot create UNumberFormat for \"hi_IN\" locale.\n"); } unum_format(g, l, resultBuffer, 512, &pos, &status); unum_close(g); /* expect "1,87,65,43,210", but with Hindi digits */ /* 01234567890123 */ if (u_strlen(resultBuffer) != 14) { ok = FALSE; } else { for (i=0; i<u_strlen(resultBuffer); ++i) { expectGroup = FALSE; switch (i) { case 1: case 4: case 7: case 10: expectGroup = TRUE; break; } /* Later -- fix this to get the actual grouping */ /* character from the resource bundle. */ isGroup = (UBool)(resultBuffer[i] == 0x002C); if (isGroup != expectGroup) { ok = FALSE; break; } } } if (!ok) { log_err("FAIL Expected %s x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got %s\n", "1876543210L", resultBuffer); } unum_close(f); unum_close(us); }
static void NativeDecimalFormat_setAttribute(JNIEnv*, jclass, jlong addr, jint javaAttr, jint value) { UNumberFormatAttribute attr = static_cast<UNumberFormatAttribute>(javaAttr); unum_setAttribute(toUNumberFormat(addr), attr, value); }
static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text, jobject position, jboolean lenient) { // LOGI("ENTER parseRBNFImpl"); const char * parsePositionClassName = "java/text/ParsePosition"; const char * longClassName = "java/lang/Long"; const char * doubleClassName = "java/lang/Double"; UErrorCode status = U_ZERO_ERROR; UNumberFormat *fmt = (UNumberFormat *)(int)addr; jchar *str = (UChar *)env->GetStringChars(text, NULL); int strlength = env->GetStringLength(text); jclass parsePositionClass = env->FindClass(parsePositionClassName); jclass longClass = env->FindClass(longClassName); jclass doubleClass = env->FindClass(doubleClassName); jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, "getIndex", "()I"); jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, "setIndex", "(I)V"); jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, "setErrorIndex", "(I)V"); jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V"); jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V"); int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL); // make sure the ParsePosition is valid. Actually icu4c would parse a number // correctly even if the parsePosition is set to -1, but since the RI fails // for that case we have to fail too if(parsePos < 0 || parsePos > strlength) { return NULL; } Formattable res; const UnicodeString src((UChar*)str, strlength, strlength); ParsePosition pp; pp.setIndex(parsePos); if(lenient) { unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_TRUE); } ((const NumberFormat*)fmt)->parse(src, res, pp); if(lenient) { unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_FALSE); } env->ReleaseStringChars(text, str); if(pp.getErrorIndex() == -1) { parsePos = pp.getIndex(); } else { env->CallVoidMethod(position, setErrorIndexMethodID, (jint) pp.getErrorIndex()); return NULL; } Formattable::Type numType; numType = res.getType(); UErrorCode fmtStatus; double resultDouble; long resultLong; int64_t resultInt64; switch(numType) { case Formattable::kDouble: resultDouble = res.getDouble(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); return env->NewObject(doubleClass, dblInitMethodID, (jdouble) resultDouble); case Formattable::kLong: resultLong = res.getLong(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); return env->NewObject(longClass, longInitMethodID, (jlong) resultLong); case Formattable::kInt64: resultInt64 = res.getInt64(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); return env->NewObject(longClass, longInitMethodID, (jlong) resultInt64); default: break; } return NULL; }
static int32_t u_printf_spellout_handler(const u_printf_stream_handler *handler, void *context, ULocaleBundle *formatBundle, const u_printf_spec_info *info, const ufmt_args *args) { double num = (double) (args[0].doubleValue); UNumberFormat *format; UChar result[UPRINTF_BUFFER_SIZE]; UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; int32_t prefixBufferLen = sizeof(prefixBuffer); int32_t minDecimalDigits; int32_t maxDecimalDigits; int32_t resultLen; UErrorCode status = U_ZERO_ERROR; prefixBuffer[0] = 0; /* mask off any necessary bits */ /* if(! info->fIsLongDouble) num &= DBL_MAX;*/ /* get the formatter */ format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT); /* handle error */ if(format == 0) return 0; /* save the formatter's state */ minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); /* set the appropriate flags and number of decimal digits on the formatter */ if(info->fPrecision != -1) { /* set the # of decimal digits */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); } else if(info->fAlt) { /* '#' means always show decimal point */ /* copy of printf behavior on Solaris - '#' shows 6 digits */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); } else { /* # of decimal digits is 6 if precision not specified */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); } /* set whether to show the sign */ if (info->fShowSign) { u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); } /* format the number */ resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); if (U_FAILURE(status)) { resultLen = 0; } /* restore the number format */ /* TODO: Is this needed? */ unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); if (info->fShowSign) { /* Reset back to original value regardless of what the error was */ UErrorCode localStatus = U_ZERO_ERROR; u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); } return handler->pad_and_justify(context, info, result, resultLen); }
static int32_t u_printf_scientific_handler(const u_printf_stream_handler *handler, void *context, ULocaleBundle *formatBundle, const u_printf_spec_info *info, const ufmt_args *args) { double num = (double) (args[0].doubleValue); UNumberFormat *format; UChar result[UPRINTF_BUFFER_SIZE]; UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; int32_t prefixBufferLen = sizeof(prefixBuffer); int32_t minDecimalDigits; int32_t maxDecimalDigits; UErrorCode status = U_ZERO_ERROR; UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; int32_t srcLen, expLen; int32_t resultLen; UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; prefixBuffer[0] = 0; /* mask off any necessary bits */ /* if(! info->fIsLongDouble) num &= DBL_MAX;*/ /* get the formatter */ format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC); /* handle error */ if(format == 0) return 0; /* set the appropriate flags on the formatter */ srcLen = unum_getSymbol(format, UNUM_EXPONENTIAL_SYMBOL, srcExpBuf, sizeof(srcExpBuf), &status); /* Upper/lower case the e */ if (info->fSpec == (UChar)0x65 /* e */) { expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf), srcExpBuf, srcLen, formatBundle->fLocale, &status); } else { expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf), srcExpBuf, srcLen, formatBundle->fLocale, &status); } unum_setSymbol(format, UNUM_EXPONENTIAL_SYMBOL, expBuf, expLen, &status); /* save the formatter's state */ minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); /* set the appropriate flags and number of decimal digits on the formatter */ if(info->fPrecision != -1) { /* set the # of decimal digits */ if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) { unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); } else { unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1); unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision); } } else if(info->fAlt) { /* '#' means always show decimal point */ /* copy of printf behavior on Solaris - '#' shows 6 digits */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); } else { /* # of decimal digits is 6 if precision not specified */ unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); } /* set whether to show the sign */ if (info->fShowSign) { u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); } /* format the number */ resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); if (U_FAILURE(status)) { resultLen = 0; } /* restore the number format */ /* TODO: Is this needed? */ unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); /* Since we're the only one using the scientific format, we don't need to save the old exponent value. */ /*unum_setSymbol(format, UNUM_EXPONENTIAL_SYMBOL, srcExpBuf, srcLen, &status);*/ if (info->fShowSign) { /* Reset back to original value regardless of what the error was */ UErrorCode localStatus = U_ZERO_ERROR; u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); } return handler->pad_and_justify(context, info, result, resultLen); }
/* HSYS */ static int32_t u_printf_integer_handler(const u_printf_stream_handler *handler, void *context, ULocaleBundle *formatBundle, const u_printf_spec_info *info, const ufmt_args *args) { int64_t num = args[0].int64Value; UNumberFormat *format; UChar result[UPRINTF_BUFFER_SIZE]; UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; int32_t prefixBufferLen = sizeof(prefixBuffer); int32_t minDigits = -1; int32_t resultLen; UErrorCode status = U_ZERO_ERROR; prefixBuffer[0] = 0; /* mask off any necessary bits */ if (info->fIsShort) num = (int16_t)num; else if (!info->fIsLongLong) num = (int32_t)num; /* get the formatter */ format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); /* handle error */ if(format == 0) return 0; /* set the appropriate flags on the formatter */ /* set the minimum integer digits */ if(info->fPrecision != -1) { /* set the minimum # of digits */ minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS); unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision); } /* set whether to show the sign */ if(info->fShowSign) { u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); } /* format the number */ resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); if (U_FAILURE(status)) { resultLen = 0; } /* restore the number format */ if (minDigits != -1) { unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits); } if (info->fShowSign) { /* Reset back to original value regardless of what the error was */ UErrorCode localStatus = U_ZERO_ERROR; u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); } return handler->pad_and_justify(context, info, result, resultLen); }
void IntlPluralRules::initializePluralRules(ExecState& exec, JSValue locales, JSValue optionsValue) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 13.1.1 InitializePluralRules (pluralRules, locales, options) // https://tc39.github.io/ecma402/#sec-initializepluralrules Vector<String> requestedLocales = canonicalizeLocaleList(exec, locales); RETURN_IF_EXCEPTION(scope, void()); JSObject* options; if (optionsValue.isUndefined()) options = constructEmptyObject(&exec, exec.lexicalGlobalObject()->nullPrototypeObjectStructure()); else { options = optionsValue.toObject(&exec); RETURN_IF_EXCEPTION(scope, void()); } HashMap<String, String> localeOpt; String localeMatcher = intlStringOption(exec, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit"); RETURN_IF_EXCEPTION(scope, void()); localeOpt.add(vm.propertyNames->localeMatcher.string(), localeMatcher); const HashSet<String> availableLocales = exec.jsCallee()->globalObject(vm)->intlNumberFormatAvailableLocales(); HashMap<String, String> resolved = resolveLocale(exec, availableLocales, requestedLocales, localeOpt, nullptr, 0, IntlPRInternal::localeData); m_locale = resolved.get(vm.propertyNames->locale.string()); if (m_locale.isEmpty()) { throwTypeError(&exec, scope, "failed to initialize PluralRules due to invalid locale"_s); return; } String typeString = intlStringOption(exec, options, Identifier::fromString(&vm, "type"), { "cardinal", "ordinal" }, "type must be \"cardinal\" or \"ordinal\"", "cardinal"); RETURN_IF_EXCEPTION(scope, void()); m_type = typeString == "ordinal" ? UPLURAL_TYPE_ORDINAL : UPLURAL_TYPE_CARDINAL; unsigned minimumIntegerDigits = intlNumberOption(exec, options, Identifier::fromString(&vm, "minimumIntegerDigits"), 1, 21, 1); RETURN_IF_EXCEPTION(scope, void()); m_minimumIntegerDigits = minimumIntegerDigits; unsigned minimumFractionDigitsDefault = 0; unsigned minimumFractionDigits = intlNumberOption(exec, options, Identifier::fromString(&vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault); RETURN_IF_EXCEPTION(scope, void()); m_minimumFractionDigits = minimumFractionDigits; unsigned maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u); unsigned maximumFractionDigits = intlNumberOption(exec, options, Identifier::fromString(&vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault); RETURN_IF_EXCEPTION(scope, void()); m_maximumFractionDigits = maximumFractionDigits; JSValue minimumSignificantDigitsValue = options->get(&exec, Identifier::fromString(&vm, "minimumSignificantDigits")); RETURN_IF_EXCEPTION(scope, void()); JSValue maximumSignificantDigitsValue = options->get(&exec, Identifier::fromString(&vm, "maximumSignificantDigits")); RETURN_IF_EXCEPTION(scope, void()); if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) { unsigned minimumSignificantDigits = intlNumberOption(exec, options, Identifier::fromString(&vm, "minimumSignificantDigits"), 1, 21, 1); RETURN_IF_EXCEPTION(scope, void()); unsigned maximumSignificantDigits = intlNumberOption(exec, options, Identifier::fromString(&vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21); RETURN_IF_EXCEPTION(scope, void()); m_minimumSignificantDigits = minimumSignificantDigits; m_maximumSignificantDigits = maximumSignificantDigits; } UErrorCode status = U_ZERO_ERROR; m_numberFormat = std::unique_ptr<UNumberFormat, UNumberFormatDeleter>(unum_open(UNUM_DECIMAL, nullptr, 0, m_locale.utf8().data(), nullptr, &status)); if (U_FAILURE(status)) { throwTypeError(&exec, scope, "failed to initialize PluralRules"_s); return; } if (m_minimumSignificantDigits) { unum_setAttribute(m_numberFormat.get(), UNUM_SIGNIFICANT_DIGITS_USED, true); unum_setAttribute(m_numberFormat.get(), UNUM_MIN_SIGNIFICANT_DIGITS, m_minimumSignificantDigits.value()); unum_setAttribute(m_numberFormat.get(), UNUM_MAX_SIGNIFICANT_DIGITS, m_maximumSignificantDigits.value()); } else { unum_setAttribute(m_numberFormat.get(), UNUM_MIN_INTEGER_DIGITS, m_minimumIntegerDigits); unum_setAttribute(m_numberFormat.get(), UNUM_MIN_FRACTION_DIGITS, m_minimumFractionDigits); unum_setAttribute(m_numberFormat.get(), UNUM_MAX_FRACTION_DIGITS, m_maximumFractionDigits); } status = U_ZERO_ERROR; m_pluralRules = std::unique_ptr<UPluralRules, UPluralRulesDeleter>(uplrules_openForType(m_locale.utf8().data(), m_type, &status)); if (U_FAILURE(status)) { throwTypeError(&exec, scope, "failed to initialize PluralRules"_s); return; } m_initializedPluralRules = true; }
/** * call-seq: * 23874.localize(:decimal, 'es_ES') => 23.874 */ VALUE rb_numeric_localize(int argc, VALUE *argv, VALUE self) { VALUE style, options; UNumberFormatStyle formatStyle; char *locale = NULL; UNumberFormat *format; UErrorCode status; UChar result[256]; /* arguments */ rb_scan_args(argc, argv, "02", &style, &options); if (style == Qnil) { formatStyle = UNUM_DECIMAL; } else { ID style_ID; Check_Type(style, T_SYMBOL); style_ID = SYM2ID(style); if (style_ID == rb_intern("decimal")) { formatStyle = UNUM_DECIMAL; } else if (style_ID == rb_intern("currency")) { formatStyle = UNUM_CURRENCY; } else if (style_ID == rb_intern("percent")) { formatStyle = UNUM_PERCENT; } else if (style_ID == rb_intern("scientific")) { formatStyle = UNUM_SCIENTIFIC; } else if (style_ID == rb_intern("spellout")) { formatStyle = UNUM_SPELLOUT; } else { rb_raise(rb_eArgError, "unsupported format style %s", rb_id2name(style_ID)); } } if (options != Qnil) { VALUE rb_locale; Check_Type(options, T_HASH); rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale"))); if (rb_locale != Qnil) { locale = StringValuePtr(rb_locale); } } /* formatter */ status = U_ZERO_ERROR; format = unum_open(formatStyle, NULL, 0, locale, NULL, &status); RAISE_ON_ERROR(status); /* set format attributes */ if (options != Qnil) { VALUE currency, precision, round_mode, round_increment; switch (formatStyle) { case UNUM_CURRENCY: currency = rb_hash_aref(options, ID2SYM(rb_intern("currency"))); if (currency != Qnil) { UChar *uStr; int32_t uStrLen; uStr = u_strFromRString(currency, &uStrLen); status = U_ZERO_ERROR; unum_setTextAttribute(format, UNUM_CURRENCY_CODE, uStr, uStrLen, &status); RAISE_ON_ERROR(status); } case UNUM_DECIMAL: /* precision */ precision = rb_hash_aref(options, ID2SYM(rb_intern("precision"))); if (precision != Qnil) { Check_Type(precision, T_FIXNUM); status = U_ZERO_ERROR; unum_setAttribute(format, UNUM_FRACTION_DIGITS, NUM2INT(precision)); RAISE_ON_ERROR(status); } round_mode = rb_hash_aref(options, ID2SYM(rb_intern("round_mode"))); if (round_mode != Qnil) { ID round_mode_ID; UNumberFormatRoundingMode rounding_mode; Check_Type(round_mode, T_SYMBOL); round_mode_ID = SYM2ID(round_mode); if (round_mode_ID == rb_intern("ceil")) { rounding_mode = UNUM_ROUND_CEILING; } else if (round_mode_ID == rb_intern("floor")) { rounding_mode = UNUM_ROUND_FLOOR; } else if (round_mode_ID == rb_intern("down")) { rounding_mode = UNUM_ROUND_DOWN; } else if (round_mode_ID == rb_intern("up")) { rounding_mode = UNUM_ROUND_UP; } else if (round_mode_ID == rb_intern("halfeven")) { rounding_mode = UNUM_FOUND_HALFEVEN; } else if (round_mode_ID == rb_intern("halfdown")) { rounding_mode = UNUM_ROUND_HALFDOWN; } else if (round_mode_ID == rb_intern("halfup")) { rounding_mode = UNUM_ROUND_HALFUP; } else { rb_raise(rb_eArgError, "unsupported rounding mode '%s'", rb_id2name(round_mode_ID)); } status = U_ZERO_ERROR; unum_setAttribute(format, UNUM_ROUNDING_MODE, rounding_mode); RAISE_ON_ERROR(status); } round_increment = rb_hash_aref(options, ID2SYM(rb_intern("round_increment"))); if (round_increment != Qnil) { Check_Type(round_increment, T_FLOAT); status = U_ZERO_ERROR; unum_setDoubleAttribute(format, UNUM_ROUNDING_INCREMENT, NUM2DBL(round_increment)); RAISE_ON_ERROR(status); } } } /* format */ status = U_ZERO_ERROR; switch (TYPE(self)) { case T_FIXNUM: unum_format(format, NUM2INT(self), result, 256, NULL, &status); break; case T_FLOAT: unum_formatDouble(format, NUM2DBL(self), result, 256, NULL, &status); break; case T_BIGNUM: unum_formatInt64(format, rb_big2ll(self), result, 256, NULL, &status); break; } RAISE_ON_ERROR(status); /* free resources */ unum_close(format); return u_strToRString(result, -1); }