* 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"
/* ### 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;
-/* ### Get available **************************************************/
+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;
+ }
+ }
+ }
+};
-static UBool U_CALLCONV uloc_cleanup(void) {
- char ** temp;
+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;
+ }
+ }
- if (_installedLocales) {
- temp = _installedLocales;
- _installedLocales = NULL;
+ // 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;
+ }
- _installedLocalesCount = 0;
- _installedLocalesInitOnce.reset();
+ void reset(UErrorCode&) override {
+ fIndex = 0;
+ }
- uprv_free(temp);
+ 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) {
+ 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);
-
- _installedLocalesCount = 0;
+static void U_CALLCONV loadInstalledLocales(UErrorCode& status) {
+ ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
- 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);
}
/**
- * 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
*/
*/
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,
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(
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
*/
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.
TESTCASE(TestSimpleResourceInfo);
TESTCASE(TestDisplayNames);
TESTCASE(TestGetAvailableLocales);
+ TESTCASE(TestGetAvailableLocalesByType);
TESTCASE(TestDataDirectory);
#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
TESTCASE(TestISOFunctions);
}
}
+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()
{
/**
* Test getAvailableLocales
**/
- static void TestGetAvailableLocales(void);
+static void TestGetAvailableLocales(void);
+static void TestGetAvailableLocalesByType(void);
/**
* Test functions to set and access a custom data directory
**/
sort stringenumeration uhash uvector
uscript_props propname
bytesinkutil
+ errorcode
group: localebuilder
localebuilder.o
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();
}
// 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);
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;
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;
*/
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++) {
}
/**
- * 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);
}
/**
* @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 Locale[] getAvailableLocales(String baseName, ClassLoader loader) {
- return getAvailEntry(baseName, loader).getLocaleList();
+ 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 Locales installed the base bundle.
+ /**
+ * Get the set of ULocales 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(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);
+ }
+
+ /**
+ * Get the set of Locales installed in the specified bundles.
+ * @return the list of available locales
+ */
+ public static final Locale[] getAvailableLocales(String baseName, ClassLoader loader) {
+ return getAvailableLocales(baseName, loader, ULocale.AvailableType.DEFAULT);
}
/**
// 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
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;
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) {
}
}
}
- 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));
}
}
}
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;
}
};
+ /**
+ * 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
/**
* {@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);
}
/**
version https://git-lfs.github.com/spec/v1
-oid sha256:5c8773434e9708bca02ad11319c35e01f29f62748851a38ae89de1334c279cca
-size 12842785
+oid sha256:43a8fe03049ca2fc11189c20cdc0baa3248a983d9885fe44f7946aca7082979a
+size 12842784
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;
}
}
+ @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
val = loc3.getKeywordValue("numbers");
assertEquals("Default, ICU keyword", null, val);
-
+
// Note: ICU does not have getUnicodeKeywordValue()
}