aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2002-05-09 23:41:42 +0000
committerTom Tromey <tromey@gcc.gnu.org>2002-05-09 23:41:42 +0000
commit952589178550158f3c4897fd75de5ae5c3b439f4 (patch)
tree57618dcad965b4ccce97c99b06078c302ae09a1c /libjava
parentaf2728a4b41b45ab6d24a4142070a8cf620c1ebc (diff)
downloadgcc-952589178550158f3c4897fd75de5ae5c3b439f4.zip
gcc-952589178550158f3c4897fd75de5ae5c3b439f4.tar.gz
gcc-952589178550158f3c4897fd75de5ae5c3b439f4.tar.bz2
ResourceBundle.java: New version from Classpath.
* java/util/ResourceBundle.java: New version from Classpath. * java/util/Locale.java: Likewise. From-SVN: r53351
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog5
-rw-r--r--libjava/java/util/Locale.java728
-rw-r--r--libjava/java/util/ResourceBundle.java681
3 files changed, 770 insertions, 644 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 3827474..de368dc 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,8 @@
+2002-05-09 Tom Tromey <tromey@redhat.com>
+
+ * java/util/ResourceBundle.java: New version from Classpath.
+ * java/util/Locale.java: Likewise.
+
2002-05-09 Jakub Jelinek <jakub@redhat.com>
* testsuite/lib/libjava.exp (libjava_arguments): Append all
diff --git a/libjava/java/util/Locale.java b/libjava/java/util/Locale.java
index 9f50172..df5dac1 100644
--- a/libjava/java/util/Locale.java
+++ b/libjava/java/util/Locale.java
@@ -1,23 +1,23 @@
-/* java.util.Locale
- Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
-
+/* Locale.java -- i18n locales
+ Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
+
This file is part of GNU Classpath.
-
+
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-
+
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
@@ -37,207 +37,241 @@ exception statement from your version. */
package java.util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
/**
- * Locales represent a specific country and culture.
- * <br><br>
- * Classes which can be passed a Locale object tailor their information
- * for a given locale. For instance, currency number formatting is
- * handled differently for the USA and France.
- * <br><br>
- * Locales are made up of a language code, a country code, and an optional
- * set of variant strings.
- * <br><br>
- * Language codes are represented by
- * <a href="http://www.indigo.ie/egt/standards/iso639/iso639-1-en.html">ISO 639:1988</a>
- * w/ additions from ISO 639/RA Newsletter No. 1/1989
- * and a decision of the Advisory Committee of ISO/TC39 on
- * August 8, 1997.
- * <br><br>
- * Country codes are represented by
- * <a href="ftp://ftp.ripe.net/iso3166-countrycodes">ISO 3166</a>.
- * <br><br>
- * Variant strings are vendor and browser specific. Standard variant
- * strings include "POSIX" for POSIX, "WIN" for MS-Windows, and "MAC" for
- * Macintosh. When there is more than one variant string, they must
+ * Locales represent a specific country and culture. Classes which can be
+ * passed a Locale object tailor their information for a given locale. For
+ * instance, currency number formatting is handled differently for the USA
+ * and France.
+ *
+ * <p>Locales are made up of a language code, a country code, and an optional
+ * set of variant strings. Language codes are represented by
+ * <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
+ * ISO 639:1988</a> w/ additions from ISO 639/RA Newsletter No. 1/1989
+ * and a decision of the Advisory Committee of ISO/TC39 on August 8, 1997.
+ *
+ * <p>Country codes are represented by
+ * <a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html">
+ * ISO 3166</a>. Variant strings are vendor and browser specific. Standard
+ * variant strings include "POSIX" for POSIX, "WIN" for MS-Windows, and
+ * "MAC" for Macintosh. When there is more than one variant string, they must
* be separated by an underscore (U+005F).
- * <br><br>
- * The default locale is determined by the values of the system properties
- * user.language, user.region, and user.variant.
+ *
+ * <p>The default locale is determined by the values of the system properties
+ * user.language, user.region, and user.variant, defaulting to "en". Note that
+ * the locale does NOT contain the conversion and formatting capabilities (for
+ * that, use ResourceBundle and java.text). Rather, it is an immutable tag
+ * object for identifying a given locale, which is referenced by these other
+ * classes when they must make locale-dependent decisions.
+ *
* @see ResourceBundle
* @see java.text.Format
* @see java.text.NumberFormat
* @see java.text.Collator
* @author Jochen Hoenicke
* @author Paul Fisher
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status updated to 1.4
*/
-public final class Locale implements java.io.Serializable, Cloneable
+public final class Locale implements Serializable, Cloneable
{
- /**
- * Locale which represents the English language.
- */
- public static final Locale ENGLISH = new Locale("en", "");
- /**
- * Locale which represents the English language.
- */
- public static final Locale FRENCH = new Locale("fr", "");
- /**
- * Locale which represents the German language.
- */
- public static final Locale GERMAN = new Locale("de", "");
- /**
- * Locale which represents the Italian language.
- */
- public static final Locale ITALIAN = new Locale("it", "");
- /**
- * Locale which represents the Japanese language.
- */
- public static final Locale JAPANESE = new Locale("ja", "");
- /**
- * Locale which represents the Korean language.
- */
- public static final Locale KOREAN = new Locale("ko", "");
- /**
- * Locale which represents the Chinese language.
- */
- public static final Locale CHINESE = new Locale("zh", "");
- /**
- * Locale which represents the Chinese language as used in China.
- */
+ /** Locale which represents the English language. */
+ public static final Locale ENGLISH = new Locale("en");
+
+ /** Locale which represents the French language. */
+ public static final Locale FRENCH = new Locale("fr");
+
+ /** Locale which represents the German language. */
+ public static final Locale GERMAN = new Locale("de");
+
+ /** Locale which represents the Italian language. */
+ public static final Locale ITALIAN = new Locale("it");
+
+ /** Locale which represents the Japanese language. */
+ public static final Locale JAPANESE = new Locale("ja");
+
+ /** Locale which represents the Korean language. */
+ public static final Locale KOREAN = new Locale("ko");
+
+ /** Locale which represents the Chinese language. */
+ public static final Locale CHINESE = new Locale("zh");
+
+ /** Locale which represents the Chinese language as used in China. */
public static final Locale SIMPLIFIED_CHINESE = new Locale("zh", "CN");
+
/**
* Locale which represents the Chinese language as used in Taiwan.
* Same as TAIWAN Locale.
*/
public static final Locale TRADITIONAL_CHINESE = new Locale("zh", "TW");
- /**
- * Locale which represents France.
- */
+
+ /** Locale which represents France. */
public static final Locale FRANCE = new Locale("fr", "FR");
- /**
- * Locale which represents Germany.
- */
+
+ /** Locale which represents Germany. */
public static final Locale GERMANY = new Locale("de", "DE");
- /**
- * Locale which represents Italy.
- */
+
+ /** Locale which represents Italy. */
public static final Locale ITALY = new Locale("it", "IT");
- /**
- * Locale which represents Japan.
- */
+
+ /** Locale which represents Japan. */
public static final Locale JAPAN = new Locale("ja", "JP");
- /**
- * Locale which represents Korea.
- */
+
+ /** Locale which represents Korea. */
public static final Locale KOREA = new Locale("ko", "KR");
+
/**
* Locale which represents China.
* Same as SIMPLIFIED_CHINESE Locale.
*/
public static final Locale CHINA = SIMPLIFIED_CHINESE;
+
/**
* Locale which represents the People's Republic of China.
* Same as CHINA Locale.
*/
public static final Locale PRC = CHINA;
+
/**
* Locale which represents Taiwan.
* Same as TRADITIONAL_CHINESE Locale.
*/
public static final Locale TAIWAN = TRADITIONAL_CHINESE;
- /**
- * Locale which represents the United Kingdom.
- */
+
+ /** Locale which represents the United Kingdom. */
public static final Locale UK = new Locale("en", "GB");
- /**
- * Locale which represents the United States.
- */
+
+ /** Locale which represents the United States. */
public static final Locale US = new Locale("en", "US");
- /**
- * Locale which represents the English speaking portion of Canada.
- */
+
+ /** Locale which represents the English speaking portion of Canada. */
public static final Locale CANADA = new Locale("en", "CA");
- /**
- * Locale which represents the French speaking portion of Canada.
- */
+
+ /** Locale which represents the French speaking portion of Canada. */
public static final Locale CANADA_FRENCH = new Locale("fr", "CA");
/**
- * We are compatible to sun's Locale.
+ * Compatible with JDK 1.1+.
*/
- static final long serialVersionUID = 9149081749638150636L;
+ private static final long serialVersionUID = 9149081749638150636L;
/**
* The language code, as returned by getLanguage().
- * @serial
+ *
+ * @serial the languange, possibly ""
*/
private String language;
+
/**
* The country code, as returned by getCountry().
- * @serial
+ *
+ * @serial the country, possibly ""
*/
private String country;
+
/**
* The variant code, as returned by getVariant().
- * @serial
+ *
+ * @serial the variant, possibly ""
*/
private String variant;
+
/**
- * This is the cached hashcode. When writing to stream, we write -1.
- * @serial
+ * This is the cached hashcode. When writing to stream, we write -1.
+ *
+ * @serial should be -1 in serial streams
*/
private int hashcode;
/**
- * Convert old iso639 codes to the new ones.
+ * The default locale. Except for during bootstrapping, this should never be
+ * null. Note the logic in the main constructor, to detect when
+ * bootstrapping has completed.
+ */
+ private static Locale defaultLocale =
+ new Locale(System.getProperty("user.language", "en"),
+ System.getProperty("user.region", ""),
+ System.getProperty("user.variant", ""));
+
+ /**
+ * Convert new iso639 codes to the old ones.
+ *
+ * @param language the language to check
+ * @return the appropriate code
*/
private String convertLanguage(String language)
{
if (language.equals(""))
return language;
-
language = language.toLowerCase();
- int index = "iw,in,ji".indexOf(language);
+ int index = "he,id,yi".indexOf(language);
if (index != -1)
- return "he,id,yi".substring(index, index + 2);
+ return "iw,in,ji".substring(index, index + 2);
return language;
}
/**
* Creates a new locale for the given language and country.
- * @param language lowercase two-letter ISO-639 A2 language code.
- * @param country uppercase two-letter ISO-3166 A2 contry code.
- * @param variant vendor and browser specific.
+ *
+ * @param language lowercase two-letter ISO-639 A2 language code
+ * @param country uppercase two-letter ISO-3166 A2 contry code
+ * @param variant vendor and browser specific
+ * @throws NullPointerException if any argument is null
*/
public Locale(String language, String country, String variant)
{
- this.language = convertLanguage(language);
- this.country = country.toUpperCase();
- this.variant = variant.toUpperCase();
- this.hashcode = (this.language.hashCode() ^ this.country.hashCode()
- ^ this.variant.hashCode());
+ // During bootstrap, we already know the strings being passed in are
+ // the correct capitalization, and not null. We can't call
+ // String.toUpperCase during this time, since that depends on the
+ // default locale.
+ if (defaultLocale != null)
+ {
+ language = convertLanguage(language);
+ country = country.toUpperCase();
+ variant = variant.toUpperCase();
+ }
+ this.language = language;
+ this.country = country;
+ this.variant = variant;
+ hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
}
/**
* Creates a new locale for the given language and country.
- * @param language lowercase two-letter ISO-639 A2 language code.
- * @param country uppercase two-letter ISO-3166 A2 country code.
+ *
+ * @param language lowercase two-letter ISO-639 A2 language code
+ * @param country uppercase two-letter ISO-3166 A2 country code
+ * @throws NullPointerException if either argument is null
*/
public Locale(String language, String country)
{
this(language, country, "");
}
- private static Locale defaultLocale =
- new Locale(System.getProperty("user.language", ""),
- System.getProperty("user.region", ""),
- System.getProperty("user.variant", ""));
+ /**
+ * Creates a new locale for a language.
+ *
+ * @param language lowercase two-letter ISO-639 A2 language code
+ * @throws NullPointerException if either argument is null
+ * @since 1.4
+ */
+ public Locale(String language)
+ {
+ this(language, "", "");
+ }
/**
- * Returns the default Locale. The default locale is generally
- * once set on start up and then never changed. Normally you
- * should use this locale for everywhere you need a locale.
- * The initial setting matches the default locale, the user has
- * chosen.
+ * Returns the default Locale. The default locale is generally once set
+ * on start up and then never changed. Normally you should use this locale
+ * for everywhere you need a locale. The initial setting matches the
+ * default locale, the user has chosen.
+ *
+ * @return the default locale for this virtual machine
*/
public static Locale getDefault()
{
@@ -245,23 +279,37 @@ public final class Locale implements java.io.Serializable, Cloneable
}
/**
- * Changes the default locale. Normally only called on program
- * start up. Note that this doesn't change the locale for other
- * programs.
+ * Changes the default locale. Normally only called on program start up.
+ * Note that this doesn't change the locale for other programs. This has
+ * a security check,
+ * <code>PropertyPermission("user.language", "write")</code>, because of
+ * its potential impact to running code.
+ *
+ * @param newLocale the new default locale
+ * @throws NullPointerException if newLocale is null
+ * @throws SecurityException if permission is denied
*/
public static void setDefault(Locale newLocale)
{
+ if (newLocale == null)
+ throw new NullPointerException();
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new PropertyPermission("user.language", "write"));
defaultLocale = newLocale;
}
/**
* Returns the list of available locales.
+ *
+ * @return the installed locales
*/
public static Locale[] getAvailableLocales()
{
/* I only return those for which localized language
* or country information exists.
- * XXX - remove hard coded list.
+ * XXX - remove hard coded list, and implement more locales (Sun's JDK 1.4
+ * has 148 installed locales!).
*/
return new Locale[]
{
@@ -271,71 +319,68 @@ public final class Locale implements java.io.Serializable, Cloneable
/**
* Returns a list of all 2-letter uppercase country codes as defined
- * in ISO 3166
+ * in ISO 3166.
+ *
+ * @return a list of acceptible country codes
*/
public static String[] getISOCountries()
{
return new String[]
{
- "AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG",
- "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD",
- "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA",
- "BW", "BV", "BR", "IO", "BN", "BG", "BF", "BI", "KH",
- "CM", "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX",
- "CC", "CO", "KM", "CG", "CK", "CR", "CI", "HR", "CU",
- "CY", "CZ", "DK", "DJ", "DM", "DO", "TP", "EC", "EG",
- "SV", "GQ", "ER", "EE", "ET", "FK", "FO", "FJ", "FI",
- "FR", "FX", "GF", "PF", "TF", "GA", "GM", "GE", "DE",
- "GH", "GI", "GR", "GL", "GD", "GP", "GU", "GT", "GN",
- "GW", "GY", "HT", "HM", "HN", "HK", "HU", "IS", "IN",
- "ID", "IR", "IQ", "IE", "IL", "IT", "JM", "JP", "JO",
- "KZ", "KE", "KI", "KP", "KR", "KW", "KG", "LA", "LV",
- "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MK",
- "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ", "MR",
- "MU", "YT", "MX", "FM", "MD", "MC", "MN", "MS", "MA",
- "MZ", "MM", "NA", "NR", "NP", "NL", "AN", "NC", "NZ",
- "NI", "NE", "NG", "NU", "NF", "MP", "NO", "OM", "PK",
- "PW", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT",
- "PR", "QA", "RE", "RO", "RU", "RW", "KN", "LC", "VC",
- "WS", "SM", "ST", "SA", "SN", "SC", "SL", "SG", "SK",
- "SI", "SB", "SO", "ZA", "GS", "ES", "LK", "SH", "PM",
- "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ",
- "TZ", "TH", "TG", "TK", "TO", "TT", "TN", "TR", "TM",
- "TC", "TV", "UG", "UA", "AE", "GB", "US", "UM", "UY",
- "UZ", "VU", "VA", "VE", "VN", "VG", "VI", "WF", "EH",
- "YE", "YU", "ZR", "ZM", "ZW"};
+ "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS",
+ "AT", "AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI",
+ "BJ", "BM", "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA",
+ "CC", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU",
+ "CV", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE",
+ "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "FX",
+ "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GL", "GM", "GN", "GP", "GQ",
+ "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
+ "ID", "IE", "IL", "IN", "IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP",
+ "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
+ "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC",
+ "MD", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS",
+ "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG",
+ "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG",
+ "PH", "PK", "PL", "PM", "PN", "PR", "PT", "PW", "PY", "QA", "RE", "RO",
+ "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK",
+ "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TC", "TD", "TF",
+ "TG", "TH", "TJ", "TK", "TM", "TN", "TO", "TP", "TR", "TT", "TV", "TW",
+ "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI",
+ "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZR", "ZW"
+ };
}
/**
* Returns a list of all 2-letter lowercase language codes as defined
* in ISO 639 (both old and new variant).
+ *
+ * @return a list of acceptable language codes
*/
public static String[] getISOLanguages()
{
return new String[]
{
- "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba",
- "be", "bg", "bh", "bi", "bn", "bo", "br", "ca", "co",
- "cs", "cy", "da", "de", "dz", "el", "en", "eo", "es",
- "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", "ga",
- "gd", "gl", "gn", "gu", "ha", "iw", "he", "hi", "hr",
- "hu", "hy", "ia", "in", "id", "ie", "ik", "is", "it",
- "iu", "ja", "jw", "ka", "kk", "kl", "km", "kn", "ko",
- "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv", "mg",
- "mi", "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my",
- "na", "ne", "nl", "no", "oc", "om", "or", "pa", "pl",
- "ps", "pt", "qu", "rm", "rn", "ro", "ru", "rw", "sa",
- "sd", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so",
- "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te",
- "tg", "th", "ti", "tk", "tl", "tn", "to", "tr", "ts",
- "tt", "tw", "ug", "uk", "ur", "uz", "vi", "vo", "wo",
- "xh", "ji", "yi", "yo", "za", "zh", "zu"};
+ "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", "bh",
+ "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", "el",
+ "en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", "ga",
+ "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", "id",
+ "ie", "ik", "in", "is", "it", "iu", "iw", "ja", "ji", "jw", "ka", "kk",
+ "kl", "km", "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv",
+ "mg", "mi", "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my", "na", "ne",
+ "nl", "no", "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn",
+ "ro", "ru", "rw", "sa", "sd", "sg", "sh", "si", "sk", "sl", "sm", "sn",
+ "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th",
+ "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt", "tw", "ug", "uk", "ur",
+ "uz", "vi", "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu"
+ };
}
/**
- * Returns the language code of this locale.
- * @return language code portion of this locale, or an empty String if
- * none exists
+ * Returns the language code of this locale. Some language codes have changed
+ * as ISO 639 has evolved; this returns the old name, even if you built
+ * the locale with the new one.
+ *
+ * @return language code portion of this locale, or an empty String
*/
public String getLanguage()
{
@@ -344,8 +389,8 @@ public final class Locale implements java.io.Serializable, Cloneable
/**
* Returns the country code of this locale.
- * @return country code portion of this locale, or an empty String if
- * none exists
+ *
+ * @return country code portion of this locale, or an empty String
*/
public String getCountry()
{
@@ -354,6 +399,8 @@ public final class Locale implements java.io.Serializable, Cloneable
/**
* Returns the variant code of this locale.
+ *
+ * @return the variant code portion of this locale, or an empty String
*/
public String getVariant()
{
@@ -361,214 +408,219 @@ public final class Locale implements java.io.Serializable, Cloneable
}
/**
- * Gets the string representation of the current locale. This
- * consists of the language, the country, and the variant,
- * separated by an underscore. If one of this three component is
- * missing the underscore will also disappear.
- * @return the string representation of this Locale.
+ * Gets the string representation of the current locale. This consists of
+ * the language, the country, and the variant, separated by an underscore.
+ * The variant is listed only if there is a language or country. Examples:
+ * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC".
+ *
+ * @return the string representation of this Locale
+ * @see #getDisplayName()
*/
public final String toString()
{
+ if (language.length() == 0 && country.length() == 0)
+ return "";
StringBuffer result = new StringBuffer(language);
- String underscore = "";
- if (language.length() != 0)
- underscore = "_";
- if (country.length() != 0)
- {
- result.append(underscore);
- result.append(country);
- underscore = "_";
- }
+ result.append('_').append(country);
if (variant.length() != 0)
- {
- result.append(underscore);
- result.append(variant);
- }
+ result.append('_').append(variant);
return result.toString();
}
/**
* Returns the three-letter ISO language abbrevation of this locale.
- * @exception MissingResourceException if the three-letter code is not
- * known.
+ *
+ * @throws MissingResourceException if the three-letter code is not known
*/
- public String getISO3Language() throws MissingResourceException
+ public String getISO3Language()
{
- int index =
- ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy," +
- "da,de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu," +
- "gv,ha,hi,hr,hu,hy,ia,ie,ik,id,is,it,iu,he,ja,yi,jw,ka,kk,kl," +
- "km,kn,ko,ks,ku,kw,ky,la,lb,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr," +
- "ms,mt,my,na,ne,nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw," +
- "sa,sd,se,sg,sh,si,sk,sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te," +
- "tg,th,ti,tk,tl,tn,to,tr,ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,yo," +
- "za,zh,zu,").indexOf(language + ",");
-
- if (index == -1 || language.length() != 2)
+ if ("".equals(language))
+ return "";
+ int index
+ = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da,"
+ + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw,"
+ + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn,"
+ + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne,"
+ + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk,"
+ + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr,"
+ + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu")
+ .indexOf(language);
+
+ if (index % 3 != 0 || language.length() != 2)
throw new MissingResourceException
- ("Can't find ISO3 language for " + language,
- "java.util.Locale", language);
+ ("Can't find ISO3 language for " + language,
+ "java.util.Locale", language);
- /* Don't read this aloud. This are the three letter language codes
- */
+ // Don't read this aloud. These are the three letter language codes.
return
- ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescym" +
- "dandeudzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrnguj" +
- "maxhauhinhrvhunhyeinaileipkindislitaikuhebjpnyidjawkatkazkal" +
- "khmkankorkaskurcorkirlatltzlinlaolitlavmlgmrimkdmalmonmolmar" +
- "msamltmyanaunepnldnorociormoripanpolpusporquerohrunronruskin" +
- "sansndsmisagsrpsinslkslvsmosnasomsqisrpsswsotsunsweswatamtel" +
- "tgkthatirtuktgltsntonturtsotattwiuigukrurduzbvievolwolxhoyor" +
- "zhazhozul").substring(index, index + 3);
+ ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu"
+ + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv"
+ + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur"
+ + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm"
+ + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi"
+ + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd"
+ + "uzbvievolwolxhoyidyorzhazhozul")
+ .substring(index, index + 3);
}
/**
* Returns the three-letter ISO country abbrevation of the locale.
- * @exception MissingResourceException if the three-letter code is not
- * known.
+ *
+ * @throws MissingResourceException if the three-letter code is not known
*/
- public String getISO3Country() throws MissingResourceException
+ public String getISO3Country()
{
- int index =
- ("AF,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE," +
- "BZ,BJ,BM,BT,BO,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD," +
- "CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CY,CZ,DK,DJ,DM,DO,TP,EC," +
- "EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,FX,GF,PF,TF,GA,GM,GE,DE,GH,GI," +
- "GR,GL,GD,GP,GU,GT,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE," +
- "IL,IT,JM,JP,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU," +
- "MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,MS,MA,MZ," +
- "MM,NA,NR,NP,NL,AN,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PA,PG,PY," +
- "PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,KN,LC,VC,WS,SM,ST,SA,SN,SC,SL," +
- "SG,SK,SI,SB,SO,ZA,GS,ES,LK,SH,PM,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ," +
- "TH,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN," +
- "VG,VI,WF,EH,YE,YU,ZM,ZW,").indexOf(country + ",");
-
- if (index == -1 || language.length() != 2)
+ if ("".equals(country))
+ return "";
+ int index
+ = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF,"
+ + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK,"
+ + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,"
+ + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ,"
+ + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT,"
+ + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,"
+ + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,"
+ + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,"
+ + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH,"
+ + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN,"
+ + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,"
+ + "WS,YE,YT,YU,ZA,ZM,ZR,ZW")
+ .indexOf(country);
+
+ if (index % 3 != 0 || language.length() != 2)
throw new MissingResourceException
- ("Can't find ISO3 country for " + country,
- "java.util.Locale", country);
+ ("Can't find ISO3 country for " + country,
+ "java.util.Locale", country);
- /* Don't read this aloud. This are the three letter country codes
- */
+ // Don't read this aloud. These are the three letter country codes.
return
- ("AFGALBDZAASMANDAGOAIAATAATGARGARMABWAUSAUTAZEBHSBHRBGDBRBBLRBEL" +
- "BLZBENBMUBTNBOLBIHBWABVTBRAIOTBRNBGRBFABDIKHMCMRCANCPVCYMCAFTCD" +
- "CHLCHNCXRCCKCOLCOMCOGCODCOKCRICIVHRVCUBCYPCZEDNKDJIDMADOMTMPECU" +
- "EGYSLVGNQERIESTETHFLKFROFJIFINFRAFXXGUFPYFATFGABGMBGEODEUGHAGIB" +
- "GRCGRLGRDGLPGUMGTMGINGNBGUYHTIHMDVATHNDHKGHUNISLINDIDNIRNIRQIRL" +
- "ISRITAJAMJPNJORKAZKENKIRPRKKORKWTKGZLAOLVALBNLSOLBRLBYLIELTULUX" +
- "MACMKDMDGMWIMYSMDVMLIMLTMHLMTQMRTMUSMYTMEXFSMMDAMCOMNGMSRMARMOZ" +
- "MMRNAMNRUNPLNLDANTNCLNZLNICNERNGANIUNFKMNPNOROMNPAKPLWPANPNGPRY" +
- "PERPHLPCNPOLPRTPRIQATREUROMRUSRWAKNALCAVCTWSMSMRSTPSAUSENSYCSLE" +
- "SGPSVKSVNSLBSOMZAFSGSESPLKASHNSPMSDNSURSJMSWZSWECHESYRTWNTJKTZA" +
- "THATGOTKLTONTTOTUNTURTKMTCATUVUGAUKRAREGBRUSAUMIURYUZBVUTVENVNM" +
- "VGBVIRWLFESHYEMYUGZMBZWE").substring(index, index + 3);
+ ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR"
+ + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR"
+ + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN"
+ + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM"
+ + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ"
+ + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO"
+ + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER"
+ + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW"
+ + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP"
+ + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI"
+ + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE")
+ .substring(index, index + 3);
}
- /**
+ /**
* Gets the country name suitable for display to the user, formatted
* for the default locale. This has the same effect as
* <pre>
* getDisplayLanguage(Locale.getDefault());
* </pre>
*
- * @return the language name of this locale localized to the
- * default locale. If the localized is not found, the ISO code
- * is returned.
+ * @return the language name of this locale localized to the default locale,
+ * with the ISO code as backup
*/
public String getDisplayLanguage()
{
- return getDisplayLanguage(getDefault());
+ return getDisplayLanguage(defaultLocale);
}
- /**
+ /**
* Gets the language name suitable for display to the user, formatted
* for a specified locale.
+ *
* @param locale locale to use for formatting
- * @return the language name of this locale localized to the
- * given locale. If the localized is not found, the ISO code
- * is returned.
+ * @return the language name of this locale localized to the given locale,
+ * with the ISO code as backup
*/
public String getDisplayLanguage(Locale locale)
{
try
{
- ResourceBundle bundle
- = ResourceBundle.getBundle("gnu.java.locale.iso639", locale);
- return bundle.getString(language);
+ ResourceBundle bundle
+ = ResourceBundle.getBundle("gnu.java.locale.iso639", locale);
+ return bundle.getString(language);
}
catch (MissingResourceException ex)
{
- return language;
+ return language;
}
}
- /**
+ /**
* Returns the country name of this locale localized to the
- * default locale. If the localized is not found, the ISO code
- * is returned. This has the same effect as
+ * default locale. If the localized is not found, the ISO code
+ * is returned. This has the same effect as
* <pre>
* getDisplayCountry(Locale.getDefault());
* </pre>
+ *
+ * @return the country name of this locale localized to the given locale,
+ * with the ISO code as backup
*/
public String getDisplayCountry()
{
- return getDisplayCountry(getDefault());
+ return getDisplayCountry(defaultLocale);
}
- /**
+ /**
* Gets the country name suitable for display to the user, formatted
* for a specified locale.
*
* @param locale locale to use for formatting
- * @return the country name of this locale localized to the given
- * locale. If the localized is not found, the ISO country code is
- * returned. */
+ * @return the country name of this locale localized to the given locale,
+ * with the ISO code as backup
+ */
public String getDisplayCountry(Locale locale)
{
try
{
- ResourceBundle bundle =
- ResourceBundle.getBundle("gnu.java.locale.iso3166", locale);
- return bundle.getString(country);
+ ResourceBundle bundle =
+ ResourceBundle.getBundle("gnu.java.locale.iso3166", locale);
+ return bundle.getString(country);
}
catch (MissingResourceException ex)
{
- return country;
+ return country;
}
}
- /**
+ /**
* Returns the variant name of this locale localized to the
- * default locale. If the localized is not found, the variant code
- * itself is returned. This has the same effect as
+ * default locale. If the localized is not found, the variant code
+ * itself is returned. This has the same effect as
* <pre>
* getDisplayVariant(Locale.getDefault());
* </pre>
+ *
+ * @return the variant code of this locale localized to the given locale,
+ * with the ISO code as backup
*/
public String getDisplayVariant()
{
- return getDisplayVariant(getDefault());
+ return getDisplayVariant(defaultLocale);
}
- /**
+ /**
* Returns the variant name of this locale localized to the
- * given locale. If the localized is not found, the variant code
+ * given locale. If the localized is not found, the variant code
* itself is returned.
+ *
+ * @param locale locale to use for formatting
+ * @return the variant code of this locale localized to the given locale,
+ * with the ISO code as backup
*/
public String getDisplayVariant(Locale locale)
{
- /*XXX - load a bundle? */
+ // XXX - load a bundle?
return variant;
}
/**
* Gets all local components suitable for display to the user, formatted
- * for the default locale. For the language component, getDisplayLanguage
- * is called. For the country component, getDisplayCountry is called.
+ * for the default locale. For the language component, getDisplayLanguage
+ * is called. For the country component, getDisplayCountry is called.
* For the variant set component, getDisplayVariant is called.
- * <br><br>
- * The returned String will be one of the following forms:<br>
+ *
+ * <p>The returned String will be one of the following forms:<br>
* <pre>
* language (country, variant)
* language (country)
@@ -578,22 +630,22 @@ public final class Locale implements java.io.Serializable, Cloneable
* country
* variant
* </pre>
- * @return String version of this locale, suitable for display to the
- * user.
+ *
+ * @return String version of this locale, suitable for display to the user
*/
public String getDisplayName()
{
- return getDisplayName(getDefault());
+ return getDisplayName(defaultLocale);
}
/**
* Gets all local components suitable for display to the user, formatted
- * for a specified locale. For the language component,
- * getDisplayLanguage(Locale) is called. For the country component,
- * getDisplayCountry(Locale) is called. For the variant set component,
+ * for a specified locale. For the language component,
+ * getDisplayLanguage(Locale) is called. For the country component,
+ * getDisplayCountry(Locale) is called. For the variant set component,
* getDisplayVariant(Locale) is called.
- * <br><br>
- * The returned String will be one of the following forms:<br>
+ *
+ * <p>The returned String will be one of the following forms:<br>
* <pre>
* language (country, variant)
* language (country)
@@ -605,63 +657,53 @@ public final class Locale implements java.io.Serializable, Cloneable
* </pre>
*
* @param locale locale to use for formatting
- *
- * @return String version of this locale, suitable for display to the
- * user.
+ * @return String version of this locale, suitable for display to the user
*/
public String getDisplayName(Locale locale)
{
StringBuffer result = new StringBuffer();
int count = 0;
String[] delimiters = {"", " (", ","};
-
if (language.length() != 0)
{
- result.append(delimiters[count++]);
- result.append(getDisplayLanguage(locale));
+ result.append(delimiters[count++]);
+ result.append(getDisplayLanguage(locale));
}
-
if (country.length() != 0)
{
- result.append(delimiters[count++]);
- result.append(getDisplayCountry(locale));
+ result.append(delimiters[count++]);
+ result.append(getDisplayCountry(locale));
}
-
if (variant.length() != 0)
{
- result.append(delimiters[count++]);
- result.append(getDisplayVariant(locale));
+ result.append(delimiters[count++]);
+ result.append(getDisplayVariant(locale));
}
-
if (count > 1)
result.append(")");
-
return result.toString();
}
/**
* Does the same as <code>Object.clone()</code> but does not throw
- * an <code>CloneNotSupportedException</code>. Why anyone would
- * use this method is a secret to me, since this class is
- * immutable.
+ * a <code>CloneNotSupportedException</code>. Why anyone would
+ * use this method is a secret to me, since this class is immutable.
+ *
+ * @return the clone
*/
public Object clone()
{
- try
- {
- return super.clone();
- }
- catch (CloneNotSupportedException ex)
- {
- return null;
- }
+ // This class is final, so no need to use native super.clone().
+ return new Locale(language, country, variant);
}
/**
- * Return the hash code for this locale. The hashcode is the logical
+ * Return the hash code for this locale. The hashcode is the logical
* xor of the hash codes of the language, the country and the variant.
* The hash code is precomputed, since <code>Locale</code>s are often
* used in hash tables.
+ *
+ * @return the hashcode
*/
public synchronized int hashCode()
{
@@ -671,30 +713,34 @@ public final class Locale implements java.io.Serializable, Cloneable
}
/**
- * Compares two locales.
- * @param obj the other locale.
- * @return true, if obj is a Locale with the same language, country, and
- * variant code as this locale, otherwise false.
+ * Compares two locales. To be equal, obj must be a Locale with the same
+ * language, country, and variant code.
+ *
+ * @param obj the other locale
+ * @return true if obj is equal to this
*/
public boolean equals(Object obj)
{
- if (this == obj)
- return true;
- if (!(obj instanceof Locale))
+ if (! (obj instanceof Locale))
return false;
Locale l = (Locale) obj;
return (language.equals(l.language)
- && country.equals(l.country)
- && variant.equals(l.variant));
+ && country.equals(l.country)
+ && variant.equals(l.variant));
}
/**
- * @serialdata According to jdk1.2 the hashcode should always be
- * written as -1;
+ * Write the locale to an object stream.
+ *
+ * @param output the stream to write to
+ * @throws IOException if the write fails
+ * @serialData the hashcode should always be written as -1, and recomputed
+ * when reading it back
*/
- private synchronized void writeObject(java.io.ObjectOutputStream output)
- throws java.io.IOException
+ private synchronized void writeObject(ObjectOutputStream output)
+ throws IOException
{
+ // Synchronized so that hashCode() doesn't get wrong value.
int tmpHashcode = hashcode;
hashcode = -1;
output.defaultWriteObject();
@@ -702,13 +748,17 @@ public final class Locale implements java.io.Serializable, Cloneable
}
/**
- * @serialdata According to jdk1.2 the hashCode is always invalid
- * and must be recomputed.
+ * Reads a locale from the input stream.
+ *
+ * @param input the stream to read from
+ * @throws IOException if reading fails
+ * @throws ClassNotFoundException if reading fails
+ * @serialData the hashCode is always invalid and must be recomputed
*/
- private void readObject(java.io.ObjectInputStream input)
- throws java.io.IOException, ClassNotFoundException
+ private void readObject(ObjectInputStream input)
+ throws IOException, ClassNotFoundException
{
input.defaultReadObject();
hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
}
-}
+} // class Locale
diff --git a/libjava/java/util/ResourceBundle.java b/libjava/java/util/ResourceBundle.java
index 895c887..150a01b 100644
--- a/libjava/java/util/ResourceBundle.java
+++ b/libjava/java/util/ResourceBundle.java
@@ -1,5 +1,5 @@
-/* java.util.ResourceBundle
- Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+/* ResourceBundle -- aids in loading resource bundles
+ Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,93 +37,106 @@ exception statement from your version. */
package java.util;
+
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
+import java.io.InputStream;
+import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import gnu.classpath.Configuration;
/**
- * A resource bundle contains locale-specific data. If you need
- * localized data, you can load a resource bundle that matches the
- * locale with <code>getBundle</code>. Now you can get your object by
- * calling <code>getObject</code> or <code>getString</code> on that
- * bundle.
- * <br>
- * When a bundle is demanded for a specific locale, the ResourceBundle
- * is searched in following order (<i>def. language code<i> stands for
- * the two letter ISO language code of the default locale (see
+ * A resource bundle contains locale-specific data. If you need localized
+ * data, you can load a resource bundle that matches the locale with
+ * <code>getBundle</code>. Now you can get your object by calling
+ * <code>getObject</code> or <code>getString</code> on that bundle.
+ *
+ * <p>When a bundle is demanded for a specific locale, the ResourceBundle
+ * is searched in following order (<i>def. language<i> stands for the
+ * two letter ISO language code of the default locale (see
* <code>Locale.getDefault()</code>).
- * <pre>
- * baseName_<i>language code</i>_<i>country code</i>_<i>variant</i>
- * baseName_<i>language code</i>_<i>country code</i>
- * baseName_<i>language code</i>
- * baseName_<i>def. language code</i>_<i>def. country code</i>_<i>def. variant</i>
- * baseName_<i>def. language code</i>_<i>def. country code</i>
- * baseName_<i>def. language code</i>
- * baseName
- * </pre>
*
- * A bundle is backed up, by less specific bundle (omiting variant,
- * country or language). But it is not backed up by the default
- * language locale.
- * <br>
- * If you provide a bundle for a given locale, say
+<pre>baseName_<i>language code</i>_<i>country code</i>_<i>variant</i>
+baseName_<i>language code</i>_<i>country code</i>
+baseName_<i>language code</i>
+baseName_<i>def. language</i>_<i>def. country</i>_<i>def. variant</i>
+baseName_<i>def. language</i>_<i>def. country</i>
+baseName_<i>def. language</i>
+baseName</pre>
+ *
+ * <p>A bundle is backed up by less specific bundles (omiting variant, country
+ * or language). But it is not backed up by the default language locale.
+ *
+ * <p>If you provide a bundle for a given locale, say
* <code>Bundle_en_UK_POSIX</code>, you must also provide a bundle for
* all sub locales, ie. <code>Bundle_en_UK</code>, <code>Bundle_en</code>, and
* <code>Bundle</code>.
- * <br>
- * When a bundle is searched, we look first for a class with
- * the given name and if that is not found for a file with
- * <code>.properties</code> extension in the classpath. The name
- * must be a fully qualified classname (with dots as path separators).
- * <br>
- * (Note: This implementation always backs up the class with a
- * properties file if that is existing, but you shouldn't rely on
- * this, if you want to be compatible to the standard JDK.)
*
+ * <p>When a bundle is searched, we look first for a class with the given
+ * name, then for a file with <code>.properties</code> extension in the
+ * classpath. The name must be a fully qualified classname (with dots as
+ * path separators).
+ *
+ * <p>(Note: This implementation always backs up the class with a properties
+ * file if that is existing, but you shouldn't rely on this, if you want to
+ * be compatible to the standard JDK.)
+ *
+ * @author Jochen Hoenicke
+ * @author Eric Blake (ebb9@email.byu.edu)
* @see Locale
+ * @see ListResourceBundle
* @see PropertyResourceBundle
- * @author Jochen Hoenicke */
+ * @since 1.1
+ * @status updated to 1.4
+ */
public abstract class ResourceBundle
{
/**
- * The parent bundle. This is consulted when you call getObject
- * and there is no such resource in the current bundle. This
- * field may be null.
+ * The parent bundle. This is consulted when you call getObject and there
+ * is no such resource in the current bundle. This field may be null.
*/
protected ResourceBundle parent;
/**
- * The locale of this resource bundle. You can read this with
+ * The locale of this resource bundle. You can read this with
* <code>getLocale</code> and it is automatically set in
- * <code>getBundle</code>.
+ * <code>getBundle</code>.
*/
private Locale locale;
/**
- * We override SecurityManager in order to access getClassContext().
+ * We override SecurityManager in order to access getClassContext().
*/
- static class Security extends SecurityManager
+ private static final class Security extends SecurityManager
{
- /** Return the ClassLoader of the class which called into this
- ResourceBundle, or null if it cannot be determined. */
+ /**
+ * Avoid accessor method of private constructor.
+ */
+ Security()
+ {
+ }
+
+ /**
+ * Return the ClassLoader of the class which called into this
+ * ResourceBundle, or null if it cannot be determined.
+ */
ClassLoader getCallingClassLoader()
{
- Class[] stack = super.getClassContext();
+ Class[] stack = getClassContext();
for (int i = 0; i < stack.length; i++)
if (stack[i] != Security.class && stack[i] != ResourceBundle.class)
- return stack[i].getClassLoader();
+ return stack[i].getClassLoader();
return null;
}
}
-
- // This will always work since java.util classes have (all) system
- // permissions.
- static Security security = (Security) AccessController.doPrivileged
- (
- new PrivilegedAction()
+
+ /** A security context for grabbing the correct class loader. */
+ private static final Security security
+ = (Security) AccessController.doPrivileged(new PrivilegedAction()
{
+ // This will always work since java.util classes have (all) system
+ // permissions.
public Object run()
{
return new Security();
@@ -132,343 +145,401 @@ public abstract class ResourceBundle
);
/**
- * The constructor. It does nothing special.
+ * The resource bundle cache. This is a two-level hash map: The key
+ * is the class loader, the value is a new HashMap. The key of this
+ * second hash map is the localized name, the value is a soft
+ * references to the resource bundle.
+ */
+ private static final Map resourceBundleCache = new HashMap();
+
+ /**
+ * The `empty' locale is created once in order to optimize
+ * tryBundle().
+ */
+ private static final Locale emptyLocale = new Locale("");
+
+ /**
+ * The constructor. It does nothing special.
*/
public ResourceBundle()
{
}
/**
- * Get a String from this resource bundle. Since most localized
- * Objects are Strings, this method provides a convenient way to get
- * them without casting.
- * @param key the name of the resource.
- * @exception MissingResourceException
- * if that particular object could not be found in this bundle nor
- * the parent bundle.
+ * Get a String from this resource bundle. Since most localized Objects
+ * are Strings, this method provides a convenient way to get them without
+ * casting.
+ *
+ * @param key the name of the resource
+ * @throws MissingResourceException if the resource can't be found
+ * @throws NullPointerException if key is null
+ * @throws ClassCastException if resource is not a string
*/
- public final String getString(String key) throws MissingResourceException
+ public final String getString(String key)
{
return (String) getObject(key);
}
/**
- * Get an array of Strings from this resource bundle. This method
+ * Get an array of Strings from this resource bundle. This method
* provides a convenient way to get it without casting.
- * @param key the name of the resource.
- * @exception MissingResourceException
- * if that particular object could not be found in this bundle nor
- * the parent bundle.
+ *
+ * @param key the name of the resource
+ * @throws MissingResourceException if the resource can't be found
+ * @throws NullPointerException if key is null
+ * @throws ClassCastException if resource is not a string
*/
public final String[] getStringArray(String key)
- throws MissingResourceException
{
return (String[]) getObject(key);
}
/**
- * Get an object from this resource bundle.
- * @param key the name of the resource.
- * @exception MissingResourceException
- * if that particular object could not be found in this bundle nor
- * the parent bundle.
+ * Get an object from this resource bundle. This will call
+ * <code>handleGetObject</code> for this resource and all of its parents,
+ * until it finds a non-null resource.
+ *
+ * @param key the name of the resource
+ * @throws MissingResourceException if the resource can't be found
+ * @throws NullPointerException if key is null
*/
- public final Object getObject(String key) throws MissingResourceException
+ public final Object getObject(String key)
{
for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)
- {
- try
- {
- Object o = bundle.handleGetObject(key);
- if (o != null)
- return o;
- }
- catch (MissingResourceException ex)
- {
- }
- }
- throw new MissingResourceException
- ("Key not found", getClass().getName(), key);
+ try
+ {
+ Object o = bundle.handleGetObject(key);
+ if (o != null)
+ return o;
+ }
+ catch (MissingResourceException ex)
+ {
+ }
+ throw new MissingResourceException("Key not found",
+ getClass().getName(), key);
}
/**
- * Get the appropriate ResourceBundle for the default locale.
- * @param baseName the name of the ResourceBundle. This should be
- * a name of a Class or a properties-File. See the class
- * description for details.
- * @return the desired resource bundle
- * @exception MissingResourceException
- * if the resource bundle couldn't be found.
+ * Return the actual locale of this bundle. You can use it after calling
+ * getBundle, to know if the bundle for the desired locale was loaded or
+ * if the fall back was used.
+ *
+ * @return the bundle's locale
*/
- public static final ResourceBundle getBundle(String baseName)
- throws MissingResourceException
+ public Locale getLocale()
{
- return getBundle(baseName, Locale.getDefault(),
- security.getCallingClassLoader());
+ return locale;
}
/**
- * Get the appropriate ResourceBundle for the given locale.
- * @param baseName the name of the ResourceBundle. This should be
- * a name of a Class or a properties-File. See the class
- * description for details.
- * @param locale A locale.
- * @return the desired resource bundle
- * @exception MissingResourceException
- * if the resource bundle couldn't be found.
+ * Set the parent of this bundle. The parent is consulted when you call
+ * getObject and there is no such resource in the current bundle.
+ *
+ * @param parent the parent of this bundle
*/
- public static final ResourceBundle getBundle(String baseName,
- Locale locale)
- throws MissingResourceException
+ protected void setParent(ResourceBundle parent)
{
- return getBundle(baseName, locale, security.getCallingClassLoader());
+ // Shall we ignore the old parent?
+ this.parent = parent;
}
/**
- * The resource bundle cache. This is a two-level hash map: The key
- * is the class loader, the value is a new HashMap. The key of this
- * second hash map is the localized name, the value is a soft
- * references to the resource bundle. */
- private static Map resourceBundleCache = new HashMap();
-
- /**
- * The `empty' locale is created once in order to optimize
- * tryBundle().
- */
- private static final Locale emptyLocale = new Locale ("", "");
-
- /**
- * Tries to load a class or a property file with the specified name.
- * @param localizedName the name.
- * @param locale the locale, that must be used exactly.
- * @param classloader the classloader.
- * @param bundle the back up (parent) bundle
- * @return the resource bundle if that could be loaded, otherwise
- * <code>bundle</code>.
+ * Get the appropriate ResourceBundle for the default locale. This is like
+ * calling <code>getBundle(baseName, Locale.getDefault(),
+ * getClass().getClassLoader()</code>, except that any security check of
+ * getClassLoader won't fail.
+ *
+ * @param baseName the name of the ResourceBundle
+ * @return the desired resource bundle
+ * @throws MissingResourceException if the resource bundle can't be found
+ * @throws NullPointerException if baseName is null
*/
- private static final ResourceBundle tryBundle(String localizedName,
- Locale locale,
- ClassLoader classloader,
- ResourceBundle bundle,
- HashMap cache)
+ public static final ResourceBundle getBundle(String baseName)
{
- {
- // First look into the cache.
- // XXX We should remove cleared references from the cache.
- Reference ref = (Reference) cache.get(localizedName);
- if (ref != null)
- {
- ResourceBundle rb = (ResourceBundle) ref.get();
- if (rb != null)
- // rb should already have the right parent, except if
- // something very strange happened.
- return rb;
- }
- }
-
- // foundBundle holds exact matches for the localizedName resource
- // bundle, which may later be cached.
- ResourceBundle foundBundle = null;
-
- try
- {
- java.io.InputStream is;
- final String resourceName =
- localizedName.replace('.', '/') + ".properties";
- if (classloader == null)
- is = ClassLoader.getSystemResourceAsStream (resourceName);
- else
- is = classloader.getResourceAsStream (resourceName);
- if (is != null)
- {
- foundBundle = new PropertyResourceBundle(is);
- foundBundle.parent = bundle;
- foundBundle.locale = locale;
- }
- }
- catch (java.io.IOException ex)
- {
- }
-
- try
- {
- Class rbClass;
- if (classloader == null)
- rbClass = Class.forName(localizedName);
- else
- rbClass = classloader.loadClass(localizedName);
- foundBundle = (ResourceBundle) rbClass.newInstance();
- foundBundle.parent = bundle;
- foundBundle.locale = locale;
- }
- catch (ClassNotFoundException ex)
- {
- }
- catch (IllegalAccessException ex)
- {
- }
- catch (InstantiationException ex)
- {
- // ignore them all
- // XXX should we also ignore ClassCastException?
- }
-
- if (foundBundle != null)
- cache.put(localizedName, new SoftReference(foundBundle));
-
- return foundBundle != null ? foundBundle : bundle;
+ return getBundle(baseName, Locale.getDefault(),
+ security.getCallingClassLoader());
}
/**
- * Tries to load a the bundle for a given locale, also loads the backup
- * locales with the same language.
+ * Get the appropriate ResourceBundle for the given locale. This is like
+ * calling <code>getBundle(baseName, locale,
+ * getClass().getClassLoader()</code>, except that any security check of
+ * getClassLoader won't fail.
*
- * @param name the name.
- * @param locale the locale, that must be used exactly.
- * @param classloader the classloader.
- * @param bundle the back up (parent) bundle
- * @return the resource bundle if that could be loaded, otherwise
- * <code>bundle</code>.
+ * @param baseName the name of the ResourceBundle
+ * @param locale A locale
+ * @return the desired resource bundle
+ * @throws MissingResourceException if the resource bundle can't be found
+ * @throws NullPointerException if baseName or locale is null
*/
- private static final ResourceBundle tryLocalBundle(String baseName,
- Locale locale,
- ClassLoader classloader,
- ResourceBundle bundle,
- HashMap cache)
+ public static final ResourceBundle getBundle(String baseName,
+ Locale locale)
{
- final String language = locale.getLanguage();
-
- if (language.length() > 0)
- {
- final String country = locale.getCountry();
- String name = baseName + "_" + language;
-
- if (country.length() != 0)
- {
- bundle = tryBundle(name,
- new Locale(language, ""),
- classloader, bundle, cache);
-
- name += "_" + country;
-
- final String variant = locale.getVariant();
-
- if (variant.length() != 0)
- {
- bundle = tryBundle(name,
- new Locale(language,
- country),
- classloader, bundle, cache);
-
- name += "_" + variant;
- }
- }
- bundle = tryBundle(name, locale, classloader, bundle, cache);
- }
- return bundle;
+ return getBundle(baseName, locale, security.getCallingClassLoader());
}
/**
- * Get the appropriate ResourceBundle for the given locale.
- * @param baseName the name of the ResourceBundle. This should be
- * a name of a Class or a properties file. See the class
- * description for details.
- * @param locale A locale.
- * @param classloader a ClassLoader.
+ * Get the appropriate ResourceBundle for the given locale. The following
+ * strategy is used:
+ *
+ * <p>A sequence of candidate bundle names are generated, and tested in
+ * this order, where the suffix 1 means the string from the specified
+ * locale, and the suffix 2 means the string from the default locale:<ul>
+ * <li>baseName + "_" + language1 + "_" + country1 + "_" + variant1</li>
+ * <li>baseName + "_" + language1 + "_" + country1</li>
+ * <li>baseName + "_" + language1</li>
+ * <li>baseName + "_" + language2 + "_" + country2 + "_" + variant2</li>
+ * <li>baseName + "_" + language2 + "_" + country2</li>
+ * <li>baseName + "_" + language2<li>
+ * <li>baseName</li>
+ * </ul>
+ *
+ * <p>In the sequence, entries with an empty string are ignored. Next,
+ * <code>getBundle</code> tries to instantiate the resource bundle:<ul>
+ * <li>First, an attempt is made to load a class in the specified classloader
+ * which is a subclass of ResourceBundle, and which has a public constructor
+ * with no arguments, via reflection.</li>
+ * <li>Next, a search is made for a property resource file, by replacing
+ * '.' with '/' and appending ".properties", and using
+ * ClassLoader.getResource(). If a file is found, then a
+ * PropertyResourceBundle is created from the file's contents.</li>
+ * </ul>
+ * If no resource bundle was found, a MissingResourceException is thrown.
+ *
+ * <p>Next, the parent chain is implemented. The remaining candidate names
+ * in the above sequence are tested in a similar manner, and if any results
+ * in a resource bundle, it is assigned as the parent of the first bundle
+ * using the <code>setParent</code> method (unless the first bundle already
+ * has a parent).
+ *
+ * <p>For example, suppose the following class and property files are
+ * provided: MyResources.class, MyResources_fr_CH.properties,
+ * MyResources_fr_CH.class, MyResources_fr.properties,
+ * MyResources_en.properties, and MyResources_es_ES.class. The contents of
+ * all files are valid (that is, public non-abstract subclasses of
+ * ResourceBundle with public nullary constructors for the ".class" files,
+ * syntactically correct ".properties" files). The default locale is
+ * Locale("en", "UK").
+ *
+ * <p>Calling getBundle with the shown locale argument values instantiates
+ * resource bundles from the following sources:<ul>
+ * <li>Locale("fr", "CH"): result MyResources_fr_CH.class, parent
+ * MyResources_fr.properties, parent MyResources.class</li>
+ * <li>Locale("fr", "FR"): result MyResources_fr.properties, parent
+ * MyResources.class</li>
+ * <li>Locale("de", "DE"): result MyResources_en.properties, parent
+ * MyResources.class</li>
+ * <li>Locale("en", "US"): result MyResources_en.properties, parent
+ * MyResources.class</li>
+ * <li>Locale("es", "ES"): result MyResources_es_ES.class, parent
+ * MyResources.class</li>
+ * </ul>
+ * The file MyResources_fr_CH.properties is never used because it is hidden
+ * by MyResources_fr_CH.class.
+ *
+ * @param baseName the name of the ResourceBundle
+ * @param locale A locale
+ * @param classloader a ClassLoader
* @return the desired resource bundle
- * @exception MissingResourceException
- * if the resource bundle couldn't be found.
+ * @throws MissingResourceException if the resource bundle can't be found
+ * @throws NullPointerException if any argument is null
+ * @since 1.2
*/
// This method is synchronized so that the cache is properly
// handled.
- public static final synchronized ResourceBundle getBundle(String baseName,
- Locale locale,
- ClassLoader classLoader)
- throws MissingResourceException
+ public static final synchronized ResourceBundle getBundle
+ (String baseName, Locale locale, ClassLoader classLoader)
{
// This implementation searches the bundle in the reverse direction
// and builds the parent chain on the fly.
-
HashMap cache = (HashMap) resourceBundleCache.get(classLoader);
+ StringBuffer sb = new StringBuffer(60);
+ sb.append(baseName).append('_').append(locale);
+ String name = sb.toString();
+
if (cache == null)
{
- cache = new HashMap();
- resourceBundleCache.put(classLoader, cache);
+ cache = new HashMap();
+ resourceBundleCache.put(classLoader, cache);
}
else
{
- // Fast path: If baseName + "_" + locale is in cache use it.
- String name = baseName + "_" + locale.toString();
- Reference ref = (Reference) cache.get(name);
- if (ref != null)
- {
- ResourceBundle rb = (ResourceBundle) ref.get();
- if (rb != null)
- // rb should already have the right parent, except if
- // something very strange happened.
- return rb;
- }
+ Reference ref = (Reference) cache.get(name);
+ if (ref != null)
+ {
+ ResourceBundle rb = (ResourceBundle) ref.get();
+ if (rb != null)
+ // rb should already have the right parent, except if
+ // something very strange happened.
+ return rb;
+ }
}
ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
- classLoader, null, cache);
+ classLoader, null, cache);
if (baseBundle == null)
// JDK says, that if one provides a bundle base_en_UK, one
// must also provide the bundles base_en and base.
// This implies that if there is no bundle for base, there
// is no bundle at all.
- throw new MissingResourceException("Bundle " + baseName + " not found", baseName, "");
+ throw new MissingResourceException("Bundle " + baseName + " not found",
+ baseName, "");
// Now use the default locale.
ResourceBundle bundle = tryLocalBundle(baseName, locale,
- classLoader, baseBundle, cache);
+ classLoader, baseBundle, cache);
if (bundle == baseBundle && !locale.equals(Locale.getDefault()))
- {
- bundle = tryLocalBundle(baseName, Locale.getDefault(),
- classLoader, baseBundle, cache);
- }
+ bundle = tryLocalBundle(baseName, Locale.getDefault(),
+ classLoader, baseBundle, cache);
+
+ // Check whether baseName_locale has been loaded; if not, map the
+ // "baseName" bundle to "baseName_locale" to avoid retrying to load
+ // baseName_locale.
+ Reference ref = (Reference) cache.get(name);
+ if (ref == null)
+ cache.put(name, new SoftReference(bundle));
+
return bundle;
}
/**
- * Return the actual locale of this bundle. You can use it after
- * calling getBundle, to know if the bundle for the desired locale
- * was loaded or if the fall back was used.
+ * Override this method to provide the resource for a keys. This gets
+ * called by <code>getObject</code>. If you don't have a resource
+ * for the given key, you should return null instead throwing a
+ * MissingResourceException. You don't have to ask the parent, getObject()
+ * already does this; nor should you throw a MissingResourceException.
+ *
+ * @param key the key of the resource
+ * @return the resource for the key, or null if not in bundle
+ * @throws NullPointerException if key is null
*/
- public Locale getLocale()
- {
- return locale;
- }
+ protected abstract Object handleGetObject(String key);
/**
- * Set the parent of this bundle. This is consulted when you call
- * getObject and there is no such resource in the current bundle.
- * @param parent the parent of this bundle.
+ * This method should return all keys for which a resource exists; you
+ * should include the enumeration of any parent's keys, after filtering out
+ * duplicates.
+ *
+ * @return an enumeration of the keys
*/
- protected void setParent(ResourceBundle parent)
- {
- // Shall we ignore the old parent?
- this.parent = parent;
- }
+ public abstract Enumeration getKeys();
/**
- * Override this method to provide the resource for a keys. This gets
- * called by <code>getObject</code>. If you don't have a resource
- * for the given key, you should return null instead throwing a
- * MissingResourceException. You don't have to ask the parent,
- * getObject() already does this.
+ * Tries to load a class or a property file with the specified name.
*
- * @param key The key of the resource.
- * @return The resource for the key, or null if not in bundle.
- * @exception MissingResourceException
- * you shouldn't throw this.
+ * @param localizedName the name
+ * @param locale the locale, that must be used exactly
+ * @param classloader the classloader
+ * @param bundle the backup (parent) bundle
+ * @return the resource bundle if it was loaded, otherwise the backup
*/
- protected abstract Object handleGetObject(String key)
- throws MissingResourceException;
+ private static final ResourceBundle tryBundle(String localizedName,
+ Locale locale,
+ ClassLoader classloader,
+ ResourceBundle bundle,
+ HashMap cache)
+ {
+ // First look into the cache.
+ // XXX We should remove cleared references from the cache.
+ Reference ref = (Reference) cache.get(localizedName);
+ if (ref != null)
+ {
+ ResourceBundle rb = (ResourceBundle) ref.get();
+ if (rb != null)
+ // rb should already have the right parent, except if
+ // something very strange happened.
+ return rb;
+ }
+
+ // foundBundle holds exact matches for the localizedName resource
+ // bundle, which may later be cached.
+ ResourceBundle foundBundle = null;
+ try
+ {
+ Class rbClass;
+ if (classloader == null)
+ rbClass = Class.forName(localizedName);
+ else
+ rbClass = classloader.loadClass(localizedName);
+ foundBundle = (ResourceBundle) rbClass.newInstance();
+ foundBundle.parent = bundle;
+ foundBundle.locale = locale;
+ }
+ catch (Exception ex)
+ {
+ // ignore them all
+ }
+ if (foundBundle == null)
+ try
+ {
+ InputStream is;
+ final String resourceName
+ = localizedName.replace('.', '/') + ".properties";
+ if (classloader == null)
+ is = ClassLoader.getSystemResourceAsStream(resourceName);
+ else
+ is = classloader.getResourceAsStream(resourceName);
+ if (is != null)
+ {
+ foundBundle = new PropertyResourceBundle(is);
+ foundBundle.parent = bundle;
+ foundBundle.locale = locale;
+ }
+ }
+ catch (IOException ex)
+ {
+ }
+
+ if (foundBundle != null)
+ cache.put(localizedName, new SoftReference(foundBundle));
+
+ return foundBundle != null ? foundBundle : bundle;
+ }
/**
- * This method should return all keys for which a resource exists.
- * @return An enumeration of the keys.
+ * Tries to load a the bundle for a given locale, also loads the backup
+ * locales with the same language.
+ *
+ * @param name the name
+ * @param locale the locale, that must be used exactly
+ * @param classloader the classloader
+ * @param bundle the backup (parent) bundle
+ * @return the resource bundle if it was loaded, otherwise the backup
*/
- public abstract Enumeration getKeys();
-}
+ private static final ResourceBundle tryLocalBundle(String baseName,
+ Locale locale,
+ ClassLoader classloader,
+ ResourceBundle bundle,
+ HashMap cache)
+ {
+ final String language = locale.getLanguage();
+ StringBuffer sb = new StringBuffer(60);
+
+ if (language.length() > 0)
+ {
+ final String country = locale.getCountry();
+ sb.append(baseName).append('_').append(language);
+ String name = sb.toString();
+
+ if (country.length() != 0)
+ {
+ bundle = tryBundle(name, new Locale(language),
+ classloader, bundle, cache);
+ sb.append('_').append(country);
+ name = sb.toString();
+
+ final String variant = locale.getVariant();
+
+ if (variant.length() != 0)
+ {
+ bundle = tryBundle(name, new Locale(language, country),
+ classloader, bundle, cache);
+ sb.append('_').append(variant);
+ name = sb.toString();
+ }
+ }
+ bundle = tryBundle(name, locale, classloader, bundle, cache);
+ }
+ return bundle;
+ }
+} // class ResourceBundle