001/* DateFormatSymbols.java -- Format over a range of numbers 002 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package java.text; 040 041import gnu.java.locale.LocaleHelper; 042 043import java.io.IOException; 044 045import java.text.spi.DateFormatSymbolsProvider; 046 047import java.util.ArrayList; 048import java.util.HashMap; 049import java.util.List; 050import java.util.Locale; 051import java.util.Map; 052import java.util.MissingResourceException; 053import java.util.Properties; 054import java.util.ResourceBundle; 055import java.util.ServiceLoader; 056import java.util.TimeZone; 057 058import java.util.spi.TimeZoneNameProvider; 059 060/** 061 * This class acts as container for locale specific date/time formatting 062 * information such as the days of the week and the months of the year. 063 * 064 * @author Per Bothner (bothner@cygnus.com) 065 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 066 * @date October 24, 1998. 067 */ 068/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3. 069 * Status: Believed complete and correct. 070 */ 071public class DateFormatSymbols implements java.io.Serializable, Cloneable 072{ 073 String[] ampms; 074 String[] eras; 075 private String localPatternChars; 076 String[] months; 077 String[] shortMonths; 078 String[] shortWeekdays; 079 String[] weekdays; 080 081 /** 082 * The set of properties for obtaining the metazone data. 083 */ 084 private static transient final Properties properties; 085 086 /** 087 * Reads in the properties. 088 */ 089 static 090 { 091 properties = new Properties(); 092 try 093 { 094 properties.load(DateFormatSymbols.class.getResourceAsStream("metazones.properties")); 095 } 096 catch (IOException exception) 097 { 098 System.out.println("Failed to load weeks resource: " + exception); 099 } 100 } 101 102 /** 103 * The timezone strings supplied by the runtime. 104 */ 105 private String[][] runtimeZoneStrings; 106 107 /** 108 * Custom timezone strings supplied by {@link #setZoneStrings()}. 109 */ 110 private String[][] zoneStrings; 111 112 private static final long serialVersionUID = -5987973545549424702L; 113 114 // The order of these prefixes must be the same as in DateFormat 115 private static final String[] formatPrefixes = 116 { 117 "full", "long", "medium", "short" 118 }; 119 120 // These are each arrays with a value for SHORT, MEDIUM, LONG, FULL, 121 // and DEFAULT (constants defined in java.text.DateFormat). While 122 // not part of the official spec, we need a way to get at locale-specific 123 // default formatting patterns. They are declared package scope so 124 // as to be easily accessible where needed (DateFormat, SimpleDateFormat). 125 transient String[] dateFormats; 126 transient String[] timeFormats; 127 128 private static String[] getStringArray(ResourceBundle res, String name) 129 { 130 return res.getString(name).split("\u00ae"); 131 } 132 133 private String[][] getZoneStrings(ResourceBundle res, Locale locale) 134 { 135 List<String[]> allZones = new ArrayList<String[]>(); 136 try 137 { 138 Map<String,String[]> systemZones = new HashMap<String,String[]>(); 139 while (true) 140 { 141 int index = 0; 142 String country = locale.getCountry(); 143 String data = res.getString("zoneStrings"); 144 String[] zones = data.split("\u00a9"); 145 for (int a = 0; a < zones.length; ++a) 146 { 147 String[] strings = zones[a].split("\u00ae"); 148 String type = properties.getProperty(strings[0] + "." + country); 149 if (type == null) 150 type = properties.getProperty(strings[0] + ".DEFAULT"); 151 if (type != null) 152 strings[0] = type; 153 if (strings.length < 5) 154 { 155 String[] newStrings = new String[5]; 156 System.arraycopy(strings, 0, newStrings, 0, strings.length); 157 for (int b = strings.length; b < newStrings.length; ++b) 158 newStrings[b] = ""; 159 strings = newStrings; 160 } 161 String[] existing = systemZones.get(strings[0]); 162 if (existing != null && existing.length > 1) 163 { 164 for (int b = 1; b < existing.length; ++b) 165 if (!existing[b].equals("")) 166 strings[b] = existing[b]; 167 } 168 systemZones.put(strings[0], strings); 169 } 170 if (res.getLocale() == Locale.ROOT) 171 break; 172 else 173 res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 174 LocaleHelper.getFallbackLocale(res.getLocale()), 175 ClassLoader.getSystemClassLoader()); 176 } 177 /* Final sanity check for missing values */ 178 for (String[] zstrings : systemZones.values()) 179 { 180 if (zstrings[1].equals("") && zstrings[2].equals("")) 181 { 182 for (Map.Entry<Object,Object> entry : properties.entrySet()) 183 { 184 String val = (String) entry.getValue(); 185 if (val.equals(zstrings[0])) 186 { 187 String key = (String) entry.getKey(); 188 String metazone = key.substring(0, key.indexOf(".")); 189 String type = properties.getProperty(metazone + "." + locale.getCountry()); 190 if (type == null) 191 type = properties.getProperty(metazone + ".DEFAULT"); 192 if (type != null) 193 { 194 String[] ostrings = systemZones.get(type); 195 zstrings[1] = ostrings[1]; 196 zstrings[2] = ostrings[2]; 197 } 198 } 199 } 200 } 201 } 202 allZones.addAll(systemZones.values()); 203 } 204 catch (MissingResourceException e) 205 { 206 /* This means runtime support for the locale 207 * is not available, so we just include providers. */ 208 } 209 for (TimeZoneNameProvider p : 210 ServiceLoader.load(TimeZoneNameProvider.class)) 211 { 212 for (Locale loc : p.getAvailableLocales()) 213 { 214 if (loc.equals(locale)) 215 { 216 for (String id : TimeZone.getAvailableIDs()) 217 { 218 String[] z = new String[5]; 219 z[0] = id; 220 z[1] = p.getDisplayName(id, false, 221 TimeZone.LONG, 222 locale); 223 z[2] = p.getDisplayName(id, false, 224 TimeZone.SHORT, 225 locale); 226 z[3] = p.getDisplayName(id, true, 227 TimeZone.LONG, 228 locale); 229 z[4] = p.getDisplayName(id, true, 230 TimeZone.SHORT, 231 locale); 232 allZones.add(z); 233 } 234 break; 235 } 236 } 237 } 238 return allZones.toArray(new String[allZones.size()][]); 239 } 240 241 private String[] formatsForKey(ResourceBundle res, String key) 242 { 243 String[] values = new String[formatPrefixes.length]; 244 245 for (int i = 0; i < formatPrefixes.length; i++) 246 values[i] = res.getString(formatPrefixes[i] + key); 247 248 return values; 249 } 250 251 /** 252 * This method initializes a new instance of <code>DateFormatSymbols</code> 253 * by loading the date format information for the specified locale. 254 * This constructor only obtains instances using the runtime's resources; 255 * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances, 256 * call {@link #getInstance(java.util.Locale)} instead. 257 * 258 * @param locale The locale for which date formatting symbols should 259 * be loaded. 260 * @throws MissingResourceException if the resources for the specified 261 * locale could not be found or loaded. 262 * @see #getInstance(java.util.Locale) 263 */ 264 public DateFormatSymbols (Locale locale) 265 throws MissingResourceException 266 { 267 ResourceBundle res 268 = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, 269 ClassLoader.getSystemClassLoader()); 270 271 ampms = getStringArray(res, "ampms"); 272 eras = getStringArray(res, "eras"); 273 localPatternChars = res.getString("localPatternChars"); 274 months = getStringArray(res, "months"); 275 shortMonths = getStringArray(res, "shortMonths"); 276 shortWeekdays = getStringArray(res, "shortWeekdays"); 277 weekdays = getStringArray(res, "weekdays"); 278 dateFormats = formatsForKey(res, "DateFormat"); 279 timeFormats = formatsForKey(res, "TimeFormat"); 280 runtimeZoneStrings = getZoneStrings(res, locale); 281 } 282 283 /** 284 * This method loads the format symbol information for the default 285 * locale. This constructor only obtains instances using the runtime's resources; 286 * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances, 287 * call {@link #getInstance()} instead. 288 * 289 * @throws MissingResourceException if the resources for the default 290 * locale could not be found or loaded. 291 * @see #getInstance() 292 */ 293 public DateFormatSymbols() 294 throws MissingResourceException 295 { 296 this (Locale.getDefault()); 297 } 298 299 /** 300 * This method returns the list of strings used for displaying AM or PM. 301 * This is a two element <code>String</code> array indexed by 302 * <code>Calendar.AM</code> and <code>Calendar.PM</code> 303 * 304 * @return The list of AM/PM display strings. 305 */ 306 public String[] getAmPmStrings() 307 { 308 return ampms; 309 } 310 311 /** 312 * This method returns the list of strings used for displaying eras 313 * (e.g., "BC" and "AD"). This is a two element <code>String</code> 314 * array indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>. 315 * 316 * @return The list of era disply strings. 317 */ 318 public String[] getEras() 319 { 320 return eras; 321 } 322 323 /** 324 * This method returns the pattern character information for this 325 * object. This is an 18 character string that contains the characters 326 * that are used in creating the date formatting strings in 327 * <code>SimpleDateFormat</code>. The following are the character 328 * positions in the string and which format character they correspond 329 * to (the character in parentheses is the default value in the US English 330 * locale): 331 * <p> 332 * <ul> 333 * <li>0 - era (G)</li> 334 * <li>1 - year (y)</li> 335 * <li>2 - month (M)</li> 336 * <li>3 - day of month (d)</li> 337 * <li>4 - hour out of 12, from 1-12 (h)</li> 338 * <li>5 - hour out of 24, from 0-23 (H)</li> 339 * <li>6 - minute (m)</li> 340 * <li>7 - second (s)</li> 341 * <li>8 - millisecond (S)</li> 342 * <li>9 - date of week (E)</li> 343 * <li>10 - date of year (D)</li> 344 * <li>11 - day of week in month, eg. "4th Thur in Nov" (F)</li> 345 * <li>12 - week in year (w)</li> 346 * <li>13 - week in month (W)</li> 347 * <li>14 - am/pm (a)</li> 348 * <li>15 - hour out of 24, from 1-24 (k)</li> 349 * <li>16 - hour out of 12, from 0-11 (K)</li> 350 * <li>17 - time zone (z)</li> 351 * </ul> 352 * 353 * @return The format patter characters 354 */ 355 public String getLocalPatternChars() 356 { 357 return localPatternChars; 358 } 359 360 /** 361 * This method returns the list of strings used for displaying month 362 * names (e.g., "January" and "February"). This is a thirteen element 363 * string array indexed by <code>Calendar.JANUARY</code> through 364 * <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 365 * elements because some calendars have thriteen months. 366 * 367 * @return The list of month display strings. 368 */ 369 public String[] getMonths () 370 { 371 return months; 372 } 373 374 /** 375 * This method returns the list of strings used for displaying abbreviated 376 * month names (e.g., "Jan" and "Feb"). This is a thirteen element 377 * <code>String</code> array indexed by <code>Calendar.JANUARY</code> 378 * through <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 379 * elements because some calendars have thirteen months. 380 * 381 * @return The list of abbreviated month display strings. 382 */ 383 public String[] getShortMonths () 384 { 385 return shortMonths; 386 } 387 388 /** 389 * This method returns the list of strings used for displaying abbreviated 390 * weekday names (e.g., "Sun" and "Mon"). This is an eight element 391 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 392 * through <code>Calendar.SATURDAY</code>. Note that the first element 393 * of this array is ignored. 394 * 395 * @return This list of abbreviated weekday display strings. 396 */ 397 public String[] getShortWeekdays () 398 { 399 return shortWeekdays; 400 } 401 402 /** 403 * This method returns the list of strings used for displaying weekday 404 * names (e.g., "Sunday" and "Monday"). This is an eight element 405 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 406 * through <code>Calendar.SATURDAY</code>. Note that the first element 407 * of this array is ignored. 408 * 409 * @return This list of weekday display strings. 410 */ 411 public String[] getWeekdays () 412 { 413 return weekdays; 414 } 415 416 /** 417 * This method returns this list of localized timezone display strings. 418 * This is a two dimensional <code>String</code> array where each row in 419 * the array contains five values: 420 * <P> 421 * <ul> 422 * <li>0 - The non-localized time zone id string.</li> 423 * <li>1 - The long name of the time zone (standard time).</li> 424 * <li>2 - The short name of the time zone (standard time).</li> 425 * <li>3 - The long name of the time zone (daylight savings time).</li> 426 * <li>4 - the short name of the time zone (daylight savings time).</li> 427 * </ul> 428 * <p> 429 * If {@link #setZoneStrings(String[][])} has been called, then the value 430 * passed to this will be returned. Otherwise the returned array contains 431 * zone names provided by the runtime environment and any 432 * {@link java.util.spi.TimeZoneProvider} instances. 433 * </p> 434 * 435 * @return The list of time zone display strings. 436 * @see #setZoneStrings(String[][]) 437 */ 438 public String[][] getZoneStrings() 439 { 440 if (zoneStrings != null) 441 return zoneStrings; 442 return runtimeZoneStrings; 443 } 444 445 /** 446 * This method sets the list of strings used to display AM/PM values to 447 * the specified list. 448 * This is a two element <code>String</code> array indexed by 449 * <code>Calendar.AM</code> and <code>Calendar.PM</code> 450 * 451 * @param value The new list of AM/PM display strings. 452 */ 453 public void setAmPmStrings (String[] value) 454 { 455 if(value==null) 456 throw new NullPointerException(); 457 ampms = value; 458 } 459 460 /** 461 * This method sets the list of strings used to display time eras to 462 * to the specified list. 463 * This is a two element <code>String</code> 464 * array indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>. 465 * 466 * @param labels The new list of era display strings. 467 */ 468 public void setEras (String[] labels) 469 { 470 if(labels==null) 471 throw new NullPointerException(); 472 eras = labels; 473 } 474 475 /** 476 * This method sets the list of characters used to specific date/time 477 * formatting strings. 478 * This is an 18 character string that contains the characters 479 * that are used in creating the date formatting strings in 480 * <code>SimpleDateFormat</code>. The following are the character 481 * positions in the string and which format character they correspond 482 * to (the character in parentheses is the default value in the US English 483 * locale): 484 * <p> 485 * <ul> 486 * <li>0 - era (G)</li> 487 * <li>1 - year (y)</li> 488 * <li>2 - month (M)</li> 489 * <li>3 - day of month (d)</li> 490 * <li>4 - hour out of 12, from 1-12 (h)</li> 491 * <li>5 - hour out of 24, from 0-23 (H)</li> 492 * <li>6 - minute (m)</li> 493 * <li>7 - second (s)</li> 494 * <li>8 - millisecond (S)</li> 495 * <li>9 - date of week (E)</li> 496 * <li>10 - date of year (D)</li> 497 * <li>11 - day of week in month, eg. "4th Thur in Nov" (F)</li> 498 * <li>12 - week in year (w)</li> 499 * <li>13 - week in month (W)</li> 500 * <li>14 - am/pm (a)</li> 501 * <li>15 - hour out of 24, from 1-24 (k)</li> 502 * <li>16 - hour out of 12, from 0-11 (K)</li> 503 * <li>17 - time zone (z)</li> 504 * </ul> 505 * 506 * @param chars The new format pattern characters 507 */ 508 public void setLocalPatternChars (String chars) 509 { 510 if(chars==null) 511 throw new NullPointerException(); 512 localPatternChars = chars; 513 } 514 515 /** 516 * This method sets the list of strings used to display month names. 517 * This is a thirteen element 518 * string array indexed by <code>Calendar.JANUARY</code> through 519 * <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 520 * elements because some calendars have thriteen months. 521 * 522 * @param labels The list of month display strings. 523 */ 524 public void setMonths (String[] labels) 525 { 526 if(labels==null) 527 throw new NullPointerException(); 528 months = labels; 529 } 530 531 /** 532 * This method sets the list of strings used to display abbreviated month 533 * names. 534 * This is a thirteen element 535 * <code>String</code> array indexed by <code>Calendar.JANUARY</code> 536 * through <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 537 * elements because some calendars have thirteen months. 538 * 539 * @param labels The new list of abbreviated month display strings. 540 */ 541 public void setShortMonths (String[] labels) 542 { 543 if(labels==null) 544 throw new NullPointerException(); 545 shortMonths = labels; 546 } 547 548 /** 549 * This method sets the list of strings used to display abbreviated 550 * weekday names. 551 * This is an eight element 552 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 553 * through <code>Calendar.SATURDAY</code>. Note that the first element 554 * of this array is ignored. 555 * 556 * @param labels This list of abbreviated weekday display strings. 557 */ 558 public void setShortWeekdays (String[] labels) 559 { 560 if(labels==null) 561 throw new NullPointerException(); 562 shortWeekdays = labels; 563 } 564 565 /** 566 * This method sets the list of strings used to display weekday names. 567 * This is an eight element 568 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 569 * through <code>Calendar.SATURDAY</code>. Note that the first element 570 * of this array is ignored. 571 * 572 * @param labels This list of weekday display strings. 573 */ 574 public void setWeekdays (String[] labels) 575 { 576 if(labels==null) 577 throw new NullPointerException(); 578 weekdays = labels; 579 } 580 581 /** 582 * This method sets the list of display strings for time zones. 583 * This is a two dimensional <code>String</code> array where each row in 584 * the array contains five values: 585 * <P> 586 * <ul> 587 * <li>0 - The non-localized time zone id string.</li> 588 * <li>1 - The long name of the time zone (standard time).</li> 589 * <li>2 - The short name of the time zone (standard time).</li> 590 * <li>3 - The long name of the time zone (daylight savings time).</li> 591 * <li>4 - the short name of the time zone (daylight savings time).</li> 592 * </ul> 593 * 594 * @params zones The list of time zone display strings. 595 */ 596 public void setZoneStrings (String[][] zones) 597 { 598 if(zones==null) 599 throw new NullPointerException(); 600 zoneStrings = zones; 601 } 602 603 /* Does a "deep" equality test - recurses into arrays. */ 604 private static boolean equals (Object x, Object y) 605 { 606 if (x == y) 607 return true; 608 if (x == null || y == null) 609 return false; 610 if (! (x instanceof Object[]) || ! (y instanceof Object[])) 611 return x.equals(y); 612 Object[] xa = (Object[]) x; 613 Object[] ya = (Object[]) y; 614 if (xa.length != ya.length) 615 return false; 616 for (int i = xa.length; --i >= 0; ) 617 { 618 if (! equals(xa[i], ya[i])) 619 return false; 620 } 621 return true; 622 } 623 624 private static int hashCode (Object x) 625 { 626 if (x == null) 627 return 0; 628 if (! (x instanceof Object[])) 629 return x.hashCode(); 630 Object[] xa = (Object[]) x; 631 int hash = 0; 632 for (int i = 0; i < xa.length; i++) 633 hash = 37 * hashCode(xa[i]); 634 return hash; 635 } 636 637 /** 638 * This method tests a specified object for equality against this object. 639 * This will be true if and only if the specified object: 640 * <p> 641 * <ul> 642 * <li> Is not <code>null</code>.</li> 643 * <li> Is an instance of <code>DateFormatSymbols</code>.</li> 644 * <li> Contains identical formatting symbols to this object.</li> 645 * </ul> 646 * 647 * @param obj The <code>Object</code> to test for equality against. 648 * 649 * @return <code>true</code> if the specified object is equal to this one, 650 * <code>false</code> otherwise. 651 */ 652 public boolean equals (Object obj) 653 { 654 if (! (obj instanceof DateFormatSymbols)) 655 return false; 656 DateFormatSymbols other = (DateFormatSymbols) obj; 657 return (equals(ampms, other.ampms) 658 && equals(eras, other.eras) 659 && equals(localPatternChars, other.localPatternChars) 660 && equals(months, other.months) 661 && equals(shortMonths, other.shortMonths) 662 && equals(shortWeekdays, other.shortWeekdays) 663 && equals(weekdays, other.weekdays) 664 && equals(zoneStrings, other.zoneStrings)); 665 } 666 667 /** 668 * Returns a new copy of this object. 669 * 670 * @return A copy of this object 671 */ 672 public Object clone () 673 { 674 try 675 { 676 return super.clone (); 677 } 678 catch (CloneNotSupportedException e) 679 { 680 return null; 681 } 682 } 683 684 /** 685 * This method returns a hash value for this object. 686 * 687 * @return A hash value for this object. 688 */ 689 public int hashCode () 690 { 691 return (hashCode(ampms) 692 ^ hashCode(eras) 693 ^ hashCode(localPatternChars) 694 ^ hashCode(months) 695 ^ hashCode(shortMonths) 696 ^ hashCode(shortWeekdays) 697 ^ hashCode(weekdays) 698 ^ hashCode(zoneStrings)); 699 } 700 701 /** 702 * Returns a {@link DateFormatSymbols} instance for the 703 * default locale obtained from either the runtime itself 704 * or one of the installed 705 * {@link java.text.spi.DateFormatSymbolsProvider} instances. 706 * This is equivalent to calling 707 * <code>getInstance(Locale.getDefault())</code>. 708 * 709 * @return a {@link DateFormatSymbols} instance for the default 710 * locale. 711 * @since 1.6 712 */ 713 public static final DateFormatSymbols getInstance() 714 { 715 return getInstance(Locale.getDefault()); 716 } 717 718 /** 719 * Returns a {@link DateFormatSymbols} instance for the 720 * specified locale obtained from either the runtime itself 721 * or one of the installed 722 * {@link java.text.spi.DateFormatSymbolsProvider} instances. 723 * 724 * @param locale the locale for which an instance should be 725 * returned. 726 * @return a {@link DateFormatSymbols} instance for the specified 727 * locale. 728 * @throws NullPointerException if <code>locale</code> is 729 * <code>null</code>. 730 * @since 1.6 731 */ 732 public static final DateFormatSymbols getInstance(Locale locale) 733 { 734 try 735 { 736 DateFormatSymbols syms = new DateFormatSymbols(locale); 737 return syms; 738 } 739 catch (MissingResourceException e) 740 { 741 /* This means runtime support for the locale 742 * is not available, so we check providers. */ 743 } 744 for (DateFormatSymbolsProvider p : 745 ServiceLoader.load(DateFormatSymbolsProvider.class)) 746 { 747 for (Locale loc : p.getAvailableLocales()) 748 { 749 if (loc.equals(locale)) 750 { 751 DateFormatSymbols syms = p.getInstance(locale); 752 if (syms != null) 753 return syms; 754 break; 755 } 756 } 757 } 758 return getInstance(LocaleHelper.getFallbackLocale(locale)); 759 } 760 761}