Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java
41149 views
1
/*
2
* Copyright (c) 2012, 2020, 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
package sun.util.locale.provider;
26
27
import java.lang.ref.SoftReference;
28
import java.text.DateFormat;
29
import java.text.DateFormatSymbols;
30
import java.text.DecimalFormat;
31
import java.text.DecimalFormatSymbols;
32
import java.text.NumberFormat;
33
import java.text.SimpleDateFormat;
34
import java.text.spi.DateFormatProvider;
35
import java.text.spi.DateFormatSymbolsProvider;
36
import java.text.spi.DecimalFormatSymbolsProvider;
37
import java.text.spi.NumberFormatProvider;
38
import java.util.Calendar;
39
import java.util.Collections;
40
import java.util.Currency;
41
import java.util.HashMap;
42
import java.util.HashSet;
43
import java.util.Locale;
44
import java.util.Map;
45
import java.util.ResourceBundle.Control;
46
import java.util.Set;
47
import java.util.TimeZone;
48
import java.util.concurrent.ConcurrentHashMap;
49
import java.util.concurrent.ConcurrentMap;
50
import java.util.concurrent.atomic.AtomicReferenceArray;
51
import java.util.spi.CalendarDataProvider;
52
import java.util.spi.CalendarNameProvider;
53
import java.util.spi.CurrencyNameProvider;
54
import java.util.spi.LocaleNameProvider;
55
import sun.text.spi.JavaTimeDateTimePatternProvider;
56
import sun.util.spi.CalendarProvider;
57
58
/**
59
* LocaleProviderdapter implementation for the Windows locale data.
60
*
61
* @author Naoto Sato
62
*/
63
public class HostLocaleProviderAdapterImpl {
64
65
// locale categories
66
private static final int CAT_DISPLAY = 0;
67
private static final int CAT_FORMAT = 1;
68
69
// NumberFormat styles
70
private static final int NF_NUMBER = 0;
71
private static final int NF_CURRENCY = 1;
72
private static final int NF_PERCENT = 2;
73
private static final int NF_INTEGER = 3;
74
private static final int NF_MAX = NF_INTEGER;
75
76
// CalendarData value types
77
private static final int CD_FIRSTDAYOFWEEK = 0;
78
private static final int CD_FIRSTWEEKOFYEAR = 1;
79
80
// Currency/Locale display name types
81
private static final int DN_CURRENCY_NAME = 0;
82
private static final int DN_CURRENCY_SYMBOL = 1;
83
private static final int DN_LOCALE_LANGUAGE = 2;
84
private static final int DN_LOCALE_SCRIPT = 3;
85
private static final int DN_LOCALE_REGION = 4;
86
private static final int DN_LOCALE_VARIANT = 5;
87
88
// Windows Calendar IDs
89
private static final int CAL_JAPAN = 3;
90
91
// Native Calendar ID to LDML calendar type map
92
private static final String[] calIDToLDML = {
93
"",
94
"gregory",
95
"gregory_en-US",
96
"japanese",
97
"roc",
98
"", // No appropriate type for CAL_KOREA
99
"islamic",
100
"buddhist",
101
"hebrew",
102
"gregory_fr",
103
"gregory_ar",
104
"gregory_en",
105
"gregory_fr", "", "", "", "", "", "", "", "", "", "",
106
"islamic-umalqura",
107
};
108
109
// Caches
110
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
111
private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
112
private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
113
private static final ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
114
115
private static final Set<Locale> supportedLocaleSet;
116
private static final String nativeDisplayLanguage;
117
static {
118
Set<Locale> tmpSet = new HashSet<>();
119
if (initialize()) {
120
// Assuming the default locales do not include any extensions, so
121
// no stripping is needed here.
122
Control c = Control.getNoFallbackControl(Control.FORMAT_DEFAULT);
123
String displayLocale = getDefaultLocale(CAT_DISPLAY);
124
Locale l = Locale.forLanguageTag(displayLocale.replace('_', '-'));
125
tmpSet.addAll(c.getCandidateLocales("", l));
126
nativeDisplayLanguage = l.getLanguage();
127
128
String formatLocale = getDefaultLocale(CAT_FORMAT);
129
if (!formatLocale.equals(displayLocale)) {
130
l = Locale.forLanguageTag(formatLocale.replace('_', '-'));
131
tmpSet.addAll(c.getCandidateLocales("", l));
132
}
133
} else {
134
nativeDisplayLanguage = "";
135
}
136
supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
137
}
138
private static final Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
139
140
public static DateFormatProvider getDateFormatProvider() {
141
return new DateFormatProvider() {
142
@Override
143
public Locale[] getAvailableLocales() {
144
return getSupportedCalendarLocales();
145
}
146
147
@Override
148
public boolean isSupportedLocale(Locale locale) {
149
return isSupportedCalendarLocale(locale);
150
}
151
152
@Override
153
public DateFormat getDateInstance(int style, Locale locale) {
154
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
155
return new SimpleDateFormat(patterns.get(style/2),
156
getCalendarLocale(locale));
157
}
158
159
@Override
160
public DateFormat getTimeInstance(int style, Locale locale) {
161
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
162
return new SimpleDateFormat(patterns.get(style/2+2),
163
getCalendarLocale(locale));
164
}
165
166
@Override
167
public DateFormat getDateTimeInstance(int dateStyle,
168
int timeStyle, Locale locale) {
169
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
170
String pattern = new StringBuilder(patterns.get(dateStyle/2))
171
.append(" ")
172
.append(patterns.get(timeStyle/2+2))
173
.toString();
174
return new SimpleDateFormat(pattern, getCalendarLocale(locale));
175
}
176
177
private AtomicReferenceArray<String> getDateTimePatterns(Locale locale) {
178
AtomicReferenceArray<String> patterns;
179
SoftReference<AtomicReferenceArray<String>> ref = dateFormatCache.get(locale);
180
181
if (ref == null || (patterns = ref.get()) == null) {
182
String langtag = removeExtensions(locale).toLanguageTag();
183
patterns = new AtomicReferenceArray<>(4);
184
patterns.compareAndSet(0, null, convertDateTimePattern(
185
getDateTimePattern(DateFormat.LONG, -1, langtag)));
186
patterns.compareAndSet(1, null, convertDateTimePattern(
187
getDateTimePattern(DateFormat.SHORT, -1, langtag)));
188
patterns.compareAndSet(2, null, convertDateTimePattern(
189
getDateTimePattern(-1, DateFormat.LONG, langtag)));
190
patterns.compareAndSet(3, null, convertDateTimePattern(
191
getDateTimePattern(-1, DateFormat.SHORT, langtag)));
192
ref = new SoftReference<>(patterns);
193
dateFormatCache.put(locale, ref);
194
}
195
196
return patterns;
197
}
198
};
199
}
200
201
public static DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
202
return new DateFormatSymbolsProvider() {
203
204
@Override
205
public Locale[] getAvailableLocales() {
206
return getSupportedCalendarLocales();
207
}
208
209
@Override
210
public boolean isSupportedLocale(Locale locale) {
211
return isSupportedCalendarLocale(locale);
212
}
213
214
@Override
215
public DateFormatSymbols getInstance(Locale locale) {
216
DateFormatSymbols dfs;
217
SoftReference<DateFormatSymbols> ref =
218
dateFormatSymbolsCache.get(locale);
219
220
if (ref == null || (dfs = ref.get()) == null) {
221
dfs = new DateFormatSymbols(locale);
222
String langTag = removeExtensions(locale).toLanguageTag();
223
224
dfs.setAmPmStrings(getAmPmStrings(langTag, dfs.getAmPmStrings()));
225
dfs.setEras(getEras(langTag, dfs.getEras()));
226
dfs.setMonths(getMonths(langTag, dfs.getMonths()));
227
dfs.setShortMonths(getShortMonths(langTag, dfs.getShortMonths()));
228
dfs.setWeekdays(getWeekdays(langTag, dfs.getWeekdays()));
229
dfs.setShortWeekdays(getShortWeekdays(langTag, dfs.getShortWeekdays()));
230
ref = new SoftReference<>(dfs);
231
dateFormatSymbolsCache.put(locale, ref);
232
}
233
return (DateFormatSymbols)dfs.clone();
234
}
235
};
236
}
237
238
public static NumberFormatProvider getNumberFormatProvider() {
239
return new NumberFormatProvider() {
240
241
@Override
242
public Locale[] getAvailableLocales() {
243
return getSupportedNativeDigitLocales();
244
}
245
246
@Override
247
public boolean isSupportedLocale(Locale locale) {
248
return isSupportedNativeDigitLocale(locale);
249
}
250
251
@Override
252
public NumberFormat getCurrencyInstance(Locale locale) {
253
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
254
return new DecimalFormat(patterns.get(NF_CURRENCY),
255
DecimalFormatSymbols.getInstance(locale));
256
}
257
258
@Override
259
public NumberFormat getIntegerInstance(Locale locale) {
260
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
261
DecimalFormat format = new DecimalFormat(patterns.get(NF_INTEGER),
262
DecimalFormatSymbols.getInstance(locale));
263
return HostLocaleProviderAdapter.makeIntegerFormatter(format);
264
}
265
266
@Override
267
public NumberFormat getNumberInstance(Locale locale) {
268
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
269
return new DecimalFormat(patterns.get(NF_NUMBER),
270
DecimalFormatSymbols.getInstance(locale));
271
}
272
273
@Override
274
public NumberFormat getPercentInstance(Locale locale) {
275
AtomicReferenceArray<String> patterns = getNumberPatterns(locale);
276
return new DecimalFormat(patterns.get(NF_PERCENT),
277
DecimalFormatSymbols.getInstance(locale));
278
}
279
280
private AtomicReferenceArray<String> getNumberPatterns(Locale locale) {
281
AtomicReferenceArray<String> patterns;
282
SoftReference<AtomicReferenceArray<String>> ref = numberFormatCache.get(locale);
283
284
if (ref == null || (patterns = ref.get()) == null) {
285
String langtag = locale.toLanguageTag();
286
patterns = new AtomicReferenceArray<>(NF_MAX+1);
287
for (int i = 0; i <= NF_MAX; i++) {
288
patterns.compareAndSet(i, null, getNumberPattern(i, langtag));
289
}
290
ref = new SoftReference<>(patterns);
291
numberFormatCache.put(locale, ref);
292
}
293
return patterns;
294
}
295
};
296
}
297
298
public static DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
299
return new DecimalFormatSymbolsProvider() {
300
301
@Override
302
public Locale[] getAvailableLocales() {
303
return getSupportedNativeDigitLocales();
304
}
305
306
@Override
307
public boolean isSupportedLocale(Locale locale) {
308
return isSupportedNativeDigitLocale(locale);
309
}
310
311
@Override
312
public DecimalFormatSymbols getInstance(Locale locale) {
313
DecimalFormatSymbols dfs;
314
SoftReference<DecimalFormatSymbols> ref =
315
decimalFormatSymbolsCache.get(locale);
316
317
if (ref == null || (dfs = ref.get()) == null) {
318
dfs = new DecimalFormatSymbols(getNumberLocale(locale));
319
String langTag = removeExtensions(locale).toLanguageTag();
320
321
// DecimalFormatSymbols.setInternationalCurrencySymbol() has
322
// a side effect of setting the currency symbol as well. So
323
// the calling order is relevant here.
324
dfs.setInternationalCurrencySymbol(getInternationalCurrencySymbol(langTag, dfs.getInternationalCurrencySymbol()));
325
dfs.setCurrencySymbol(getCurrencySymbol(langTag, dfs.getCurrencySymbol()));
326
dfs.setDecimalSeparator(getDecimalSeparator(langTag, dfs.getDecimalSeparator()));
327
dfs.setGroupingSeparator(getGroupingSeparator(langTag, dfs.getGroupingSeparator()));
328
dfs.setInfinity(getInfinity(langTag, dfs.getInfinity()));
329
dfs.setMinusSign(getMinusSign(langTag, dfs.getMinusSign()));
330
dfs.setMonetaryDecimalSeparator(getMonetaryDecimalSeparator(langTag, dfs.getMonetaryDecimalSeparator()));
331
dfs.setNaN(getNaN(langTag, dfs.getNaN()));
332
dfs.setPercent(getPercent(langTag, dfs.getPercent()));
333
dfs.setPerMill(getPerMill(langTag, dfs.getPerMill()));
334
dfs.setZeroDigit(getZeroDigit(langTag, dfs.getZeroDigit()));
335
ref = new SoftReference<>(dfs);
336
decimalFormatSymbolsCache.put(locale, ref);
337
}
338
return (DecimalFormatSymbols)dfs.clone();
339
}
340
};
341
}
342
343
public static CalendarDataProvider getCalendarDataProvider() {
344
return new CalendarDataProvider() {
345
@Override
346
public Locale[] getAvailableLocales() {
347
return getSupportedCalendarLocales();
348
}
349
350
@Override
351
public boolean isSupportedLocale(Locale locale) {
352
return isSupportedCalendarLocale(locale);
353
}
354
355
@Override
356
public int getFirstDayOfWeek(Locale locale) {
357
int first = getCalendarDataValue(
358
removeExtensions(locale).toLanguageTag(),
359
CD_FIRSTDAYOFWEEK);
360
if (first != -1) {
361
return (first + 1) % 7 + 1;
362
} else {
363
return 0;
364
}
365
}
366
367
@Override
368
public int getMinimalDaysInFirstWeek(Locale locale) {
369
int firstWeek = getCalendarDataValue(
370
removeExtensions(locale).toLanguageTag(),
371
CD_FIRSTWEEKOFYEAR);
372
// Interpret the value from Windows LOCALE_IFIRSTWEEKOFYEAR setting
373
return switch (firstWeek) {
374
case 1 -> 7; // First full week following 1/1 is the first week of the year.
375
case 2 -> 4; // First week containing at least four days is the first week of the year.
376
default -> 1; // First week can be a single day, if 1/1 falls on the last day of the week.
377
};
378
}
379
};
380
}
381
382
public static CalendarNameProvider getCalendarNameProvider() {
383
return new CalendarNameProvider() {
384
@Override
385
public Locale[] getAvailableLocales() {
386
return getSupportedCalendarLocales();
387
}
388
389
@Override
390
public boolean isSupportedLocale(Locale locale) {
391
return isSupportedCalendarLocale(locale);
392
}
393
394
@Override
395
public String getDisplayName(String calendarType, int field,
396
int value, int style, Locale locale) {
397
String[] names = getCalendarDisplayStrings(removeExtensions(locale).toLanguageTag(),
398
getCalendarIDFromLDMLType(calendarType), field, style);
399
if (field == Calendar.DAY_OF_WEEK) {
400
// Align value to array index
401
value--;
402
}
403
if (names != null && value >= 0 && value < names.length) {
404
return names[value];
405
} else {
406
return null;
407
}
408
}
409
410
@Override
411
public Map<String, Integer> getDisplayNames(String calendarType,
412
int field, int style, Locale locale) {
413
Map<String, Integer> map = null;
414
String[] names = getCalendarDisplayStrings(removeExtensions(locale).toLanguageTag(),
415
getCalendarIDFromLDMLType(calendarType), field, style);
416
if (names != null) {
417
map = new HashMap<>();
418
for (int value = 0; value < names.length; value++) {
419
if (names[value] != null) {
420
map.put(names[value],
421
// Align array index to field value
422
field == Calendar.DAY_OF_WEEK ? value + 1 : value);
423
}
424
}
425
map = map.isEmpty() ? null : map;
426
}
427
return map;
428
}
429
};
430
}
431
432
public static CalendarProvider getCalendarProvider() {
433
return new CalendarProvider() {
434
@Override
435
public Locale[] getAvailableLocales() {
436
return getSupportedCalendarLocales();
437
}
438
439
@Override
440
public boolean isSupportedLocale(Locale locale) {
441
return isSupportedCalendarLocale(locale);
442
}
443
444
@Override
445
public Calendar getInstance(TimeZone zone, Locale locale) {
446
return new Calendar.Builder()
447
.setLocale(getCalendarLocale(locale))
448
.setTimeZone(zone)
449
.setInstant(System.currentTimeMillis())
450
.build();
451
}
452
};
453
}
454
455
public static CurrencyNameProvider getCurrencyNameProvider() {
456
return new CurrencyNameProvider() {
457
@Override
458
public Locale[] getAvailableLocales() {
459
return supportedLocale;
460
}
461
462
@Override
463
public boolean isSupportedLocale(Locale locale) {
464
// Ignore the extensions for now
465
return supportedLocaleSet.contains(locale.stripExtensions()) &&
466
locale.getLanguage().equals(nativeDisplayLanguage);
467
}
468
469
@Override
470
public String getSymbol(String currencyCode, Locale locale) {
471
// Retrieves the currency symbol by calling
472
// GetLocaleInfoEx(LOCALE_SCURRENCY).
473
// It only works with the "locale"'s currency in its native
474
// language.
475
try {
476
if (Currency.getInstance(locale).getCurrencyCode()
477
.equals(currencyCode)) {
478
return getDisplayString(locale.toLanguageTag(),
479
DN_CURRENCY_SYMBOL, currencyCode);
480
}
481
} catch (IllegalArgumentException iae) {}
482
return null;
483
}
484
485
@Override
486
public String getDisplayName(String currencyCode, Locale locale) {
487
// Retrieves the display name by calling
488
// GetLocaleInfoEx(LOCALE_SNATIVECURRNAME).
489
// It only works with the "locale"'s currency in its native
490
// language.
491
try {
492
if (Currency.getInstance(locale).getCurrencyCode()
493
.equals(currencyCode)) {
494
return getDisplayString(locale.toLanguageTag(),
495
DN_CURRENCY_NAME, currencyCode);
496
}
497
} catch (IllegalArgumentException iae) {}
498
return null;
499
}
500
};
501
}
502
503
public static LocaleNameProvider getLocaleNameProvider() {
504
return new LocaleNameProvider() {
505
@Override
506
public Locale[] getAvailableLocales() {
507
return supportedLocale;
508
}
509
510
@Override
511
public boolean isSupportedLocale(Locale locale) {
512
return supportedLocaleSet.contains(locale.stripExtensions()) &&
513
locale.getLanguage().equals(nativeDisplayLanguage);
514
}
515
516
@Override
517
public String getDisplayLanguage(String languageCode, Locale locale) {
518
// Retrieves the display language name by calling
519
// GetLocaleInfoEx(LOCALE_SLOCALIZEDLANGUAGENAME).
520
return getDisplayString(locale.toLanguageTag(),
521
DN_LOCALE_LANGUAGE, languageCode);
522
}
523
524
@Override
525
public String getDisplayCountry(String countryCode, Locale locale) {
526
// Retrieves the display country name by calling
527
// GetLocaleInfoEx(LOCALE_SLOCALIZEDCOUNTRYNAME).
528
String str = getDisplayString(locale.toLanguageTag(),
529
DN_LOCALE_REGION,
530
nativeDisplayLanguage+"-"+countryCode);
531
// Hack: Windows 10 returns translated "Unknown Region (XX)"
532
// for localized XX region name. Take that as not known.
533
if (str != null && str.endsWith("("+countryCode+")")) {
534
return null;
535
}
536
return str;
537
}
538
539
@Override
540
public String getDisplayScript(String scriptCode, Locale locale) {
541
return null;
542
}
543
544
@Override
545
public String getDisplayVariant(String variantCode, Locale locale) {
546
return null;
547
}
548
};
549
}
550
551
public static JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() {
552
return new JavaTimeDateTimePatternProvider() {
553
@Override
554
public Locale[] getAvailableLocales() {
555
return getSupportedCalendarLocales();
556
}
557
558
@Override
559
public boolean isSupportedLocale(Locale locale) {
560
return isSupportedCalendarLocale(locale);
561
}
562
563
@Override
564
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
565
AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
566
String datePattern = dateStyle != - 1 ? patterns.get(dateStyle / 2) : "";
567
String timePattern = timeStyle != - 1 ? patterns.get(timeStyle / 2 + 2) : "";
568
String delim = dateStyle != -1 && timeStyle != - 1 ? " " : "";
569
return toJavaTimeDateTimePattern(calType, datePattern + delim + timePattern);
570
}
571
572
private AtomicReferenceArray<String> getDateTimePatterns(Locale locale) {
573
AtomicReferenceArray<String> patterns;
574
SoftReference<AtomicReferenceArray<String>> ref = dateFormatCache.get(locale);
575
576
if (ref == null || (patterns = ref.get()) == null) {
577
String langtag = removeExtensions(locale).toLanguageTag();
578
patterns = new AtomicReferenceArray<>(4);
579
patterns.compareAndSet(0, null, convertDateTimePattern(
580
getDateTimePattern(DateFormat.LONG, -1, langtag)));
581
patterns.compareAndSet(1, null, convertDateTimePattern(
582
getDateTimePattern(DateFormat.SHORT, -1, langtag)));
583
patterns.compareAndSet(2, null, convertDateTimePattern(
584
getDateTimePattern(-1, DateFormat.LONG, langtag)));
585
patterns.compareAndSet(3, null, convertDateTimePattern(
586
getDateTimePattern(-1, DateFormat.SHORT, langtag)));
587
ref = new SoftReference<>(patterns);
588
dateFormatCache.put(locale, ref);
589
}
590
return patterns;
591
}
592
/**
593
* This method will convert JRE Date/time Pattern String to JSR310
594
* type Date/Time Pattern
595
*/
596
private String toJavaTimeDateTimePattern(String calendarType, String jrePattern) {
597
int length = jrePattern.length();
598
StringBuilder sb = new StringBuilder(length);
599
boolean inQuote = false;
600
int count = 0;
601
char lastLetter = 0;
602
for (int i = 0; i < length; i++) {
603
char c = jrePattern.charAt(i);
604
if (c == '\'') {
605
// '' is treated as a single quote regardless of being
606
// in a quoted section.
607
if ((i + 1) < length) {
608
char nextc = jrePattern.charAt(i + 1);
609
if (nextc == '\'') {
610
i++;
611
if (count != 0) {
612
convert(calendarType, lastLetter, count, sb);
613
lastLetter = 0;
614
count = 0;
615
}
616
sb.append("''");
617
continue;
618
}
619
}
620
if (!inQuote) {
621
if (count != 0) {
622
convert(calendarType, lastLetter, count, sb);
623
lastLetter = 0;
624
count = 0;
625
}
626
inQuote = true;
627
} else {
628
inQuote = false;
629
}
630
sb.append(c);
631
continue;
632
}
633
if (inQuote) {
634
sb.append(c);
635
continue;
636
}
637
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
638
if (count != 0) {
639
convert(calendarType, lastLetter, count, sb);
640
lastLetter = 0;
641
count = 0;
642
}
643
sb.append(c);
644
continue;
645
}
646
if (lastLetter == 0 || lastLetter == c) {
647
lastLetter = c;
648
count++;
649
continue;
650
}
651
convert(calendarType, lastLetter, count, sb);
652
lastLetter = c;
653
count = 1;
654
}
655
if (inQuote) {
656
// should not come here.
657
// returning null so that FALLBACK provider will kick in.
658
return null;
659
}
660
if (count != 0) {
661
convert(calendarType, lastLetter, count, sb);
662
}
663
return sb.toString();
664
}
665
666
private void convert(String calendarType, char letter, int count, StringBuilder sb) {
667
switch (letter) {
668
case 'G':
669
if (calendarType.equals("japanese")) {
670
if (count >= 4) {
671
count = 1;
672
} else {
673
count = 5;
674
}
675
} else if (!calendarType.equals("iso8601")) {
676
// Adjust the number of 'G's
677
// Gregorian calendar is iso8601 for java.time
678
if (count >= 4) {
679
// JRE full -> JavaTime full
680
count = 4;
681
} else {
682
// JRE short -> JavaTime short
683
count = 1;
684
}
685
}
686
break;
687
case 'y':
688
if (calendarType.equals("japanese") && count >= 4) {
689
// JRE specific "gan-nen" support
690
count = 1;
691
}
692
break;
693
default:
694
// JSR 310 and CLDR define 5-letter patterns for narrow text.
695
if (count > 4) {
696
count = 4;
697
}
698
break;
699
}
700
appendN(letter, count, sb);
701
}
702
703
private void appendN(char c, int n, StringBuilder sb) {
704
for (int i = 0; i < n; i++) {
705
sb.append(c);
706
}
707
}
708
};
709
}
710
711
private static String convertDateTimePattern(String winPattern) {
712
String ret = winPattern.replaceAll("dddd", "EEEE");
713
ret = ret.replaceAll("ddd", "EEE");
714
ret = ret.replaceAll("tt", "a");
715
ret = ret.replaceAll("g", "GG");
716
return ret;
717
}
718
719
private static Locale[] getSupportedCalendarLocales() {
720
if (supportedLocale.length != 0 &&
721
supportedLocaleSet.contains(Locale.JAPAN) &&
722
isJapaneseCalendar()) {
723
Locale[] sup = new Locale[supportedLocale.length+1];
724
sup[0] = JRELocaleConstants.JA_JP_JP;
725
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
726
return sup;
727
}
728
return supportedLocale;
729
}
730
731
private static boolean isSupportedCalendarLocale(Locale locale) {
732
Locale base = stripVariantAndExtensions(locale);
733
734
if (!supportedLocaleSet.contains(base)) {
735
return false;
736
}
737
738
int calid = getCalendarID(base.toLanguageTag());
739
if (calid <= 0 || calid >= calIDToLDML.length) {
740
return false;
741
}
742
743
String requestedCalType = locale.getUnicodeLocaleType("ca");
744
String nativeCalType = calIDToLDML[calid]
745
.replaceFirst("_.*", ""); // remove locale part.
746
747
if (requestedCalType == null) {
748
return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
749
} else {
750
return requestedCalType.equals(nativeCalType);
751
}
752
}
753
754
private static Locale[] getSupportedNativeDigitLocales() {
755
if (supportedLocale.length != 0 &&
756
supportedLocaleSet.contains(JRELocaleConstants.TH_TH) &&
757
isNativeDigit("th-TH")) {
758
Locale[] sup = new Locale[supportedLocale.length+1];
759
sup[0] = JRELocaleConstants.TH_TH_TH;
760
System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
761
return sup;
762
}
763
return supportedLocale;
764
}
765
766
private static boolean isSupportedNativeDigitLocale(Locale locale) {
767
// special case for th_TH_TH
768
if (JRELocaleConstants.TH_TH_TH.equals(locale)) {
769
return isNativeDigit("th-TH");
770
}
771
772
String numtype = null;
773
Locale base = locale;
774
if (locale.hasExtensions()) {
775
numtype = locale.getUnicodeLocaleType("nu");
776
base = locale.stripExtensions();
777
}
778
779
if (supportedLocaleSet.contains(base)) {
780
// Only supports Latin or Thai (in thai locales) digits.
781
if (numtype == null || numtype.equals("latn")) {
782
return true;
783
} else if (locale.getLanguage().equals("th")) {
784
return "thai".equals(numtype) &&
785
isNativeDigit(locale.toLanguageTag());
786
}
787
}
788
789
return false;
790
}
791
792
private static Locale removeExtensions(Locale src) {
793
return new Locale.Builder().setLocale(src).clearExtensions().build();
794
}
795
796
private static boolean isJapaneseCalendar() {
797
return getCalendarID("ja-JP") == CAL_JAPAN;
798
}
799
800
private static Locale stripVariantAndExtensions(Locale locale) {
801
if (locale.hasExtensions() || locale.getVariant() != "") {
802
// strip off extensions and variant.
803
locale = new Locale.Builder()
804
.setLocale(locale)
805
.clearExtensions()
806
.build();
807
}
808
809
return locale;
810
}
811
812
private static Locale getCalendarLocale(Locale locale) {
813
int calid = getCalendarID(stripVariantAndExtensions(locale).toLanguageTag());
814
if (calid > 0 && calid < calIDToLDML.length) {
815
Locale.Builder lb = new Locale.Builder();
816
String[] caltype = calIDToLDML[calid].split("_");
817
if (caltype.length > 1) {
818
lb.setLocale(Locale.forLanguageTag(caltype[1]));
819
} else {
820
lb.setLocale(locale);
821
}
822
lb.setUnicodeLocaleKeyword("ca", caltype[0]);
823
return lb.build();
824
}
825
826
return locale;
827
}
828
829
private static int getCalendarIDFromLDMLType(String ldmlType) {
830
for (int i = 0; i < calIDToLDML.length; i++) {
831
if (calIDToLDML[i].startsWith(ldmlType)) {
832
return i;
833
}
834
}
835
return -1;
836
}
837
838
private static Locale getNumberLocale(Locale src) {
839
if (JRELocaleConstants.TH_TH.equals(src)) {
840
if (isNativeDigit("th-TH")) {
841
Locale.Builder lb = new Locale.Builder().setLocale(src);
842
lb.setUnicodeLocaleKeyword("nu", "thai");
843
return lb.build();
844
}
845
}
846
847
return src;
848
}
849
850
// native methods
851
852
// initialize
853
private static native boolean initialize();
854
private static native String getDefaultLocale(int cat);
855
856
// For DateFormatProvider
857
private static native String getDateTimePattern(int dateStyle, int timeStyle, String langTag);
858
private static native int getCalendarID(String langTag);
859
860
// For DateFormatSymbolsProvider
861
private static native String[] getAmPmStrings(String langTag, String[] ampm);
862
private static native String[] getEras(String langTag, String[] eras);
863
private static native String[] getMonths(String langTag, String[] months);
864
private static native String[] getShortMonths(String langTag, String[] smonths);
865
private static native String[] getWeekdays(String langTag, String[] wdays);
866
private static native String[] getShortWeekdays(String langTag, String[] swdays);
867
868
// For NumberFormatProvider
869
private static native String getNumberPattern(int numberStyle, String langTag);
870
private static native boolean isNativeDigit(String langTag);
871
872
// For DecimalFormatSymbolsProvider
873
private static native String getCurrencySymbol(String langTag, String currencySymbol);
874
private static native char getDecimalSeparator(String langTag, char decimalSeparator);
875
private static native char getGroupingSeparator(String langTag, char groupingSeparator);
876
private static native String getInfinity(String langTag, String infinity);
877
private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
878
private static native char getMinusSign(String langTag, char minusSign);
879
private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
880
private static native String getNaN(String langTag, String nan);
881
private static native char getPercent(String langTag, char percent);
882
private static native char getPerMill(String langTag, char perMill);
883
private static native char getZeroDigit(String langTag, char zeroDigit);
884
885
// For CalendarDataProvider
886
private static native int getCalendarDataValue(String langTag, int type);
887
888
// For CalendarNameProvider
889
private static native String[] getCalendarDisplayStrings(String langTag, int calid, int field, int style);
890
891
// For Locale/CurrencyNameProvider
892
private static native String getDisplayString(String langTag, int key, String value);
893
}
894
895