Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java
41161 views
1
/*
2
* Copyright (c) 2012, 2021, 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 static java.util.Calendar.*;
28
import java.util.Comparator;
29
import java.util.Locale;
30
import java.util.Map;
31
import java.util.Set;
32
import java.util.TreeMap;
33
import java.util.spi.CalendarNameProvider;
34
import sun.util.calendar.CalendarSystem;
35
import sun.util.calendar.Era;
36
37
/**
38
* Concrete implementation of the {@link java.util.spi.CalendarNameProvider
39
* CalendarNameProvider} class for the JRE LocaleProviderAdapter.
40
*
41
* @author Masayoshi Okutsu
42
* @author Naoto Sato
43
*/
44
public class CalendarNameProviderImpl extends CalendarNameProvider implements AvailableLanguageTags {
45
protected final LocaleProviderAdapter.Type type;
46
protected final Set<String> langtags;
47
48
public CalendarNameProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {
49
this.type = type;
50
this.langtags = langtags;
51
}
52
53
@Override
54
public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) {
55
return getDisplayNameImpl(calendarType, field, value, style, locale, false);
56
}
57
58
public String getJavaTimeDisplayName(String calendarType, int field, int value, int style, Locale locale) {
59
return getDisplayNameImpl(calendarType, field, value, style, locale, true);
60
}
61
62
public String getDisplayNameImpl(String calendarType, int field, int value, int style, Locale locale, boolean javatime) {
63
String name = null;
64
String key = getResourceKey(calendarType, field, style, javatime);
65
if (key != null) {
66
LocaleResources lr = LocaleProviderAdapter.forType(type).getLocaleResources(locale);
67
String[] strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
68
69
// If standalone names are requested and no "standalone." resources are found,
70
// try the default ones instead.
71
if (strings == null && key.contains("standalone.")) {
72
key = key.replaceFirst("standalone.", "");
73
strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
74
}
75
76
if (strings != null && strings.length > 0) {
77
if (field == DAY_OF_WEEK || field == YEAR) {
78
--value;
79
}
80
if (value < 0) {
81
return null;
82
} else if (value >= strings.length) {
83
if (field == ERA && "japanese".equals(calendarType)) {
84
Era[] jeras = CalendarSystem.forName("japanese").getEras();
85
if (value <= jeras.length) {
86
// Localized era name could not be retrieved from this provider.
87
// This can occur either for Reiwa or SupEra.
88
//
89
// If it's CLDR provider, try COMPAT first, which is guaranteed to have
90
// the name for Reiwa.
91
if (type == LocaleProviderAdapter.Type.CLDR) {
92
lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale);
93
key = getResourceKeyFor(LocaleProviderAdapter.Type.JRE,
94
calendarType, field, style, javatime);
95
strings =
96
javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
97
}
98
if (strings == null || value >= strings.length) {
99
// Get the default name for SupEra
100
Era supEra = jeras[value - 1]; // 0-based index
101
if (javatime) {
102
return getBaseStyle(style) == NARROW_FORMAT ?
103
supEra.getAbbreviation() :
104
supEra.getName();
105
} else {
106
return (style & LONG) != 0 ?
107
supEra.getName() :
108
supEra.getAbbreviation();
109
}
110
}
111
} else {
112
return null;
113
}
114
} else {
115
return null;
116
}
117
}
118
name = strings[value];
119
// If name is empty in standalone, try its `format' style.
120
if (name.isEmpty()
121
&& (style == SHORT_STANDALONE || style == LONG_STANDALONE
122
|| style == NARROW_STANDALONE)) {
123
name = getDisplayName(calendarType, field, value,
124
getBaseStyle(style),
125
locale);
126
}
127
}
128
}
129
return name;
130
}
131
132
private static final int[] REST_OF_STYLES = {
133
SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE,
134
NARROW_FORMAT, NARROW_STANDALONE
135
};
136
137
@Override
138
public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) {
139
Map<String, Integer> names;
140
if (style == ALL_STYLES) {
141
names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale, false);
142
for (int st : REST_OF_STYLES) {
143
names.putAll(getDisplayNamesImpl(calendarType, field, st, locale, false));
144
}
145
} else {
146
// specific style
147
names = getDisplayNamesImpl(calendarType, field, style, locale, false);
148
}
149
return names.isEmpty() ? null : names;
150
}
151
152
// NOTE: This method should be used ONLY BY JSR 310 classes.
153
public Map<String, Integer> getJavaTimeDisplayNames(String calendarType, int field, int style, Locale locale) {
154
Map<String, Integer> names;
155
names = getDisplayNamesImpl(calendarType, field, style, locale, true);
156
return names.isEmpty() ? null : names;
157
}
158
159
private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field,
160
int style, Locale locale, boolean javatime) {
161
String key = getResourceKey(calendarType, field, style, javatime);
162
Map<String, Integer> map = new TreeMap<>(LengthBasedComparator.INSTANCE);
163
if (key != null) {
164
LocaleResources lr = LocaleProviderAdapter.forType(type).getLocaleResources(locale);
165
String[] strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
166
167
// If standalone names are requested and no "standalone." resources are found,
168
// try the default ones instead.
169
if (strings == null && key.contains("standalone.")) {
170
key = key.replaceFirst("standalone.", "");
171
strings = javatime ? lr.getJavaTimeNames(key) : lr.getCalendarNames(key);
172
}
173
174
if (strings != null) {
175
if (!hasDuplicates(strings) || field == AM_PM) {
176
if (field == YEAR) {
177
if (strings.length > 0) {
178
map.put(strings[0], 1);
179
}
180
} else {
181
int base = (field == DAY_OF_WEEK) ? 1 : 0;
182
// Duplicates can happen with AM_PM field. In such a case,
183
// am/pm (index 0 and 1) have precedence over day
184
// periods.
185
for (int i = strings.length - 1; i >= 0; i--) {
186
String name = strings[i];
187
// Ignore any empty string (some standalone month names
188
// or flexible day periods are not defined)
189
if (name.isEmpty()) {
190
continue;
191
}
192
if (field == AM_PM && !javatime && i > PM) {
193
// Unlike in the case of java.time.format.DateTimeFormatter(Builder),
194
// when dealing with java.util.Calendar, don't set AM_PM field value
195
// to anything that isn't either AM or PM (this can happen when
196
// day periods are involved)
197
continue;
198
} else {
199
map.put(name, base + i);
200
}
201
}
202
}
203
}
204
}
205
}
206
return map;
207
}
208
209
private static int getBaseStyle(int style) {
210
return style & ~(SHORT_STANDALONE - SHORT_FORMAT);
211
}
212
213
/**
214
* Comparator implementation for TreeMap which iterates keys from longest
215
* to shortest.
216
*/
217
private static class LengthBasedComparator implements Comparator<String> {
218
private static final LengthBasedComparator INSTANCE = new LengthBasedComparator();
219
220
private LengthBasedComparator() {
221
}
222
223
@Override
224
public int compare(String o1, String o2) {
225
int n = o2.length() - o1.length();
226
return (n == 0) ? o1.compareTo(o2) : n;
227
}
228
}
229
230
@Override
231
public Locale[] getAvailableLocales() {
232
return LocaleProviderAdapter.toLocaleArray(langtags);
233
}
234
235
@Override
236
public boolean isSupportedLocale(Locale locale) {
237
if (Locale.ROOT.equals(locale)) {
238
return true;
239
}
240
String calendarType = null;
241
if (locale.hasExtensions()) {
242
calendarType = locale.getUnicodeLocaleType("ca");
243
locale = locale.stripExtensions();
244
}
245
246
if (calendarType != null) {
247
switch (calendarType) {
248
case "buddhist":
249
case "japanese":
250
case "gregory":
251
case "islamic":
252
case "roc":
253
break;
254
default:
255
// Unknown calendar type
256
return false;
257
}
258
}
259
if (langtags.contains(locale.toLanguageTag())) {
260
return true;
261
}
262
String oldname = locale.toString().replace('_', '-');
263
return langtags.contains(oldname);
264
}
265
266
@Override
267
public Set<String> getAvailableLanguageTags() {
268
return langtags;
269
}
270
271
// Check if each string is unique, except null or empty strings,
272
// as these strings are used for keys in the name-to-value map.
273
private boolean hasDuplicates(String[] strings) {
274
int len = strings.length;
275
for (int i = 0; i < len - 1; i++) {
276
String a = strings[i];
277
if (a != null && !a.isEmpty()) {
278
for (int j = i + 1; j < len; j++) {
279
if (a.equals(strings[j])) {
280
return true;
281
}
282
}
283
}
284
}
285
return false;
286
}
287
288
private String getResourceKey(String type, int field, int style, boolean javatime) {
289
return getResourceKeyFor(this.type, type, field, style, javatime);
290
}
291
292
private static String getResourceKeyFor(LocaleProviderAdapter.Type adapterType,
293
String type, int field, int style, boolean javatime) {
294
int baseStyle = getBaseStyle(style);
295
boolean isStandalone = (style != baseStyle);
296
297
if ("gregory".equals(type)) {
298
type = null;
299
}
300
boolean isNarrow = (baseStyle == NARROW_FORMAT);
301
StringBuilder key = new StringBuilder();
302
// If javatime is true, use prefix "java.time.".
303
if (javatime) {
304
key.append("java.time.");
305
}
306
switch (field) {
307
case ERA:
308
if (type != null) {
309
key.append(type).append('.');
310
}
311
if (isNarrow) {
312
key.append("narrow.");
313
} else {
314
// JRE and CLDR use different resource key conventions
315
// due to historical reasons. (JRE DateFormatSymbols.getEras returns
316
// abbreviations while other getShort*() return abbreviations.)
317
if (adapterType == LocaleProviderAdapter.Type.JRE) {
318
if (javatime) {
319
if (baseStyle == LONG) {
320
key.append("long.");
321
}
322
}
323
if (baseStyle == SHORT) {
324
key.append("short.");
325
}
326
} else { // this.type == LocaleProviderAdapter.Type.CLDR
327
if (baseStyle == LONG) {
328
key.append("long.");
329
}
330
}
331
}
332
key.append("Eras");
333
break;
334
335
case YEAR:
336
if (!isNarrow) {
337
key.append(type).append(".FirstYear");
338
}
339
break;
340
341
case MONTH:
342
if ("islamic".equals(type)) {
343
key.append(type).append('.');
344
}
345
if (isStandalone) {
346
key.append("standalone.");
347
}
348
key.append("Month").append(toStyleName(baseStyle));
349
break;
350
351
case DAY_OF_WEEK:
352
// support standalone day names
353
if (isStandalone) {
354
key.append("standalone.");
355
}
356
key.append("Day").append(toStyleName(baseStyle));
357
break;
358
359
case AM_PM:
360
if (isNarrow) {
361
key.append("narrow.");
362
}
363
key.append("AmPmMarkers");
364
break;
365
}
366
return key.length() > 0 ? key.toString() : null;
367
}
368
369
private static String toStyleName(int baseStyle) {
370
switch (baseStyle) {
371
case SHORT:
372
return "Abbreviations";
373
case NARROW_FORMAT:
374
return "Narrows";
375
}
376
return "Names";
377
}
378
}
379
380