mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-14 17:24:01 +00:00
ICU-20627 Adding getAvailableLocalesByType, ICU4C and ICU4J.
This commit is contained in:
parent
9a3f15c2b3
commit
1d2861bb0c
14 changed files with 551 additions and 115 deletions
|
@ -19,11 +19,13 @@
|
|||
* that then do not depend on resource bundle code and res_index bundles.
|
||||
*/
|
||||
|
||||
#include "unicode/errorcode.h"
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/uloc.h"
|
||||
#include "unicode/ures.h"
|
||||
#include "cmemory.h"
|
||||
#include "cstring.h"
|
||||
#include "ucln_cmn.h"
|
||||
#include "uassert.h"
|
||||
#include "umutex.h"
|
||||
|
@ -95,85 +97,174 @@ U_NAMESPACE_USE
|
|||
|
||||
/* ### Constants **************************************************/
|
||||
|
||||
/* These strings describe the resources we attempt to load from
|
||||
the locale ResourceBundle data file.*/
|
||||
static const char _kIndexLocaleName[] = "res_index";
|
||||
static const char _kIndexTag[] = "InstalledLocales";
|
||||
namespace {
|
||||
|
||||
static char** _installedLocales = NULL;
|
||||
static int32_t _installedLocalesCount = 0;
|
||||
static icu::UInitOnce _installedLocalesInitOnce;
|
||||
// Enough capacity for the two lists in the res_index.res file
|
||||
const char** gAvailableLocaleNames[2] = {};
|
||||
int32_t gAvailableLocaleCounts[2] = {};
|
||||
icu::UInitOnce ginstalledLocalesInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
||||
class AvailableLocalesSink : public ResourceSink {
|
||||
public:
|
||||
void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) U_OVERRIDE {
|
||||
ResourceTable resIndexTable = value.getTable(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
for (int32_t i = 0; resIndexTable.getKeyAndValue(i, key, value); ++i) {
|
||||
ULocAvailableType type;
|
||||
if (uprv_strcmp(key, "InstalledLocales") == 0) {
|
||||
type = ULOC_AVAILABLE_DEFAULT;
|
||||
} else if (uprv_strcmp(key, "AliasLocales") == 0) {
|
||||
type = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES;
|
||||
} else {
|
||||
// CLDRVersion, etc.
|
||||
continue;
|
||||
}
|
||||
ResourceTable availableLocalesTable = value.getTable(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
gAvailableLocaleCounts[type] = availableLocalesTable.getSize();
|
||||
gAvailableLocaleNames[type] = static_cast<const char**>(
|
||||
uprv_malloc(gAvailableLocaleCounts[type] * sizeof(const char*)));
|
||||
if (gAvailableLocaleNames[type] == nullptr) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
for (int32_t j = 0; availableLocalesTable.getKeyAndValue(j, key, value); ++j) {
|
||||
gAvailableLocaleNames[type][j] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AvailableLocalesStringEnumeration : public StringEnumeration {
|
||||
public:
|
||||
AvailableLocalesStringEnumeration(ULocAvailableType type) : fType(type) {
|
||||
}
|
||||
|
||||
const char* next(int32_t *resultLength, UErrorCode&) override {
|
||||
ULocAvailableType actualType = fType;
|
||||
int32_t actualIndex = fIndex++;
|
||||
|
||||
// If the "combined" list was requested, resolve that now
|
||||
if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
|
||||
int32_t defaultLocalesCount = gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT];
|
||||
if (actualIndex < defaultLocalesCount) {
|
||||
actualType = ULOC_AVAILABLE_DEFAULT;
|
||||
} else {
|
||||
actualIndex -= defaultLocalesCount;
|
||||
actualType = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the requested string
|
||||
int32_t count = gAvailableLocaleCounts[actualType];
|
||||
const char* result;
|
||||
if (actualIndex < count) {
|
||||
result = gAvailableLocaleNames[actualType][actualIndex];
|
||||
if (resultLength != nullptr) {
|
||||
*resultLength = static_cast<int32_t>(uprv_strlen(result));
|
||||
}
|
||||
} else {
|
||||
result = nullptr;
|
||||
if (resultLength != nullptr) {
|
||||
*resultLength = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void reset(UErrorCode&) override {
|
||||
fIndex = 0;
|
||||
}
|
||||
|
||||
int32_t count(UErrorCode&) const override {
|
||||
if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
|
||||
return gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT]
|
||||
+ gAvailableLocaleCounts[ULOC_AVAILABLE_ONLY_LEGACY_ALIASES];
|
||||
} else {
|
||||
return gAvailableLocaleCounts[fType];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ULocAvailableType fType;
|
||||
int32_t fIndex = 0;
|
||||
};
|
||||
|
||||
/* ### Get available **************************************************/
|
||||
|
||||
static UBool U_CALLCONV uloc_cleanup(void) {
|
||||
char ** temp;
|
||||
|
||||
if (_installedLocales) {
|
||||
temp = _installedLocales;
|
||||
_installedLocales = NULL;
|
||||
|
||||
_installedLocalesCount = 0;
|
||||
_installedLocalesInitOnce.reset();
|
||||
|
||||
uprv_free(temp);
|
||||
for (int32_t i = 0; i < UPRV_LENGTHOF(gAvailableLocaleNames); i++) {
|
||||
uprv_free(gAvailableLocaleNames[i]);
|
||||
gAvailableLocaleNames[i] = nullptr;
|
||||
gAvailableLocaleCounts[i] = 0;
|
||||
}
|
||||
ginstalledLocalesInitOnce.reset();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Load Installed Locales. This function will be called exactly once
|
||||
// via the initOnce mechanism.
|
||||
|
||||
static void U_CALLCONV loadInstalledLocales() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t i = 0;
|
||||
int32_t localeCount;
|
||||
|
||||
U_ASSERT(_installedLocales == NULL);
|
||||
U_ASSERT(_installedLocalesCount == 0);
|
||||
static void U_CALLCONV loadInstalledLocales(UErrorCode& status) {
|
||||
ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
|
||||
|
||||
_installedLocalesCount = 0;
|
||||
|
||||
icu::LocalUResourceBundlePointer indexLocale(ures_openDirect(NULL, _kIndexLocaleName, &status));
|
||||
icu::StackUResourceBundle installed;
|
||||
|
||||
ures_getByKey(indexLocale.getAlias(), _kIndexTag, installed.getAlias(), &status);
|
||||
|
||||
if(U_SUCCESS(status)) {
|
||||
localeCount = ures_getSize(installed.getAlias());
|
||||
_installedLocales = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
|
||||
if (_installedLocales != NULL) {
|
||||
ures_resetIterator(installed.getAlias());
|
||||
while(ures_hasNext(installed.getAlias())) {
|
||||
ures_getNextString(installed.getAlias(), NULL, (const char **)&_installedLocales[i++], &status);
|
||||
}
|
||||
_installedLocales[i] = NULL;
|
||||
_installedLocalesCount = localeCount;
|
||||
ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
|
||||
}
|
||||
}
|
||||
icu::LocalUResourceBundlePointer rb(ures_openDirect(NULL, "res_index", &status));
|
||||
AvailableLocalesSink sink;
|
||||
ures_getAllItemsWithFallback(rb.getAlias(), "", sink, status);
|
||||
}
|
||||
|
||||
static void _load_installedLocales()
|
||||
{
|
||||
umtx_initOnce(_installedLocalesInitOnce, &loadInstalledLocales);
|
||||
void _load_installedLocales(UErrorCode& status) {
|
||||
umtx_initOnce(ginstalledLocalesInitOnce, &loadInstalledLocales, status);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
U_CAPI const char* U_EXPORT2
|
||||
uloc_getAvailable(int32_t offset)
|
||||
{
|
||||
|
||||
_load_installedLocales();
|
||||
|
||||
if (offset > _installedLocalesCount)
|
||||
return NULL;
|
||||
return _installedLocales[offset];
|
||||
uloc_getAvailable(int32_t offset) {
|
||||
icu::ErrorCode status;
|
||||
_load_installedLocales(status);
|
||||
if (status.isFailure()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (offset > gAvailableLocaleCounts[0]) {
|
||||
// *status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
return gAvailableLocaleNames[0][offset];
|
||||
}
|
||||
|
||||
U_CAPI int32_t U_EXPORT2
|
||||
uloc_countAvailable()
|
||||
{
|
||||
_load_installedLocales();
|
||||
return _installedLocalesCount;
|
||||
uloc_countAvailable() {
|
||||
icu::ErrorCode status;
|
||||
_load_installedLocales(status);
|
||||
if (status.isFailure()) {
|
||||
return 0;
|
||||
}
|
||||
return gAvailableLocaleCounts[0];
|
||||
}
|
||||
|
||||
U_CAPI UEnumeration* U_EXPORT2
|
||||
uloc_openAvailableByType(ULocAvailableType type, UErrorCode* status) {
|
||||
if (U_FAILURE(*status)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (type < 0 || type >= ULOC_AVAILABLE_COUNT) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
_load_installedLocales(*status);
|
||||
if (U_FAILURE(*status)) {
|
||||
return nullptr;
|
||||
}
|
||||
LocalPointer<AvailableLocalesStringEnumeration> result(
|
||||
new AvailableLocalesStringEnumeration(type), *status);
|
||||
if (U_FAILURE(*status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return uenum_openFromStringEnumeration(result.orphan(), status);
|
||||
}
|
||||
|
||||
|
|
|
@ -742,12 +742,18 @@ uloc_getDisplayName(const char* localeID,
|
|||
|
||||
|
||||
/**
|
||||
* Gets the specified locale from a list of all available locales.
|
||||
* The return value is a pointer to an item of
|
||||
* a locale name array. Both this array and the pointers
|
||||
* it contains are owned by ICU and should not be deleted or written through
|
||||
* by the caller. The locale name is terminated by a null pointer.
|
||||
* @param n the specific locale name index of the available locale list
|
||||
* Gets the specified locale from a list of available locales.
|
||||
*
|
||||
* This method corresponds to uloc_openAvailableByType called with the
|
||||
* ULOC_AVAILABLE_DEFAULT type argument.
|
||||
*
|
||||
* The return value is a pointer to an item of a locale name array. Both this
|
||||
* array and the pointers it contains are owned by ICU and should not be
|
||||
* deleted or written through by the caller. The locale name is terminated by
|
||||
* a null pointer.
|
||||
*
|
||||
* @param n the specific locale name index of the available locale list;
|
||||
* should not exceed the number returned by uloc_countAvailable.
|
||||
* @return a specified locale name of all available locales
|
||||
* @stable ICU 2.0
|
||||
*/
|
||||
|
@ -762,6 +768,72 @@ uloc_getAvailable(int32_t n);
|
|||
*/
|
||||
U_STABLE int32_t U_EXPORT2 uloc_countAvailable(void);
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
|
||||
/**
|
||||
* Types for uloc_getAvailableByType and uloc_countAvailableByType.
|
||||
*
|
||||
* @draft ICU 65
|
||||
*/
|
||||
typedef enum ULocAvailableType {
|
||||
/**
|
||||
* Locales that return data when passed to ICU APIs,
|
||||
* but not including legacy or alias locales.
|
||||
*
|
||||
* @draft ICU 65
|
||||
*/
|
||||
ULOC_AVAILABLE_DEFAULT,
|
||||
|
||||
/**
|
||||
* Legacy or alias locales that return data when passed to ICU APIs.
|
||||
* Examples of supported legacy or alias locales:
|
||||
*
|
||||
* - iw (alias to he)
|
||||
* - mo (alias to ro)
|
||||
* - zh_CN (alias to zh_Hans_CN)
|
||||
* - sr_BA (alias to sr_Cyrl_BA)
|
||||
* - ars (alias to ar_SA)
|
||||
*
|
||||
* The locales in this set are disjoint from the ones in
|
||||
* ULOC_AVAILABLE_DEFAULT. To get both sets at the same time, use
|
||||
* ULOC_AVAILABLE_WITH_LEGACY_ALIASES.
|
||||
*
|
||||
* @draft ICU 65
|
||||
*/
|
||||
ULOC_AVAILABLE_ONLY_LEGACY_ALIASES,
|
||||
|
||||
/**
|
||||
* The union of the locales in ULOC_AVAILABLE_DEFAULT and
|
||||
* ULOC_AVAILABLE_ONLY_LEGACY_ALIAS.
|
||||
*
|
||||
* @draft ICU 65
|
||||
*/
|
||||
ULOC_AVAILABLE_WITH_LEGACY_ALIASES,
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
ULOC_AVAILABLE_COUNT
|
||||
#endif
|
||||
} ULocAvailableType;
|
||||
|
||||
/**
|
||||
* Gets a list of available locales according to the type argument, allowing
|
||||
* the user to access different sets of supported locales in ICU.
|
||||
*
|
||||
* The returned UEnumeration must be closed by the caller.
|
||||
*
|
||||
* @param type Type choice from ULocAvailableType.
|
||||
* @param status Set if an error occurred.
|
||||
* @return a UEnumeration owned by the caller, or nullptr on failure.
|
||||
* @draft ICU 65
|
||||
*/
|
||||
U_DRAFT UEnumeration* U_EXPORT2
|
||||
uloc_openAvailableByType(ULocAvailableType type, UErrorCode* status);
|
||||
|
||||
#endif // U_HIDE_DRAFT_API
|
||||
|
||||
/**
|
||||
*
|
||||
* Gets a list of all available 2-letter language codes defined in ISO 639,
|
||||
|
|
|
@ -340,10 +340,10 @@ class IndexRequest(AbstractRequest):
|
|||
return ("// Warning this file is automatically generated\n"
|
||||
"{INDEX_NAME}:table(nofallback) {{\n"
|
||||
"{FORMATTED_VERSION}"
|
||||
" InstalledLocales {{\n"
|
||||
" InstalledLocales:table {{\n"
|
||||
"{FORMATTED_INSTALLED_LOCALES}\n"
|
||||
" }}\n"
|
||||
" AliasLocales {{\n"
|
||||
" AliasLocales:table {{\n"
|
||||
"{FORMATTED_ALIAS_LOCALES}\n"
|
||||
" }}\n"
|
||||
"}}").format(
|
||||
|
|
|
@ -743,4 +743,18 @@ U_CFUNC UBool assertIntEquals(const char* message, int64_t expected, int64_t act
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
U_CFUNC UBool assertPtrEquals(const char* message, const void* expected, const void* actual) {
|
||||
if (expected != actual) {
|
||||
log_err("FAIL: %s; got 0x%llx; expected 0x%llx\n",
|
||||
message, actual, expected);
|
||||
return FALSE;
|
||||
}
|
||||
#ifdef VERBOSE_ASSERTIONS
|
||||
else {
|
||||
log_verbose("Ok: %s; got 0x%llx\n", message, actual);
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -147,6 +147,12 @@ U_CFUNC UBool assertUEquals(const char* msg, const UChar* expectedString,
|
|||
*/
|
||||
U_CFUNC UBool assertIntEquals(const char* msg, int64_t expected, int64_t actual);
|
||||
|
||||
/**
|
||||
* Assert that the addresses of the two pointers are the same, returning
|
||||
* TRUE if they are equal.
|
||||
*/
|
||||
U_CFUNC UBool assertPtrEquals(const char* msg, const void* expected, const void* actual);
|
||||
|
||||
/*
|
||||
* note - isICUVersionBefore and isICUVersionAtLeast have been removed.
|
||||
* use log_knownIssue() instead.
|
||||
|
|
|
@ -218,6 +218,7 @@ void addLocaleTest(TestNode** root)
|
|||
TESTCASE(TestSimpleResourceInfo);
|
||||
TESTCASE(TestDisplayNames);
|
||||
TESTCASE(TestGetAvailableLocales);
|
||||
TESTCASE(TestGetAvailableLocalesByType);
|
||||
TESTCASE(TestDataDirectory);
|
||||
#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
|
||||
TESTCASE(TestISOFunctions);
|
||||
|
@ -834,6 +835,77 @@ static void TestGetAvailableLocales()
|
|||
}
|
||||
}
|
||||
|
||||
static void TestGetAvailableLocalesByType() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
UEnumeration* uenum = uloc_openAvailableByType(ULOC_AVAILABLE_DEFAULT, &status);
|
||||
assertSuccess("Constructing the UEnumeration", &status);
|
||||
|
||||
assertIntEquals("countAvailable() should be same in old and new methods",
|
||||
uloc_countAvailable(),
|
||||
uenum_count(uenum, &status));
|
||||
|
||||
for (int32_t i = 0; i < uloc_countAvailable(); i++) {
|
||||
const char* old = uloc_getAvailable(i);
|
||||
int32_t len = 0;
|
||||
const char* new = uenum_next(uenum, &len, &status);
|
||||
assertEquals("Old and new strings should equal", old, new);
|
||||
assertIntEquals("String length should be correct", uprv_strlen(old), len);
|
||||
}
|
||||
assertPtrEquals("Should get nullptr on the last string",
|
||||
NULL, uenum_next(uenum, NULL, &status));
|
||||
|
||||
uenum_close(uenum);
|
||||
|
||||
uenum = uloc_openAvailableByType(ULOC_AVAILABLE_ONLY_LEGACY_ALIASES, &status);
|
||||
UBool found_he = FALSE;
|
||||
UBool found_iw = FALSE;
|
||||
const char* loc;
|
||||
while ((loc = uenum_next(uenum, NULL, &status))) {
|
||||
if (uprv_strcmp("he", loc) == 0) {
|
||||
found_he = TRUE;
|
||||
}
|
||||
if (uprv_strcmp("iw", loc) == 0) {
|
||||
found_iw = TRUE;
|
||||
}
|
||||
}
|
||||
assertTrue("Should NOT have found he amongst the legacy/alias locales", !found_he);
|
||||
assertTrue("Should have found iw amongst the legacy/alias locales", found_iw);
|
||||
uenum_close(uenum);
|
||||
|
||||
uenum = uloc_openAvailableByType(ULOC_AVAILABLE_WITH_LEGACY_ALIASES, &status);
|
||||
found_he = FALSE;
|
||||
found_iw = FALSE;
|
||||
const UChar* uloc; // test the UChar conversion
|
||||
int32_t count = 0;
|
||||
while ((uloc = uenum_unext(uenum, NULL, &status))) {
|
||||
if (u_strcmp(u"iw", uloc) == 0) {
|
||||
found_iw = TRUE;
|
||||
}
|
||||
if (u_strcmp(u"he", uloc) == 0) {
|
||||
found_he = TRUE;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
assertTrue("Should have found he amongst all locales", found_he);
|
||||
assertTrue("Should have found iw amongst all locales", found_iw);
|
||||
assertIntEquals("Should return as many strings as claimed",
|
||||
count, uenum_count(uenum, &status));
|
||||
|
||||
// Reset the enumeration and it should still work
|
||||
uenum_reset(uenum, &status);
|
||||
count = 0;
|
||||
while ((loc = uenum_next(uenum, NULL, &status))) {
|
||||
count++;
|
||||
}
|
||||
assertIntEquals("After reset, should return as many strings as claimed",
|
||||
count, uenum_count(uenum, &status));
|
||||
|
||||
uenum_close(uenum);
|
||||
|
||||
assertSuccess("No errors should have occurred", &status);
|
||||
}
|
||||
|
||||
/* test for u_getDataDirectory, u_setDataDirectory, uloc_getISO3Language */
|
||||
static void TestDataDirectory()
|
||||
{
|
||||
|
|
|
@ -36,7 +36,8 @@ static void TestDisplayNames(void);
|
|||
/**
|
||||
* Test getAvailableLocales
|
||||
**/
|
||||
static void TestGetAvailableLocales(void);
|
||||
static void TestGetAvailableLocales(void);
|
||||
static void TestGetAvailableLocalesByType(void);
|
||||
/**
|
||||
* Test functions to set and access a custom data directory
|
||||
**/
|
||||
|
|
|
@ -639,6 +639,7 @@ group: resourcebundle
|
|||
sort stringenumeration uhash uvector
|
||||
uscript_props propname
|
||||
bytesinkutil
|
||||
errorcode
|
||||
|
||||
group: localebuilder
|
||||
localebuilder.o
|
||||
|
|
|
@ -933,7 +933,7 @@ public abstract class Collator implements Comparator<Object>, Freezable<Collator
|
|||
public static final ULocale[] getAvailableULocales() {
|
||||
if (shim == null) {
|
||||
return ICUResourceBundle.getAvailableULocales(
|
||||
ICUData.ICU_COLLATION_BASE_NAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
ICUData.ICU_COLLATION_BASE_NAME, ICUResourceBundle.ICU_DATA_CLASS_LOADER);
|
||||
}
|
||||
return shim.getAvailableULocales();
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ final class CollatorServiceShim extends Collator.ServiceShim {
|
|||
|
||||
// Ported from C++ Collator::makeInstance().
|
||||
private static final Collator makeInstance(ULocale desiredLocale) {
|
||||
Output<ULocale> validLocale = new Output<ULocale>(ULocale.ROOT);
|
||||
Output<ULocale> validLocale = new Output<>(ULocale.ROOT);
|
||||
CollationTailoring t =
|
||||
CollationLoader.loadTailoring(desiredLocale, validLocale);
|
||||
return new RuleBasedCollator(t, validLocale.value);
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.io.InputStreamReader;
|
|||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -132,7 +133,8 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
r = (ICUResourceBundle) UResourceBundle.getBundleInstance(baseName, parent);
|
||||
if (isAvailable != null) {
|
||||
isAvailable[0] = false;
|
||||
ULocale[] availableULocales = getAvailEntry(baseName, loader).getULocaleList();
|
||||
ULocale[] availableULocales = getAvailEntry(baseName, loader)
|
||||
.getULocaleList(ULocale.AvailableType.DEFAULT);
|
||||
for (int i = 0; i < availableULocales.length; i++) {
|
||||
if (parent.equals(availableULocales[i])) {
|
||||
isAvailable[0] = true;
|
||||
|
@ -249,7 +251,8 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
*/
|
||||
public static final String[] getKeywordValues(String baseName, String keyword) {
|
||||
Set<String> keywords = new HashSet<>();
|
||||
ULocale locales[] = getAvailEntry(baseName, ICU_DATA_CLASS_LOADER).getULocaleList();
|
||||
ULocale locales[] = getAvailEntry(baseName, ICU_DATA_CLASS_LOADER)
|
||||
.getULocaleList(ULocale.AvailableType.DEFAULT);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < locales.length; i++) {
|
||||
|
@ -493,11 +496,12 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the set of Locales installed in the specified bundles.
|
||||
* Get the set of Locales installed in the specified bundles, for the specified type.
|
||||
* @return the list of available locales
|
||||
*/
|
||||
public static final ULocale[] getAvailableULocales(String baseName, ClassLoader loader) {
|
||||
return getAvailEntry(baseName, loader).getULocaleList();
|
||||
public static final ULocale[] getAvailableULocales(String baseName, ClassLoader loader,
|
||||
ULocale.AvailableType type) {
|
||||
return getAvailEntry(baseName, loader).getULocaleList(type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -505,7 +509,48 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
* @return the list of available locales
|
||||
*/
|
||||
public static final ULocale[] getAvailableULocales() {
|
||||
return getAvailableULocales(ICUData.ICU_BASE_NAME, ICU_DATA_CLASS_LOADER);
|
||||
return getAvailableULocales(ICUData.ICU_BASE_NAME, ICU_DATA_CLASS_LOADER, ULocale.AvailableType.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of ULocales installed the base bundle, for the specified type.
|
||||
* @return the list of available locales for the specified type
|
||||
*/
|
||||
public static final ULocale[] getAvailableULocales(ULocale.AvailableType type) {
|
||||
return getAvailableULocales(ICUData.ICU_BASE_NAME, ICU_DATA_CLASS_LOADER, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of Locales installed in the specified bundles.
|
||||
* @return the list of available locales
|
||||
*/
|
||||
public static final ULocale[] getAvailableULocales(String baseName, ClassLoader loader) {
|
||||
return getAvailableULocales(baseName, loader, ULocale.AvailableType.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of Locales installed in the specified bundles, for the specified type.
|
||||
* @return the list of available locales
|
||||
*/
|
||||
public static final Locale[] getAvailableLocales(String baseName, ClassLoader loader,
|
||||
ULocale.AvailableType type) {
|
||||
return getAvailEntry(baseName, loader).getLocaleList(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of ULocales installed the base bundle.
|
||||
* @return the list of available locales
|
||||
*/
|
||||
public static final Locale[] getAvailableLocales() {
|
||||
return getAvailableLocales(ICUData.ICU_BASE_NAME, ICU_DATA_CLASS_LOADER, ULocale.AvailableType.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of Locales installed the base bundle, for the specified type.
|
||||
* @return the list of available locales
|
||||
*/
|
||||
public static final Locale[] getAvailableLocales(ULocale.AvailableType type) {
|
||||
return getAvailableLocales(ICUData.ICU_BASE_NAME, ICU_DATA_CLASS_LOADER, type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -513,15 +558,7 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
* @return the list of available locales
|
||||
*/
|
||||
public static final Locale[] getAvailableLocales(String baseName, ClassLoader loader) {
|
||||
return getAvailEntry(baseName, loader).getLocaleList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of Locales installed the base bundle.
|
||||
* @return the list of available locales
|
||||
*/
|
||||
public static final Locale[] getAvailableLocales() {
|
||||
return getAvailEntry(ICUData.ICU_BASE_NAME, ICU_DATA_CLASS_LOADER).getLocaleList();
|
||||
return getAvailableLocales(baseName, loader, ULocale.AvailableType.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -569,31 +606,50 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
// Flag for enabling/disabling debugging code
|
||||
private static final boolean DEBUG = ICUDebug.enabled("localedata");
|
||||
|
||||
private static final ULocale[] createULocaleList(String baseName,
|
||||
ClassLoader root) {
|
||||
private static final class AvailableLocalesSink extends UResource.Sink {
|
||||
|
||||
EnumMap<ULocale.AvailableType, ULocale[]> output;
|
||||
|
||||
public AvailableLocalesSink(EnumMap<ULocale.AvailableType, ULocale[]> output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
|
||||
UResource.Table resIndexTable = value.getTable();
|
||||
for (int i = 0; resIndexTable.getKeyAndValue(i, key, value); ++i) {
|
||||
ULocale.AvailableType type;
|
||||
if (key.contentEquals("InstalledLocales")) {
|
||||
type = ULocale.AvailableType.DEFAULT;
|
||||
} else if (key.contentEquals("AliasLocales")) {
|
||||
type = ULocale.AvailableType.ONLY_LEGACY_ALIASES;
|
||||
} else {
|
||||
// CLDRVersion, etc.
|
||||
continue;
|
||||
}
|
||||
UResource.Table availableLocalesTable = value.getTable();
|
||||
ULocale[] locales = new ULocale[availableLocalesTable.getSize()];
|
||||
for (int j = 0; availableLocalesTable.getKeyAndValue(j, key, value); ++j) {
|
||||
locales[j] = new ULocale(key.toString());
|
||||
}
|
||||
output.put(type, locales);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final EnumMap<ULocale.AvailableType, ULocale[]> createULocaleList(
|
||||
String baseName, ClassLoader root) {
|
||||
// the canned list is a subset of all the available .res files, the idea
|
||||
// is we don't export them
|
||||
// all. gotta be a better way to do this, since to add a locale you have
|
||||
// to update this list,
|
||||
// and it's embedded in our binary resources.
|
||||
ICUResourceBundle bundle = (ICUResourceBundle) UResourceBundle.instantiateBundle(baseName, ICU_RESOURCE_INDEX, root, true);
|
||||
ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.instantiateBundle(baseName, ICU_RESOURCE_INDEX, root, true);
|
||||
|
||||
bundle = (ICUResourceBundle)bundle.get(INSTALLED_LOCALES);
|
||||
int length = bundle.getSize();
|
||||
int i = 0;
|
||||
ULocale[] locales = new ULocale[length];
|
||||
UResourceBundleIterator iter = bundle.getIterator();
|
||||
iter.reset();
|
||||
while (iter.hasNext()) {
|
||||
String locstr = iter.next().getKey();
|
||||
if (locstr.equals("root")) {
|
||||
locales[i++] = ULocale.ROOT;
|
||||
} else {
|
||||
locales[i++] = new ULocale(locstr);
|
||||
}
|
||||
}
|
||||
bundle = null;
|
||||
return locales;
|
||||
EnumMap<ULocale.AvailableType, ULocale[]> result = new EnumMap<>(ULocale.AvailableType.class);
|
||||
AvailableLocalesSink sink = new AvailableLocalesSink(result);
|
||||
rb.getAllItemsWithFallback("", sink);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Same as createULocaleList() but catches the MissingResourceException
|
||||
|
@ -739,7 +795,7 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
private static final class AvailEntry {
|
||||
private String prefix;
|
||||
private ClassLoader loader;
|
||||
private volatile ULocale[] ulocales;
|
||||
private volatile EnumMap<ULocale.AvailableType, ULocale[]> ulocales;
|
||||
private volatile Locale[] locales;
|
||||
private volatile Set<String> nameSet;
|
||||
private volatile Set<String> fullNameSet;
|
||||
|
@ -749,7 +805,9 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
this.loader = loader;
|
||||
}
|
||||
|
||||
ULocale[] getULocaleList() {
|
||||
ULocale[] getULocaleList(ULocale.AvailableType type) {
|
||||
// Direct data is available for DEFAULT and ONLY_LEGACY_ALIASES
|
||||
assert type != ULocale.AvailableType.WITH_LEGACY_ALIASES;
|
||||
if (ulocales == null) {
|
||||
synchronized(this) {
|
||||
if (ulocales == null) {
|
||||
|
@ -757,14 +815,14 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||
}
|
||||
}
|
||||
}
|
||||
return ulocales;
|
||||
return ulocales.get(type);
|
||||
}
|
||||
Locale[] getLocaleList() {
|
||||
Locale[] getLocaleList(ULocale.AvailableType type) {
|
||||
if (locales == null) {
|
||||
getULocaleList();
|
||||
getULocaleList(type);
|
||||
synchronized(this) {
|
||||
if (locales == null) {
|
||||
locales = ICUResourceBundle.getLocaleList(ulocales);
|
||||
locales = ICUResourceBundle.getLocaleList(ulocales.get(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ import java.io.Serializable;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -121,6 +125,52 @@ public final class ULocale implements Serializable, Comparable<ULocale> {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Types for {@link ULocale#getAvailableLocalesByType}
|
||||
*
|
||||
* @draft ICU 65
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public static enum AvailableType {
|
||||
/**
|
||||
* Locales that return data when passed to ICU APIs,
|
||||
* but not including legacy or alias locales.
|
||||
*
|
||||
* @draft ICU 65
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Legacy or alias locales that return data when passed to ICU APIs.
|
||||
* Examples of supported legacy or alias locales:
|
||||
*
|
||||
* <ul>
|
||||
* <li>iw (alias to he)
|
||||
* <li>mo (alias to ro)
|
||||
* <li>zh_CN (alias to zh_Hans_CN)
|
||||
* <li>sr_BA (alias to sr_Cyrl_BA)
|
||||
* <li>ars (alias to ar_SA)
|
||||
* </ul>
|
||||
*
|
||||
* The locales in this set are disjoint from the ones in
|
||||
* DEFAULT. To get both sets at the same time, use
|
||||
* WITH_LEGACY_ALIASES.
|
||||
*
|
||||
* @draft ICU 65
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
ONLY_LEGACY_ALIASES,
|
||||
|
||||
/**
|
||||
* The union of the locales in DEFAULT and ONLY_LEGACY_ALIASES.
|
||||
*
|
||||
* @draft ICU 65
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
WITH_LEGACY_ALIASES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful constant for language.
|
||||
* @stable ICU 3.0
|
||||
|
@ -786,11 +836,38 @@ public final class ULocale implements Serializable, Comparable<ULocale> {
|
|||
|
||||
/**
|
||||
* {@icunote} Unlike the Locale API, this returns an array of <code>ULocale</code>,
|
||||
* not <code>Locale</code>. Returns a list of all installed locales.
|
||||
* not <code>Locale</code>.
|
||||
*
|
||||
* <p>Returns a list of all installed locales. This is equivalent to calling
|
||||
* {@link #getAvailableLocalesByType} with AvialableType.DEFAULT.
|
||||
*
|
||||
* @stable ICU 3.0
|
||||
*/
|
||||
public static ULocale[] getAvailableLocales() {
|
||||
return ICUResourceBundle.getAvailableULocales();
|
||||
return ICUResourceBundle.getAvailableULocales().clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all installed locales according to the specified type.
|
||||
*
|
||||
* @draft ICU 65
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public static Collection<ULocale> getAvailableLocalesByType(AvailableType type) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
List<ULocale> result;
|
||||
if (type == ULocale.AvailableType.WITH_LEGACY_ALIASES) {
|
||||
result = new ArrayList<>();
|
||||
Collections.addAll(result,
|
||||
ICUResourceBundle.getAvailableULocales(ULocale.AvailableType.DEFAULT));
|
||||
Collections.addAll(result,
|
||||
ICUResourceBundle.getAvailableULocales(ULocale.AvailableType.ONLY_LEGACY_ALIASES));
|
||||
} else {
|
||||
result = Arrays.asList(ICUResourceBundle.getAvailableULocales(type));
|
||||
}
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5c8773434e9708bca02ad11319c35e01f29f62748851a38ae89de1334c279cca
|
||||
size 12842785
|
||||
oid sha256:43a8fe03049ca2fc11189c20cdc0baa3248a983d9885fe44f7946aca7082979a
|
||||
size 12842784
|
||||
|
|
|
@ -15,6 +15,7 @@ package com.ibm.icu.dev.test.util;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -1024,6 +1025,49 @@ public class ULocaleTest extends TestFmwk {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestGetAvailableByType() {
|
||||
assertEquals("countAvailable() should be same in old and new methods",
|
||||
ULocale.getAvailableLocales().length,
|
||||
ULocale.getAvailableLocalesByType(ULocale.AvailableType.DEFAULT).size());
|
||||
|
||||
assertEquals("getAvailable() should return same in old and new methods",
|
||||
Arrays.asList(ULocale.getAvailableLocales()),
|
||||
ULocale.getAvailableLocalesByType(ULocale.AvailableType.DEFAULT));
|
||||
|
||||
Collection<ULocale> legacyLocales = ULocale
|
||||
.getAvailableLocalesByType(ULocale.AvailableType.ONLY_LEGACY_ALIASES);
|
||||
assertTrue("getAvailable() legacy/alias should return nonempty", legacyLocales.size() > 0);
|
||||
|
||||
boolean found_he = false;
|
||||
boolean found_iw = false;
|
||||
for (ULocale loc : legacyLocales) {
|
||||
if (loc.getName().equals("he")) {
|
||||
found_he = true;
|
||||
}
|
||||
if (loc.getName().equals("iw")) {
|
||||
found_iw = true;
|
||||
}
|
||||
}
|
||||
assertFalse("Should NOT have found he amongst the legacy/alias locales", found_he);
|
||||
assertTrue("Should have found iw amongst the legacy/alias locales", found_iw);
|
||||
|
||||
Collection<ULocale> allLocales = ULocale
|
||||
.getAvailableLocalesByType(ULocale.AvailableType.WITH_LEGACY_ALIASES);
|
||||
found_he = false;
|
||||
found_iw = false;
|
||||
for (ULocale loc : allLocales) {
|
||||
if (loc.getName().equals("he")) {
|
||||
found_he = true;
|
||||
}
|
||||
if (loc.getName().equals("iw")) {
|
||||
found_iw = true;
|
||||
}
|
||||
}
|
||||
assertTrue("Should have found he amongst the legacy/alias locales", found_he);
|
||||
assertTrue("Should have found iw amongst the legacy/alias locales", found_iw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestDisplayNames() {
|
||||
// consistency check, also check that all data is available
|
||||
|
@ -4154,7 +4198,7 @@ public class ULocaleTest extends TestFmwk {
|
|||
|
||||
val = loc3.getKeywordValue("numbers");
|
||||
assertEquals("Default, ICU keyword", null, val);
|
||||
|
||||
|
||||
// Note: ICU does not have getUnicodeKeywordValue()
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue