Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java
32287 views
1
/*
2
* Copyright (c) 2012, 2013, 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 build.tools.cldrconverter;
27
28
import build.tools.cldrconverter.BundleGenerator.BundleType;
29
import java.io.File;
30
import java.nio.file.DirectoryStream;
31
import java.nio.file.FileSystems;
32
import java.nio.file.Files;
33
import java.nio.file.Path;
34
import java.util.*;
35
import javax.xml.parsers.SAXParser;
36
import javax.xml.parsers.SAXParserFactory;
37
import org.xml.sax.SAXNotRecognizedException;
38
import org.xml.sax.SAXNotSupportedException;
39
40
41
/**
42
* Converts locale data from "Locale Data Markup Language" format to
43
* JRE resource bundle format. LDML is the format used by the Common
44
* Locale Data Repository maintained by the Unicode Consortium.
45
*/
46
public class CLDRConverter {
47
48
static final String LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldml.dtd";
49
static final String SPPL_LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldmlSupplemental.dtd";
50
51
private static String CLDR_BASE = "../CLDR/21.0.1/";
52
static String LOCAL_LDML_DTD;
53
static String LOCAL_SPPL_LDML_DTD;
54
private static String SOURCE_FILE_DIR;
55
private static String SPPL_SOURCE_FILE;
56
private static String NUMBERING_SOURCE_FILE;
57
private static String METAZONES_SOURCE_FILE;
58
static String DESTINATION_DIR = "build/gensrc";
59
60
static final String LOCALE_NAME_PREFIX = "locale.displayname.";
61
static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol.";
62
static final String CURRENCY_NAME_PREFIX = "currency.displayname.";
63
static final String CALENDAR_NAME_PREFIX = "calendarname.";
64
static final String TIMEZONE_ID_PREFIX = "timezone.id.";
65
static final String ZONE_NAME_PREFIX = "timezone.displayname.";
66
static final String METAZONE_ID_PREFIX = "metazone.id.";
67
68
private static SupplementDataParseHandler handlerSuppl;
69
static NumberingSystemsParseHandler handlerNumbering;
70
static MetaZonesParseHandler handlerMetaZones;
71
private static BundleGenerator bundleGenerator;
72
73
static enum DraftType {
74
UNCONFIRMED,
75
PROVISIONAL,
76
CONTRIBUTED,
77
APPROVED;
78
79
private static final Map<String, DraftType> map = new HashMap<>();
80
static {
81
for (DraftType dt : values()) {
82
map.put(dt.getKeyword(), dt);
83
}
84
}
85
static private DraftType defaultType = CONTRIBUTED;
86
87
private final String keyword;
88
89
private DraftType() {
90
keyword = this.name().toLowerCase(Locale.ROOT);
91
92
}
93
94
static DraftType forKeyword(String keyword) {
95
return map.get(keyword);
96
}
97
98
static DraftType getDefault() {
99
return defaultType;
100
}
101
102
static void setDefault(String keyword) {
103
defaultType = Objects.requireNonNull(forKeyword(keyword));
104
}
105
106
String getKeyword() {
107
return keyword;
108
}
109
}
110
111
static boolean USE_UTF8 = false;
112
private static boolean verbose;
113
114
private CLDRConverter() {
115
// no instantiation
116
}
117
118
@SuppressWarnings("AssignmentToForLoopParameter")
119
public static void main(String[] args) throws Exception {
120
if (args.length != 0) {
121
String currentArg = null;
122
try {
123
for (int i = 0; i < args.length; i++) {
124
currentArg = args[i];
125
switch (currentArg) {
126
case "-draft":
127
String draftDataType = args[++i];
128
try {
129
DraftType.setDefault(draftDataType);
130
} catch (NullPointerException e) {
131
severe("Error: incorrect draft value: %s%n", draftDataType);
132
System.exit(1);
133
}
134
info("Using the specified data type: %s%n", draftDataType);
135
break;
136
137
case "-base":
138
// base directory for input files
139
CLDR_BASE = args[++i];
140
if (!CLDR_BASE.endsWith("/")) {
141
CLDR_BASE += "/";
142
}
143
break;
144
145
case "-o":
146
// output directory
147
DESTINATION_DIR = args[++i];
148
break;
149
150
case "-utf8":
151
USE_UTF8 = true;
152
break;
153
154
case "-verbose":
155
verbose = true;
156
break;
157
158
case "-help":
159
usage();
160
System.exit(0);
161
break;
162
163
default:
164
throw new RuntimeException();
165
}
166
}
167
} catch (RuntimeException e) {
168
severe("unknown or imcomplete arg(s): " + currentArg);
169
usage();
170
System.exit(1);
171
}
172
}
173
174
// Set up path names
175
LOCAL_LDML_DTD = CLDR_BASE + "common/dtd/ldml.dtd";
176
LOCAL_SPPL_LDML_DTD = CLDR_BASE + "common/dtd/ldmlSupplemental.dtd";
177
SOURCE_FILE_DIR = CLDR_BASE + "common/main";
178
SPPL_SOURCE_FILE = CLDR_BASE + "common/supplemental/supplementalData.xml";
179
NUMBERING_SOURCE_FILE = CLDR_BASE + "common/supplemental/numberingSystems.xml";
180
METAZONES_SOURCE_FILE = CLDR_BASE + "common/supplemental/metaZones.xml";
181
182
bundleGenerator = new ResourceBundleGenerator();
183
184
List<Bundle> bundles = readBundleList();
185
convertBundles(bundles);
186
}
187
188
private static void usage() {
189
errout("Usage: java CLDRConverter [options]%n"
190
+ "\t-help output this usage message and exit%n"
191
+ "\t-verbose output information%n"
192
+ "\t-draft [approved | provisional | unconfirmed]%n"
193
+ "\t\t draft level for using data (default: approved)%n"
194
+ "\t-base dir base directory for CLDR input files%n"
195
+ "\t-o dir output directory (defaut: ./build/gensrc)%n"
196
+ "\t-utf8 use UTF-8 rather than \\uxxxx (for debug)%n");
197
}
198
199
static void info(String fmt, Object... args) {
200
if (verbose) {
201
System.out.printf(fmt, args);
202
}
203
}
204
205
static void info(String msg) {
206
if (verbose) {
207
System.out.println(msg);
208
}
209
}
210
211
static void warning(String fmt, Object... args) {
212
System.err.print("Warning: ");
213
System.err.printf(fmt, args);
214
}
215
216
static void warning(String msg) {
217
System.err.print("Warning: ");
218
errout(msg);
219
}
220
221
static void severe(String fmt, Object... args) {
222
System.err.print("Error: ");
223
System.err.printf(fmt, args);
224
}
225
226
static void severe(String msg) {
227
System.err.print("Error: ");
228
errout(msg);
229
}
230
231
private static void errout(String msg) {
232
if (msg.contains("%n")) {
233
System.err.printf(msg);
234
} else {
235
System.err.println(msg);
236
}
237
}
238
239
/**
240
* Configure the parser to allow access to DTDs on the file system.
241
*/
242
private static void enableFileAccess(SAXParser parser) throws SAXNotSupportedException {
243
try {
244
parser.setProperty("http://javax.xml.XMLConstants/property/accessExternalDTD", "file");
245
} catch (SAXNotRecognizedException ignore) {
246
// property requires >= JAXP 1.5
247
}
248
}
249
250
private static List<Bundle> readBundleList() throws Exception {
251
ResourceBundle.Control defCon = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
252
List<Bundle> retList = new ArrayList<>();
253
Path path = FileSystems.getDefault().getPath(SOURCE_FILE_DIR);
254
try (DirectoryStream<Path> dirStr = Files.newDirectoryStream(path)) {
255
for (Path entry : dirStr) {
256
String fileName = entry.getFileName().toString();
257
if (fileName.endsWith(".xml")) {
258
String id = fileName.substring(0, fileName.indexOf('.'));
259
Locale cldrLoc = Locale.forLanguageTag(toLanguageTag(id));
260
List<Locale> candList = defCon.getCandidateLocales("", cldrLoc);
261
StringBuilder sb = new StringBuilder();
262
for (Locale loc : candList) {
263
if (!loc.equals(Locale.ROOT)) {
264
sb.append(toLocaleName(loc.toLanguageTag()));
265
sb.append(",");
266
}
267
}
268
if (sb.indexOf("root") == -1) {
269
sb.append("root");
270
}
271
Bundle b = new Bundle(id, sb.toString(), null, null);
272
// Insert the bundle for en at the top so that it will get
273
// processed first.
274
if ("en".equals(id)) {
275
retList.add(0, b);
276
} else {
277
retList.add(b);
278
}
279
}
280
}
281
}
282
return retList;
283
}
284
285
private static Map<String, Map<String, Object>> cldrBundles = new HashMap<>();
286
287
static Map<String, Object> getCLDRBundle(String id) throws Exception {
288
Map<String, Object> bundle = cldrBundles.get(id);
289
if (bundle != null) {
290
return bundle;
291
}
292
SAXParserFactory factory = SAXParserFactory.newInstance();
293
factory.setValidating(true);
294
SAXParser parser = factory.newSAXParser();
295
enableFileAccess(parser);
296
LDMLParseHandler handler = new LDMLParseHandler(id);
297
File file = new File(SOURCE_FILE_DIR + File.separator + id + ".xml");
298
if (!file.exists()) {
299
// Skip if the file doesn't exist.
300
return Collections.emptyMap();
301
}
302
303
info("..... main directory .....");
304
info("Reading file " + file);
305
parser.parse(file, handler);
306
307
bundle = handler.getData();
308
cldrBundles.put(id, bundle);
309
String country = getCountryCode(id);
310
if (country != null) {
311
bundle = handlerSuppl.getData(country);
312
if (bundle != null) {
313
//merge two maps into one map
314
Map<String, Object> temp = cldrBundles.remove(id);
315
bundle.putAll(temp);
316
cldrBundles.put(id, bundle);
317
}
318
}
319
return bundle;
320
}
321
322
private static void convertBundles(List<Bundle> bundles) throws Exception {
323
// Parse SupplementalData file and store the information in the HashMap
324
// Calendar information such as firstDay and minDay are stored in
325
// supplementalData.xml as of CLDR1.4. Individual territory is listed
326
// with its ISO 3166 country code while default is listed using UNM49
327
// region and composition numerical code (001 for World.)
328
SAXParserFactory factorySuppl = SAXParserFactory.newInstance();
329
factorySuppl.setValidating(true);
330
SAXParser parserSuppl = factorySuppl.newSAXParser();
331
enableFileAccess(parserSuppl);
332
handlerSuppl = new SupplementDataParseHandler();
333
File fileSupply = new File(SPPL_SOURCE_FILE);
334
parserSuppl.parse(fileSupply, handlerSuppl);
335
336
// Parse numberingSystems to get digit zero character information.
337
SAXParserFactory numberingParser = SAXParserFactory.newInstance();
338
numberingParser.setValidating(true);
339
SAXParser parserNumbering = numberingParser.newSAXParser();
340
enableFileAccess(parserNumbering);
341
handlerNumbering = new NumberingSystemsParseHandler();
342
File fileNumbering = new File(NUMBERING_SOURCE_FILE);
343
parserNumbering.parse(fileNumbering, handlerNumbering);
344
345
// Parse metaZones to create mappings between Olson tzids and CLDR meta zone names
346
SAXParserFactory metazonesParser = SAXParserFactory.newInstance();
347
metazonesParser.setValidating(true);
348
SAXParser parserMetaZones = metazonesParser.newSAXParser();
349
enableFileAccess(parserMetaZones);
350
handlerMetaZones = new MetaZonesParseHandler();
351
File fileMetaZones = new File(METAZONES_SOURCE_FILE);
352
parserNumbering.parse(fileMetaZones, handlerMetaZones);
353
354
// For generating information on supported locales.
355
Map<String, SortedSet<String>> metaInfo = new HashMap<>();
356
metaInfo.put("LocaleNames", new TreeSet<String>());
357
metaInfo.put("CurrencyNames", new TreeSet<String>());
358
metaInfo.put("TimeZoneNames", new TreeSet<String>());
359
metaInfo.put("CalendarData", new TreeSet<String>());
360
metaInfo.put("FormatData", new TreeSet<String>());
361
362
for (Bundle bundle : bundles) {
363
// Get the target map, which contains all the data that should be
364
// visible for the bundle's locale
365
366
Map<String, Object> targetMap = bundle.getTargetMap();
367
368
EnumSet<Bundle.Type> bundleTypes = bundle.getBundleTypes();
369
370
// Fill in any missing resources in the base bundle from en and en-US data.
371
// This is because CLDR root.xml is supposed to be language neutral and doesn't
372
// provide some resource data. Currently, the runtime assumes that there are all
373
// resources though the parent resource bundle chain.
374
if (bundle.isRoot()) {
375
Map<String, Object> enData = new HashMap<>();
376
// Create a superset of en-US and en bundles data in order to
377
// fill in any missing resources in the base bundle.
378
enData.putAll(Bundle.getBundle("en").getTargetMap());
379
enData.putAll(Bundle.getBundle("en_US").getTargetMap());
380
for (String key : enData.keySet()) {
381
if (!targetMap.containsKey(key)) {
382
targetMap.put(key, enData.get(key));
383
}
384
}
385
// Add DateTimePatternChars because CLDR no longer supports localized patterns.
386
targetMap.put("DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ");
387
}
388
389
// Now the map contains just the entries that need to be in the resources bundles.
390
// Go ahead and generate them.
391
if (bundleTypes.contains(Bundle.Type.LOCALENAMES)) {
392
Map<String, Object> localeNamesMap = extractLocaleNames(targetMap, bundle.getID());
393
if (!localeNamesMap.isEmpty() || bundle.isRoot()) {
394
metaInfo.get("LocaleNames").add(toLanguageTag(bundle.getID()));
395
bundleGenerator.generateBundle("util", "LocaleNames", bundle.getID(), true, localeNamesMap, BundleType.OPEN);
396
}
397
}
398
if (bundleTypes.contains(Bundle.Type.CURRENCYNAMES)) {
399
Map<String, Object> currencyNamesMap = extractCurrencyNames(targetMap, bundle.getID(), bundle.getCurrencies());
400
if (!currencyNamesMap.isEmpty() || bundle.isRoot()) {
401
metaInfo.get("CurrencyNames").add(toLanguageTag(bundle.getID()));
402
bundleGenerator.generateBundle("util", "CurrencyNames", bundle.getID(), true, currencyNamesMap, BundleType.OPEN);
403
}
404
}
405
if (bundleTypes.contains(Bundle.Type.TIMEZONENAMES)) {
406
Map<String, Object> zoneNamesMap = extractZoneNames(targetMap, bundle.getID());
407
if (!zoneNamesMap.isEmpty() || bundle.isRoot()) {
408
metaInfo.get("TimeZoneNames").add(toLanguageTag(bundle.getID()));
409
bundleGenerator.generateBundle("util", "TimeZoneNames", bundle.getID(), true, zoneNamesMap, BundleType.TIMEZONE);
410
}
411
}
412
if (bundleTypes.contains(Bundle.Type.CALENDARDATA)) {
413
Map<String, Object> calendarDataMap = extractCalendarData(targetMap, bundle.getID());
414
if (!calendarDataMap.isEmpty() || bundle.isRoot()) {
415
metaInfo.get("CalendarData").add(toLanguageTag(bundle.getID()));
416
bundleGenerator.generateBundle("util", "CalendarData", bundle.getID(), true, calendarDataMap, BundleType.PLAIN);
417
}
418
}
419
if (bundleTypes.contains(Bundle.Type.FORMATDATA)) {
420
Map<String, Object> formatDataMap = extractFormatData(targetMap, bundle.getID());
421
// LocaleData.getAvailableLocales depends on having FormatData bundles around
422
if (!formatDataMap.isEmpty() || bundle.isRoot()) {
423
metaInfo.get("FormatData").add(toLanguageTag(bundle.getID()));
424
bundleGenerator.generateBundle("text", "FormatData", bundle.getID(), true, formatDataMap, BundleType.PLAIN);
425
}
426
}
427
428
// For testing
429
SortedSet<String> allLocales = new TreeSet<>();
430
allLocales.addAll(metaInfo.get("CurrencyNames"));
431
allLocales.addAll(metaInfo.get("LocaleNames"));
432
allLocales.addAll(metaInfo.get("CalendarData"));
433
allLocales.addAll(metaInfo.get("FormatData"));
434
metaInfo.put("All", allLocales);
435
}
436
437
bundleGenerator.generateMetaInfo(metaInfo);
438
}
439
440
/*
441
* Returns the language portion of the given id.
442
* If id is "root", "" is returned.
443
*/
444
static String getLanguageCode(String id) {
445
int index = id.indexOf('_');
446
String lang = null;
447
if (index != -1) {
448
lang = id.substring(0, index);
449
} else {
450
lang = "root".equals(id) ? "" : id;
451
}
452
return lang;
453
}
454
455
/**
456
* Examine if the id includes the country (territory) code. If it does, it returns
457
* the country code.
458
* Otherwise, it returns null. eg. when the id is "zh_Hans_SG", it return "SG".
459
*/
460
private static String getCountryCode(String id) {
461
//Truncate a variant code with '@' if there is any
462
//(eg. de_DE@collation=phonebook,currency=DOM)
463
if (id.indexOf('@') != -1) {
464
id = id.substring(0, id.indexOf('@'));
465
}
466
String[] tokens = id.split("_");
467
for (int index = 1; index < tokens.length; ++index) {
468
if (tokens[index].length() == 2
469
&& Character.isLetter(tokens[index].charAt(0))
470
&& Character.isLetter(tokens[index].charAt(1))) {
471
return tokens[index];
472
}
473
}
474
return null;
475
}
476
477
private static class KeyComparator implements Comparator<String> {
478
static KeyComparator INSTANCE = new KeyComparator();
479
480
private KeyComparator() {
481
}
482
483
@Override
484
public int compare(String o1, String o2) {
485
int len1 = o1.length();
486
int len2 = o2.length();
487
if (!isDigit(o1.charAt(0)) && !isDigit(o2.charAt(0))) {
488
// Shorter string comes first unless either starts with a digit.
489
if (len1 < len2) {
490
return -1;
491
}
492
if (len1 > len2) {
493
return 1;
494
}
495
}
496
return o1.compareTo(o2);
497
}
498
499
private boolean isDigit(char c) {
500
return c >= '0' && c <= '9';
501
}
502
}
503
504
private static Map<String, Object> extractLocaleNames(Map<String, Object> map, String id) {
505
Map<String, Object> localeNames = new TreeMap<>(KeyComparator.INSTANCE);
506
for (String key : map.keySet()) {
507
if (key.startsWith(LOCALE_NAME_PREFIX)) {
508
localeNames.put(key.substring(LOCALE_NAME_PREFIX.length()), map.get(key));
509
}
510
}
511
return localeNames;
512
}
513
514
@SuppressWarnings("AssignmentToForLoopParameter")
515
private static Map<String, Object> extractCurrencyNames(Map<String, Object> map, String id, String names)
516
throws Exception {
517
Map<String, Object> currencyNames = new TreeMap<>(KeyComparator.INSTANCE);
518
for (String key : map.keySet()) {
519
if (key.startsWith(CURRENCY_NAME_PREFIX)) {
520
currencyNames.put(key.substring(CURRENCY_NAME_PREFIX.length()), map.get(key));
521
} else if (key.startsWith(CURRENCY_SYMBOL_PREFIX)) {
522
currencyNames.put(key.substring(CURRENCY_SYMBOL_PREFIX.length()), map.get(key));
523
}
524
}
525
return currencyNames;
526
}
527
528
private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) {
529
Map<String, Object> names = new HashMap<>();
530
for (String tzid : handlerMetaZones.keySet()) {
531
String tzKey = TIMEZONE_ID_PREFIX + tzid;
532
Object data = map.get(tzKey);
533
if (data instanceof String[]) {
534
names.put(tzid, data);
535
} else {
536
String meta = handlerMetaZones.get(tzid);
537
if (meta != null) {
538
String metaKey = METAZONE_ID_PREFIX + meta;
539
data = map.get(metaKey);
540
if (data instanceof String[]) {
541
// Keep the metazone prefix here.
542
names.put(metaKey, data);
543
names.put(tzid, meta);
544
}
545
}
546
}
547
}
548
return names;
549
}
550
551
private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) {
552
Map<String, Object> calendarData = new LinkedHashMap<>();
553
copyIfPresent(map, "firstDayOfWeek", calendarData);
554
copyIfPresent(map, "minimalDaysInFirstWeek", calendarData);
555
return calendarData;
556
}
557
558
static final String[] FORMAT_DATA_ELEMENTS = {
559
"MonthNames",
560
"standalone.MonthNames",
561
"MonthAbbreviations",
562
"standalone.MonthAbbreviations",
563
"MonthNarrows",
564
"standalone.MonthNarrows",
565
"DayNames",
566
"standalone.DayNames",
567
"DayAbbreviations",
568
"standalone.DayAbbreviations",
569
"DayNarrows",
570
"standalone.DayNarrows",
571
"QuarterNames",
572
"standalone.QuarterNames",
573
"QuarterAbbreviations",
574
"standalone.QuarterAbbreviations",
575
"QuarterNarrows",
576
"standalone.QuarterNarrows",
577
"AmPmMarkers",
578
"narrow.AmPmMarkers",
579
"long.Eras",
580
"Eras",
581
"narrow.Eras",
582
"field.era",
583
"field.year",
584
"field.month",
585
"field.week",
586
"field.weekday",
587
"field.dayperiod",
588
"field.hour",
589
"field.minute",
590
"field.second",
591
"field.zone",
592
"TimePatterns",
593
"DatePatterns",
594
"DateTimePatterns",
595
"DateTimePatternChars"
596
};
597
598
private static Map<String, Object> extractFormatData(Map<String, Object> map, String id) {
599
Map<String, Object> formatData = new LinkedHashMap<>();
600
for (CalendarType calendarType : CalendarType.values()) {
601
String prefix = calendarType.keyElementName();
602
for (String element : FORMAT_DATA_ELEMENTS) {
603
String key = prefix + element;
604
copyIfPresent(map, "java.time." + key, formatData);
605
copyIfPresent(map, key, formatData);
606
}
607
}
608
// Workaround for islamic-umalqura name support (JDK-8015986)
609
switch (id) {
610
case "ar":
611
map.put(CLDRConverter.CALENDAR_NAME_PREFIX
612
+ CalendarType.ISLAMIC_UMALQURA.lname(),
613
// derived from CLDR 24 draft
614
"\u0627\u0644\u062a\u0642\u0648\u064a\u0645 "
615
+"\u0627\u0644\u0625\u0633\u0644\u0627\u0645\u064a "
616
+"[\u0623\u0645 \u0627\u0644\u0642\u0631\u0649]");
617
break;
618
case "en":
619
map.put(CLDRConverter.CALENDAR_NAME_PREFIX
620
+ CalendarType.ISLAMIC_UMALQURA.lname(),
621
// derived from CLDR 24 draft
622
"Islamic Calendar [Umm al-Qura]");
623
break;
624
}
625
// Copy available calendar names
626
for (String key : map.keySet()) {
627
if (key.startsWith(CLDRConverter.CALENDAR_NAME_PREFIX)) {
628
String type = key.substring(CLDRConverter.CALENDAR_NAME_PREFIX.length());
629
for (CalendarType calendarType : CalendarType.values()) {
630
if (type.equals(calendarType.lname())) {
631
Object value = map.get(key);
632
formatData.put(key, value);
633
String ukey = CLDRConverter.CALENDAR_NAME_PREFIX + calendarType.uname();
634
if (!key.equals(ukey)) {
635
formatData.put(ukey, value);
636
}
637
}
638
}
639
}
640
}
641
642
copyIfPresent(map, "DefaultNumberingSystem", formatData);
643
644
@SuppressWarnings("unchecked")
645
List<String> numberingScripts = (List<String>) map.remove("numberingScripts");
646
if (numberingScripts != null) {
647
for (String script : numberingScripts) {
648
copyIfPresent(map, script + "." + "NumberElements", formatData);
649
}
650
} else {
651
copyIfPresent(map, "NumberElements", formatData);
652
}
653
copyIfPresent(map, "NumberPatterns", formatData);
654
return formatData;
655
}
656
657
private static void copyIfPresent(Map<String, Object> src, String key, Map<String, Object> dest) {
658
Object value = src.get(key);
659
if (value != null) {
660
dest.put(key, value);
661
}
662
}
663
664
// --- code below here is adapted from java.util.Properties ---
665
private static final String specialSaveCharsJava = "\"";
666
private static final String specialSaveCharsProperties = "=: \t\r\n\f#!";
667
668
/*
669
* Converts unicodes to encoded &#92;uxxxx
670
* and writes out any of the characters in specialSaveChars
671
* with a preceding slash
672
*/
673
static String saveConvert(String theString, boolean useJava) {
674
if (theString == null) {
675
return "";
676
}
677
678
String specialSaveChars;
679
if (useJava) {
680
specialSaveChars = specialSaveCharsJava;
681
} else {
682
specialSaveChars = specialSaveCharsProperties;
683
}
684
boolean escapeSpace = false;
685
686
int len = theString.length();
687
StringBuilder outBuffer = new StringBuilder(len * 2);
688
Formatter formatter = new Formatter(outBuffer, Locale.ROOT);
689
690
for (int x = 0; x < len; x++) {
691
char aChar = theString.charAt(x);
692
switch (aChar) {
693
case ' ':
694
if (x == 0 || escapeSpace) {
695
outBuffer.append('\\');
696
}
697
outBuffer.append(' ');
698
break;
699
case '\\':
700
outBuffer.append('\\');
701
outBuffer.append('\\');
702
break;
703
case '\t':
704
outBuffer.append('\\');
705
outBuffer.append('t');
706
break;
707
case '\n':
708
outBuffer.append('\\');
709
outBuffer.append('n');
710
break;
711
case '\r':
712
outBuffer.append('\\');
713
outBuffer.append('r');
714
break;
715
case '\f':
716
outBuffer.append('\\');
717
outBuffer.append('f');
718
break;
719
default:
720
if (aChar < 0x0020 || (!USE_UTF8 && aChar > 0x007e)) {
721
formatter.format("\\u%04x", (int)aChar);
722
} else {
723
if (specialSaveChars.indexOf(aChar) != -1) {
724
outBuffer.append('\\');
725
}
726
outBuffer.append(aChar);
727
}
728
}
729
}
730
return outBuffer.toString();
731
}
732
733
private static String toLanguageTag(String locName) {
734
if (locName.indexOf('_') == -1) {
735
return locName;
736
}
737
String tag = locName.replaceAll("_", "-");
738
Locale loc = Locale.forLanguageTag(tag);
739
return loc.toLanguageTag();
740
}
741
742
private static String toLocaleName(String tag) {
743
if (tag.indexOf('-') == -1) {
744
return tag;
745
}
746
return tag.replaceAll("-", "_");
747
}
748
}
749
750