| /* |
| * (C) Copyright IBM Corp. 2002 - All Rights Reserved |
| */ |
| |
| package com.ibm.icu.impl; |
| |
| import java.lang.ref.SoftReference; |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * Provides information about and access to resource bundles in the |
| * com.ibm.text.resources package. Unlike the java version, this does |
| * not include resources from any other location. In particular, it |
| * does not look in the boot or system class path. |
| */ |
| public class ICULocaleData { |
| private static Locale[] localeList; |
| private static final String PACKAGE1 = "com.ibm.icu.impl.data"; |
| private static final String[] packageNames = { PACKAGE1 }; |
| private static boolean debug = ICUDebug.enabled("localedata"); |
| |
| /** |
| * Returns a list of the installed locales. |
| * |
| * The following note by Rich is obsolete, see below. -- dlf 01 Oct. 2002 |
| * ----- |
| * @param key A resource tag. Currently, this parameter is ignored. The obvious |
| * intent, however, is for getAvailableLocales() to return a list of only those |
| * locales that contain a resource with the specified resource tag. |
| * |
| * <p>Before we implement this function this way, however, some thought should be |
| * given to whether this is really the right thing to do. Because of the lookup |
| * algorithm, a NumberFormat, for example, is "installed" for all locales. But if |
| * we're trying to put up a list of NumberFormats to choose from, we may want to see |
| * only a list of those locales that uniquely define a NumberFormat rather than |
| * inheriting one from another locale. Thus, if fr and fr_CA uniquely define |
| * NumberFormat data, but fr_BE doesn't, the user wouldn't see "French (Belgium)" in |
| * the list and would go for "French (default)" instead. Of course, this means |
| * "Engish (United States)" would not be in the list, since it is the default locale. |
| * This might be okay, but might be confusing to some users. |
| * |
| * <p>In addition, the other functions that call getAvailableLocales() don't currently |
| * all pass the right thing for "key," meaning that all of these functions should be |
| * looked at before anything is done to this function. |
| * |
| * <p>We recommend that someone take some careful consideration of these issues before |
| * modifying this function to pay attention to the "key" parameter. --rtg 1/26/98 |
| * ----- |
| * |
| * Return a list of the locales supported by a collection of resource bundles. |
| * All ICULocaleData-based services that use a particular resource bundle support |
| * all the locales from that bundle. If support for a particular service is spotty, |
| * a different bundle prefix should be used for that service. |
| * @param bundlePrefix the prefix of the resource bundles to use. |
| */ |
| public static Locale[] getAvailableLocales(String bundlePrefix) { |
| return (Locale[])getAvailEntry(bundlePrefix).getLocaleList().clone(); |
| } |
| |
| /** |
| * Convenience method that returns a list of all the avilable LOCALE_ELEMENTS locales. |
| */ |
| public static Locale[] getAvailableLocales() { |
| return getAvailableLocales(LOCALE_ELEMENTS); |
| } |
| |
| /** |
| * Return a set of the locale names supported by a collection of resource bundles. |
| * @param bundlePrefix the prefix of the resource bundles to use. |
| */ |
| public static Set getAvailableLocaleNameSet(String bundlePrefix) { |
| return getAvailEntry(bundlePrefix).getLocaleNameSet(); |
| } |
| |
| /** |
| * Return a set of the locale names supported by a collection of resource bundles. |
| * @param bundlePrefix the prefix of the resource bundles to use. |
| */ |
| public static Set getAvailableLocaleNameSet() { |
| return getAvailableLocaleNameSet(LOCALE_ELEMENTS); |
| } |
| |
| /** |
| * Holds the prefix, and lazily creates the Locale[] list or the locale name Set as needed. |
| */ |
| private static final class AvailEntry { |
| private String prefix; |
| private Locale[] locales; |
| private Set nameSet; |
| |
| AvailEntry(String prefix) { |
| this.prefix = prefix; |
| } |
| |
| Locale[] getLocaleList() { |
| if (locales == null) { |
| locales = createLocaleList(prefix); |
| } |
| return locales; |
| } |
| |
| Set getLocaleNameSet() { |
| if (nameSet == null) { |
| nameSet = createLocaleNameSet(prefix); |
| } |
| return nameSet; |
| } |
| } |
| |
| /** |
| * Stores the locale information in a cache accessed by key (bundle prefix). The |
| * cached objects are AvailEntries. The cache is held by a SoftReference |
| * so it can be GC'd. |
| */ |
| private static AvailEntry getAvailEntry(String key) { |
| AvailEntry ae = null; |
| Map lcache = null; |
| if (lcacheref != null) { |
| lcache = (Map)lcacheref.get(); |
| if (lcache != null) { |
| ae = (AvailEntry)lcache.get(key); |
| } |
| } |
| |
| if (ae == null) { |
| ae = new AvailEntry(key); |
| if (lcache == null) { |
| lcache = new HashMap(); |
| lcache.put(key, ae); |
| lcacheref = new SoftReference(lcache); |
| } else { |
| lcache.put(key, ae); |
| } |
| } |
| |
| return ae; |
| } |
| private static SoftReference lcacheref; |
| |
| /** |
| * The default name for resources containing ICU locale data. |
| */ |
| public static final String LOCALE_ELEMENTS = "LocaleElements"; |
| |
| /** |
| * Gets a LocaleElements resource bundle. |
| */ |
| public static ResourceBundle getLocaleElements(Locale locale) { |
| return getResourceBundle(LOCALE_ELEMENTS, locale); |
| } |
| |
| /** |
| * Gets a LocaleElements resource bundle. |
| */ |
| public static ResourceBundle getLocaleElements(String localeName) { |
| return getResourceBundle(LOCALE_ELEMENTS, localeName); |
| } |
| |
| /** |
| * Still need permissions to use our own class loader, is there no way |
| * to load class resources from new locations that aren't already on the |
| * class path? |
| */ |
| private static ResourceBundle instantiateBundle(String name, Locale l) { |
| ResourceBundle rb = ResourceBundle.getBundle(name, l); |
| return rb; |
| } |
| |
| /** |
| * Get a resource bundle from the lookup chain. |
| */ |
| public static ResourceBundle getResourceBundle(String bundleName, String localeName) { |
| Locale locale = LocaleUtility.getLocaleFromName(localeName); |
| return getResourceBundle(bundleName, locale); |
| } |
| |
| /** |
| * Get a resource bundle from the lookup chain. |
| */ |
| public static ResourceBundle getResourceBundle(String bundleName, Locale locale) { |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| for (int i = 0; i < packageNames.length; ++i) { |
| try { |
| String path = packageNames[i] + "." + bundleName; |
| if (debug) System.out.println("calling instantiateBundle: " + path + "_" + locale); |
| ResourceBundle rb = instantiateBundle(path, locale); |
| return rb; |
| } |
| catch (MissingResourceException e) { |
| if (debug) System.out.println(bundleName + "_" + locale + " not found in " + packageNames[i]); |
| throw e; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Get a resource bundle from the lookup chain. |
| */ |
| public static ResourceBundle getResourceBundle(String[] packages, String bundleName, String localeName) { |
| Locale locale = LocaleUtility.getLocaleFromName(localeName); |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| for (int i = 0; i < packages.length; ++i) { |
| try { |
| String path = packages[i] + "." + bundleName; |
| if (debug) System.out.println("calling instantiateBundle: " + path + "_" + locale); |
| ResourceBundle rb = instantiateBundle(path, locale); |
| return rb; |
| } |
| catch (MissingResourceException e) { |
| if (debug) System.out.println(bundleName + "_" + locale + " not found in " + packages[i]); |
| throw e; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get a resource bundle from the lookup chain. |
| */ |
| public static ResourceBundle getResourceBundle(String packageName, String bundleName, String localeName) { |
| Locale locale = LocaleUtility.getLocaleFromName(localeName); |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| |
| try { |
| String path = packageName + "." + bundleName; |
| if (debug) System.out.println("calling instantiateBundle: " + path + "_" + locale); |
| ResourceBundle rb = instantiateBundle(path, locale); |
| return rb; |
| } |
| catch (MissingResourceException e) { |
| if (debug) System.out.println(bundleName + "_" + locale + " not found in " + packageName); |
| throw e; |
| } |
| } |
| /** |
| * Get a resource bundle from the resource bundle path. Unlike getResourceBundle, this |
| * returns an 'unparented' bundle that exactly matches the bundle name and locale name. |
| */ |
| public static ResourceBundle loadResourceBundle(String bundleName, Locale locale) { |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| return loadResourceBundle(bundleName, locale.toString()); |
| } |
| |
| /** |
| * Get a resource bundle from the resource bundle path. Unlike getResourceBundle, this |
| * returns an 'unparented' bundle that exactly matches the bundle name and locale name. |
| */ |
| public static ResourceBundle loadResourceBundle(String bundleName, String localeName) { |
| if (localeName != null && localeName.length() > 0) { |
| bundleName = bundleName + "_" + localeName; |
| } |
| for (int i = 0; i < packageNames.length; ++i) { |
| String name = packageNames[i] + "." + bundleName; |
| try { |
| if (name.indexOf("_zh_") == -1) { // DLF temporary hack |
| Class rbclass = Class.forName(name); |
| ResourceBundle rb = (ResourceBundle)rbclass.newInstance(); |
| return rb; |
| } |
| } |
| catch (ClassNotFoundException e) { |
| if (debug) { |
| System.out.println(bundleName + " not found in " + packageNames[i]); |
| } |
| // ignore, keep looking |
| } |
| catch (Exception e) { |
| if (debug) { |
| System.out.println(e.getMessage()); |
| } |
| } |
| } |
| if (debug) { |
| System.out.println(bundleName + " not found."); |
| } |
| |
| return null; |
| } |
| |
| // ========== privates ========== |
| |
| private static Set createLocaleNameSet(String bundleName) { |
| try { |
| ResourceBundle index = getResourceBundle(bundleName, "index"); |
| Object[][] localeStrings = (Object[][]) index.getObject("InstalledLocales"); |
| String[] localeNames = new String[localeStrings.length]; |
| |
| // barf gag choke spit hack... |
| // since java's Locale 'fixes' the locale string for some locales, |
| // we have to fix our names to match, otherwise the Locale[] list |
| // won't match the locale name set. What were they thinking?!? |
| for (int i = 0; i < localeNames.length; ++i) { |
| localeNames[i] = LocaleUtility.getLocaleFromName((String)localeStrings[i][0]).toString(); |
| } |
| |
| HashSet set = new HashSet(); |
| set.addAll(Arrays.asList(localeNames)); |
| return Collections.unmodifiableSet(set); |
| } |
| catch (MissingResourceException e) { |
| System.out.println("couldn't find index for bundleName: " + bundleName); |
| Thread.dumpStack(); |
| } |
| return Collections.EMPTY_SET; |
| } |
| |
| private static Locale[] createLocaleList(String bundleName) { |
| try { |
| ResourceBundle index = getResourceBundle(bundleName, "index"); |
| Object[][] localeStrings = (Object[][]) index.getObject("InstalledLocales"); |
| Locale[] locales = new Locale[localeStrings.length]; |
| for (int i = 0; i < localeStrings.length; ++i) { |
| locales[i] = LocaleUtility.getLocaleFromName((String)localeStrings[i][0]); |
| } |
| return locales; |
| } |
| catch (MissingResourceException e) { |
| System.out.println("couldn't find index for bundleName: " + bundleName); |
| Thread.dumpStack(); |
| } |
| return new Locale[0]; |
| } |
| } |