xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/tool/ExtractMessages.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
1 package org.unicode.cldr.tool;
2 
3 import com.ibm.icu.impl.Relation;
4 import com.ibm.icu.lang.UCharacter;
5 import com.ibm.icu.text.Collator;
6 import com.ibm.icu.text.DateFormatSymbols;
7 import com.ibm.icu.text.UnicodeSet;
8 import com.ibm.icu.util.ULocale;
9 import java.io.File;
10 import java.io.IOException;
11 import java.io.PrintWriter;
12 import java.util.Locale;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.TreeMap;
16 import java.util.TreeSet;
17 import java.util.regex.Matcher;
18 import org.unicode.cldr.draft.FileUtilities;
19 import org.unicode.cldr.util.CLDRFile;
20 import org.unicode.cldr.util.CLDRFile.WinningChoice;
21 import org.unicode.cldr.util.CLDRPaths;
22 import org.unicode.cldr.util.CldrUtility;
23 import org.unicode.cldr.util.Factory;
24 import org.unicode.cldr.util.Pair;
25 import org.unicode.cldr.util.PathUtilities;
26 import org.unicode.cldr.util.PatternCache;
27 import org.unicode.cldr.util.SimpleFactory;
28 import org.unicode.cldr.util.StandardCodes;
29 import org.unicode.cldr.util.TransliteratorUtilities;
30 import org.unicode.cldr.util.XMLFileReader;
31 
32 class ExtractMessages {
33     public static final UnicodeSet LATIN_SCRIPT = new UnicodeSet("[:script=latin:]").freeze();
34 
35     private static Matcher fileMatcher;
36 
37     public static PrintWriter output;
38 
39     public static boolean SKIPEQUALS = true;
40     public static boolean SKIPIFCLDR = true;
41     public static String DIR = CLDRPaths.GEN_DIRECTORY + "/../additions/";
42 
main(String[] args)43     public static void main(String[] args) throws IOException {
44         double startTime = System.currentTimeMillis();
45         output = FileUtilities.openUTF8Writer(DIR, "additions.txt");
46         int totalCount = 0;
47         Set<String> skipped = new TreeSet<>();
48 
49         try {
50             String sourceDirectory = getProperty("SOURCE", null);
51             if (sourceDirectory == null) {
52                 System.out.println("Need Source Directory! ");
53                 return;
54             }
55             fileMatcher = PatternCache.get(getProperty("FILE", ".*")).matcher("");
56 
57             SKIPIFCLDR = getProperty("SKIPIFCLDR", null) != null;
58 
59             boolean showMissing = true;
60 
61             File src = new File(sourceDirectory);
62 
63             XMLFileReader xfr = new XMLFileReader().setHandler(new EnglishHandler());
64             xfr.read(
65                     src + "/en.xmb",
66                     XMLFileReader.CONTENT_HANDLER | XMLFileReader.ERROR_HANDLER,
67                     false);
68 
69             for (File file : src.listFiles()) {
70                 if (file.isDirectory()) continue;
71                 if (file.length() == 0) continue;
72                 String canonicalFile = PathUtilities.getNormalizedPathString(file);
73                 if (!canonicalFile.endsWith(".xtb")) {
74                     continue;
75                 }
76 
77                 String name = file.getName();
78                 name = name.substring(0, name.length() - 4);
79 
80                 if (!fileMatcher.reset(name).matches()) {
81                     continue;
82                 }
83                 System.out.println("* " + canonicalFile);
84 
85                 try {
86                     otherHandler.setLocale(name);
87                 } catch (RuntimeException e1) {
88                     System.out.println(
89                             "Skipping, no CLDR locale file: "
90                                     + name
91                                     + "\t"
92                                     + english.getName(name)
93                                     + "\t"
94                                     + e1.getClass().getName()
95                                     + "\t"
96                                     + e1.getMessage());
97                     skipped.add(name);
98                     continue;
99                 }
100 
101                 xfr = new XMLFileReader().setHandler(otherHandler);
102                 try {
103                     xfr.read(
104                             canonicalFile,
105                             XMLFileReader.CONTENT_HANDLER | XMLFileReader.ERROR_HANDLER,
106                             false);
107                 } catch (RuntimeException e) {
108                     System.out.println(e.getMessage());
109                     continue;
110                 }
111 
112                 // now write it out
113                 CLDRFile newFile = SimpleFactory.makeFile(otherHandler.getLocale());
114                 int itemCount = 0;
115                 for (DataHandler dataHandler : dataHandlers) {
116                     if (showMissing) {
117                         System.out.println("case " + dataHandler.type + ":");
118                         for (String value : dataHandler.missing) {
119                             System.out.println("addName(\"" + value + "\", \"XXX\", true);");
120                         }
121                     }
122 
123                     for (String id : dataHandler.id_to_value.keySet()) {
124                         Set<String> otherValue = dataHandler.id_to_value.getAll(id);
125                         if (otherValue == null || otherValue.size() == 0) continue;
126                         String cldrValue = dataHandler.id_to_cldrValue.get(id);
127                         int count = 0;
128                         for (String oValue : otherValue) {
129                             itemCount++;
130                             output.println(
131                                     otherHandler.getLocale()
132                                             + "\t"
133                                             + dataHandler.type
134                                             + "\t"
135                                             + id
136                                             + "\t"
137                                             + oValue
138                                             + (cldrValue == null ? "" : "\tcldr:\t" + cldrValue)
139                                             + (count == 0
140                                                     ? ""
141                                                     : "\talt:\t" + String.valueOf(count)));
142                             newFile.add(dataHandler.getPath(id, count), oValue);
143                         }
144                     }
145                 }
146                 PrintWriter cldrOut =
147                         FileUtilities.openUTF8Writer(DIR, otherHandler.getLocale() + ".xml");
148                 newFile.write(cldrOut);
149                 cldrOut.close();
150 
151                 output.println();
152                 showMissing = false;
153                 output.flush();
154                 System.out.println("\titems: " + itemCount);
155                 totalCount += itemCount;
156             }
157 
158             for (String name : skipped) {
159                 System.out.println(
160                         "\tSkipping, no CLDR locale file: " + name + "\t" + english.getName(name));
161             }
162             double deltaTime = System.currentTimeMillis() - startTime;
163             System.out.println("Elapsed: " + deltaTime / 1000.0 + " seconds");
164             System.out.println("\ttotal items: " + totalCount);
165         } finally {
166             output.close();
167         }
168     }
169 
getProperty(String key, String defaultValue)170     private static String getProperty(String key, String defaultValue) {
171         String fileRegex = System.getProperty(key);
172         if (fileRegex == null) fileRegex = defaultValue;
173         System.out.println("-D" + key + "=" + fileRegex);
174         return fileRegex;
175     }
176 
177     private static Map<String, Pair<String, DataHandler>> numericId_Id = new TreeMap<>();
178     private static Matcher numericIdMatcher =
179             PatternCache.get("\\[@id=\"([^\"]+)\"\\]").matcher("");
180     private static Factory cldrFactory = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*");
181     private static CLDRFile english = cldrFactory.make("en", true);
182 
183     private static class EnglishHandler extends XMLFileReader.SimpleHandler {
184 
185         @Override
handlePathValue(String path, String value)186         public void handlePathValue(String path, String value) {
187             for (DataHandler handler : dataHandlers) {
188                 if (handler.matches(path)) {
189                     // //messagebundle/msg[@id="1907015897505457162"][@seq="71982"][@desc="Andorra
190                     // is a display name for a timezone"][@xml:space="default"]
191                     numericIdMatcher.reset(path).find();
192                     String id = numericIdMatcher.group(1);
193                     value = value.trim();
194                     if (value.length() == 0) return; // skip empties
195                     value = TransliteratorUtilities.fromXML.transliterate(value);
196                     String realID = handler.getCode(value);
197                     if (realID == null) {
198                         handler.missing.add(value);
199                         return;
200                     }
201                     numericId_Id.put(id, new Pair<>(realID, handler));
202                     // System.out.println(id + "\t" + path + "\t" + value);
203                 }
204             }
205         }
206     }
207 
208     public static Collator col = Collator.getInstance(ULocale.ENGLISH);
209 
210     static {
211         col.setStrength(Collator.SECONDARY);
212     }
213 
214     private static OtherHandler otherHandler = new OtherHandler();
215 
216     private static class OtherHandler extends XMLFileReader.SimpleHandler {
217         private String locale;
218         private ULocale uLocale;
219         CLDRFile cldrFile;
220         boolean usesLatin;
221 
222         @Override
handlePathValue(String path, String value)223         public void handlePathValue(String path, String value) {
224             // //messagebundle/msg[@id="1907015897505457162"][@seq="71982"][@desc="Andorra is a
225             // display name for a timezone"][@xml:space="default"]
226             value = value.trim();
227             if (value.length() == 0) return; // skip empties
228 
229             numericIdMatcher.reset(path).find();
230             String numericId = numericIdMatcher.group(1);
231             Pair<String, DataHandler> id_handler = numericId_Id.get(numericId);
232             if (id_handler == null) return;
233             String id = id_handler.getFirst();
234             DataHandler dataHandler = id_handler.getSecond();
235 
236             if (!usesLatin && LATIN_SCRIPT.containsSome(value)) {
237                 // output.println(locale + "\tSkipping item with latin characters\t" + id + "\t" +
238                 // value);
239                 return;
240             }
241 
242             // this should be reorganized to put more in the DataHandler, but for now...
243 
244             value = dataHandler.fixValue(uLocale, value);
245 
246             String cldrValue = dataHandler.getCldrValue(cldrFile, id);
247             if (cldrValue != null) {
248                 if (col.compare(cldrValue, value) == 0) {
249                     // System.out.println("Duplicate for " + id + "\t" + value);
250                     if (SKIPEQUALS) return;
251                 } else {
252                     if (SKIPIFCLDR) return;
253                     // output.println(locale + "\tDifferent value for\t" + id + "\t" + value +
254                     // "\tcldr:\t" + cldrValue);
255                 }
256             }
257             dataHandler.addValues(id, value, cldrValue);
258         }
259 
setLocale(String locale)260         public void setLocale(String locale) {
261 
262             // skip en, fr_CA
263             // as, sa bad
264             // ku cldr-latin, g-arabic
265             // ml, my, pa, te has mixed english
266             // TODO move this into datahandler eventually
267             locale = fixLocale(locale);
268             this.locale = locale;
269             this.uLocale = new ULocale(locale);
270             String lang = uLocale.getLanguage();
271             if (locale.equals("fr_CA") || lang.equals("en")) {
272                 throw new RuntimeException("Skipping " + locale);
273             }
274             cldrFile = cldrFactory.make(locale, false);
275             UnicodeSet exemplars = cldrFile.getExemplarSet("", WinningChoice.WINNING);
276             usesLatin = exemplars != null && exemplars.containsSome(LATIN_SCRIPT);
277             for (DataHandler dataHandler : dataHandlers) {
278                 dataHandler.reset(cldrFile);
279             }
280         }
281 
getLocale()282         public String getLocale() {
283             return locale;
284         }
285     }
286 
287     static Map<String, String> fixLocaleMap =
288             CldrUtility.asMap(
289                     new String[][] {
290                         {"zh_CN", "zh"},
291                         {"zh_TW", "zh_Hant"},
292                         {"pt_BR", "pt"},
293                         {"in", "id"},
294                         {"iw", "he"},
295                         {"jw", "jv"},
296                         {"ku", "ku_Arab"},
297                     });
298 
fixLocale(String locale)299     private static String fixLocale(String locale) {
300         locale = locale.replace('-', '_');
301         String newLocale = fixLocaleMap.get(locale);
302         if (newLocale != null) {
303             locale = newLocale;
304         }
305         return locale;
306     }
307 
308     /*
309      * Language
310      * -DXMLPATH=".*form of language.*"
311      *
312      * Country
313      * -DXMLPATH=".*the country or region.*"
314      *
315      * Currency
316      * -DXMLPATH=".*currency name.*"
317      *
318      * Month Long/Short
319      * -DXMLPATH=".*Name of the month of .*"
320      * -DXMLPATH=".*3 letter abbreviation for name of Month.*"
321      *
322      * Week Long/Short
323      * -DXMLPATH=".*day in week.*"
324      * -DXMLPATH=".*Short Version of .*"
325      *
326      * Timezone
327      * DXMLPATH=".*is a display name for a timezone.*"
328      */
329 
330     enum Type {
331         LANGUAGE,
332         REGION,
333         CURRENCY,
334         MONTH,
335         MONTHSHORT,
336         DAY,
337         DAYSHORT,
338         TIMEZONE
339     }
340 
341     static StandardCodes sc = StandardCodes.make();
342     static DateFormatSymbols dfs = new DateFormatSymbols(ULocale.ENGLISH);
343 
344     static DataHandler[] dataHandlers = {
345         new DataHandler(Type.LANGUAGE, ".*form of language.*"),
346         new DataHandler(Type.REGION, ".*the country or region.*"),
347         new DataHandler(Type.CURRENCY, ".*currency name.*"),
348         new DataHandler(Type.MONTH, ".*Name of the month of .*"),
349         new DataHandler(Type.MONTHSHORT, ".*3 letter abbreviation for name of Month.*"),
350         new DataHandler(Type.DAY, ".*day in week.*"),
351         new DataHandler(Type.DAYSHORT, ".*Short Version of .*"),
352         new DataHandler(Type.TIMEZONE, ".*is a display name for a timezone.*"),
353     };
354 
355     enum CasingAction {
356         NONE,
357         FORCE_TITLE,
358         FORCE_LOWER
359     }
360 
361     static class DataHandler implements Comparable<DataHandler> {
362         // mostly stable
363         private Matcher matcher;
364         private Type type;
365         private Map<String, String> name_code = new TreeMap<>();
366         // private Map<String,String> code_name = new TreeMap();
367         private Set<String> missing = new TreeSet<>();
368 
369         // changes with each locale, must call reset
370         private Relation<String, String> id_to_value =
371                 Relation.of(new TreeMap<String, Set<String>>(), TreeSet.class);
372         private Map<String, String> id_to_cldrValue = new TreeMap<>();
373         private CasingAction forceCasing = CasingAction.NONE;
374 
reset(CLDRFile cldrFile)375         public void reset(CLDRFile cldrFile) {
376             id_to_value.clear();
377             id_to_cldrValue.clear();
378             forceCasing = CasingAction.NONE;
379             String key = null;
380             switch (type) {
381                 case LANGUAGE:
382                     key = "en";
383                     break;
384                 case REGION:
385                     key = "FR";
386                     break;
387                 case CURRENCY:
388                     key = "GBP";
389                     break;
390                 case MONTH:
391                 case MONTHSHORT:
392                     key = "1";
393                     break;
394                 case DAY:
395                 case DAYSHORT:
396                     key = "mon";
397                     break;
398                 case TIMEZONE:
399                     key = "America/New_York";
400                     break;
401             }
402             String sample = getCldrValue(cldrFile, key);
403             if (sample != null) {
404                 if (UCharacter.isLowerCase(sample.charAt(0))) {
405                     forceCasing = CasingAction.FORCE_LOWER;
406                 } else if (UCharacter.isUpperCase(sample.charAt(0))) {
407                     forceCasing = CasingAction.FORCE_TITLE;
408                 }
409             }
410         }
411 
fixValue(ULocale uLocale, String value)412         public String fixValue(ULocale uLocale, String value) {
413             value = TransliteratorUtilities.fromXML.transliterate(value);
414 
415             if (forceCasing == CasingAction.FORCE_LOWER) {
416                 if (!UCharacter.isLowerCase(value.charAt(0))) {
417                     value = UCharacter.toLowerCase(value);
418                 }
419             } else if (forceCasing == CasingAction.FORCE_TITLE) {
420                 if (!UCharacter.isUpperCase(value.charAt(0))) {
421                     value = UCharacter.toTitleCase(uLocale, value, null);
422                 }
423             }
424 
425             return value;
426         }
427 
addValues(String id, String value, String cldrValue)428         public void addValues(String id, String value, String cldrValue) {
429             id_to_value.put(id, value);
430             if (cldrValue != null) {
431                 id_to_cldrValue.put(id, cldrValue);
432             }
433         }
434 
addName(String name, String code, boolean skipMessage)435         public void addName(String name, String code, boolean skipMessage) {
436             // String old = code_name.get(code);
437             // if (old != null) {
438             // if (!skipMessage) {
439             // System.out.println("Name collision:\t" + code + "\tnew: " + name + "\tkeeping: " +
440             // old);
441             // }
442             // } else {
443             // }
444             // code_name.put(code, name);
445             name_code.put(name, code);
446         }
447 
DataHandler(Type type, String pattern)448         DataHandler(Type type, String pattern) {
449             this.type = type;
450             matcher = PatternCache.get(pattern).matcher("");
451             switch (type) {
452                 case LANGUAGE:
453                     for (String code : sc.getAvailableCodes("language")) {
454                         String name = english.getName("language", code);
455                         if (name == null) {
456                             // System.out.println("Missing name for: " + code);
457                             continue;
458                         }
459                         addName(name, code.replace("-", "_"), false);
460                     }
461                     // add irregular names
462                     addName("English (US)", "en_US", true);
463                     addName("English (UK)", "en_GB", true);
464                     // addName("English (AU)", "en_AU/short");
465                     // addName("Portuguese (PT)", "pt_PT/short");
466                     // addName("Portuguese (BR)", "pt_BR/short");
467                     addName("Chinese (Simplified)", "zh_Hans", true);
468                     addName("Chinese (Traditional)", "zh_Hant", true);
469                     addName("Norwegian (Nynorsk)", "nn", true);
470                     addName("Portuguese (Portugal)", "pt_PT", true);
471                     addName("Portuguese (Brazil)", "pt_BR", true);
472                     addName("English (Australia)", "en_AU", true);
473                     addName("Scots Gaelic", "gd", true);
474                     addName("Frisian", "fy", true);
475                     addName("Sesotho", "st", true);
476                     addName("Kyrgyz", "ky", true);
477                     addName("Laothian", "lo", true);
478                     addName("Cambodian", "km", true);
479                     addName("Greenlandic", "kl", true);
480                     addName("Inupiak", "ik", true);
481                     addName("Volapuk", "vo", true);
482                     addName("Byelorussian", "be", true);
483                     addName("Faeroese", "fo", true);
484                     addName("Singhalese", "si", true);
485                     addName("Gaelic", "ga", true); // IRISH
486                     addName("Bhutani", "dz", true);
487                     addName("Setswana", "tn", true);
488                     addName("Siswati", "ss", true);
489                     addName("Sangro", "sg", true);
490                     // addName("Kirundi", "XXX"); // no ISO2 code
491                     // addName("Sudanese", "XXX"); // ???
492                     break;
493                 case REGION:
494                     for (String code : sc.getAvailableCodes("territory")) {
495                         String name = english.getName("territory", code);
496                         if (name == null) {
497                             // System.out.println("Missing name for: " + code);
498                             continue;
499                         }
500                         addName(name, code, false);
501                     }
502                     // add irregular names
503                     addName("Bosnia and Herzegowina", "BA", true);
504                     addName("Congo", "CG", true);
505                     addName("Congo, Democratic Republic of the", "CD", true);
506                     addName("Congo, The Democratic Republic of the", "CD", true);
507                     addName("Cote D'ivoire", "CI", true);
508                     addName("Côte d'Ivoire", "CI", true);
509                     addName("Equitorial Guinea", "GQ", true);
510                     addName("French Quiana", "GF", true);
511                     addName("Heard and Mc Donald Islands", "HM", true);
512                     addName("Holy See (Vatican City State)", "VA", true);
513                     addName("Iran (Islamic Republic of)", "IR", true);
514                     addName("Korea, Democratic People's Republic of", "KP", true);
515                     addName("Korea, Republic of", "KR", true);
516                     addName("Libyan Arab Jamahiriya", "LY", true);
517                     addName("Lichtenstein", "LI", true);
518                     addName("Macao", "MO", true);
519                     addName("Micronesia, Federated States of", "FM", true);
520                     addName("Palestine", "PS", true);
521                     addName("Serbia and Montenegro", "CS", true);
522                     addName("Slovakia (Slovak Republic)", "SK", true);
523                     addName("São Tomé and Príncipe", "ST", true);
524                     addName("The Former Yugoslav Republic of Macedonia", "MK", true);
525                     addName("United States minor outlying islands", "UM", true);
526                     addName("Vatican City", "VA", true);
527                     addName("Virgin Islands, British", "VG", true);
528                     addName("Virgin Islands, U.S.", "VI", true);
529                     addName("Zaire", "CD", true);
530                     addName("Åland Islands", "AX", true);
531                     break;
532                 case CURRENCY:
533                     for (String code : sc.getAvailableCodes("currency")) {
534                         String name = english.getName("currency", code);
535                         if (name == null) {
536                             // System.out.println("Missing name for: " + code);
537                             continue;
538                         }
539                         addName(name, code, false);
540                     }
541                     // add irregular names
542                     addName("Australian Dollars", "AUD", true);
543                     addName("Bolivian Boliviano", "BOB", true);
544                     addName("British Pounds Sterling", "GBP", true);
545                     addName("Bulgarian Lev", "BGN", true);
546                     addName("Canadian Dollars", "CAD", true);
547                     addName("Czech Koruna", "CZK", true);
548                     addName("Danish Kroner", "DKK", true);
549                     addName("Denmark Kroner", "DKK", true);
550                     addName("Deutsche Marks", "DEM", true);
551                     addName("Euros", "EUR", true);
552                     addName("French Franks", "FRF", true);
553                     addName("Hong Kong Dollars", "HKD", true);
554                     addName("Israeli Shekel", "ILS", true);
555                     addName("Lithuanian Litas", "LTL", true);
556                     addName("Mexico Peso", "MXN", true);
557                     addName("New Romanian Leu", "RON", true);
558                     addName("New Taiwan Dollar", "TWD", true);
559                     addName("New Zealand Dollars", "NZD", true);
560                     addName("Norway Kroner", "NOK", true);
561                     addName("Norwegian Kroner", "NOK", true);
562                     addName("Peruvian Nuevo Sol", "PEN", true);
563                     addName("Polish New Zloty", "PLN", true);
564                     addName("Polish NewZloty", "PLN", true);
565                     addName("Russian Rouble", "RUB", true);
566                     addName("Singapore Dollars", "SGD", true);
567                     addName("Slovenian Tolar", "SIT", true);
568                     addName("Sweden Kronor", "SEK", true);
569                     addName("Swedish Kronor", "SEK", true);
570                     addName("Swiss Francs", "CHF", true);
571                     addName("US Dollars", "USD", true);
572                     addName("United Arab EmiratesD irham", "AED", true);
573                     addName("Venezuela Bolivar", "VEB", true);
574                     addName("Yuan Renminbi", "CNY", true);
575                     break;
576                 case TIMEZONE:
577                     for (String code : sc.getAvailableCodes("tzid")) {
578                         String[] parts = code.split("/");
579                         addName(parts[parts.length - 1].replace("_", " "), code, false);
580                     }
581                     // add irregular names
582                     addName("Alaska Time", "America/Anchorage", true);
583                     // addName("Atlantic Time", "XXX", true);
584                     // addName("Atlantic Time - Halifax", "America/Halifax", true);
585                     addName("Canary Islands", "Atlantic/Canary", true);
586                     // addName("Central European Time", "XXX", true);
587                     // addName("Central European Time - Madrid", "Europe/Madrid", true);
588                     // addName("Central Time", "America/Chicago", true);
589                     // addName("Central Time - Adelaide", "Australia/Adelaide", true);
590                     // addName("Central Time - Darwin", "Australia/Darwin", true);
591                     // addName("Central Time - Mexico City", "America/Mexico_City", true);
592                     // addName("Central Time - Mexico City, Monterrey", "America/Monterrey", true);
593                     // addName("Central Time - Regina", "America/Regina", true);
594                     // addName("Central Time - Sasketchewan", "XXX", true);
595                     // addName("Central Time - Winnipeg", "America/Winnipeg", true);
596                     // addName("China Time - Beijing", "XXX", true);
597                     addName("Dumont D'Urville", "Antarctica/DumontDUrville", true);
598                     addName("Easter Island", "Pacific/Easter", true);
599                     // addName("Eastern European Time", "XXX", true);
600                     // addName("Eastern Standard Time", "XXX", true);
601                     // addName("Eastern Time", "XXX", true);
602                     // addName("Eastern Time - Brisbane", "Australia/Brisbane", true);
603                     // addName("Eastern Time - Hobart", "Australia/Hobart", true);
604                     // addName("Eastern Time - Iqaluit", "America/Iqaluit", true);
605                     // addName("Eastern Time - Melbourne, Sydney", "XXX", true);
606                     // addName("Eastern Time - Montreal", "XXX", true);
607                     // addName("Eastern Time - Toronto", "XXX", true);
608                     // addName("GMT (no daylight saving)", "XXX", true);
609                     // addName("Greenwich Mean Time", "XXX", true);
610                     // addName("Hanoi", "XXX", true);
611                     // addName("Hawaii Time", "XXX", true);
612                     // addName("India Standard Time", "XXX", true);
613                     // addName("International Date Line West", "XXX", true);
614                     // addName("Japan Time", "XXX", true);
615                     // addName("Moscow+00", "XXX", true);
616                     // addName("Moscow+01 - Samara", "XXX", true);
617                     // addName("Moscow+02 - Yekaterinburg", "XXX", true);
618                     // addName("Moscow+03 - Omsk, Novosibirsk", "XXX", true);
619                     // addName("Moscow+04 - Krasnoyarsk", "XXX", true);
620                     // addName("Moscow+05 - Irkutsk", "XXX", true);
621                     // addName("Moscow+06 - Yakutsk", "XXX", true);
622                     // addName("Moscow+07 - Vladivostok, Sakhalin", "XXX", true);
623                     // addName("Moscow+07 - Yuzhno-Sakhalinsk", "XXX", true);
624                     // addName("Moscow+08 - Magadan", "XXX", true);
625                     // addName("Moscow+09 - Kamchatka, Anadyr", "XXX", true);
626                     // addName("Moscow+09 - Petropavlovsk-Kamchatskiy", "XXX", true);
627                     // addName("Moscow-01 - Kaliningrad", "XXX", true);
628                     // addName("Mountain Time", "XXX", true);
629                     // addName("Mountain Time - Arizona", "XXX", true);
630                     // addName("Mountain Time - Chihuahua, Mazatlan", "XXX", true);
631                     // addName("Mountain Time - Dawson Creek", "XXX", true);
632                     // addName("Mountain Time - Edmonton", "XXX", true);
633                     // addName("Mountain Time - Hermosillo", "XXX", true);
634                     // addName("Mountain Time - Yellowknife", "XXX", true);
635                     // addName("Newfoundland Time - St. Johns", "XXX", true);
636                     // addName("Pacific Time", "XXX", true);
637                     // addName("Pacific Time - Tijuana", "XXX", true);
638                     // addName("Pacific Time - Vancouver", "XXX", true);
639                     // addName("Pacific Time - Whitehorse", "XXX", true);
640                     addName("Salvador", "America/El_Salvador", true);
641                     addName("St. Kitts", "America/St_Kitts", true);
642                     addName("St. Lucia", "America/St_Lucia", true);
643                     addName("St. Thomas", "America/St_Thomas", true);
644                     addName("St. Vincent", "America/St_Vincent", true);
645                     // addName("Tel Aviv", "XXX", true);
646                     // addName("Western European Time", "XXX", true);
647                     // addName("Western European Time - Canary Islands", "XXX", true);
648                     // addName("Western European Time - Ceuta", "XXX", true);
649                     // addName("Western Time - Perth", "XXX", true);
650                     break;
651                 case MONTH:
652                 case MONTHSHORT:
653                     String[] names = type == Type.MONTH ? dfs.getMonths() : dfs.getShortMonths();
654                     for (int i = 0; i < names.length; ++i) {
655                         addName(names[i], String.valueOf(i + 1), true);
656                     }
657                     break;
658                 case DAY:
659                 case DAYSHORT:
660                     String[] names2 = type == Type.DAY ? dfs.getWeekdays() : dfs.getShortWeekdays();
661                     for (int i = 1; i < names2.length; ++i) {
662                         addName(
663                                 names2[i],
664                                 names2[i].substring(0, 3).toLowerCase(Locale.ENGLISH),
665                                 true);
666                     }
667                     break;
668                 default:
669                     // throw new IllegalArgumentException();
670                     break;
671             }
672         }
673 
getCldrValue(CLDRFile cldrFile, String id)674         public String getCldrValue(CLDRFile cldrFile, String id) {
675             String result = cldrFile.getStringValue(getPath(id));
676             // cldrFile.getName(CLDRFile.LANGUAGE_NAME, id, false);
677             if (result == null && type == Type.TIMEZONE) {
678                 String[] parts = id.split("/");
679                 result = parts[parts.length - 1].replace("_", " ");
680             }
681             return result;
682         }
683 
matches(String text)684         boolean matches(String text) {
685             return matcher.reset(text).matches();
686         }
687 
getCode(String value)688         String getCode(String value) {
689             return name_code.get(value);
690         }
691 
692         @Override
compareTo(DataHandler o)693         public int compareTo(DataHandler o) {
694             throw new IllegalArgumentException();
695         }
696 
getPath(String id, int count)697         String getPath(String id, int count) {
698             String result = getPath(id);
699             count += 650;
700             result += "[@alt=\"proposed-x" + count + "\"]";
701             result += "[@draft=\"provisional\"]";
702             return result;
703         }
704 
getPath(String id)705         String getPath(String id) {
706             switch (type) {
707                 case LANGUAGE:
708                     return CLDRFile.getKey(CLDRFile.LANGUAGE_NAME, id);
709                 case REGION:
710                     return CLDRFile.getKey(CLDRFile.TERRITORY_NAME, id);
711                 case CURRENCY:
712                     return CLDRFile.getKey(CLDRFile.CURRENCY_NAME, id);
713                 case TIMEZONE:
714                     return "//ldml/dates/timeZoneNames/zone[@type=\"$1\"]/exemplarCity"
715                             .replace("$1", id);
716                 case MONTH:
717                     return "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/months/monthContext[@type=\"format\"]/monthWidth[@type=\"wide\"]/month[@type=\"$1\"]"
718                             .replace("$1", id);
719                 case MONTHSHORT:
720                     return "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/months/monthContext[@type=\"format\"]/monthWidth[@type=\"abbreviated\"]/month[@type=\"$1\"]"
721                             .replace("$1", id);
722                 case DAY:
723                     return "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/days/dayContext[@type=\"format\"]/dayWidth[@type=\"wide\"]/day[@type=\"$1\"]"
724                             .replace("$1", id);
725                 case DAYSHORT:
726                     return "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/days/dayContext[@type=\"format\"]/dayWidth[@type=\"abbreviated\"]/day[@type=\"$1\"]"
727                             .replace("$1", id);
728             }
729             return null;
730             //
731         }
732     }
733 }
734