1. /*
  2. * @(#)Locale.java 1.48 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * @(#)Locale.java 1.48 01/11/29
  9. *
  10. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  11. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  12. *
  13. * Portions copyright (c) 1996-1998 Sun Microsystems, Inc.
  14. * All Rights Reserved.
  15. *
  16. * The original version of this source code and documentation
  17. * is copyrighted and owned by Taligent, Inc., a wholly-owned
  18. * subsidiary of IBM. These materials are provided under terms
  19. * of a License Agreement between Taligent and Sun. This technology
  20. * is protected by multiple US and International patents.
  21. *
  22. * This notice and attribution to Taligent may not be removed.
  23. * Taligent is a registered trademark of Taligent, Inc.
  24. *
  25. * Permission to use, copy, modify, and distribute this software
  26. * and its documentation for NON-COMMERCIAL purposes and without
  27. * fee is hereby granted provided that this copyright notice
  28. * appears in all copies. Please refer to the file "copyright.html"
  29. * for further important copyright and licensing information.
  30. *
  31. * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  32. * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  33. * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  34. * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  35. * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  36. * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  37. *
  38. */
  39. package java.util;
  40. import java.io.*;
  41. import java.security.AccessController;
  42. import sun.security.action.GetPropertyAction;
  43. import java.text.resources.LocaleData;
  44. import java.text.MessageFormat;
  45. /**
  46. *
  47. * A <code>Locale</code> object represents a specific geographical, political,
  48. * or cultural region. An operation that requires a <code>Locale</code> to perform
  49. * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
  50. * to tailor information for the user. For example, displaying a number
  51. * is a locale-sensitive operation--the number should be formatted
  52. * according to the customs/conventions of the user's native country,
  53. * region, or culture.
  54. *
  55. * <P>
  56. * You create a <code>Locale</code> object using one of the two constructors in
  57. * this class:
  58. * <blockquote>
  59. * <pre>
  60. * Locale(String language, String country)
  61. * Locale(String language, String country, String variant)
  62. * </pre>
  63. * </blockquote>
  64. * The first argument to both constructors is a valid <STRONG>ISO
  65. * Language Code.</STRONG> These codes are the lower-case two-letter
  66. * codes as defined by ISO-639.
  67. * You can find a full list of these codes at a number of sites, such as:
  68. * <BR><a href ="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
  69. * <code>http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt</code></a>
  70. *
  71. * <P>
  72. * The second argument to both constructors is a valid <STRONG>ISO Country
  73. * Code.</STRONG> These codes are the upper-case two-letter codes
  74. * as defined by ISO-3166.
  75. * You can find a full list of these codes at a number of sites, such as:
  76. * <BR><a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html">
  77. * <code>http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html</code></a>
  78. *
  79. * <P>
  80. * The second constructor requires a third argument--the <STRONG>Variant.</STRONG>
  81. * The Variant codes are vendor and browser-specific.
  82. * For example, use WIN for Windows, MAC for Macintosh, and POSIX for POSIX.
  83. * Where there are two variants, separate them with an underscore, and
  84. * put the most important one first. For
  85. * example, a Traditional Spanish collation might construct a locale with
  86. * parameters for language, country and variant as: "es", "ES", "Traditional_WIN".
  87. *
  88. * <P>
  89. * Because a <code>Locale</code> object is just an identifier for a region,
  90. * no validity check is performed when you construct a <code>Locale</code>.
  91. * If you want to see whether particular resources are available for the
  92. * <code>Locale</code> you construct, you must query those resources. For
  93. * example, ask the <code>NumberFormat</code> for the locales it supports
  94. * using its <code>getAvailableLocales</code> method.
  95. * <BR><STRONG>Note:</STRONG> When you ask for a resource for a particular
  96. * locale, you get back the best available match, not necessarily
  97. * precisely what you asked for. For more information, look at
  98. * {@link ResourceBundle}.
  99. *
  100. * <P>
  101. * The <code>Locale</code> class provides a number of convenient constants
  102. * that you can use to create <code>Locale</code> objects for commonly used
  103. * locales. For example, the following creates a <code>Locale</code> object
  104. * for the United States:
  105. * <blockquote>
  106. * <pre>
  107. * Locale.US
  108. * </pre>
  109. * </blockquote>
  110. *
  111. * <P>
  112. * Once you've created a <code>Locale</code> you can query it for information about
  113. * itself. Use <code>getCountry</code> to get the ISO Country Code and
  114. * <code>getLanguage</code> to get the ISO Language Code. You can
  115. * use <code>getDisplayCountry</code> to get the
  116. * name of the country suitable for displaying to the user. Similarly,
  117. * you can use <code>getDisplayLanguage</code> to get the name of
  118. * the language suitable for displaying to the user. Interestingly,
  119. * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
  120. * and have two versions: one that uses the default locale and one
  121. * that uses the locale specified as an argument.
  122. *
  123. * <P>
  124. * The JDK provides a number of classes that perform locale-sensitive
  125. * operations. For example, the <code>NumberFormat</code> class formats
  126. * numbers, currency, or percentages in a locale-sensitive manner. Classes
  127. * such as <code>NumberFormat</code> have a number of convenience methods
  128. * for creating a default object of that type. For example, the
  129. * <code>NumberFormat</code> class provides these three convenience methods
  130. * for creating a default <code>NumberFormat</code> object:
  131. * <blockquote>
  132. * <pre>
  133. * NumberFormat.getInstance()
  134. * NumberFormat.getCurrencyInstance()
  135. * NumberFormat.getPercentInstance()
  136. * </pre>
  137. * </blockquote>
  138. * These methods have two variants; one with an explicit locale
  139. * and one without; the latter using the default locale.
  140. * <blockquote>
  141. * <pre>
  142. * NumberFormat.getInstance(myLocale)
  143. * NumberFormat.getCurrencyInstance(myLocale)
  144. * NumberFormat.getPercentInstance(myLocale)
  145. * </pre>
  146. * </blockquote>
  147. * A <code>Locale</code> is the mechanism for identifying the kind of object
  148. * (<code>NumberFormat</code>) that you would like to get. The locale is
  149. * <STRONG>just</STRONG> a mechanism for identifying objects,
  150. * <STRONG>not</STRONG> a container for the objects themselves.
  151. *
  152. * <P>
  153. * Each class that performs locale-sensitive operations allows you
  154. * to get all the available objects of that type. You can sift
  155. * through these objects by language, country, or variant,
  156. * and use the display names to present a menu to the user.
  157. * For example, you can create a menu of all the collation objects
  158. * suitable for a given language. Such classes must implement these
  159. * three class methods:
  160. * <blockquote>
  161. * <pre>
  162. * public static Locale[] getAvailableLocales()
  163. * public static String getDisplayName(Locale objectLocale,
  164. * Locale displayLocale)
  165. * public static final String getDisplayName(Locale objectLocale)
  166. * // getDisplayName will throw MissingResourceException if the locale
  167. * // is not one of the available locales.
  168. * </pre>
  169. * </blockquote>
  170. *
  171. * @see ResourceBundle
  172. * @see java.text.Format
  173. * @see java.text.NumberFormat
  174. * @see java.text.Collator
  175. * @version 1.21 29 Jan 1997
  176. * @author Mark Davis
  177. */
  178. public final class Locale implements Cloneable, Serializable {
  179. /** Useful constant for language.
  180. */
  181. static public final Locale ENGLISH = new Locale("en","","");
  182. /** Useful constant for language.
  183. */
  184. static public final Locale FRENCH = new Locale("fr","","");
  185. /** Useful constant for language.
  186. */
  187. static public final Locale GERMAN = new Locale("de","","");
  188. /** Useful constant for language.
  189. */
  190. static public final Locale ITALIAN = new Locale("it","","");
  191. /** Useful constant for language.
  192. */
  193. static public final Locale JAPANESE = new Locale("ja","","");
  194. /** Useful constant for language.
  195. */
  196. static public final Locale KOREAN = new Locale("ko","","");
  197. /** Useful constant for language.
  198. */
  199. static public final Locale CHINESE = new Locale("zh","","");
  200. /** Useful constant for language.
  201. */
  202. static public final Locale SIMPLIFIED_CHINESE = new Locale("zh","CN","");
  203. /** Useful constant for language.
  204. */
  205. static public final Locale TRADITIONAL_CHINESE = new Locale("zh","TW","");
  206. /** Useful constant for country.
  207. */
  208. static public final Locale FRANCE = new Locale("fr","FR","");
  209. /** Useful constant for country.
  210. */
  211. static public final Locale GERMANY = new Locale("de","DE","");
  212. /** Useful constant for country.
  213. */
  214. static public final Locale ITALY = new Locale("it","IT","");
  215. /** Useful constant for country.
  216. */
  217. static public final Locale JAPAN = new Locale("ja","JP","");
  218. /** Useful constant for country.
  219. */
  220. static public final Locale KOREA = new Locale("ko","KR","");
  221. /** Useful constant for country.
  222. */
  223. static public final Locale CHINA = new Locale("zh","CN","");
  224. /** Useful constant for country.
  225. */
  226. static public final Locale PRC = new Locale("zh","CN","");
  227. /** Useful constant for country.
  228. */
  229. static public final Locale TAIWAN = new Locale("zh","TW","");
  230. /** Useful constant for country.
  231. */
  232. static public final Locale UK = new Locale("en","GB","");
  233. /** Useful constant for country.
  234. */
  235. static public final Locale US = new Locale("en","US","");
  236. /** Useful constant for country.
  237. */
  238. static public final Locale CANADA = new Locale("en","CA","");
  239. /** Useful constant for country.
  240. */
  241. static public final Locale CANADA_FRENCH = new Locale("fr","CA","");
  242. /** serialization ID
  243. */
  244. static final long serialVersionUID = 9149081749638150636L;
  245. /**
  246. * Construct a locale from language, country, variant.
  247. * NOTE: ISO 639 is not a stable standard; some of the language codes it defines
  248. * (specifically iw, ji, and in) have changed. This constructor accepts both the
  249. * old codes (iw, ji, and in) and the new codes (he, yi, and id), but all other
  250. * API on Locale will return only the OLD codes.
  251. * @param language lowercase two-letter ISO-639 code.
  252. * @param country uppercase two-letter ISO-3166 code.
  253. * @param variant vendor and browser specific code. See class description.
  254. */
  255. public Locale(String language, String country, String variant) {
  256. // we accept both the old and the new ISO codes for the languages whose ISO
  257. // codes have changed, but we always store the OLD code, for backward compatibility
  258. language = toLowerCase(language).intern();
  259. if (language == "he")
  260. language = "iw";
  261. else if (language == "yi")
  262. language = "ji";
  263. else if (language == "id")
  264. language = "in";
  265. this.language = language;
  266. this.country = toUpperCase(country).intern();
  267. this.variant = toUpperCase(variant).intern();
  268. }
  269. /**
  270. * Construct a locale from language, country.
  271. * NOTE: ISO 639 is not a stable standard; some of the language codes it defines
  272. * (specifically iw, ji, and in) have changed. This constructor accepts both the
  273. * old codes (iw, ji, and in) and the new codes (he, yi, and id), but all other
  274. * API on Locale will return only the OLD codes.
  275. * @param language lowercase two-letter ISO-639 code.
  276. * @param country uppercase two-letter ISO-3166 code.
  277. */
  278. public Locale(String language, String country) {
  279. this(language, country, "");
  280. }
  281. /**
  282. * Common method of getting the current default Locale.
  283. * Used for the presentation: menus, dialogs, etc.
  284. * Generally set once when your applet or application is initialized,
  285. * then never reset. (If you do reset the default locale, you
  286. * probably want to reload your GUI, so that the change is reflected
  287. * in your interface.)
  288. * <p>More advanced programs will allow users to use different locales
  289. * for different fields, e.g. in a spreadsheet.
  290. * <BR>Note that the initial setting will match the host system.
  291. */
  292. public static Locale getDefault() {
  293. return defaultLocale; // this variable is now initialized at static init time
  294. }
  295. /**
  296. * Sets the default locale for the whole JVM.
  297. * Normally set once at the beginning of an application,
  298. * then never reset. <code>setDefault</code> does not reset the host locale.
  299. *
  300. * <p>If there is a security manager, its <code>checkPermission</code>
  301. * method is called with a <code>PropertyPermission("user.language", "write")</code>
  302. * permission.
  303. *
  304. * @throws SecurityException
  305. * if a security manager exists and its
  306. * <code>checkPermission</code> method doesn't allow the operation.
  307. * @param newLocale The new default Locale.
  308. * @see SecurityManager#checkPermission
  309. * @see java.util.PropertyPermission
  310. */
  311. public static synchronized void setDefault(Locale newLocale) {
  312. if (newLocale == null)
  313. throw new NullPointerException("Can't set default locale to NULL");
  314. SecurityManager sm = System.getSecurityManager();
  315. if (sm != null) sm.checkPermission(new PropertyPermission
  316. ("user.language", "write"));
  317. defaultLocale = newLocale;
  318. }
  319. /**
  320. * Returns a list of all installed locales.
  321. */
  322. public static Locale[] getAvailableLocales() {
  323. return LocaleData.getAvailableLocales("LocaleString");
  324. }
  325. /**
  326. * Returns a list of all 2-letter country codes defined in ISO 3166.
  327. * Can be used to create Locales.
  328. */
  329. public static String[] getISOCountries() {
  330. if (isoCountries == null) {
  331. isoCountries = new String[compressedIsoCountries.length() / 6];
  332. for (int i = 0; i < isoCountries.length; i++)
  333. isoCountries[i] = compressedIsoCountries.substring((i * 6) + 1, (i * 6) + 3);
  334. }
  335. String[] result = new String[isoCountries.length];
  336. System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
  337. return result;
  338. }
  339. /**
  340. * Returns a list of all 2-letter language codes defined in ISO 639.
  341. * Can be used to create Locales.
  342. * [NOTE: ISO 639 is not a stable standard-- some languages' codes have changed.
  343. * The list this function returns includes both the new and the old codes for the
  344. * languages whose codes have changed.]
  345. */
  346. public static String[] getISOLanguages() {
  347. if (isoLanguages == null) {
  348. isoLanguages = new String[compressedIsoLanguages.length() / 6];
  349. for (int i = 0; i < isoLanguages.length; i++)
  350. isoLanguages[i] = compressedIsoLanguages.substring((i * 6) + 1, (i * 6) + 3);
  351. }
  352. String[] result = new String[isoLanguages.length];
  353. System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
  354. return result;
  355. }
  356. /**
  357. * Given an ISO country code, returns an array of Strings containing the ISO
  358. * codes of the languages spoken in that country. Official languages are listed
  359. * in the returned table before unofficial languages, but other than that, the
  360. * order of the returned list is indeterminate. If the value the user passes in
  361. * for "country" is not a valid ISO 316 country code, or if we don't have language
  362. * information for the specified country, this function returns an empty array.
  363. *
  364. * [This function is not currently part of Locale's API, but is needed in the
  365. * implementation. We hope to add it to the API in a future release.]
  366. */
  367. static String[] getLanguagesForCountry(String country) {
  368. // To save on the size of a static array in the .class file, we keep the
  369. // data around encoded into a String. The first time this function is called,
  370. // the String s parsed to produce a Hashtable, which is then used for all
  371. // lookups.
  372. if (ctry2LangMapping == null) {
  373. ctry2LangMapping = new Hashtable();
  374. int i = 0;
  375. int j;
  376. while (i < compressedCtry2LangMapping.length()) {
  377. String key = compressedCtry2LangMapping.substring(i, i + 2);
  378. i += 2;
  379. for (j = i; j < compressedCtry2LangMapping.length(); j += 2)
  380. if (Character.isUpperCase(compressedCtry2LangMapping.charAt(j)))
  381. break;
  382. String compressedValues = compressedCtry2LangMapping.substring(i, j);
  383. String[] values = new String[compressedValues.length() / 2];
  384. for (int k = 0; k < values.length; k++)
  385. values[k] = compressedValues.substring(k * 2, (k * 2) + 2);
  386. ctry2LangMapping.put(key, values);
  387. i = j;
  388. }
  389. }
  390. String[] result = (String[])ctry2LangMapping.get(country);
  391. if (result == null)
  392. result = new String[0];
  393. return result;
  394. }
  395. /**
  396. * Returns the language code for this locale, which will either be the empty string
  397. * or a lowercase ISO 639 code.
  398. * <p>NOTE: ISO 639 is not a stable standard-- some languages' codes have changed.
  399. * Locale's constructor recognizes both the new and the old codes for the languages
  400. * whose codes have changed, but this function always returns the old code. If you
  401. * want to check for a specific language whose code has changed, don't do <pre>
  402. * if (locale.getLanguage().equals("he")
  403. * ...
  404. * </pre>Instead, do<pre>
  405. * if (locale.getLanguage().equals(new Locale("he", "", "").getLanguage())
  406. * ...</pre>
  407. * @see #getDisplayLanguage
  408. */
  409. public String getLanguage() {
  410. return language;
  411. }
  412. /**
  413. * Returns the country/region code for this locale, which will either be the empty string
  414. * or an upercase ISO 3166 2-letter code.
  415. * @see #getDisplayCountry
  416. */
  417. public String getCountry() {
  418. return country;
  419. }
  420. /**
  421. * Returns the variant code for this locale.
  422. * @see #getDisplayVariant
  423. */
  424. public String getVariant() {
  425. return variant;
  426. }
  427. /**
  428. * Getter for the programmatic name of the entire locale,
  429. * with the language, country and variant separated by underbars.
  430. * Language is always lower case, and country is always upper case.
  431. * If the language is missing, the string will begin with an underbar.
  432. * If both the language and country fields are missing, this function
  433. * will return the empty string, even if the variant field is filled in
  434. * (you can't have a locale with just a variant-- the variant must accompany
  435. * a valid language or country code).
  436. * Examples: "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr_MAC"
  437. * @see #getDisplayName
  438. */
  439. public final String toString() {
  440. boolean l = language.length() != 0;
  441. boolean c = country.length() != 0;
  442. boolean v = variant.length() != 0;
  443. StringBuffer result = new StringBuffer(language);
  444. if (c||(l&&v)) {
  445. result.append('_').append(country); // This may just append '_'
  446. }
  447. if (v&&(l||c)) {
  448. result.append('_').append(variant);
  449. }
  450. return result.toString();
  451. }
  452. /**
  453. * Returns a three-letter abbreviation for this locale's language. If the locale
  454. * doesn't specify a language, this will be the empty string. Otherwise, this will
  455. * be a lowercase ISO 639-2/T language code.
  456. * @exception MissingResourceException Throws MissingResourceException if the
  457. * three-letter language abbreviation is not available for this locale.
  458. */
  459. public String getISO3Language() throws MissingResourceException {
  460. int length = language.length();
  461. if (length == 0) {
  462. return "";
  463. }
  464. int index = compressedIsoLanguages.indexOf("," + language);
  465. if (index == -1 || length != 2) {
  466. throw new MissingResourceException("Couldn't find 3-letter language code for "
  467. + language, "LocaleElements_" + toString(), "ShortLanguage");
  468. }
  469. return compressedIsoLanguages.substring(index + 3, index + 6);
  470. }
  471. /**
  472. * Returns a three-letter abbreviation for this locale's country. If the locale
  473. * doesn't specify a country, this will be tbe the empty string. Otherwise, this will
  474. * be an uppercase ISO 3166 3-letter country code.
  475. * @exception MissingResourceException Throws MissingResourceException if the
  476. * three-letter country abbreviation is not available for this locale.
  477. */
  478. public String getISO3Country() throws MissingResourceException {
  479. int length = country.length();
  480. if (length == 0) {
  481. return "";
  482. }
  483. int index = compressedIsoCountries.indexOf("," + country);
  484. if (index == -1 || length != 2) {
  485. throw new MissingResourceException("Couldn't find 3-letter country code for "
  486. + country, "LocaleElements_" + toString(), "ShortCountry");
  487. }
  488. return compressedIsoCountries.substring(index + 3, index + 6);
  489. }
  490. /**
  491. * Returns a name for the locale's language that is appropriate for display to the
  492. * user.
  493. * If possible, the name returned will be localized for the default locale.
  494. * For example, if the locale is fr_FR and the default locale
  495. * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
  496. * the default locale is fr_FR, getDisplayLanguage() will return "anglais".
  497. * If the name returned cannot be localized for the default locale,
  498. * (say, we don't have a Japanese name for Croatian),
  499. * this function falls back on the English name, and uses the ISO code as a last-resort
  500. * value. If the locale doesn't specify a language, this function returns the empty string.
  501. */
  502. public final String getDisplayLanguage() {
  503. return getDisplayLanguage(getDefault());
  504. }
  505. /**
  506. * Returns a name for the locale's language that is appropriate for display to the
  507. * user.
  508. * If possible, the name returned will be localized according to inLocale.
  509. * For example, if the locale is fr_FR and inLocale
  510. * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
  511. * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
  512. * If the name returned cannot be localized according to inLocale,
  513. * (say, we don't have a Japanese name for Croatian),
  514. * this function falls back on the default locale, on the English name, and finally
  515. * on the ISO code as a last-resort value. If the locale doesn't specify a language,
  516. * this function returns the empty string.
  517. */
  518. public String getDisplayLanguage(Locale inLocale) {
  519. String langCode = language;
  520. if (langCode.length() == 0)
  521. return "";
  522. Locale workingLocale = (Locale)inLocale.clone();
  523. String result = null;
  524. int phase = 0;
  525. boolean done = false;
  526. if (workingLocale.variant.length() == 0)
  527. phase = 1;
  528. if (workingLocale.country.length() == 0)
  529. phase = 2;
  530. while (!done) {
  531. try {
  532. ResourceBundle bundle = ResourceBundle.getBundle(
  533. "java.text.resources.LocaleElements", workingLocale);
  534. result = findStringMatch((String[][])bundle.getObject("Languages"),
  535. langCode, langCode);
  536. if (result.length() != 0)
  537. done = true;
  538. }
  539. catch (Exception e) {
  540. // just fall through
  541. }
  542. if (!done) {
  543. switch (phase) {
  544. case 0:
  545. workingLocale.variant = "";
  546. break;
  547. case 1:
  548. workingLocale.country = "";
  549. break;
  550. case 2:
  551. workingLocale = getDefault();
  552. break;
  553. case 3:
  554. workingLocale = new Locale("", "", "");
  555. break;
  556. default:
  557. return langCode;
  558. }
  559. phase++;
  560. }
  561. }
  562. return result;
  563. }
  564. /**
  565. * Returns a name for the locale's country that is appropriate for display to the
  566. * user.
  567. * If possible, the name returned will be localized for the default locale.
  568. * For example, if the locale is fr_FR and the default locale
  569. * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
  570. * the default locale is fr_FR, getDisplayLanguage() will return "Etats-Unis".
  571. * If the name returned cannot be localized for the default locale,
  572. * (say, we don't have a Japanese name for Croatia),
  573. * this function falls back on the English name, and uses the ISO code as a last-resort
  574. * value. If the locale doesn't specify a country, this function returns the empty string.
  575. */
  576. public final String getDisplayCountry() {
  577. return getDisplayCountry(getDefault());
  578. }
  579. /**
  580. * Returns a name for the locale's country that is appropriate for display to the
  581. * user.
  582. * If possible, the name returned will be localized according to inLocale.
  583. * For example, if the locale is fr_FR and inLocale
  584. * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
  585. * inLocale is fr_FR, getDisplayLanguage() will return "Etats-Unis".
  586. * If the name returned cannot be localized according to inLocale.
  587. * (say, we don't have a Japanese name for Croatia),
  588. * this function falls back on the default locale, on the English name, and finally
  589. * on the ISO code as a last-resort value. If the locale doesn't specify a country,
  590. * this function returns the empty string.
  591. */
  592. public String getDisplayCountry(Locale inLocale) {
  593. String ctryCode = country;
  594. if (ctryCode.length() == 0)
  595. return "";
  596. Locale workingLocale = (Locale)inLocale.clone();
  597. String result = null;
  598. int phase = 0;
  599. boolean done = false;
  600. if (workingLocale.variant.length() == 0)
  601. phase = 1;
  602. if (workingLocale.country.length() == 0)
  603. phase = 2;
  604. while (!done) {
  605. try {
  606. ResourceBundle bundle = ResourceBundle.getBundle(
  607. "java.text.resources.LocaleElements", workingLocale);
  608. result = findStringMatch((String[][])bundle.getObject("Countries"),
  609. ctryCode, ctryCode);
  610. if (result.length() != 0)
  611. done = true;
  612. }
  613. catch (Exception e) {
  614. // just fall through
  615. }
  616. if (!done) {
  617. switch (phase) {
  618. case 0:
  619. workingLocale.variant = "";
  620. break;
  621. case 1:
  622. workingLocale.country = "";
  623. break;
  624. case 2:
  625. workingLocale = getDefault();
  626. break;
  627. case 3:
  628. workingLocale = new Locale("", "", "");
  629. break;
  630. default:
  631. return ctryCode;
  632. }
  633. phase++;
  634. }
  635. }
  636. return result;
  637. }
  638. /**
  639. * Returns a name for the locale's variant code that is appropriate for display to the
  640. * user. If possible, the name will be localized for the default locale. If the locale
  641. * doesn't specify a variant code, this function returns the empty string.
  642. */
  643. public final String getDisplayVariant() {
  644. return getDisplayVariant(getDefault());
  645. }
  646. /**
  647. * Returns a name for the locale's variant code that is appropriate for display to the
  648. * user. If possible, the name will be localized for inLocale. If the locale
  649. * doesn't specify a variant code, this function returns the empty string.
  650. */
  651. public String getDisplayVariant(Locale inLocale) {
  652. if (variant.length() == 0)
  653. return "";
  654. ResourceBundle bundle = ResourceBundle.getBundle(
  655. "java.text.resources.LocaleElements", inLocale);
  656. String names[] = getDisplayVariantArray(bundle);
  657. // Get the localized patterns for formatting a list, and use
  658. // them to format the list.
  659. String[] patterns;
  660. try {
  661. patterns = (String[])bundle.getObject("LocaleNamePatterns");
  662. }
  663. catch (MissingResourceException e) {
  664. patterns = null;
  665. }
  666. return formatList(patterns, names);
  667. }
  668. /**
  669. * Returns a name for the locale that is appropriate for display to the
  670. * user. This will be the values returned by getDisplayLanguage(), getDisplayCountry(),
  671. * and getDisplayVariant() assembled into a single string. The display name will have
  672. * one of the following forms:<p><blockquote>
  673. * language (country, variant)<p>
  674. * language (country)<p>
  675. * language (variant)<p>
  676. * country (variant)<p>
  677. * language<p>
  678. * country<p>
  679. * variant<p></blockquote>
  680. * depending on which fields are specified in the locale. If the language, country,
  681. * and variant fields are all empty, this function returns the empty string.
  682. */
  683. public final String getDisplayName() {
  684. return getDisplayName(getDefault());
  685. }
  686. /**
  687. * Returns a name for the locale that is appropriate for display to the
  688. * user. This will be the values returned by getDisplayLanguage(), getDisplayCountry(),
  689. * and getDisplayVariant() assembled into a single string. The display name will have
  690. * one of the following forms:<p><blockquote>
  691. * language (country, variant)<p>
  692. * language (country)<p>
  693. * language (variant)<p>
  694. * country (variant)<p>
  695. * language<p>
  696. * country<p>
  697. * variant<p></blockquote>
  698. * depending on which fields are specified in the locale. If the language, country,
  699. * and variant fields are all empty, this function returns the empty string.
  700. */
  701. public String getDisplayName(Locale inLocale) {
  702. ResourceBundle bundle = ResourceBundle.getBundle(
  703. "java.text.resources.LocaleElements", inLocale);
  704. String languageName = getDisplayLanguage(inLocale);
  705. String countryName = getDisplayCountry(inLocale);
  706. String[] variantNames = getDisplayVariantArray(bundle);
  707. // Get the localized patterns for formatting a display name.
  708. String[] patterns;
  709. try {
  710. patterns = (String[])bundle.getObject("LocaleNamePatterns");
  711. }
  712. catch (MissingResourceException e) {
  713. patterns = null;
  714. }
  715. // The display name consists of a main name, followed by qualifiers.
  716. // Typically, the format is "MainName (Qualifier, Qualifier)" but this
  717. // depends on what pattern is stored in the display locale.
  718. String mainName = null;
  719. String[] qualifierNames = null;
  720. // The main name is the language, or if there is no language, the country.
  721. // If there is neither language nor country (an anomalous situation) then
  722. // the display name is simply the variant's display name.
  723. if (languageName.length() != 0) {
  724. mainName = languageName;
  725. if (countryName.length() != 0) {
  726. qualifierNames = new String[variantNames.length + 1];
  727. System.arraycopy(variantNames, 0, qualifierNames, 1, variantNames.length);
  728. qualifierNames[0] = countryName;
  729. }
  730. else qualifierNames = variantNames;
  731. }
  732. else if (countryName.length() != 0) {
  733. mainName = countryName;
  734. qualifierNames = variantNames;
  735. }
  736. else {
  737. return formatList(patterns, variantNames);
  738. }
  739. // Create an array whose first element is the number of remaining
  740. // elements. This serves as a selector into a ChoiceFormat pattern from
  741. // the resource. The second and third elements are the main name and
  742. // the qualifier; if there are no qualifiers, the third element is
  743. // unused by the format pattern.
  744. Object[] displayNames = {
  745. new Integer(qualifierNames.length != 0 ? 2 : 1),
  746. mainName,
  747. // We could also just call formatList() and have it handle the empty
  748. // list case, but this is more efficient, and we want it to be
  749. // efficient since all the language-only locales will not have any
  750. // qualifiers.
  751. qualifierNames.length != 0 ? formatList(patterns, qualifierNames) : null
  752. };
  753. if (patterns != null) {
  754. return new MessageFormat(patterns[0]).format(displayNames);
  755. }
  756. else {
  757. // If we cannot get the message format pattern, then we use a simple
  758. // hard-coded pattern. This should not occur in practice unless the
  759. // installation is missing some core files (LocaleElements etc.).
  760. StringBuffer result = new StringBuffer();
  761. result.append((String)displayNames[1]);
  762. if (displayNames.length > 2) {
  763. result.append(" (");
  764. result.append((String)displayNames[2]);
  765. result.append(")");
  766. }
  767. return result.toString();
  768. }
  769. }
  770. /**
  771. * Overrides Cloneable
  772. */
  773. public Object clone()
  774. {
  775. try {
  776. Locale that = (Locale)super.clone();
  777. return that;
  778. } catch (CloneNotSupportedException e) {
  779. throw new InternalError();
  780. }
  781. }
  782. /**
  783. * Override hashCode.
  784. * Since Locales are often used in hashtables, caches the value
  785. * for speed.
  786. */
  787. // XXX Depending on performance of synchronized, may want to
  788. // XXX just compute in constructor.
  789. public synchronized int hashCode() {
  790. if (hashcode == -1) {
  791. hashcode =
  792. language.hashCode() ^
  793. country.hashCode() ^
  794. variant.hashCode();
  795. }
  796. return hashcode;
  797. }
  798. // Overrides
  799. /**
  800. * Returns true if this Locale is equal to another object. A Locale is
  801. * deemed equal to another Locale with identical language, country,
  802. * and variant, and unequal to all other objects.
  803. *
  804. * @return true if this Locale is equal to the specified object.
  805. */
  806. public boolean equals(Object obj) {
  807. if (this == obj) // quick check
  808. return true;
  809. if (!(obj instanceof Locale)) // (1) same object?
  810. return false;
  811. Locale other = (Locale) obj;
  812. if (hashCode() != other.hashCode()) return false; // quick check
  813. if (language != other.language) return false;
  814. if (country != other.country) return false;
  815. if (variant != other.variant) return false;
  816. return true; // we made it through the guantlet.
  817. // (1) We don't check super.equals since it is Object.
  818. // Since Locale is final, we don't have to check both directions.
  819. }
  820. // ================= privates =====================================
  821. // XXX instance and class variables. For now keep these separate, since it is
  822. // faster to match. Later, make into single string.
  823. /**
  824. * @serial
  825. * @see #getLanguage
  826. */
  827. private String language = "";
  828. /**
  829. * @serial
  830. * @see #getCountry
  831. */
  832. private String country = "";
  833. /**
  834. * @serial
  835. * @see #getVariant
  836. */
  837. private String variant = "";
  838. /**
  839. * Placeholder for the object's hash code. Always -1.
  840. * @serial
  841. */
  842. private int hashcode = -1; // lazy evaluated
  843. private static Locale defaultLocale;
  844. static {
  845. String language =
  846. (String) AccessController.doPrivileged(
  847. new GetPropertyAction("user.language","EN"));
  848. String country =
  849. (String) AccessController.doPrivileged(
  850. new GetPropertyAction("user.region",""));
  851. /* The user.region property may be of the form country, country_variant,
  852. * or _variant. Since the Locale constructor takes the country value as
  853. * an unparsed literal, and we don't want to change that behavior, we
  854. * must premunge it here into country and variant. - liu 7/24/98 */
  855. String variant = "";
  856. int i = country.indexOf('_');
  857. if (i >= 0) {
  858. variant = country.substring(i+1);
  859. country = country.substring(0, i);
  860. }
  861. defaultLocale = new Locale(language, country, variant);
  862. }
  863. /**
  864. * Return an array of the display names of the variant.
  865. * @param bundle the ResourceBundle to use to get the display names
  866. * @return an array of display names, possible of zero length.
  867. */
  868. private String[] getDisplayVariantArray(ResourceBundle bundle) {
  869. // Split the variant name into tokens separated by '_'.
  870. StringTokenizer tokenizer = new StringTokenizer(variant, "_");
  871. String[] names = new String[tokenizer.countTokens()];
  872. // For each variant token, lookup the display name. If
  873. // not found, use the variant name itself.
  874. for (int i=0; i<names.length; ++i) {
  875. String token = tokenizer.nextToken();
  876. try {
  877. names[i] = (String)bundle.getObject("%%" + token);
  878. }
  879. catch (MissingResourceException e) {
  880. names[i] = token;
  881. }
  882. }
  883. return names;
  884. }
  885. /**
  886. * Format a list with an array of patterns.
  887. * @param patterns an array of three patterns. The first pattern is not
  888. * used. The second pattern should create a MessageFormat taking 0-3 arguments
  889. * and formatting them into a list. The third pattern should take 2 arguments
  890. * and is used by composeList. If patterns is null, then a the list is
  891. * formatted by concatenation with the delimiter ','.
  892. * @param stringList the list of strings to be formatted.
  893. * @return a string representing the list.
  894. */
  895. private static String formatList(String[] patterns, String[] stringList) {
  896. // If we have no list patterns, compose the list in a simple,
  897. // non-localized way.
  898. if (patterns == null) {
  899. StringBuffer result = new StringBuffer();
  900. for (int i=0; i<stringList.length; ++i) {
  901. if (i>0) result.append(',');
  902. result.append(stringList[i]);
  903. }
  904. return result.toString();
  905. }
  906. // Compose the list down to three elements if necessary
  907. if (stringList.length > 3) {
  908. MessageFormat format = new MessageFormat(patterns[2]);
  909. stringList = composeList(format, stringList);
  910. }
  911. // Rebuild the argument list with the list length as the first element
  912. Object[] args = new Object[stringList.length + 1];
  913. System.arraycopy(stringList, 0, args, 1, stringList.length);
  914. args[0] = new Integer(stringList.length);
  915. // Format it using the pattern in the resource
  916. MessageFormat format = new MessageFormat(patterns[1]);
  917. return format.format(args);
  918. }
  919. /**
  920. * Given a list of strings, return a list shortened to three elements.
  921. * Shorten it by applying the given format to the first two elements
  922. * recursively.
  923. * @param format a format which takes two arguments
  924. * @param list a list of strings
  925. * @return if the list is three elements or shorter, the same list;
  926. * otherwise, a new list of three elements.
  927. */
  928. private static String[] composeList(MessageFormat format, String[] list) {
  929. if (list.length <= 3) return list;
  930. // Use the given format to compose the first two elements into one
  931. String[] listItems = { list[0], list[1] };
  932. String newItem = format.format(listItems);
  933. // Form a new list one element shorter
  934. String[] newList = new String[list.length-1];
  935. System.arraycopy(list, 2, newList, 1, newList.length-1);
  936. newList[0] = newItem;
  937. // Recurse
  938. return composeList(format, newList);
  939. }
  940. /**
  941. * @serialData The first three fields are three <code>String</code> objects:
  942. * the first is a 2-letter ISO 639 code representing the locale's language,
  943. * the second is a 2-letter ISO 3166 code representing the locale's region or
  944. * country, and the third is an optional chain of variant codes defined by this
  945. * library. Any of the fields may be the empty string. The fourth field is an
  946. * <code>int</code> whose value is always -1. This is a sentinel value indicating
  947. * the <code>Locale</code>'s hash code must be recomputed.
  948. */
  949. private void writeObject(ObjectOutputStream out) throws IOException {
  950. // hashcode is semantically transient. We couldn't define it as transient
  951. // because versions of this class that DIDN'T declare it as transient have
  952. // already shipped. What we're doing here is making sure that the written-out
  953. // version of hashcode is always -1, regardless of what's really stored there
  954. // (we hold onto the original value just in case someone might want it again).
  955. // Writing -1 ensures that version 1.1 Locales will always recalculate their
  956. // hash codes after being streamed back in. This is necessary because
  957. // String.hashCode() calculates its hash code differently in 1.2 than it did
  958. // in 1.1.
  959. int temp = hashcode;
  960. hashcode = -1;
  961. out.defaultWriteObject();
  962. hashcode = temp;
  963. }
  964. /**
  965. * @serialData The first three fields are three <code>String</code> objects:
  966. * the first is a 2-letter ISO 639 code representing the locale's language,
  967. * the second is a 2-letter ISO 3166 code representing the locale's region or
  968. * country, and the third is an optional chain of variant codes defined by this
  969. * library. Any of the fields may be the empty string. The fourth field is an
  970. * <code>int</code>representing the locale's hash code, but is ignored by
  971. * <code>readObject()</code>. Whatever this field's value, the hash code is
  972. * initialized to -1, a sentinel value that indicates the hash code must be
  973. * recomputed.
  974. */
  975. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  976. // hashcode is semantically transient. We couldn't define it as transient
  977. // because versions of this class that DIDN'T deslcare is as transient have
  978. // already shipped. This code makes sure that whatever value for hashcode
  979. // was written on the stream, we ignore it and recalculate it on demand. This
  980. // is necessary because String.hashCode() calculates is hash code differently
  981. // in version 1.2 than it did in 1.1.
  982. in.defaultReadObject();
  983. hashcode = -1;
  984. language = language.intern();
  985. country = country.intern();
  986. variant = variant.intern();
  987. }
  988. /**
  989. * List of all 2-letter language codes currently defined in ISO 639.
  990. * (Because the Java VM specification turns an array constant into executable code
  991. * that generates the array element by element, we keep the array in compressed
  992. * form in a single string and build the array from it at run time when requested.)
  993. * [We're now also using this table to store a mapping from 2-letter ISO language codes
  994. * to 3-letter ISO language codes. Each group of characters consists of a comma, a
  995. * 2-letter code, and a 3-letter code. We look up a 3-letter code by searching for
  996. * a comma followed by a 2-letter code and then getting the three letters following
  997. * the 2-letter code.]
  998. */
  999. private static String[] isoLanguages = null;
  1000. private static final String compressedIsoLanguages =
  1001. ",aaaar,ababk,afafr,amamh,arara,asasm,ayaym,azaze,babak,bebel,bgbul,bhbih,bibis,bnben,"
  1002. + "bobod,brbre,cacat,cocos,csces,cycym,dadan,dedeu,dzdzo,elell,eneng,eoepo,esspa,"
  1003. + "etest,eueus,fafas,fifin,fjfij,fofao,frfra,fyfry,gagai,gdgdh,glglg,gngrn,guguj,"
  1004. + "hahau,heheb,hihin,hrhrv,huhun,hyhye,iaina,idind,ieile,ikipk,inind,isisl,itita,"
  1005. + "iuiku,iwheb,jajpn,jiyid,jwjaw,kakat,kkkaz,klkal,kmkhm,knkan,kokor,kskas,kukur,"
  1006. + "kykir,lalat,lnlin,lolao,ltlit,lvlav,mgmlg,mimri,mkmkd,mlmal,mnmon,momol,mrmar,"
  1007. + "msmsa,mtmlt,mymya,nanau,nenep,nlnld,nonor,ococi,omorm,orori,papan,plpol,pspus,"
  1008. + "ptpor,quque,rmroh,rnrun,roron,rurus,rwkin,sasan,sdsnd,sgsag,shsrp,sisin,skslk,"
  1009. + "slslv,smsmo,snsna,sosom,sqsqi,srsrp,ssssw,stsot,susun,svswe,swswa,tatat,tetel,"
  1010. + "tgtgk,ththa,titir,tktuk,tltgl,tntsn,toton,trtur,tstsn,tttat,twtwi,uguig,ukukr,"
  1011. + "ururd,uzuzb,vivie,vovol,wowol,xhxho,yiyid,yoyor,zazha,zhzho,zuzul";
  1012. /**
  1013. * List of all 2-letter country codes currently defined in ISO 3166.
  1014. * (Because the Java VM specification turns an array constant into executable code
  1015. * that generates the array element by element, we keep the array in compressed
  1016. * form in a single string and build the array from it at run time when requested.)
  1017. * [We're now also using this table to store a mapping from 2-letter ISO country codes
  1018. * to 3-letter ISO country codes. Each group of characters consists of a comma, a
  1019. * 2-letter code, and a 3-letter code. We look up a 3-letter code by searching for
  1020. * a comma followed by a 2-letter code and then getting the three letters following
  1021. * the 2-letter code.]
  1022. */
  1023. private static String[] isoCountries = null;
  1024. private static final String compressedIsoCountries =
  1025. ",ADAND,AEARE,AFAFG,AGATG,AIAIA,ALALB,AMARM,ANANT,AOAGO,AQATA,ARARG,ASASM,ATAUT,"
  1026. + "AUAUS,AWABW,AZAZE,BABIH,BBBRB,BDBGD,BEBEL,BFBFA,BGBGR,BHBHR,BIBDI,BJBEN,BMBMU,"
  1027. + "BNBRN,BOBOL,BRBRA,BSBHS,BTBTN,BVBVT,BWBWA,BYBLR,BZBLZ,CACAN,CCCCK,CFCAF,CGCOG,"
  1028. + "CHCHE,CICIV,CKCOK,CLCHL,CMCMR,CNCHN,COCOL,CRCRI,CUCUB,CVCPV,CXCXR,CYCYP,CZCZE,"
  1029. + "DEDEU,DJDJI,DKDNK,DMDMA,DODOM,DZDZA,ECECU,EEEST,EGEGY,EHESH,ERERI,ESESP,ETETH,"
  1030. + "FIFIN,FJFJI,FKFLK,FMFSM,FOFRO,FRFRA,FXFXX,GAGAB,GBGBR,GDGRD,GEGEO,GFGUF,GHGHA,"
  1031. + "GIGIB,GLGRL,GMGMB,GNGIN,GPGLP,GQGNQ,GRGRC,GSSGS,GTGTM,GUGUM,GWGNB,GYGUY,HKHKG,"
  1032. + "HMHMD,HNHND,HRHRV,HTHTI,HUHUN,IDIDN,IEIRL,ILISR,ININD,IOIOT,IQIRQ,IRIRN,ISISL,"
  1033. + "ITITA,JMJAM,JOJOR,JPJPN,KEKEN,KGKGZ,KHKHM,KIKIR,KMCOM,KNKNA,KPPRK,KRKOR,KWKWT,"
  1034. + "KYCYM,KZKAZ,LALAO,LBLBN,LCLCA,LILIE,LKLKA,LRLBR,LSLSO,LTLTU,LULUX,LVLVA,LYLBY,"
  1035. + "MAMAR,MCMCO,MDMDA,MGMDG,MHMHL,MKMKD,MLMLI,MMMMR,MNMNG,MOMAC,MPMNP,MQMTQ,MRMRT,"
  1036. + "MSMSR,MTMLT,MUMUS,MVMDV,MWMWI,MXMEX,MYMYS,MZMOZ,NANAM,NCNCL,NENER,NFNFK,NGNGA,"
  1037. + "NINIC,NLNLD,NONOR,NPNPL,NRNRU,NUNIU,NZNZL,OMOMN,PAPAN,PEPER,PFPYF,PGPNG,PHPHL,"
  1038. + "PKPAK,PLPOL,PMSPM,PNPCN,PRPRI,PTPRT,PWPLW,PYPRY,QAQAT,REREU,ROROM,RURUS,RWRWA,"
  1039. + "SASAU,SBSLB,SCSYC,SDSDN,SESWE,SGSGP,SHSHN,SISVN,SJSJM,SKSVK,SLSLE,SMSMR,SNSEN,"
  1040. + "SOSOM,SRSUR,STSTP,SVSLV,SYSYR,SZSWZ,TCTCA,TDTCD,TFATF,TGTGO,THTHA,TJTJK,TKTKL,"
  1041. + "TMTKM,TNTUN,TOTON,TPTMP,TRTUR,TTTTO,TVTUV,TWTWN,TZTZA,UAUKR,UGUGA,UMUMI,USUSA,"
  1042. + "UYURY,UZUZB,VAVAT,VCVCT,VEVEN,VGVGB,VIVIR,VNVNM,VUVUT,WFWLF,WSWSM,YEYEM,YTMYT,"
  1043. + "YUYUG,ZAZAF,ZMZMB,ZRZAR,ZWZWE";
  1044. /**
  1045. * Table mapping ISO country codes to the ISO language codes of the languages spoken
  1046. * in those countries.
  1047. * (Because the Java VM specification for building arrays and hashtables causes
  1048. * code that builds the tables element by element to be produces, we compress the data
  1049. * into a single encoded String, and lazy evaluate the table from it.)
  1050. */
  1051. private static Hashtable ctry2LangMapping = null;
  1052. private static final String compressedCtry2LangMapping =
  1053. "ADfresAEarenAFpsAGenAIrnALsqAMhyruANnlenAOptAResASensmATdeAUenAWnlenAZazhyru"
  1054. + "BAsrshhrslmksqBBenBDbnhibhenBEfrnldeBFfrBGbgtrBHarenBIrnfrswBJfrBMenBNmsenzh"
  1055. + "BOesayquBRptBSenBTdzenneBVnoBWentnBYberuBZenesCAenfrCCenCFfrsgCGfrCHfrdeitrm"
  1056. + "CIfrCKmienCLesCMenfrCNzhboCOesCResCUesCVptCXenCYeltrenCZcsskDEdeDJarfrsoDKda"
  1057. + "DMenfrDOesDZarfrECesquEEetruEGarenfrEHarfritERamtiarenitESeseucaglETamaren"
  1058. + "FIfisvFJenfjhiFKenFMenFOfodaFRfreubrcoFXfrGAfrGBengdcyGDenfrGEkahyruGFfrGHen"
  1059. + "GIenesGLdaikklGMenwoGNfrGPfrenGQesGRelGTesGUenGWptGYenhiurHKzhenHNesHRhrHTfr"
  1060. + "HUhuIDinennlIEengaILiwarjiINhienguknksmlmrneorpasatateIOenIQarkutkIRfaarku"
  1061. + "ISisITitfrdeJMenJOarJPjaKEenswKGkyKHkmKIenKMfrarKNenKPkoKRkoKWarenKYenKZkkru"
  1062. + "LAlofrLBarenfrLCenfrLIdeLKtasienLRenLSstenLTltruplLUfrdeLVlvltruLYarenit"
  1063. + "MAarfresMCfrenitMDmorobgMGmgenfrMKmkshtrMLfrMMmyMNmnruMOzhptMQfrMRarfrMSen"
  1064. + "MTmtenitMUenfrhiMWenMXesMYmsenMZptNAenafdeNEfrhaNFenNGenhayoNIesNLnlfyNOno"
  1065. + "NPneNRnaenNUenNZenmiOMarenPAesenPEesquayPFfrPGenPHentlesPKurenpspasdPLplPMfren"
  1066. + "PNenPResenPTptPWenPYesgnQAarenREfrtaROrohuRUruRWenfrrwSAarSBenSCenfrSDarsu"
  1067. + "SEsvSGzhenmstaSHenSIslSJnoSKskhuplshSLenSMitSNfrSOarenitsoSRnleneshiSTptSVes"
  1068. + "SYarSZenssTCenTDfrarTFfrTGfrTHthTJtgruuzTKenmiTMtkruTNarTOentoTRtrkuTTenTVen"
  1069. + "TWzhTZenswUAukruUGenswUMenUSenesUYesUZuzruVAlaitVCenVEesVGenVIenVNvizhfr"
  1070. + "VUenfrbiWFfrWSensmYEarYTfrmgswYUsrshmkhuZAafenZMenZRfrswZWensn";
  1071. /*
  1072. * Locale needs its own, locale insenitive version of toLowerCase to
  1073. * avoid circularity problems between Locale and String.
  1074. * The most straightforward algorithm is used. Look at optimizations later.
  1075. */
  1076. private String toLowerCase(String str) {
  1077. char[] buf = str.toCharArray();
  1078. for (int i = 0; i < buf.length; i++) {
  1079. buf[i] = Character.toLowerCase( buf[i] );
  1080. }
  1081. return new String( buf );
  1082. }
  1083. /*
  1084. * Locale needs its own, locale insensitive version of toUpperCase to
  1085. * avoid circularity problems between Locale and String.
  1086. * The most straightforward algorithm is used. Look at optimizations later.
  1087. */
  1088. private String toUpperCase(String str) {
  1089. char[] buf = str.toCharArray();
  1090. for (int i = 0; i < buf.length; i++) {
  1091. buf[i] = Character.toUpperCase( buf[i] );
  1092. }
  1093. return new String( buf );
  1094. }
  1095. private String findStringMatch(String[][] languages,
  1096. String desiredLanguage, String fallbackLanguage)
  1097. {
  1098. for (int i = 0; i < languages.length; ++i)
  1099. if (desiredLanguage.equals(languages[i][0]))
  1100. return languages[i][1];
  1101. if (!fallbackLanguage.equals(desiredLanguage))
  1102. for (int i = 0; i < languages.length; ++i)
  1103. if (fallbackLanguage.equals(languages[i][0]))
  1104. return languages[i][1];
  1105. if (!"EN".equals(desiredLanguage) && "EN".equals(fallbackLanguage))
  1106. for (int i = 0; i < languages.length; ++i)
  1107. if ("EN".equals(languages[i][0]))
  1108. return languages[i][1];
  1109. return "";
  1110. }
  1111. }