1 /* 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.util.locale.provider; 27 28 import java.lang.ref.SoftReference; 29 import java.text.*; 30 import java.text.spi.DateFormatProvider; 31 import java.text.spi.DateFormatSymbolsProvider; 32 import java.text.spi.DecimalFormatSymbolsProvider; 33 import java.text.spi.NumberFormatProvider; 34 import java.util.Collections; 35 import java.util.HashSet; 36 import java.util.Locale; 37 import java.util.Map; 38 import java.util.ResourceBundle.Control; 39 import java.util.Set; 40 import java.util.concurrent.ConcurrentHashMap; 41 import java.util.concurrent.ConcurrentMap; 42 import java.util.concurrent.atomic.AtomicReferenceArray; 43 import java.util.spi.CalendarDataProvider; 44 import java.util.spi.CalendarNameProvider; 45 import java.util.spi.CurrencyNameProvider; 46 import java.util.spi.LocaleNameProvider; 47 import java.util.spi.TimeZoneNameProvider; 48 49 /** 50 * LocaleProviderAdapter implementation for the Mac OS X locale data 51 * 52 * @author Naoto Sato 53 */ 54 public class HostLocaleProviderAdapterImpl { 55 56 // per supported locale instances 57 private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatPatternsMap = 58 new ConcurrentHashMap<>(2); 59 private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatPatternsMap = 60 new ConcurrentHashMap<>(2); 61 private static ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsMap = 62 new ConcurrentHashMap<>(2); 63 private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsMap = 64 new ConcurrentHashMap<>(2); 65 66 // locale categories 67 private static final int CAT_DISPLAY = 0; 68 private static final int CAT_FORMAT = 1; 69 70 // NumberFormat styles 71 private static final int NF_NUMBER = 0; 72 private static final int NF_CURRENCY = 1; 73 private static final int NF_PERCENT = 2; 74 private static final int NF_INTEGER = 3; 75 private static final int NF_MAX = NF_INTEGER; 76 77 // CalendarData value types 78 private static final int CD_FIRSTDAYOFWEEK = 0; 79 private static final int CD_MINIMALDAYSINFIRSTWEEK = 1; 80 81 // Locale/Currency display name types 82 private static final int DN_LOCALE_LANGUAGE = 0; 83 private static final int DN_LOCALE_SCRIPT = 1; 84 private static final int DN_LOCALE_REGION = 2; 85 private static final int DN_LOCALE_VARIANT = 3; 86 private static final int DN_CURRENCY_CODE = 4; 87 private static final int DN_CURRENCY_SYMBOL = 5; 88 89 // TimeZone display name types 90 private static final int DN_TZ_SHORT_STANDARD = 0; 91 private static final int DN_TZ_SHORT_DST = 1; 92 private static final int DN_TZ_LONG_STANDARD = 2; 93 private static final int DN_TZ_LONG_DST = 3; 94 95 private static final Set<Locale> supportedLocaleSet; 96 static { 97 Set<Locale> tmpSet = new HashSet<Locale>(); 98 // Assuming the default locales do not include any extensions, so 99 // no stripping is needed here. 100 Locale l = Locale.forLanguageTag(getDefaultLocale(CAT_FORMAT).replaceAll("_","-")); 101 tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l)); 102 l = Locale.forLanguageTag(getDefaultLocale(CAT_DISPLAY).replaceAll("_","-")); 103 tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l)); 104 supportedLocaleSet = Collections.unmodifiableSet(tmpSet); 105 } 106 private final static Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]); 107 108 public static DateFormatProvider getDateFormatProvider() { 109 return new DateFormatProvider() { 110 111 @Override 112 public Locale[] getAvailableLocales() { 113 return getSupportedCalendarLocales(); 114 } 115 116 @Override 117 public boolean isSupportedLocale(Locale locale) { 118 return isSupportedCalendarLocale(locale); 119 } 120 121 @Override 122 public DateFormat getDateInstance(int style, Locale locale) { 123 return new SimpleDateFormat(getDateTimePattern(style, -1, locale), 124 getCalendarLocale(locale)); 125 } 126 127 @Override 128 public DateFormat getTimeInstance(int style, Locale locale) { 129 return new SimpleDateFormat(getDateTimePattern(-1, style, locale), 130 getCalendarLocale(locale)); 131 } 132 133 @Override 134 public DateFormat getDateTimeInstance(int dateStyle, 135 int timeStyle, Locale locale) { 136 return new SimpleDateFormat(getDateTimePattern(dateStyle, timeStyle, locale), 137 getCalendarLocale(locale)); 138 } 139 140 private String getDateTimePattern(int dateStyle, int timeStyle, Locale locale) { 141 AtomicReferenceArray<String> dateFormatPatterns; 142 SoftReference<AtomicReferenceArray<String>> ref = dateFormatPatternsMap.get(locale); 143 144 if (ref == null || (dateFormatPatterns = ref.get()) == null) { 145 dateFormatPatterns = new AtomicReferenceArray<>(5 * 5); 146 ref = new SoftReference<>(dateFormatPatterns); 147 dateFormatPatternsMap.put(locale, ref); 148 } 149 150 int index = (dateStyle + 1) * 5 + timeStyle + 1; 151 String pattern = dateFormatPatterns.get(index); 152 if (pattern == null) { 153 String langTag = locale.toLanguageTag(); 154 pattern = translateDateFormatLetters(getCalendarID(langTag), 155 getDateTimePatternNative(dateStyle, timeStyle, langTag)); 156 if (!dateFormatPatterns.compareAndSet(index, null, pattern)) { 157 pattern = dateFormatPatterns.get(index); 158 } 159 } 160 161 return pattern; 162 } 163 }; 164 } 165 166 public static DateFormatSymbolsProvider getDateFormatSymbolsProvider() { 167 return new DateFormatSymbolsProvider() { 168 @Override 169 public Locale[] getAvailableLocales() { 170 if (isSupportedLocale(Locale.getDefault(Locale.Category.FORMAT))) { 171 return supportedLocale; 172 } 173 174 return new Locale[0]; 175 } 176 177 @Override 178 public boolean isSupportedLocale(Locale locale) { 179 // Only supports the locale with Gregorian calendar 180 Locale base = locale.stripExtensions(); 181 if (supportedLocaleSet.contains(base)) { 182 return getCalendarID(locale.toLanguageTag()).equals("gregorian"); 183 } 184 return false; 185 } 186 187 @Override 188 public DateFormatSymbols getInstance(Locale locale) { 189 DateFormatSymbols dateFormatSymbols; 190 SoftReference<DateFormatSymbols> ref = dateFormatSymbolsMap.get(locale); 191 192 if (ref == null || (dateFormatSymbols = ref.get()) == null) { 193 dateFormatSymbols = new DateFormatSymbols(locale); 194 String langTag = locale.toLanguageTag(); 195 dateFormatSymbols.setAmPmStrings(getAmPmStrings(langTag, dateFormatSymbols.getAmPmStrings())); 196 dateFormatSymbols.setEras(getEras(langTag, dateFormatSymbols.getEras())); 197 dateFormatSymbols.setMonths(getMonths(langTag, dateFormatSymbols.getMonths())); 198 dateFormatSymbols.setShortMonths(getShortMonths(langTag, dateFormatSymbols.getShortMonths())); 199 dateFormatSymbols.setWeekdays(getWeekdays(langTag, dateFormatSymbols.getWeekdays())); 200 dateFormatSymbols.setShortWeekdays(getShortWeekdays(langTag, dateFormatSymbols.getShortWeekdays())); 201 ref = new SoftReference<>(dateFormatSymbols); 202 dateFormatSymbolsMap.put(locale, ref); 203 } 204 return (DateFormatSymbols)dateFormatSymbols.clone(); 205 } 206 }; 207 } 208 209 public static NumberFormatProvider getNumberFormatProvider() { 210 return new NumberFormatProvider() { 211 @Override 212 public Locale[] getAvailableLocales() { 213 return supportedLocale; 214 } 215 216 @Override 217 public boolean isSupportedLocale(Locale locale) { 218 // Ignore the extensions for now 219 return supportedLocaleSet.contains(locale.stripExtensions()); 220 } 221 222 @Override 223 public NumberFormat getCurrencyInstance(Locale locale) { 224 return new DecimalFormat(getNumberPattern(NF_CURRENCY, locale), 225 DecimalFormatSymbols.getInstance(locale)); 226 } 227 228 @Override 229 public NumberFormat getIntegerInstance(Locale locale) { 230 return new DecimalFormat(getNumberPattern(NF_INTEGER, locale), 231 DecimalFormatSymbols.getInstance(locale)); 232 } 233 234 @Override 235 public NumberFormat getNumberInstance(Locale locale) { 236 return new DecimalFormat(getNumberPattern(NF_NUMBER, locale), 237 DecimalFormatSymbols.getInstance(locale)); 238 } 239 240 @Override 241 public NumberFormat getPercentInstance(Locale locale) { 242 return new DecimalFormat(getNumberPattern(NF_PERCENT, locale), 243 DecimalFormatSymbols.getInstance(locale)); 244 } 245 246 private String getNumberPattern(int style, Locale locale) { 247 AtomicReferenceArray<String> numberFormatPatterns; 248 SoftReference<AtomicReferenceArray<String>> ref = numberFormatPatternsMap.get(locale); 249 250 if (ref == null || (numberFormatPatterns = ref.get()) == null) { 251 numberFormatPatterns = new AtomicReferenceArray<>(4); 252 ref = new SoftReference<>(numberFormatPatterns); 253 numberFormatPatternsMap.put(locale, ref); 254 } 255 256 String pattern = numberFormatPatterns.get(style); 257 if (pattern == null) { 258 pattern = getNumberPatternNative(style, locale.toLanguageTag()); 259 if (!numberFormatPatterns.compareAndSet(style, null, pattern)) { 260 pattern = numberFormatPatterns.get(style); 261 } 262 } 263 264 return pattern; 265 } 266 }; 267 } 268 269 public static DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() { 270 return new DecimalFormatSymbolsProvider() { 271 272 @Override 273 public Locale[] getAvailableLocales() { 274 return supportedLocale; 275 } 276 277 @Override 278 public boolean isSupportedLocale(Locale locale) { 279 // Ignore the extensions for now 280 return supportedLocaleSet.contains(locale.stripExtensions()); 281 } 282 283 @Override 284 public DecimalFormatSymbols getInstance(Locale locale) { 285 DecimalFormatSymbols decimalFormatSymbols; 286 SoftReference<DecimalFormatSymbols> ref = decimalFormatSymbolsMap.get(locale); 287 288 if (ref == null || (decimalFormatSymbols = ref.get()) == null) { 289 decimalFormatSymbols = new DecimalFormatSymbols(locale); 290 String langTag = locale.toLanguageTag(); 291 292 // DecimalFormatSymbols.setInternationalCurrencySymbol() has 293 // a side effect of setting the currency symbol as well. So 294 // the calling order is relevant here. 295 decimalFormatSymbols.setInternationalCurrencySymbol(getInternationalCurrencySymbol(langTag, decimalFormatSymbols.getInternationalCurrencySymbol())); 296 decimalFormatSymbols.setCurrencySymbol(getCurrencySymbol(langTag, decimalFormatSymbols.getCurrencySymbol())); 297 decimalFormatSymbols.setDecimalSeparator(getDecimalSeparator(langTag, decimalFormatSymbols.getDecimalSeparator())); 298 decimalFormatSymbols.setGroupingSeparator(getGroupingSeparator(langTag, decimalFormatSymbols.getGroupingSeparator())); 299 decimalFormatSymbols.setInfinity(getInfinity(langTag, decimalFormatSymbols.getInfinity())); 300 decimalFormatSymbols.setMinusSign(getMinusSign(langTag, decimalFormatSymbols.getMinusSign())); 301 decimalFormatSymbols.setMonetaryDecimalSeparator(getMonetaryDecimalSeparator(langTag, decimalFormatSymbols.getMonetaryDecimalSeparator())); 302 decimalFormatSymbols.setNaN(getNaN(langTag, decimalFormatSymbols.getNaN())); 303 decimalFormatSymbols.setPercent(getPercent(langTag, decimalFormatSymbols.getPercent())); 304 decimalFormatSymbols.setPerMill(getPerMill(langTag, decimalFormatSymbols.getPerMill())); 305 decimalFormatSymbols.setZeroDigit(getZeroDigit(langTag, decimalFormatSymbols.getZeroDigit())); 306 decimalFormatSymbols.setExponentSeparator(getExponentSeparator(langTag, decimalFormatSymbols.getExponentSeparator())); 307 ref = new SoftReference<>(decimalFormatSymbols); 308 decimalFormatSymbolsMap.put(locale, ref); 309 } 310 return (DecimalFormatSymbols)decimalFormatSymbols.clone(); 311 } 312 }; 313 } 314 315 public static CalendarDataProvider getCalendarDataProvider() { 316 return new CalendarDataProvider() { 317 @Override 318 public Locale[] getAvailableLocales() { 319 return getSupportedCalendarLocales(); 320 } 321 322 @Override 323 public boolean isSupportedLocale(Locale locale) { 324 return isSupportedCalendarLocale(locale); 325 } 326 327 @Override 328 public int getFirstDayOfWeek(Locale locale) { 329 return getCalendarInt(locale.toLanguageTag(), CD_FIRSTDAYOFWEEK); 330 } 331 332 @Override 333 public int getMinimalDaysInFirstWeek(Locale locale) { 334 return getCalendarInt(locale.toLanguageTag(), CD_MINIMALDAYSINFIRSTWEEK); 335 } 336 }; 337 } 338 339 public static CalendarNameProvider getCalendarNameProvider() { 340 return new CalendarNameProvider() { 341 @Override 342 public Locale[] getAvailableLocales() { 343 return getSupportedCalendarLocales(); 344 } 345 346 @Override 347 public boolean isSupportedLocale(Locale locale) { 348 return isSupportedCalendarLocale(locale); 349 } 350 351 @Override 352 public String getDisplayName(String calType, int field, int value, 353 int style, Locale locale) { 354 return null; 355 } 356 357 @Override 358 public Map<String, Integer> getDisplayNames(String calType, 359 int field, int style, Locale locale) { 360 return null; 361 } 362 }; 363 } 364 365 public static CurrencyNameProvider getCurrencyNameProvider() { 366 return new CurrencyNameProvider() { 367 @Override 368 public Locale[] getAvailableLocales() { 369 return supportedLocale; 370 } 371 372 @Override 373 public boolean isSupportedLocale(Locale locale) { 374 // Ignore the extensions for now 375 return supportedLocaleSet.contains(locale.stripExtensions()); 376 } 377 378 @Override 379 public String getDisplayName(String code, Locale locale) { 380 return getDisplayString(locale.toLanguageTag(), DN_CURRENCY_CODE, code); 381 } 382 383 @Override 384 public String getSymbol(String code, Locale locale) { 385 return getDisplayString(locale.toLanguageTag(), DN_CURRENCY_SYMBOL, code); 386 } 387 }; 388 } 389 390 public static LocaleNameProvider getLocaleNameProvider() { 391 return new LocaleNameProvider() { 392 @Override 393 public Locale[] getAvailableLocales() { 394 return supportedLocale; 395 } 396 397 @Override 398 public boolean isSupportedLocale(Locale locale) { 399 // Ignore the extensions for now 400 return supportedLocaleSet.contains(locale.stripExtensions()); 401 } 402 403 @Override 404 public String getDisplayLanguage(String languageCode, Locale locale) { 405 return getDisplayString(locale.toLanguageTag(), DN_LOCALE_LANGUAGE, languageCode); 406 } 407 408 @Override 409 public String getDisplayCountry(String countryCode, Locale locale) { 410 return getDisplayString(locale.toLanguageTag(), DN_LOCALE_REGION, countryCode); 411 } 412 413 @Override 414 public String getDisplayScript(String scriptCode, Locale locale) { 415 return getDisplayString(locale.toLanguageTag(), DN_LOCALE_SCRIPT, scriptCode); 416 } 417 418 @Override 419 public String getDisplayVariant(String variantCode, Locale locale) { 420 return getDisplayString(locale.toLanguageTag(), DN_LOCALE_VARIANT, variantCode); 421 } 422 }; 423 } 424 425 public static TimeZoneNameProvider getTimeZoneNameProvider() { 426 return new TimeZoneNameProvider() { 427 @Override 428 public Locale[] getAvailableLocales() { 429 return supportedLocale; 430 } 431 432 @Override 433 public boolean isSupportedLocale(Locale locale) { 434 // Ignore the extensions for now 435 return supportedLocaleSet.contains(locale.stripExtensions()); 436 } 437 438 @Override 439 public String getDisplayName(String ID, boolean daylight, int style, Locale locale) { 440 return getTimeZoneDisplayString(locale.toLanguageTag(), style * 2 + (daylight ? 1 : 0), ID); 441 } 442 }; 443 } 444 445 private static Locale[] getSupportedCalendarLocales() { 446 if (supportedLocale.length != 0 && 447 supportedLocaleSet.contains(Locale.JAPAN) && 448 isJapaneseCalendar()) { 449 Locale[] sup = new Locale[supportedLocale.length+1]; 450 sup[0] = JRELocaleConstants.JA_JP_JP; 451 System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length); 452 return sup; 453 } 454 return supportedLocale; 455 } 456 457 private static boolean isSupportedCalendarLocale(Locale locale) { 458 // special case for ja_JP_JP 459 if (JRELocaleConstants.JA_JP_JP.equals(locale)) { 460 return isJapaneseCalendar(); 461 } 462 463 Locale base = locale.stripExtensions(); 464 if (!supportedLocaleSet.contains(base)) { 465 return false; 466 } 467 468 String caltype = locale.getUnicodeLocaleType("ca"); 469 if (caltype == null) { 470 return true; 471 } 472 473 return caltype.replaceFirst("gregory", "gregorian").equals( 474 getCalendarID(locale.toLanguageTag())); 475 } 476 477 private static boolean isJapaneseCalendar() { 478 return getCalendarID("ja-JP").equals("japanese"); 479 } 480 481 private static Locale getCalendarLocale(Locale locale) { 482 Locale.Builder lb = new Locale.Builder().setLocale(locale); 483 String calid = getCalendarID(locale.toLanguageTag()); 484 switch (calid) { 485 case "gregorian": 486 calid = "gregory"; 487 // FALL THROUGH! 488 case "japanese": 489 case "buddhist": 490 lb.setUnicodeLocaleKeyword("ca", calid); 491 return lb.build(); 492 default: 493 return locale; 494 } 495 } 496 497 // The following methods are copied from CLDRConverter build tool. 498 private static String translateDateFormatLetters(String calendarType, String cldrFormat) { 499 String pattern = cldrFormat; 500 int length = pattern.length(); 501 boolean inQuote = false; 502 StringBuilder jrePattern = new StringBuilder(length); 503 int count = 0; 504 char lastLetter = 0; 505 506 for (int i = 0; i < length; i++) { 507 char c = pattern.charAt(i); 508 509 if (c == '\'') { 510 // '' is treated as a single quote regardless of being 511 // in a quoted section. 512 if ((i + 1) < length) { 513 char nextc = pattern.charAt(i + 1); 514 if (nextc == '\'') { 515 i++; 516 if (count != 0) { 517 convert(calendarType, lastLetter, count, jrePattern); 518 lastLetter = 0; 519 count = 0; 520 } 521 jrePattern.append("''"); 522 continue; 523 } 524 } 525 if (!inQuote) { 526 if (count != 0) { 527 convert(calendarType, lastLetter, count, jrePattern); 528 lastLetter = 0; 529 count = 0; 530 } 531 inQuote = true; 532 } else { 533 inQuote = false; 534 } 535 jrePattern.append(c); 536 continue; 537 } 538 if (inQuote) { 539 jrePattern.append(c); 540 continue; 541 } 542 if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) { 543 if (count != 0) { 544 convert(calendarType, lastLetter, count, jrePattern); 545 lastLetter = 0; 546 count = 0; 547 } 548 jrePattern.append(c); 549 continue; 550 } 551 552 if (lastLetter == 0 || lastLetter == c) { 553 lastLetter = c; 554 count++; 555 continue; 556 } 557 convert(calendarType, lastLetter, count, jrePattern); 558 lastLetter = c; 559 count = 1; 560 } 561 562 if (count != 0) { 563 convert(calendarType, lastLetter, count, jrePattern); 564 } 565 if (cldrFormat.contentEquals(jrePattern)) { 566 return cldrFormat; 567 } 568 return jrePattern.toString(); 569 } 570 571 private static void convert(String calendarType, char cldrLetter, int count, StringBuilder sb) { 572 switch (cldrLetter) { 573 case 'G': 574 if (!calendarType.equals("gregorian")) { 575 // Adjust the number of 'G's for JRE SimpleDateFormat 576 if (count == 5) { 577 // CLDR narrow -> JRE short 578 count = 1; 579 } else if (count == 1) { 580 // CLDR abbr -> JRE long 581 count = 4; 582 } 583 } 584 appendN(cldrLetter, count, sb); 585 break; 586 587 // TODO: support 'c' and 'e' in JRE SimpleDateFormat 588 // Use 'u' and 'E' for now. 589 case 'c': 590 case 'e': 591 switch (count) { 592 case 1: 593 sb.append('u'); 594 break; 595 case 3: 596 case 4: 597 appendN('E', count, sb); 598 break; 599 case 5: 600 appendN('E', 3, sb); 601 break; 602 } 603 break; 604 605 case 'v': 606 case 'V': 607 appendN('z', count, sb); 608 break; 609 610 case 'Z': 611 if (count == 4 || count == 5) { 612 sb.append("XXX"); 613 } 614 break; 615 616 case 'u': 617 case 'U': 618 case 'q': 619 case 'Q': 620 case 'l': 621 case 'g': 622 case 'j': 623 case 'A': 624 // Unsupported letter. Just append it within quotes 625 sb.append('\''); 626 sb.append(cldrLetter); 627 sb.append('\''); 628 break; 629 630 default: 631 appendN(cldrLetter, count, sb); 632 break; 633 } 634 } 635 636 private static void appendN(char c, int n, StringBuilder sb) { 637 for (int i = 0; i < n; i++) { 638 sb.append(c); 639 } 640 } 641 642 // initialize 643 private static native String getDefaultLocale(int cat); 644 645 // For DateFormatProvider 646 private static native String getDateTimePatternNative(int dateStyle, int timeStyle, String langtag); 647 private static native String getCalendarID(String langTag); 648 649 // For NumberFormatProvider 650 private static native String getNumberPatternNative(int style, String langtag); 651 652 // For DateFormatSymbolsProvider 653 private static native String[] getAmPmStrings(String langTag, String[] ampm); 654 private static native String[] getEras(String langTag, String[] eras); 655 private static native String[] getMonths(String langTag, String[] months); 656 private static native String[] getShortMonths(String langTag, String[] smonths); 657 private static native String[] getWeekdays(String langTag, String[] wdays); 658 private static native String[] getShortWeekdays(String langTag, String[] swdays); 659 660 // For DecimalFormatSymbolsProvider 661 private static native String getCurrencySymbol(String langTag, String currencySymbol); 662 private static native char getDecimalSeparator(String langTag, char decimalSeparator); 663 private static native char getGroupingSeparator(String langTag, char groupingSeparator); 664 private static native String getInfinity(String langTag, String infinity); 665 private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol); 666 private static native char getMinusSign(String langTag, char minusSign); 667 private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator); 668 private static native String getNaN(String langTag, String nan); 669 private static native char getPercent(String langTag, char percent); 670 private static native char getPerMill(String langTag, char perMill); 671 private static native char getZeroDigit(String langTag, char zeroDigit); 672 private static native String getExponentSeparator(String langTag, String exponent); 673 674 // For CalendarDataProvider 675 private static native int getCalendarInt(String langTag, int type); 676 677 // For Locale/CurrencyNameProvider 678 private static native String getDisplayString(String langTag, int key, String value); 679 680 // For TimeZoneNameProvider 681 private static native String getTimeZoneDisplayString(String langTag, int style, String value); 682 }