1 | /* ResourceBundle -- aids in loading resource bundles
|
---|
2 | Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
|
---|
3 |
|
---|
4 | This file is part of GNU Classpath.
|
---|
5 |
|
---|
6 | GNU Classpath is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2, or (at your option)
|
---|
9 | any later version.
|
---|
10 |
|
---|
11 | GNU Classpath is distributed in the hope that it will be useful, but
|
---|
12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
14 | General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with GNU Classpath; see the file COPYING. If not, write to the
|
---|
18 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
---|
19 | 02111-1307 USA.
|
---|
20 |
|
---|
21 | Linking this library statically or dynamically with other modules is
|
---|
22 | making a combined work based on this library. Thus, the terms and
|
---|
23 | conditions of the GNU General Public License cover the whole
|
---|
24 | combination.
|
---|
25 |
|
---|
26 | As a special exception, the copyright holders of this library give you
|
---|
27 | permission to link this library with independent modules to produce an
|
---|
28 | executable, regardless of the license terms of these independent
|
---|
29 | modules, and to copy and distribute the resulting executable under
|
---|
30 | terms of your choice, provided that you also meet, for each linked
|
---|
31 | independent module, the terms and conditions of the license of that
|
---|
32 | module. An independent module is a module which is not derived from
|
---|
33 | or based on this library. If you modify this library, you may extend
|
---|
34 | this exception to your version of the library, but you are not
|
---|
35 | obligated to do so. If you do not wish to do so, delete this
|
---|
36 | exception statement from your version. */
|
---|
37 |
|
---|
38 |
|
---|
39 | package java.util;
|
---|
40 |
|
---|
41 | import java.lang.ref.Reference;
|
---|
42 | import java.lang.ref.SoftReference;
|
---|
43 | import java.io.InputStream;
|
---|
44 | import java.io.IOException;
|
---|
45 | import gnu.classpath.Configuration;
|
---|
46 |
|
---|
47 | /**
|
---|
48 | * A resource bundle contains locale-specific data. If you need localized
|
---|
49 | * data, you can load a resource bundle that matches the locale with
|
---|
50 | * <code>getBundle</code>. Now you can get your object by calling
|
---|
51 | * <code>getObject</code> or <code>getString</code> on that bundle.
|
---|
52 | *
|
---|
53 | * <p>When a bundle is demanded for a specific locale, the ResourceBundle
|
---|
54 | * is searched in following order (<i>def. language<i> stands for the
|
---|
55 | * two letter ISO language code of the default locale (see
|
---|
56 | * <code>Locale.getDefault()</code>).
|
---|
57 | *
|
---|
58 | <pre>baseName_<i>language code</i>_<i>country code</i>_<i>variant</i>
|
---|
59 | baseName_<i>language code</i>_<i>country code</i>
|
---|
60 | baseName_<i>language code</i>
|
---|
61 | baseName_<i>def. language</i>_<i>def. country</i>_<i>def. variant</i>
|
---|
62 | baseName_<i>def. language</i>_<i>def. country</i>
|
---|
63 | baseName_<i>def. language</i>
|
---|
64 | baseName</pre>
|
---|
65 | *
|
---|
66 | * <p>A bundle is backed up by less specific bundles (omitting variant, country
|
---|
67 | * or language). But it is not backed up by the default language locale.
|
---|
68 | *
|
---|
69 | * <p>If you provide a bundle for a given locale, say
|
---|
70 | * <code>Bundle_en_UK_POSIX</code>, you must also provide a bundle for
|
---|
71 | * all sub locales, ie. <code>Bundle_en_UK</code>, <code>Bundle_en</code>, and
|
---|
72 | * <code>Bundle</code>.
|
---|
73 | *
|
---|
74 | * <p>When a bundle is searched, we look first for a class with the given
|
---|
75 | * name, then for a file with <code>.properties</code> extension in the
|
---|
76 | * classpath. The name must be a fully qualified classname (with dots as
|
---|
77 | * path separators).
|
---|
78 | *
|
---|
79 | * <p>(Note: This implementation always backs up the class with a properties
|
---|
80 | * file if that is existing, but you shouldn't rely on this, if you want to
|
---|
81 | * be compatible to the standard JDK.)
|
---|
82 | *
|
---|
83 | * @author Jochen Hoenicke
|
---|
84 | * @author Eric Blake (ebb9@email.byu.edu)
|
---|
85 | * @see Locale
|
---|
86 | * @see ListResourceBundle
|
---|
87 | * @see PropertyResourceBundle
|
---|
88 | * @since 1.1
|
---|
89 | * @status updated to 1.4
|
---|
90 | */
|
---|
91 | public abstract class ResourceBundle
|
---|
92 | {
|
---|
93 | /**
|
---|
94 | * The parent bundle. This is consulted when you call getObject and there
|
---|
95 | * is no such resource in the current bundle. This field may be null.
|
---|
96 | */
|
---|
97 | protected ResourceBundle parent;
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * The locale of this resource bundle. You can read this with
|
---|
101 | * <code>getLocale</code> and it is automatically set in
|
---|
102 | * <code>getBundle</code>.
|
---|
103 | */
|
---|
104 | private Locale locale;
|
---|
105 |
|
---|
106 | private static native ClassLoader getCallingClassLoader();
|
---|
107 |
|
---|
108 | /**
|
---|
109 | * The resource bundle cache. This is a two-level hash map: The key
|
---|
110 | * is the class loader, the value is a new HashMap. The key of this
|
---|
111 | * second hash map is the localized name, the value is a soft
|
---|
112 | * references to the resource bundle.
|
---|
113 | */
|
---|
114 | private static Map resourceBundleCache;
|
---|
115 |
|
---|
116 | /**
|
---|
117 | * The last default Locale we saw. If this ever changes then we have to
|
---|
118 | * reset our caches.
|
---|
119 | */
|
---|
120 | private static Locale lastDefaultLocale;
|
---|
121 |
|
---|
122 | /**
|
---|
123 | * The `empty' locale is created once in order to optimize
|
---|
124 | * tryBundle().
|
---|
125 | */
|
---|
126 | private static final Locale emptyLocale = new Locale("");
|
---|
127 |
|
---|
128 | /**
|
---|
129 | * The constructor. It does nothing special.
|
---|
130 | */
|
---|
131 | public ResourceBundle()
|
---|
132 | {
|
---|
133 | }
|
---|
134 |
|
---|
135 | /**
|
---|
136 | * Get a String from this resource bundle. Since most localized Objects
|
---|
137 | * are Strings, this method provides a convenient way to get them without
|
---|
138 | * casting.
|
---|
139 | *
|
---|
140 | * @param key the name of the resource
|
---|
141 | * @throws MissingResourceException if the resource can't be found
|
---|
142 | * @throws NullPointerException if key is null
|
---|
143 | * @throws ClassCastException if resource is not a string
|
---|
144 | */
|
---|
145 | public final String getString(String key)
|
---|
146 | {
|
---|
147 | return (String) getObject(key);
|
---|
148 | }
|
---|
149 |
|
---|
150 | /**
|
---|
151 | * Get an array of Strings from this resource bundle. This method
|
---|
152 | * provides a convenient way to get it without casting.
|
---|
153 | *
|
---|
154 | * @param key the name of the resource
|
---|
155 | * @throws MissingResourceException if the resource can't be found
|
---|
156 | * @throws NullPointerException if key is null
|
---|
157 | * @throws ClassCastException if resource is not a string
|
---|
158 | */
|
---|
159 | public final String[] getStringArray(String key)
|
---|
160 | {
|
---|
161 | return (String[]) getObject(key);
|
---|
162 | }
|
---|
163 |
|
---|
164 | /**
|
---|
165 | * Get an object from this resource bundle. This will call
|
---|
166 | * <code>handleGetObject</code> for this resource and all of its parents,
|
---|
167 | * until it finds a non-null resource.
|
---|
168 | *
|
---|
169 | * @param key the name of the resource
|
---|
170 | * @throws MissingResourceException if the resource can't be found
|
---|
171 | * @throws NullPointerException if key is null
|
---|
172 | */
|
---|
173 | public final Object getObject(String key)
|
---|
174 | {
|
---|
175 | for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)
|
---|
176 | try
|
---|
177 | {
|
---|
178 | Object o = bundle.handleGetObject(key);
|
---|
179 | if (o != null)
|
---|
180 | return o;
|
---|
181 | }
|
---|
182 | catch (MissingResourceException ex)
|
---|
183 | {
|
---|
184 | }
|
---|
185 | throw new MissingResourceException("Key not found",
|
---|
186 | getClass().getName(), key);
|
---|
187 | }
|
---|
188 |
|
---|
189 | /**
|
---|
190 | * Return the actual locale of this bundle. You can use it after calling
|
---|
191 | * getBundle, to know if the bundle for the desired locale was loaded or
|
---|
192 | * if the fall back was used.
|
---|
193 | *
|
---|
194 | * @return the bundle's locale
|
---|
195 | */
|
---|
196 | public Locale getLocale()
|
---|
197 | {
|
---|
198 | return locale;
|
---|
199 | }
|
---|
200 |
|
---|
201 | /**
|
---|
202 | * Set the parent of this bundle. The parent is consulted when you call
|
---|
203 | * getObject and there is no such resource in the current bundle.
|
---|
204 | *
|
---|
205 | * @param parent the parent of this bundle
|
---|
206 | */
|
---|
207 | protected void setParent(ResourceBundle parent)
|
---|
208 | {
|
---|
209 | this.parent = parent;
|
---|
210 | }
|
---|
211 |
|
---|
212 | /**
|
---|
213 | * Get the appropriate ResourceBundle for the default locale. This is like
|
---|
214 | * calling <code>getBundle(baseName, Locale.getDefault(),
|
---|
215 | * getClass().getClassLoader()</code>, except that any security check of
|
---|
216 | * getClassLoader won't fail.
|
---|
217 | *
|
---|
218 | * @param baseName the name of the ResourceBundle
|
---|
219 | * @return the desired resource bundle
|
---|
220 | * @throws MissingResourceException if the resource bundle can't be found
|
---|
221 | * @throws NullPointerException if baseName is null
|
---|
222 | */
|
---|
223 | public static final ResourceBundle getBundle(String baseName)
|
---|
224 | {
|
---|
225 | return getBundle(baseName, Locale.getDefault(),
|
---|
226 | getCallingClassLoader());
|
---|
227 | }
|
---|
228 |
|
---|
229 | /**
|
---|
230 | * Get the appropriate ResourceBundle for the given locale. This is like
|
---|
231 | * calling <code>getBundle(baseName, locale,
|
---|
232 | * getClass().getClassLoader()</code>, except that any security check of
|
---|
233 | * getClassLoader won't fail.
|
---|
234 | *
|
---|
235 | * @param baseName the name of the ResourceBundle
|
---|
236 | * @param locale A locale
|
---|
237 | * @return the desired resource bundle
|
---|
238 | * @throws MissingResourceException if the resource bundle can't be found
|
---|
239 | * @throws NullPointerException if baseName or locale is null
|
---|
240 | */
|
---|
241 | public static final ResourceBundle getBundle(String baseName,
|
---|
242 | Locale locale)
|
---|
243 | {
|
---|
244 | return getBundle(baseName, locale, getCallingClassLoader());
|
---|
245 | }
|
---|
246 |
|
---|
247 | /**
|
---|
248 | * Get the appropriate ResourceBundle for the given locale. The following
|
---|
249 | * strategy is used:
|
---|
250 | *
|
---|
251 | * <p>A sequence of candidate bundle names are generated, and tested in
|
---|
252 | * this order, where the suffix 1 means the string from the specified
|
---|
253 | * locale, and the suffix 2 means the string from the default locale:<ul>
|
---|
254 | * <li>baseName + "_" + language1 + "_" + country1 + "_" + variant1</li>
|
---|
255 | * <li>baseName + "_" + language1 + "_" + country1</li>
|
---|
256 | * <li>baseName + "_" + language1</li>
|
---|
257 | * <li>baseName + "_" + language2 + "_" + country2 + "_" + variant2</li>
|
---|
258 | * <li>baseName + "_" + language2 + "_" + country2</li>
|
---|
259 | * <li>baseName + "_" + language2<li>
|
---|
260 | * <li>baseName</li>
|
---|
261 | * </ul>
|
---|
262 | *
|
---|
263 | * <p>In the sequence, entries with an empty string are ignored. Next,
|
---|
264 | * <code>getBundle</code> tries to instantiate the resource bundle:<ul>
|
---|
265 | * <li>First, an attempt is made to load a class in the specified classloader
|
---|
266 | * which is a subclass of ResourceBundle, and which has a public constructor
|
---|
267 | * with no arguments, via reflection.</li>
|
---|
268 | * <li>Next, a search is made for a property resource file, by replacing
|
---|
269 | * '.' with '/' and appending ".properties", and using
|
---|
270 | * ClassLoader.getResource(). If a file is found, then a
|
---|
271 | * PropertyResourceBundle is created from the file's contents.</li>
|
---|
272 | * </ul>
|
---|
273 | * If no resource bundle was found, a MissingResourceException is thrown.
|
---|
274 | *
|
---|
275 | * <p>Next, the parent chain is implemented. The remaining candidate names
|
---|
276 | * in the above sequence are tested in a similar manner, and if any results
|
---|
277 | * in a resource bundle, it is assigned as the parent of the first bundle
|
---|
278 | * using the <code>setParent</code> method (unless the first bundle already
|
---|
279 | * has a parent).
|
---|
280 | *
|
---|
281 | * <p>For example, suppose the following class and property files are
|
---|
282 | * provided: MyResources.class, MyResources_fr_CH.properties,
|
---|
283 | * MyResources_fr_CH.class, MyResources_fr.properties,
|
---|
284 | * MyResources_en.properties, and MyResources_es_ES.class. The contents of
|
---|
285 | * all files are valid (that is, public non-abstract subclasses of
|
---|
286 | * ResourceBundle with public nullary constructors for the ".class" files,
|
---|
287 | * syntactically correct ".properties" files). The default locale is
|
---|
288 | * Locale("en", "UK").
|
---|
289 | *
|
---|
290 | * <p>Calling getBundle with the shown locale argument values instantiates
|
---|
291 | * resource bundles from the following sources:<ul>
|
---|
292 | * <li>Locale("fr", "CH"): result MyResources_fr_CH.class, parent
|
---|
293 | * MyResources_fr.properties, parent MyResources.class</li>
|
---|
294 | * <li>Locale("fr", "FR"): result MyResources_fr.properties, parent
|
---|
295 | * MyResources.class</li>
|
---|
296 | * <li>Locale("de", "DE"): result MyResources_en.properties, parent
|
---|
297 | * MyResources.class</li>
|
---|
298 | * <li>Locale("en", "US"): result MyResources_en.properties, parent
|
---|
299 | * MyResources.class</li>
|
---|
300 | * <li>Locale("es", "ES"): result MyResources_es_ES.class, parent
|
---|
301 | * MyResources.class</li>
|
---|
302 | * </ul>
|
---|
303 | * The file MyResources_fr_CH.properties is never used because it is hidden
|
---|
304 | * by MyResources_fr_CH.class.
|
---|
305 | *
|
---|
306 | * @param baseName the name of the ResourceBundle
|
---|
307 | * @param locale A locale
|
---|
308 | * @param classloader a ClassLoader
|
---|
309 | * @return the desired resource bundle
|
---|
310 | * @throws MissingResourceException if the resource bundle can't be found
|
---|
311 | * @throws NullPointerException if any argument is null
|
---|
312 | * @since 1.2
|
---|
313 | */
|
---|
314 | // This method is synchronized so that the cache is properly
|
---|
315 | // handled.
|
---|
316 | public static final synchronized ResourceBundle getBundle
|
---|
317 | (String baseName, Locale locale, ClassLoader classLoader)
|
---|
318 | {
|
---|
319 | // This implementation searches the bundle in the reverse direction
|
---|
320 | // and builds the parent chain on the fly.
|
---|
321 | Locale defaultLocale = Locale.getDefault();
|
---|
322 | if (defaultLocale != lastDefaultLocale)
|
---|
323 | {
|
---|
324 | resourceBundleCache = new HashMap();
|
---|
325 | lastDefaultLocale = defaultLocale;
|
---|
326 | }
|
---|
327 | HashMap cache = (HashMap) resourceBundleCache.get(classLoader);
|
---|
328 | StringBuffer sb = new StringBuffer(60);
|
---|
329 | sb.append(baseName).append('_').append(locale);
|
---|
330 | String name = sb.toString();
|
---|
331 |
|
---|
332 | if (cache == null)
|
---|
333 | {
|
---|
334 | cache = new HashMap();
|
---|
335 | resourceBundleCache.put(classLoader, cache);
|
---|
336 | }
|
---|
337 | else if (cache.containsKey(name))
|
---|
338 | {
|
---|
339 | Reference ref = (Reference) cache.get(name);
|
---|
340 | ResourceBundle result = null;
|
---|
341 | // If REF is null, that means that we added a `null' value to
|
---|
342 | // the hash map. That means we failed to find the bundle
|
---|
343 | // previously, and we cached that fact. The JDK does this, so
|
---|
344 | // it must be ok.
|
---|
345 | if (ref == null)
|
---|
346 | throw new MissingResourceException("Bundle " + baseName
|
---|
347 | + " not found",
|
---|
348 | baseName, "");
|
---|
349 | else
|
---|
350 | {
|
---|
351 | ResourceBundle rb = (ResourceBundle) ref.get();
|
---|
352 | if (rb != null)
|
---|
353 | {
|
---|
354 | // RB should already have the right parent, except if
|
---|
355 | // something very strange happened.
|
---|
356 | return rb;
|
---|
357 | }
|
---|
358 | // If RB is null, then we previously found it but it was
|
---|
359 | // collected. So we try again.
|
---|
360 | }
|
---|
361 | }
|
---|
362 |
|
---|
363 | // It is ok if this returns null. We aren't required to have the
|
---|
364 | // base bundle.
|
---|
365 | ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
|
---|
366 | classLoader, null, cache);
|
---|
367 |
|
---|
368 | // Now use our locale, followed by the default locale. We only
|
---|
369 | // need to try the default locale if our locale is different, and
|
---|
370 | // if our locale failed to yield a result other than the base
|
---|
371 | // bundle.
|
---|
372 | ResourceBundle bundle = tryLocalBundle(baseName, locale,
|
---|
373 | classLoader, baseBundle, cache);
|
---|
374 | if (bundle == baseBundle && !locale.equals(defaultLocale))
|
---|
375 | {
|
---|
376 | bundle = tryLocalBundle(baseName, defaultLocale,
|
---|
377 | classLoader, baseBundle, cache);
|
---|
378 | // We need to record that the argument locale maps to the
|
---|
379 | // bundle we just found. If we didn't find a bundle, record
|
---|
380 | // that instead.
|
---|
381 | if (bundle == null)
|
---|
382 | cache.put(name, null);
|
---|
383 | else
|
---|
384 | cache.put(name, new SoftReference(bundle));
|
---|
385 | }
|
---|
386 |
|
---|
387 | if (bundle == null)
|
---|
388 | throw new MissingResourceException("Bundle " + baseName + " not found",
|
---|
389 | baseName, "");
|
---|
390 |
|
---|
391 | return bundle;
|
---|
392 | }
|
---|
393 |
|
---|
394 | /**
|
---|
395 | * Override this method to provide the resource for a keys. This gets
|
---|
396 | * called by <code>getObject</code>. If you don't have a resource
|
---|
397 | * for the given key, you should return null instead throwing a
|
---|
398 | * MissingResourceException. You don't have to ask the parent, getObject()
|
---|
399 | * already does this; nor should you throw a MissingResourceException.
|
---|
400 | *
|
---|
401 | * @param key the key of the resource
|
---|
402 | * @return the resource for the key, or null if not in bundle
|
---|
403 | * @throws NullPointerException if key is null
|
---|
404 | */
|
---|
405 | protected abstract Object handleGetObject(String key);
|
---|
406 |
|
---|
407 | /**
|
---|
408 | * This method should return all keys for which a resource exists; you
|
---|
409 | * should include the enumeration of any parent's keys, after filtering out
|
---|
410 | * duplicates.
|
---|
411 | *
|
---|
412 | * @return an enumeration of the keys
|
---|
413 | */
|
---|
414 | public abstract Enumeration getKeys();
|
---|
415 |
|
---|
416 | /**
|
---|
417 | * Tries to load a class or a property file with the specified name.
|
---|
418 | *
|
---|
419 | * @param localizedName the name
|
---|
420 | * @param locale the locale, that must be used exactly
|
---|
421 | * @param classloader the classloader
|
---|
422 | * @param bundle the backup (parent) bundle
|
---|
423 | * @return the resource bundle if it was loaded, otherwise the backup
|
---|
424 | */
|
---|
425 | private static final ResourceBundle tryBundle(String localizedName,
|
---|
426 | Locale locale,
|
---|
427 | ClassLoader classloader,
|
---|
428 | ResourceBundle bundle,
|
---|
429 | HashMap cache)
|
---|
430 | {
|
---|
431 | // First look into the cache.
|
---|
432 | if (cache.containsKey(localizedName))
|
---|
433 | {
|
---|
434 | Reference ref = (Reference) cache.get(localizedName);
|
---|
435 | ResourceBundle result = null;
|
---|
436 | // If REF is null, that means that we added a `null' value to
|
---|
437 | // the hash map. That means we failed to find the bundle
|
---|
438 | // previously, and we cached that fact. The JDK does this, so
|
---|
439 | // it must be ok.
|
---|
440 | if (ref == null)
|
---|
441 | return null;
|
---|
442 | else
|
---|
443 | {
|
---|
444 | ResourceBundle rb = (ResourceBundle) ref.get();
|
---|
445 | if (rb != null)
|
---|
446 | {
|
---|
447 | // RB should already have the right parent, except if
|
---|
448 | // something very strange happened.
|
---|
449 | return rb;
|
---|
450 | }
|
---|
451 | // If RB is null, then we previously found it but it was
|
---|
452 | // collected. So we try again.
|
---|
453 | }
|
---|
454 | }
|
---|
455 |
|
---|
456 | // foundBundle holds exact matches for the localizedName resource
|
---|
457 | // bundle, which may later be cached.
|
---|
458 | ResourceBundle foundBundle = null;
|
---|
459 | try
|
---|
460 | {
|
---|
461 | Class rbClass;
|
---|
462 | if (classloader == null)
|
---|
463 | rbClass = Class.forName(localizedName);
|
---|
464 | else
|
---|
465 | rbClass = classloader.loadClass(localizedName);
|
---|
466 | foundBundle = (ResourceBundle) rbClass.newInstance();
|
---|
467 | foundBundle.parent = bundle;
|
---|
468 | foundBundle.locale = locale;
|
---|
469 | }
|
---|
470 | catch (Exception ex)
|
---|
471 | {
|
---|
472 | // ignore them all
|
---|
473 | }
|
---|
474 | if (foundBundle == null)
|
---|
475 | {
|
---|
476 | try
|
---|
477 | {
|
---|
478 | InputStream is;
|
---|
479 | final String resourceName
|
---|
480 | = localizedName.replace('.', '/') + ".properties";
|
---|
481 | if (classloader == null)
|
---|
482 | is = ClassLoader.getSystemResourceAsStream(resourceName);
|
---|
483 | else
|
---|
484 | is = classloader.getResourceAsStream(resourceName);
|
---|
485 | if (is != null)
|
---|
486 | {
|
---|
487 | foundBundle = new PropertyResourceBundle(is);
|
---|
488 | foundBundle.parent = bundle;
|
---|
489 | foundBundle.locale = locale;
|
---|
490 | }
|
---|
491 | }
|
---|
492 | catch (IOException ex)
|
---|
493 | {
|
---|
494 | }
|
---|
495 | }
|
---|
496 |
|
---|
497 | // Put the result into the hash table. If we didn't find anything
|
---|
498 | // here, we record our parent bundle. If we record `null' that means
|
---|
499 | // nothing, not even the base, was found.
|
---|
500 | if (foundBundle == null)
|
---|
501 | foundBundle = bundle;
|
---|
502 | if (foundBundle == null)
|
---|
503 | cache.put(localizedName, null);
|
---|
504 | else
|
---|
505 | cache.put(localizedName, new SoftReference(foundBundle));
|
---|
506 | return foundBundle;
|
---|
507 | }
|
---|
508 |
|
---|
509 | /**
|
---|
510 | * Tries to load a the bundle for a given locale, also loads the backup
|
---|
511 | * locales with the same language.
|
---|
512 | *
|
---|
513 | * @param name the name
|
---|
514 | * @param locale the locale
|
---|
515 | * @param classloader the classloader
|
---|
516 | * @param bundle the backup (parent) bundle
|
---|
517 | * @return the resource bundle if it was loaded, otherwise the backup
|
---|
518 | */
|
---|
519 | private static final ResourceBundle tryLocalBundle(String baseName,
|
---|
520 | Locale locale,
|
---|
521 | ClassLoader classloader,
|
---|
522 | ResourceBundle bundle,
|
---|
523 | HashMap cache)
|
---|
524 | {
|
---|
525 | final String language = locale.getLanguage();
|
---|
526 | final String country = locale.getCountry();
|
---|
527 | final String variant = locale.getVariant();
|
---|
528 |
|
---|
529 | StringBuffer sb = new StringBuffer(60);
|
---|
530 | sb.append(baseName);
|
---|
531 | sb.append('_');
|
---|
532 |
|
---|
533 | if (language.length() > 0)
|
---|
534 | {
|
---|
535 | sb.append(language);
|
---|
536 | bundle = tryBundle(sb.toString(), new Locale(language),
|
---|
537 | classloader, bundle, cache);
|
---|
538 | }
|
---|
539 | // If LANGUAGE was empty, we still need to try the other
|
---|
540 | // components, and the `_' is required.
|
---|
541 | sb.append('_');
|
---|
542 |
|
---|
543 | if (country.length() > 0)
|
---|
544 | {
|
---|
545 | sb.append(country);
|
---|
546 | bundle = tryBundle(sb.toString(), new Locale(language, country),
|
---|
547 | classloader, bundle, cache);
|
---|
548 | }
|
---|
549 | sb.append('_');
|
---|
550 |
|
---|
551 | if (variant.length() > 0)
|
---|
552 | {
|
---|
553 | sb.append(variant);
|
---|
554 | bundle = tryBundle(sb.toString(), locale,
|
---|
555 | classloader, bundle, cache);
|
---|
556 | }
|
---|
557 |
|
---|
558 | return bundle;
|
---|
559 | }
|
---|
560 | }
|
---|