src/share/jaxws_classes/com/sun/xml/internal/dtdparser/MessageCatalog.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 397
b99d7e355d4b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.xml.internal.dtdparser;
aoqi@0 27
aoqi@0 28 import java.io.InputStream;
aoqi@0 29 import java.text.FieldPosition;
aoqi@0 30 import java.text.MessageFormat;
aoqi@0 31 import java.util.Hashtable;
aoqi@0 32 import java.util.Locale;
aoqi@0 33 import java.util.MissingResourceException;
aoqi@0 34 import java.util.ResourceBundle;
aoqi@0 35
aoqi@0 36
aoqi@0 37 /**
aoqi@0 38 * This class provides support for multi-language string lookup, as needed
aoqi@0 39 * to localize messages from applications supporting multiple languages
aoqi@0 40 * at the same time. One class of such applications is network services,
aoqi@0 41 * such as HTTP servers, which talk to clients who may not be from the
aoqi@0 42 * same locale as the server. This class supports a form of negotiation
aoqi@0 43 * for the language used in presenting a message from some package, where
aoqi@0 44 * both user (client) preferences and application (server) support are
aoqi@0 45 * accounted for when choosing locales and formatting messages.
aoqi@0 46 * <p/>
aoqi@0 47 * <P> Each package should have a singleton package-private message catalog
aoqi@0 48 * class. This ensures that the correct class loader will always be used to
aoqi@0 49 * access message resources, and minimizes use of memory: <PRE>
aoqi@0 50 * package <em>some.package</em>;
aoqi@0 51 * <p/>
aoqi@0 52 * // "foo" might be public
aoqi@0 53 * class foo {
aoqi@0 54 * ...
aoqi@0 55 * // package private
aoqi@0 56 * static final Catalog messages = new Catalog ();
aoqi@0 57 * static final class Catalog extends MessageCatalog {
aoqi@0 58 * Catalog () { super (Catalog.class); }
aoqi@0 59 * }
aoqi@0 60 * ...
aoqi@0 61 * }
aoqi@0 62 * </PRE>
aoqi@0 63 * <p/>
aoqi@0 64 * <P> Messages for a known client could be generated using code
aoqi@0 65 * something like this: <PRE>
aoqi@0 66 * String clientLanguages [];
aoqi@0 67 * Locale clientLocale;
aoqi@0 68 * String clientMessage;
aoqi@0 69 * <p/>
aoqi@0 70 * // client languages will probably be provided by client,
aoqi@0 71 * // e.g. by an HTTP/1.1 "Accept-Language" header.
aoqi@0 72 * clientLanguages = new String [] { "en-ca", "fr-ca", "ja", "zh" };
aoqi@0 73 * clientLocale = foo.messages.chooseLocale (clientLanguages);
aoqi@0 74 * clientMessage = foo.messages.getMessage (clientLocale,
aoqi@0 75 * "fileCount",
aoqi@0 76 * new Object [] { new Integer (numberOfFiles) }
aoqi@0 77 * );
aoqi@0 78 * </PRE>
aoqi@0 79 * <p/>
aoqi@0 80 * <P> At this time, this class does not include functionality permitting
aoqi@0 81 * messages to be passed around and localized after-the-fact. The consequence
aoqi@0 82 * of this is that the locale for messages must be passed down through layers
aoqi@0 83 * which have no normal reason to support such passdown, or else the system
aoqi@0 84 * default locale must be used instead of the one the client needs.
aoqi@0 85 * <p/>
aoqi@0 86 * <P> <hr> The following guidelines should be used when constructiong
aoqi@0 87 * multi-language applications: <OL>
aoqi@0 88 * <p/>
aoqi@0 89 * <LI> Always use <a href=#chooseLocale>chooseLocale</a> to select the
aoqi@0 90 * locale you pass to your <code>getMessage</code> call. This lets your
aoqi@0 91 * applications use IETF standard locale names, and avoids needless
aoqi@0 92 * use of system defaults.
aoqi@0 93 * <p/>
aoqi@0 94 * <LI> The localized messages for a given package should always go in
aoqi@0 95 * a separate <em>resources</em> sub-package. There are security
aoqi@0 96 * implications; see below.
aoqi@0 97 * <p/>
aoqi@0 98 * <LI> Make sure that a language name is included in each bundle name,
aoqi@0 99 * so that the developer's locale will not be inadvertently used. That
aoqi@0 100 * is, don't create defaults like <em>resources/Messages.properties</em>
aoqi@0 101 * or <em>resources/Messages.class</em>, since ResourceBundle will choose
aoqi@0 102 * such defaults rather than giving software a chance to choose a more
aoqi@0 103 * appropriate language for its messages. Your message bundles should
aoqi@0 104 * have names like <em>Messages_en.properties</em> (for the "en", or
aoqi@0 105 * English, language) or <em>Messages_ja.class</em> ("ja" indicates the
aoqi@0 106 * Japanese language).
aoqi@0 107 * <p/>
aoqi@0 108 * <LI> Only use property files for messages in languages which can
aoqi@0 109 * be limited to the ISO Latin/1 (8859-1) characters supported by the
aoqi@0 110 * property file format. (This is mostly Western European languages.)
aoqi@0 111 * Otherwise, subclass ResourceBundle to provide your messages; it is
aoqi@0 112 * simplest to subclass <code>java.util.ListResourceBundle</code>.
aoqi@0 113 * <p/>
aoqi@0 114 * <LI> Never use another package's message catalog or resource bundles.
aoqi@0 115 * It should not be possible for a change internal to one package (such
aoqi@0 116 * as eliminating or improving messages) to break another package.
aoqi@0 117 * <p/>
aoqi@0 118 * </OL>
aoqi@0 119 * <p/>
aoqi@0 120 * <P> The "resources" sub-package can be treated separately from the
aoqi@0 121 * package with which it is associated. That main package may be sealed
aoqi@0 122 * and possibly signed, preventing other software from adding classes to
aoqi@0 123 * the package which would be able to access methods and data which are
aoqi@0 124 * not designed to be publicly accessible. On the other hand, resources
aoqi@0 125 * such as localized messages are often provided after initial product
aoqi@0 126 * shipment, without a full release cycle for the product. Such files
aoqi@0 127 * (text and class files) need to be added to some package. Since they
aoqi@0 128 * should not be added to the main package, the "resources" subpackage is
aoqi@0 129 * used without risking the security or integrity of that main package
aoqi@0 130 * as distributed in its JAR file.
aoqi@0 131 *
aoqi@0 132 * @author David Brownell
aoqi@0 133 * @version 1.1, 00/08/05
aoqi@0 134 * @see java.util.Locale
aoqi@0 135 * @see java.util.ListResourceBundle
aoqi@0 136 * @see java.text.MessageFormat
aoqi@0 137 */
aoqi@0 138 // leave this as "abstract" -- each package needs its own subclass,
aoqi@0 139 // else it's not always going to be using the right class loader.
aoqi@0 140 abstract public class MessageCatalog {
aoqi@0 141 private String bundleName;
aoqi@0 142
aoqi@0 143 /**
aoqi@0 144 * Create a message catalog for use by classes in the same package
aoqi@0 145 * as the specified class. This uses <em>Messages</em> resource
aoqi@0 146 * bundles in the <em>resources</em> sub-package of class passed as
aoqi@0 147 * a parameter.
aoqi@0 148 *
aoqi@0 149 * @param packageMember Class whose package has localized messages
aoqi@0 150 */
aoqi@0 151 protected MessageCatalog(Class packageMember) {
aoqi@0 152 this(packageMember, "Messages");
aoqi@0 153 }
aoqi@0 154
aoqi@0 155 /**
aoqi@0 156 * Create a message catalog for use by classes in the same package
aoqi@0 157 * as the specified class. This uses the specified resource
aoqi@0 158 * bundle name in the <em>resources</em> sub-package of class passed
aoqi@0 159 * as a parameter; for example, <em>resources.Messages</em>.
aoqi@0 160 *
aoqi@0 161 * @param packageMember Class whose package has localized messages
aoqi@0 162 * @param bundle Name of a group of resource bundles
aoqi@0 163 */
aoqi@0 164 private MessageCatalog(Class packageMember, String bundle) {
aoqi@0 165 int index;
aoqi@0 166
aoqi@0 167 bundleName = packageMember.getName();
aoqi@0 168 index = bundleName.lastIndexOf('.');
aoqi@0 169 if (index == -1) // "ClassName"
aoqi@0 170 bundleName = "";
aoqi@0 171 else // "some.package.ClassName"
aoqi@0 172 bundleName = bundleName.substring(0, index) + ".";
aoqi@0 173 bundleName = bundleName + "resources." + bundle;
aoqi@0 174 }
aoqi@0 175
aoqi@0 176
aoqi@0 177 /**
aoqi@0 178 * Get a message localized to the specified locale, using the message ID
aoqi@0 179 * and package name if no message is available. The locale is normally
aoqi@0 180 * that of the client of a service, chosen with knowledge that both the
aoqi@0 181 * client and this server support that locale. There are two error
aoqi@0 182 * cases: first, when the specified locale is unsupported or null, the
aoqi@0 183 * default locale is used if possible; second, when no bundle supports
aoqi@0 184 * that locale, the message ID and package name are used.
aoqi@0 185 *
aoqi@0 186 * @param locale The locale of the message to use. If this is null,
aoqi@0 187 * the default locale will be used.
aoqi@0 188 * @param messageId The ID of the message to use.
aoqi@0 189 * @return The message, localized as described above.
aoqi@0 190 */
aoqi@0 191 public String getMessage(Locale locale,
aoqi@0 192 String messageId) {
aoqi@0 193 ResourceBundle bundle;
aoqi@0 194
aoqi@0 195 // cope with unsupported locale...
aoqi@0 196 if (locale == null)
aoqi@0 197 locale = Locale.getDefault();
aoqi@0 198
aoqi@0 199 try {
aoqi@0 200 bundle = ResourceBundle.getBundle(bundleName, locale);
aoqi@0 201 } catch (MissingResourceException e) {
aoqi@0 202 bundle = ResourceBundle.getBundle(bundleName, Locale.ENGLISH);
aoqi@0 203 }
aoqi@0 204 return bundle.getString(messageId);
aoqi@0 205 }
aoqi@0 206
aoqi@0 207
aoqi@0 208 /**
aoqi@0 209 * Format a message localized to the specified locale, using the message
aoqi@0 210 * ID with its package name if none is available. The locale is normally
aoqi@0 211 * the client of a service, chosen with knowledge that both the client
aoqi@0 212 * server support that locale. There are two error cases: first, if the
aoqi@0 213 * specified locale is unsupported or null, the default locale is used if
aoqi@0 214 * possible; second, when no bundle supports that locale, the message ID
aoqi@0 215 * and package name are used.
aoqi@0 216 *
aoqi@0 217 * @param locale The locale of the message to use. If this is null,
aoqi@0 218 * the default locale will be used.
aoqi@0 219 * @param messageId The ID of the message format to use.
aoqi@0 220 * @param parameters Used when formatting the message. Objects in
aoqi@0 221 * this list are turned to strings if they are not Strings, Numbers,
aoqi@0 222 * or Dates (that is, if MessageFormat would treat them as errors).
aoqi@0 223 * @return The message, localized as described above.
aoqi@0 224 * @see java.text.MessageFormat
aoqi@0 225 */
aoqi@0 226 public String getMessage(Locale locale,
aoqi@0 227 String messageId,
aoqi@0 228 Object parameters []) {
aoqi@0 229 if (parameters == null)
aoqi@0 230 return getMessage(locale, messageId);
aoqi@0 231
aoqi@0 232 // since most messages won't be tested (sigh), be friendly to
aoqi@0 233 // the inevitable developer errors of passing random data types
aoqi@0 234 // to the message formatting code.
aoqi@0 235 for (int i = 0; i < parameters.length; i++) {
aoqi@0 236 if (!(parameters[i] instanceof String)
aoqi@0 237 && !(parameters[i] instanceof Number)
aoqi@0 238 && !(parameters[i] instanceof java.util.Date)) {
aoqi@0 239 if (parameters[i] == null)
aoqi@0 240 parameters[i] = "(null)";
aoqi@0 241 else
aoqi@0 242 parameters[i] = parameters[i].toString();
aoqi@0 243 }
aoqi@0 244 }
aoqi@0 245
aoqi@0 246 // similarly, cope with unsupported locale...
aoqi@0 247 if (locale == null)
aoqi@0 248 locale = Locale.getDefault();
aoqi@0 249
aoqi@0 250 // get the appropriately localized MessageFormat object
aoqi@0 251 ResourceBundle bundle;
aoqi@0 252 MessageFormat format;
aoqi@0 253
aoqi@0 254 try {
aoqi@0 255 bundle = ResourceBundle.getBundle(bundleName, locale);
aoqi@0 256 } catch (MissingResourceException e) {
aoqi@0 257 bundle = ResourceBundle.getBundle(bundleName, Locale.ENGLISH);
aoqi@0 258 /*String retval;
aoqi@0 259
aoqi@0 260 retval = packagePrefix (messageId);
aoqi@0 261 for (int i = 0; i < parameters.length; i++) {
aoqi@0 262 retval += ' ';
aoqi@0 263 retval += parameters [i];
aoqi@0 264 }
aoqi@0 265 return retval;*/
aoqi@0 266 }
aoqi@0 267 format = new MessageFormat(bundle.getString(messageId));
aoqi@0 268 format.setLocale(locale);
aoqi@0 269
aoqi@0 270 // return the formatted message
aoqi@0 271 StringBuffer result = new StringBuffer();
aoqi@0 272
aoqi@0 273 result = format.format(parameters, result, new FieldPosition(0));
aoqi@0 274 return result.toString();
aoqi@0 275 }
aoqi@0 276
aoqi@0 277
aoqi@0 278 /**
aoqi@0 279 * Chooses a client locale to use, using the first language specified in
aoqi@0 280 * the list that is supported by this catalog. If none of the specified
aoqi@0 281 * languages is supported, a null value is returned. Such a list of
aoqi@0 282 * languages might be provided in an HTTP/1.1 "Accept-Language" header
aoqi@0 283 * field, or through some other content negotiation mechanism.
aoqi@0 284 * <p/>
aoqi@0 285 * <P> The language specifiers recognized are RFC 1766 style ("fr" for
aoqi@0 286 * all French, "fr-ca" for Canadian French), although only the strict
aoqi@0 287 * ISO subset (two letter language and country specifiers) is currently
aoqi@0 288 * supported. Java-style locale strings ("fr_CA") are also supported.
aoqi@0 289 *
aoqi@0 290 * @param languages Array of language specifiers, ordered with the most
aoqi@0 291 * preferable one at the front. For example, "en-ca" then "fr-ca",
aoqi@0 292 * followed by "zh_CN".
aoqi@0 293 * @return The most preferable supported locale, or null.
aoqi@0 294 * @see java.util.Locale
aoqi@0 295 */
aoqi@0 296 public Locale chooseLocale(String languages []) {
aoqi@0 297 if ((languages = canonicalize(languages)) != null) {
aoqi@0 298 for (int i = 0; i < languages.length; i++)
aoqi@0 299 if (isLocaleSupported(languages[i]))
aoqi@0 300 return getLocale(languages[i]);
aoqi@0 301 }
aoqi@0 302 return null;
aoqi@0 303 }
aoqi@0 304
aoqi@0 305
aoqi@0 306 //
aoqi@0 307 // Canonicalizes the RFC 1766 style language strings ("en-in") to
aoqi@0 308 // match standard Java usage ("en_IN"), removing strings that don't
aoqi@0 309 // use two character ISO language and country codes. Avoids all
aoqi@0 310 // memory allocations possible, so that if the strings passed in are
aoqi@0 311 // just lowercase ISO codes (a common case) the input is returned.
aoqi@0 312 //
aoqi@0 313 private String[] canonicalize(String languages []) {
aoqi@0 314 boolean didClone = false;
aoqi@0 315 int trimCount = 0;
aoqi@0 316
aoqi@0 317 if (languages == null)
aoqi@0 318 return languages;
aoqi@0 319
aoqi@0 320 for (int i = 0; i < languages.length; i++) {
aoqi@0 321 String lang = languages[i];
aoqi@0 322 int len = lang.length();
aoqi@0 323
aoqi@0 324 // no RFC1766 extensions allowed; "zh" and "zh-tw" (etc) are OK
aoqi@0 325 // as are regular locale names with no variant ("de_CH").
aoqi@0 326 if (!(len == 2 || len == 5)) {
aoqi@0 327 if (!didClone) {
aoqi@0 328 languages = (String[]) languages.clone();
aoqi@0 329 didClone = true;
aoqi@0 330 }
aoqi@0 331 languages[i] = null;
aoqi@0 332 trimCount++;
aoqi@0 333 continue;
aoqi@0 334 }
aoqi@0 335
aoqi@0 336 // language code ... if already lowercase, we change nothing
aoqi@0 337 if (len == 2) {
aoqi@0 338 lang = lang.toLowerCase();
aoqi@0 339 if (lang != languages[i]) {
aoqi@0 340 if (!didClone) {
aoqi@0 341 languages = (String[]) languages.clone();
aoqi@0 342 didClone = true;
aoqi@0 343 }
aoqi@0 344 languages[i] = lang;
aoqi@0 345 }
aoqi@0 346 continue;
aoqi@0 347 }
aoqi@0 348
aoqi@0 349 // language_country ... fixup case, force "_"
aoqi@0 350 char buf [] = new char[5];
aoqi@0 351
aoqi@0 352 buf[0] = Character.toLowerCase(lang.charAt(0));
aoqi@0 353 buf[1] = Character.toLowerCase(lang.charAt(1));
aoqi@0 354 buf[2] = '_';
aoqi@0 355 buf[3] = Character.toUpperCase(lang.charAt(3));
aoqi@0 356 buf[4] = Character.toUpperCase(lang.charAt(4));
aoqi@0 357 if (!didClone) {
aoqi@0 358 languages = (String[]) languages.clone();
aoqi@0 359 didClone = true;
aoqi@0 360 }
aoqi@0 361 languages[i] = new String(buf);
aoqi@0 362 }
aoqi@0 363
aoqi@0 364 // purge any shadows of deleted RFC1766 extended language codes
aoqi@0 365 if (trimCount != 0) {
aoqi@0 366 String temp [] = new String[languages.length - trimCount];
aoqi@0 367 int i;
aoqi@0 368
aoqi@0 369 for (i = 0, trimCount = 0; i < temp.length; i++) {
aoqi@0 370 while (languages[i + trimCount] == null)
aoqi@0 371 trimCount++;
aoqi@0 372 temp[i] = languages[i + trimCount];
aoqi@0 373 }
aoqi@0 374 languages = temp;
aoqi@0 375 }
aoqi@0 376 return languages;
aoqi@0 377 }
aoqi@0 378
aoqi@0 379
aoqi@0 380 //
aoqi@0 381 // Returns a locale object supporting the specified locale, using
aoqi@0 382 // a small cache to speed up some common languages and reduce the
aoqi@0 383 // needless allocation of memory.
aoqi@0 384 //
aoqi@0 385 private Locale getLocale(String localeName) {
aoqi@0 386 String language, country;
aoqi@0 387 int index;
aoqi@0 388
aoqi@0 389 index = localeName.indexOf('_');
aoqi@0 390 if (index == -1) {
aoqi@0 391 //
aoqi@0 392 // Special case the builtin JDK languages
aoqi@0 393 //
aoqi@0 394 if (localeName.equals("de"))
aoqi@0 395 return Locale.GERMAN;
aoqi@0 396 if (localeName.equals("en"))
aoqi@0 397 return Locale.ENGLISH;
aoqi@0 398 if (localeName.equals("fr"))
aoqi@0 399 return Locale.FRENCH;
aoqi@0 400 if (localeName.equals("it"))
aoqi@0 401 return Locale.ITALIAN;
aoqi@0 402 if (localeName.equals("ja"))
aoqi@0 403 return Locale.JAPANESE;
aoqi@0 404 if (localeName.equals("ko"))
aoqi@0 405 return Locale.KOREAN;
aoqi@0 406 if (localeName.equals("zh"))
aoqi@0 407 return Locale.CHINESE;
aoqi@0 408
aoqi@0 409 language = localeName;
aoqi@0 410 country = "";
aoqi@0 411 } else {
aoqi@0 412 if (localeName.equals("zh_CN"))
aoqi@0 413 return Locale.SIMPLIFIED_CHINESE;
aoqi@0 414 if (localeName.equals("zh_TW"))
aoqi@0 415 return Locale.TRADITIONAL_CHINESE;
aoqi@0 416
aoqi@0 417 //
aoqi@0 418 // JDK also has constants for countries: en_GB, en_US, en_CA,
aoqi@0 419 // fr_FR, fr_CA, de_DE, ja_JP, ko_KR. We don't use those.
aoqi@0 420 //
aoqi@0 421 language = localeName.substring(0, index);
aoqi@0 422 country = localeName.substring(index + 1);
aoqi@0 423 }
aoqi@0 424
aoqi@0 425 return new Locale(language, country);
aoqi@0 426 }
aoqi@0 427
aoqi@0 428
aoqi@0 429 //
aoqi@0 430 // cache for isLanguageSupported(), below ... key is a language
aoqi@0 431 // or locale name, value is a Boolean
aoqi@0 432 //
aoqi@0 433 private Hashtable cache = new Hashtable(5);
aoqi@0 434
aoqi@0 435
aoqi@0 436 /**
aoqi@0 437 * Returns true iff the specified locale has explicit language support.
aoqi@0 438 * For example, the traditional Chinese locale "zh_TW" has such support
aoqi@0 439 * if there are message bundles suffixed with either "zh_TW" or "zh".
aoqi@0 440 * <p/>
aoqi@0 441 * <P> This method is used to bypass part of the search path mechanism
aoqi@0 442 * of the <code>ResourceBundle</code> class, specifically the parts which
aoqi@0 443 * force use of default locales and bundles. Such bypassing is required
aoqi@0 444 * in order to enable use of a client's preferred languages. Following
aoqi@0 445 * the above example, if a client prefers "zh_TW" but can also accept
aoqi@0 446 * "ja", this method would be used to detect that there are no "zh_TW"
aoqi@0 447 * resource bundles and hence that "ja" messages should be used. This
aoqi@0 448 * bypasses the ResourceBundle mechanism which will return messages in
aoqi@0 449 * some other locale (picking some hard-to-anticipate default) instead
aoqi@0 450 * of reporting an error and letting the client choose another locale.
aoqi@0 451 *
aoqi@0 452 * @param localeName A standard Java locale name, using two character
aoqi@0 453 * language codes optionally suffixed by country codes.
aoqi@0 454 * @return True iff the language of that locale is supported.
aoqi@0 455 * @see java.util.Locale
aoqi@0 456 */
aoqi@0 457 public boolean isLocaleSupported(String localeName) {
aoqi@0 458 //
aoqi@0 459 // Use previous results if possible. We expect that the codebase
aoqi@0 460 // is immutable, so we never worry about changing the cache.
aoqi@0 461 //
aoqi@0 462 Boolean value = (Boolean) cache.get(localeName);
aoqi@0 463
aoqi@0 464 if (value != null)
aoqi@0 465 return value.booleanValue();
aoqi@0 466
aoqi@0 467 //
aoqi@0 468 // Try "language_country_variant", then "language_country",
aoqi@0 469 // then finally "language" ... assuming the longest locale name
aoqi@0 470 // is passed. If not, we'll try fewer options.
aoqi@0 471 //
aoqi@0 472 ClassLoader loader = null;
aoqi@0 473
aoqi@0 474 for (; ;) {
aoqi@0 475 String name = bundleName + "_" + localeName;
aoqi@0 476
aoqi@0 477 // look up classes ...
aoqi@0 478 try {
aoqi@0 479 Class.forName(name);
aoqi@0 480 cache.put(localeName, Boolean.TRUE);
aoqi@0 481 return true;
aoqi@0 482 } catch (Exception e) {
aoqi@0 483 }
aoqi@0 484
aoqi@0 485 // ... then property files (only for ISO Latin/1 messages)
aoqi@0 486 InputStream in;
aoqi@0 487
aoqi@0 488 if (loader == null)
aoqi@0 489 loader = getClass().getClassLoader();
aoqi@0 490
aoqi@0 491 name = name.replace('.', '/');
aoqi@0 492 name = name + ".properties";
aoqi@0 493 if (loader == null)
aoqi@0 494 in = ClassLoader.getSystemResourceAsStream(name);
aoqi@0 495 else
aoqi@0 496 in = loader.getResourceAsStream(name);
aoqi@0 497 if (in != null) {
aoqi@0 498 cache.put(localeName, Boolean.TRUE);
aoqi@0 499 return true;
aoqi@0 500 }
aoqi@0 501
aoqi@0 502 int index = localeName.indexOf('_');
aoqi@0 503
aoqi@0 504 if (index > 0)
aoqi@0 505 localeName = localeName.substring(0, index);
aoqi@0 506 else
aoqi@0 507 break;
aoqi@0 508 }
aoqi@0 509
aoqi@0 510 //
aoqi@0 511 // If we got this far, we failed. Remember for later.
aoqi@0 512 //
aoqi@0 513 cache.put(localeName, Boolean.FALSE);
aoqi@0 514 return false;
aoqi@0 515 }
aoqi@0 516 }

mercurial