/* PAL Function: GetLocaleInfoGroupingSizes Obtains grouping sizes for decimal and currency Returns 1 for success, 0 otherwise */ extern "C" int32_t GlobalizationNative_GetLocaleInfoGroupingSizes( const UChar* localeName, LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } UNumberFormatStyle style; switch (localeGroupingData) { case Digit: style = UNUM_DECIMAL; break; case Monetary: style = UNUM_CURRENCY; break; default: return UErrorCodeToBool(U_UNSUPPORTED_ERROR); } UNumberFormat* numformat = unum_open(style, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE); *secondaryGroupSize = unum_getAttribute(numformat, UNUM_SECONDARY_GROUPING_SIZE); unum_close(numformat); } return UErrorCodeToBool(status); }
/* Function: InvokeCallbackForDateTimePattern Gets the DateTime pattern for the specified skeleton and invokes the callback with the retrieved value. */ static int InvokeCallbackForDateTimePattern(const char* locale, const UChar* patternSkeleton, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); if (U_FAILURE(err)) return FALSE; UErrorCode ignore = U_ZERO_ERROR; int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, NULL, 0, &ignore) + 1; UChar* bestPattern = calloc(patternLen, sizeof(UChar)); if (bestPattern == NULL) { udatpg_close(pGenerator); return FALSE; } udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern, patternLen, &err); udatpg_close(pGenerator); if (U_SUCCESS(err)) { callback(bestPattern, context); } free(bestPattern); return UErrorCodeToBool(err); }
/* Function: InvokeCallbackForDatePattern Gets the ICU date pattern for the specified locale and EStyle and invokes the callback with the result. */ static int InvokeCallbackForDatePattern(const char* locale, UDateFormatStyle style, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale, NULL, 0, NULL, 0, &err); if (U_FAILURE(err)) return FALSE; UErrorCode ignore = U_ZERO_ERROR; int32_t patternLen = udat_toPattern(pFormat, FALSE, NULL, 0, &ignore) + 1; UChar* pattern = calloc(patternLen, sizeof(UChar)); if (pattern == NULL) { udat_close(pFormat); return FALSE; } udat_toPattern(pFormat, FALSE, pattern, patternLen, &err); udat_close(pFormat); if (U_SUCCESS(err)) { callback(pattern, context); } free(pattern); return UErrorCodeToBool(err); }
int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength) { char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; UErrorCode status = U_ZERO_ERROR; const char* defaultLocale = DetectDefaultLocaleName(); uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status); u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status); if (U_SUCCESS(status)) { int localeNameLen = FixupLocaleName(value, valueLength); char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; int32_t collationLen = uloc_getKeywordValue(defaultLocale, "collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, &status); if (U_SUCCESS(status) && collationLen > 0) { // copy the collation; managed uses a "_" to represent collation (not // "@collation=") u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen, &status); u_charsToUChars_safe(collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1, &status); } } return UErrorCodeToBool(status); }
extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) { Locale locale = GetLocale(localeName, true); if (locale.isBogus()) { // localeName not properly formatted return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } // other validation done on managed side UErrorCode status = u_charsToUChars_safe(locale.getName(), value, valueLength); if (U_SUCCESS(status)) { FixupLocaleName(value, valueLength); } return UErrorCodeToBool(status); }
/* PAL Function: GetLocaleTimeFormat Obtains time format information (in ICU format, it needs to be coverted to .NET Format). Returns 1 for success, 0 otherwise */ extern "C" int32_t GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); if (U_FAILURE(err)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, nullptr, 0, nullptr, 0, &err); UDateFormatHolder formatHolder(pFormat, err); if (U_FAILURE(err)) return UErrorCodeToBool(err); udat_toPattern(pFormat, false, value, valueLength, &err); return UErrorCodeToBool(err); }
/* PAL Function: GetLocaleTimeFormat Obtains time format information (in ICU format, it needs to be coverted to .NET Format). Returns 1 for success, 0 otherwise */ int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err); UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, NULL, 0, NULL, 0, &err); udat_toPattern(pFormat, FALSE, value, valueLength, &err); udat_close(pFormat); return UErrorCodeToBool(err); }
int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, localeNameBuffer, ULOC_FULLNAME_CAPACITY, TRUE, &status); u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status); if (U_SUCCESS(status)) { FixupLocaleName(value, valueLength); } return UErrorCodeToBool(status); }
/* PAL Function: GetLocaleInfoString Obtains string locale information. Returns 1 for success, 0 otherwise */ int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &status); if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } switch (localeStringData) { case LocaleString_LocalizedDisplayName: uloc_getDisplayName(locale, DetectDefaultLocaleName(), value, valueLength, &status); break; case LocaleString_EnglishDisplayName: uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status); break; case LocaleString_NativeDisplayName: uloc_getDisplayName(locale, locale, value, valueLength, &status); break; case LocaleString_LocalizedLanguageName: uloc_getDisplayLanguage(locale, DetectDefaultLocaleName(), value, valueLength, &status); break; case LocaleString_EnglishLanguageName: uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status); break; case LocaleString_NativeLanguageName: uloc_getDisplayLanguage(locale, locale, value, valueLength, &status); break; case LocaleString_EnglishCountryName: uloc_getDisplayCountry(locale, ULOC_ENGLISH, value, valueLength, &status); break; case LocaleString_NativeCountryName: uloc_getDisplayCountry(locale, locale, value, valueLength, &status); break; case LocaleString_ListSeparator: // fall through case LocaleString_ThousandSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case LocaleString_DecimalSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); break; case LocaleString_Digits: status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++) { int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1; status = GetDigitSymbol( locale, status, (UNumberFormatSymbol)symbol, charIndex, value, valueLength); } break; case LocaleString_MonetarySymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength); break; case LocaleString_Iso4217MonetarySymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); break; case LocaleString_CurrencyEnglishName: status = GetLocaleCurrencyName(locale, FALSE, value, valueLength); break; case LocaleString_CurrencyNativeName: status = GetLocaleCurrencyName(locale, TRUE, value, valueLength); break; case LocaleString_MonetaryDecimalSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); break; case LocaleString_MonetaryThousandSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case LocaleString_AMDesignator: status = GetLocaleInfoAmPm(locale, TRUE, value, valueLength); break; case LocaleString_PMDesignator: status = GetLocaleInfoAmPm(locale, FALSE, value, valueLength); break; case LocaleString_PositiveSign: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength); break; case LocaleString_NegativeSign: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength); break; case LocaleString_Iso639LanguageTwoLetterName: status = GetLocaleIso639LanguageTwoLetterName(locale, value, valueLength); break; case LocaleString_Iso639LanguageThreeLetterName: status = GetLocaleIso639LanguageThreeLetterName(locale, value, valueLength); break; case LocaleString_Iso3166CountryName: status = GetLocaleIso3166CountryName(locale, value, valueLength); break; case LocaleString_Iso3166CountryName2: status = GetLocaleIso3166CountryCode(locale, value, valueLength); break; case LocaleString_NaNSymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength); break; case LocaleString_PositiveInfinitySymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength); break; case LocaleString_ParentName: { // ICU supports lang[-script][-region][-variant] so up to 4 parents // including invariant locale char localeNameTemp[ULOC_FULLNAME_CAPACITY]; uloc_getParent(locale, localeNameTemp, ULOC_FULLNAME_CAPACITY, &status); u_charsToUChars_safe(localeNameTemp, value, valueLength, &status); if (U_SUCCESS(status)) { FixupLocaleName(value, valueLength); } break; } case LocaleString_PercentSymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength); break; case LocaleString_PerMilleSymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength); break; default: status = U_UNSUPPORTED_ERROR; break; }; return UErrorCodeToBool(status); }
/* Function: GetJapaneseEraInfo Gets the starting Gregorian date of the specified Japanese Era. */ int32_t GlobalizationNative_GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int32_t* startMonth, int32_t* startDay) { *startYear = -1; *startMonth = -1; *startDay = -1; UErrorCode err = U_ZERO_ERROR; UCalendar* pCal = ucal_open(NULL, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); if (U_FAILURE(err)) return FALSE; ucal_set(pCal, UCAL_ERA, era); ucal_set(pCal, UCAL_YEAR, 1); // UCAL_EXTENDED_YEAR is the gregorian year for the JapaneseCalendar *startYear = ucal_get(pCal, UCAL_EXTENDED_YEAR, &err); if (U_FAILURE(err)) { ucal_close(pCal); return FALSE; } // set the date to Jan 1 ucal_set(pCal, UCAL_MONTH, 0); ucal_set(pCal, UCAL_DATE, 1); int32_t currentEra; for (int i = 0; U_SUCCESS(err) && i <= 12; i++) { currentEra = ucal_get(pCal, UCAL_ERA, &err); if (currentEra == era) { for (int i = 0; U_SUCCESS(err) && i < 31; i++) { // subtract 1 day at a time until we get out of the specified Era ucal_add(pCal, UCAL_DATE, -1, &err); currentEra = ucal_get(pCal, UCAL_ERA, &err); if (U_SUCCESS(err) && currentEra != era) { // add back 1 day to get back into the specified Era ucal_add(pCal, UCAL_DATE, 1, &err); *startMonth = ucal_get(pCal, UCAL_MONTH, &err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based *startDay = ucal_get(pCal, UCAL_DATE, &err); ucal_close(pCal); return UErrorCodeToBool(err); } } } // add 1 month at a time until we get into the specified Era ucal_add(pCal, UCAL_MONTH, 1, &err); } ucal_close(pCal); return FALSE; }
/* Function: EnumSymbols Enumerates all of the symbols of a type for a locale and calendar and invokes a callback for each value. */ static int32_t EnumSymbols(const char* locale, CalendarId calendarId, UDateFormatSymbolType type, int32_t startIndex, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, NULL, 0, NULL, 0, &err); if (U_FAILURE(err)) return FALSE; char localeWithCalendarName[ULOC_FULLNAME_CAPACITY]; strncpy(localeWithCalendarName, locale, ULOC_FULLNAME_CAPACITY); uloc_setKeywordValue("calendar", GetCalendarName(calendarId), localeWithCalendarName, ULOC_FULLNAME_CAPACITY, &err); UCalendar* pCalendar = ucal_open(NULL, 0, localeWithCalendarName, UCAL_DEFAULT, &err); if (U_FAILURE(err)) { udat_close(pFormat); return FALSE; } udat_setCalendar(pFormat, pCalendar); int32_t symbolCount = udat_countSymbols(pFormat, type); UChar stackSymbolBuf[100]; UChar* symbolBuf; for (int32_t i = startIndex; U_SUCCESS(err) && i < symbolCount; i++) { UErrorCode ignore = U_ZERO_ERROR; int symbolLen = udat_getSymbols(pFormat, type, i, NULL, 0, &ignore) + 1; if (symbolLen <= sizeof(stackSymbolBuf) / sizeof(stackSymbolBuf[0])) { symbolBuf = stackSymbolBuf; } else { symbolBuf = calloc(symbolLen, sizeof(UChar)); if (symbolBuf == NULL) { err = U_MEMORY_ALLOCATION_ERROR; break; } } udat_getSymbols(pFormat, type, i, symbolBuf, symbolLen, &err); if (U_SUCCESS(err)) { callback(symbolBuf, context); } if (symbolBuf != stackSymbolBuf) { free(symbolBuf); } } udat_close(pFormat); ucal_close(pCalendar); return UErrorCodeToBool(err); }
/* PAL Function: GetLocaleInfoInt Obtains integer locale information Returns 1 for success, 0 otherwise */ extern "C" int32_t GlobalizationNative_GetLocaleInfoInt( const UChar* localeName, LocaleNumberData localeNumberData, int32_t* value) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } switch (localeNumberData) { case LanguageId: *value = uloc_getLCID(locale); break; case MeasurementSystem: status = GetMeasurementSystem(locale, value); break; case FractionalDigitsCount: { UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); unum_close(numformat); } break; } case NegativeNumberFormat: *value = GetNumberNegativePattern(locale); break; case MonetaryFractionalDigitsCount: { UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); unum_close(numformat); } break; } case PositiveMonetaryNumberFormat: *value = GetCurrencyPositivePattern(locale); break; case NegativeMonetaryNumberFormat: *value = GetCurrencyNegativePattern(locale); break; case FirstWeekOfYear: { // corresponds to DateTimeFormat.CalendarWeekRule UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); UCalendarHolder calHolder(pCal, status); if (U_SUCCESS(status)) { // values correspond to LOCALE_IFIRSTWEEKOFYEAR int minDaysInWeek = ucal_getAttribute(pCal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK); if (minDaysInWeek == 1) { *value = CalendarWeekRule::FirstDay; } else if (minDaysInWeek == 7) { *value = CalendarWeekRule::FirstFullWeek; } else if (minDaysInWeek >= 4) { *value = CalendarWeekRule::FirstFourDayWeek; } else { status = U_UNSUPPORTED_ERROR; } } break; } case ReadingLayout: { // coresponds to values 0 and 1 in LOCALE_IREADINGLAYOUT (values 2 and 3 not // used in coreclr) // 0 - Left to right (such as en-US) // 1 - Right to left (such as arabic locales) ULayoutType orientation = uloc_getCharacterOrientation(locale, &status); // alternative implementation in ICU 54+ is uloc_isRightToLeft() which // also supports script tags in locale if (U_SUCCESS(status)) { *value = (orientation == ULOC_LAYOUT_RTL) ? 1 : 0; } break; } case FirstDayofWeek: { UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); UCalendarHolder calHolder(pCal, status); if (U_SUCCESS(status)) { *value = ucal_getAttribute(pCal, UCAL_FIRST_DAY_OF_WEEK) - 1; // .NET is 0-based and ICU is 1-based } break; } case NegativePercentFormat: *value = GetPercentNegativePattern(locale); break; case PositivePercentFormat: *value = GetPercentPositivePattern(locale); break; default: status = U_UNSUPPORTED_ERROR; assert(false); break; } return UErrorCodeToBool(status); }