xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/tool/ShowData.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
1 /*
2  ******************************************************************************
3  * Copyright (C) 2005-2010, International Business Machines Corporation and        *
4  * others. All Rights Reserved.                                               *
5  ******************************************************************************
6  */
7 package org.unicode.cldr.tool;
8 
9 import com.google.common.base.Joiner;
10 import com.ibm.icu.dev.tool.shared.UOption;
11 import com.ibm.icu.impl.Relation;
12 import com.ibm.icu.lang.UScript;
13 import com.ibm.icu.text.Collator;
14 import com.ibm.icu.text.RuleBasedCollator;
15 import com.ibm.icu.text.Transliterator;
16 import com.ibm.icu.text.UnicodeSet;
17 import com.ibm.icu.text.UnicodeSetIterator;
18 import com.ibm.icu.util.ULocale;
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.PrintWriter;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Set;
30 import java.util.TreeMap;
31 import java.util.TreeSet;
32 import org.unicode.cldr.draft.FileUtilities;
33 import org.unicode.cldr.test.CoverageLevel2;
34 import org.unicode.cldr.util.CLDRConfig;
35 import org.unicode.cldr.util.CLDRFile;
36 import org.unicode.cldr.util.CLDRPaths;
37 import org.unicode.cldr.util.CLDRURLS;
38 import org.unicode.cldr.util.CldrUtility;
39 import org.unicode.cldr.util.CldrUtility.VariableReplacer;
40 import org.unicode.cldr.util.ExtractCollationRules;
41 import org.unicode.cldr.util.Factory;
42 import org.unicode.cldr.util.FileCopier;
43 import org.unicode.cldr.util.LanguageTagParser;
44 import org.unicode.cldr.util.Level;
45 import org.unicode.cldr.util.LocaleIDParser;
46 import org.unicode.cldr.util.PathHeader;
47 import org.unicode.cldr.util.PathHeader.SectionId;
48 import org.unicode.cldr.util.StringId;
49 import org.unicode.cldr.util.TransliteratorUtilities;
50 
51 public class ShowData {
52     private static final boolean TOO_BIG_FOR_GITHUB = true;
53 
54     private static final int HELP1 = 0,
55             HELP2 = 1,
56             SOURCEDIR = 2,
57             DESTDIR = 3,
58             MATCH = 4,
59             GET_SCRIPTS = 5,
60             LAST_DIR = 6,
61             COVERAGE = 7;
62 
63     private static final UOption[] options = {
64         UOption.HELP_H(),
65         UOption.HELP_QUESTION_MARK(),
66         UOption.SOURCEDIR().setDefault(CLDRPaths.MAIN_DIRECTORY),
67         UOption.DESTDIR().setDefault(CLDRPaths.CHART_DIRECTORY + "summary/"),
68         UOption.create("match", 'm', UOption.REQUIRES_ARG).setDefault(".*"),
69         UOption.create("getscript", 'g', UOption.NO_ARG),
70         UOption.create("last", 'l', UOption.REQUIRES_ARG)
71                 .setDefault(CLDRPaths.LAST_RELEASE_DIRECTORY + "common/main/"),
72         UOption.create("coverage", 'c', UOption.REQUIRES_ARG).setDefault(Level.MODERN.toString()),
73     };
74 
dateFooter()75     public static String dateFooter() {
76         return "<p>Generation: "
77                 + CldrUtility.isoFormatDateOnly(new java.util.Date())
78                 + "</p>"
79                 + System.lineSeparator();
80     }
81 
82     static RuleBasedCollator uca = (RuleBasedCollator) Collator.getInstance(ULocale.ROOT);
83 
84     {
85         uca.setNumericCollation(true);
86     }
87 
88     static PathHeader.Factory prettyPathMaker =
89             PathHeader.getFactory(CLDRConfig.getInstance().getEnglish());
90 
91     static CLDRFile english;
92 
93     static Set<String> locales;
94 
95     static Relation<String, String> parentToChildren =
96             Relation.of(new TreeMap<String, Set<String>>(), TreeSet.class);
97 
98     static Factory cldrFactory;
99 
main(String[] args)100     public static void main(String[] args) throws Exception {
101         // String p =
102         // prettyPathMaker.getPrettyPath("//ldml/characters/exemplarCharacters[@alt=\"proposed-u151-4\"]");
103         // String q = prettyPathMaker.getOriginal(p);
104 
105         double deltaTime = System.currentTimeMillis();
106         try {
107             CLDRConfig testInfo = ToolConfig.getToolInstance();
108             UOption.parseArgs(args, options);
109             String sourceDir = options[SOURCEDIR].value; // Utility.COMMON_DIRECTORY
110             // + "main/";
111             String targetDir = options[DESTDIR].value; // Utility.GEN_DIRECTORY +
112             // "main/";
113             cldrFactory =
114                     CLDRConfig.getInstance()
115                             .getMainAndAnnotationsFactory(); // ignore source directory for now
116             english = cldrFactory.make("en", true);
117             String lastSourceDir = options[LAST_DIR].value; // Utility.COMMON_DIRECTORY
118 
119             Level requiredCoverage =
120                     Level.fromString(options[COVERAGE].toString()); // Utility.COMMON_DIRECTORY
121 
122             if (options[GET_SCRIPTS].doesOccur) {
123                 getScripts();
124                 return;
125             }
126 
127             FileCopier.ensureDirectoryExists(options[DESTDIR].value);
128             FileCopier.copy(
129                     ShowData.class, "summary-index.css", options[DESTDIR].value, "index.css");
130             FileCopier.copy(
131                     ShowData.class, "summary-index.html", options[DESTDIR].value, "index.html");
132             FormattedFileWriter.copyIncludeHtmls(options[DESTDIR].value);
133 
134             ToolUtilities.registerExtraTransliterators();
135 
136             // Factory collationFactory = Factory
137             // .make(sourceDir.replace("incoming/vetted/","common/") + "../collation/", ".*");
138             // ExtractCollationRules collationRules = new ExtractCollationRules();
139 
140             locales = new TreeSet<>(cldrFactory.getAvailable());
141             new CldrUtility.MatcherFilter(options[MATCH].value).retainAll(locales);
142             // Set paths = new TreeSet();
143             Set<PathHeader> prettySet = new TreeSet<>();
144 
145             CLDRFile.Status status = new CLDRFile.Status();
146             LocaleIDParser localeIDParser = new LocaleIDParser();
147 
148             // Map nonDistinguishingAttributes = new LinkedHashMap();
149             // CLDRFile parent = null;
150 
151             Map<PathHeader, Relation<String, String>> pathHeaderToValuesToLocale = new TreeMap<>();
152 
153             Set<String> defaultContents =
154                     testInfo.getSupplementalDataInfo().getDefaultContentLocales();
155 
156             // get all the locales in a group (with same written language)
157             LanguageTagParser ltp = new LanguageTagParser();
158 
159             LikelySubtags ls = new LikelySubtags();
160 
161             for (String locale : locales) {
162                 if (defaultContents.contains(locale)) {
163                     continue;
164                 }
165                 if (locale.startsWith("supplem")
166                         || locale.startsWith("character")
167                         || locale.equals("root")) {
168                     continue;
169                 }
170                 String max = ls.maximize(locale);
171                 if (max == null) {
172                     max = locale;
173                 }
174                 String baseLanguage = ls.minimize(ltp.set(max).getLanguageScript());
175                 if (baseLanguage.equals(locale)) {
176                     parentToChildren.put("root", locale);
177                     parentToChildren.put(locale, locale);
178                 } else {
179                     parentToChildren.put(baseLanguage, locale);
180                 }
181             }
182 
183             for (Entry<String, Set<String>> group : parentToChildren.keyValuesSet()) {
184                 String locale = group.getKey();
185                 Set<String> children = group.getValue();
186                 Map<String, CLDRFile> sublocales = new TreeMap<>();
187 
188                 boolean doResolved = localeIDParser.set(locale).getRegion().length() == 0;
189                 String languageSubtag = localeIDParser.getLanguage();
190                 // boolean isLanguageLocale = locale.equals(languageSubtag);
191 
192                 CLDRFile file = cldrFactory.make(locale, true);
193                 if (file.isNonInheriting()) continue; // skip supplementals
194 
195                 // get all of the paths
196                 Set<String> allPaths = new HashSet<>();
197                 file.forEach(allPaths::add);
198 
199                 if (!locale.equals("root")) {
200                     for (String childLocale : children) {
201                         CLDRFile childCldrFile = cldrFactory.make(childLocale, false);
202                         if (childCldrFile != null) {
203                             childCldrFile.forEach(allPaths::add);
204                         }
205                         sublocales.put(childLocale, childCldrFile);
206                     }
207                 }
208 
209                 boolean showEnglish = !languageSubtag.equals("en");
210                 CoverageLevel2 coverageLevel =
211                         CoverageLevel2.getInstance(testInfo.getSupplementalDataInfo(), locale);
212 
213                 // put into set of simpler paths
214                 // and filter if necessary
215                 int skippedCount = 0;
216                 int aliasedCount = 0;
217                 int inheritedCount = 0;
218                 prettySet.clear();
219                 for (Iterator<String> it2 = allPaths.iterator(); it2.hasNext(); ) {
220                     String path = it2.next();
221                     if (path.indexOf("/alias") >= 0) {
222                         skippedCount++;
223                         continue; // skip code fllback
224                     }
225                     if (path.indexOf("/usesMetazone") >= 0) {
226                         skippedCount++;
227                         continue; // skip code fllback
228                     }
229                     if (path.indexOf("/references") >= 0) {
230                         skippedCount++;
231                         continue; // skip references
232                     }
233                     if (path.indexOf("[@alt=\"proposed") >= 0) {
234                         skippedCount++;
235                         continue; // skip code fllback
236                     }
237                     if (path.indexOf("/identity") >= 0) {
238                         skippedCount++;
239                         continue; // skip code fllback
240                     }
241                     PathHeader prettyString = prettyPathMaker.fromPath(path);
242                     if (prettyString.getSectionId() != SectionId.Special) {
243                         prettySet.add(prettyString);
244                     }
245                 }
246 
247                 PrintWriter pw = FileUtilities.openUTF8Writer(targetDir, locale + ".html");
248 
249                 String[] headerAndFooter = new String[2];
250 
251                 getChartTemplate(
252                         "Locale Data Summary for " + getLocaleNameAndCode(locale),
253                         ToolConstants.CHART_DISPLAY_VERSION,
254                         "<script>"
255                                 + System.lineSeparator()
256                                 + "if (location.href.split('?')[1].split(',')[0]=='hide') {"
257                                 + System.lineSeparator()
258                                 + "document.write('<style>');"
259                                 + System.lineSeparator()
260                                 + "document.write('.xx {display:none}');"
261                                 + System.lineSeparator()
262                                 + "document.write('</style>');"
263                                 + System.lineSeparator()
264                                 + "}"
265                                 + System.lineSeparator()
266                                 + "</script>",
267                         headerAndFooter,
268                         locale.equals("root") ? "Main Charts Index" : null,
269                         false);
270                 pw.println(headerAndFooter[0]);
271                 showLinks(pw, locale);
272                 showChildren(pw, locale);
273                 if (true) {
274                     pw.println(
275                             "<p><b>Aliased/Inherited: </b><a href='"
276                                     + locale
277                                     + ".html?hide'>Hide</a> <a href='"
278                                     + locale
279                                     + ".html'>Show </a></p>");
280                 }
281                 pw.println("<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\">");
282 
283                 pw.println(
284                         "<tr><th>No</th>"
285                                 + "<th width='10%'>Section</th>"
286                                 + "<th width='10%'>Page</th>"
287                                 + "<th width='10%'>Header</th>"
288                                 + "<th width='10%'>Code</th>"
289                                 + (showEnglish ? "<th>English</th>" : "")
290                                 + "<th>Native</th>"
291                                 + "<th>Sublocales…</th>"
292                                 + "</tr>");
293 
294                 int count = 0;
295                 PathHeader oldParts = null;
296 
297                 Relation<String, String> childValueToLocales =
298                         Relation.of(new TreeMap<String, Set<String>>(), TreeSet.class);
299 
300                 for (PathHeader prettyPath : prettySet) {
301                     String path = prettyPath.getOriginalPath();
302                     boolean zeroOutEnglish = path.indexOf("/references") < 0;
303 
304                     String source = file.getSourceLocaleID(path, status);
305                     boolean isAliased = !status.pathWhereFound.equals(path);
306                     if (isAliased) {
307                         aliasedCount++;
308                         continue;
309                     }
310                     String value = file.getStringValue(path);
311 
312                     // String baileyValue = file.getBaileyValue(path, null, null);
313                     boolean isInherited =
314                             !source.equals(locale); // !CldrUtility.equals(baileyValue, value);
315                     if (isInherited) {
316                         inheritedCount++;
317                     }
318 
319                     // StringBuffer tempDraftRef = new StringBuffer();
320 
321                     String lastValue = null;
322                     boolean lastEquals = false;
323 
324                     childValueToLocales.clear();
325 
326                     for (Entry<String, CLDRFile> s : sublocales.entrySet()) {
327                         String newChildValue = s.getValue().getStringValue(path);
328                         if (newChildValue == null
329                                 || CldrUtility.equals(newChildValue, value)
330                                 || CldrUtility.INHERITANCE_MARKER.equals(newChildValue)) {
331                             continue;
332                         }
333                         childValueToLocales.put(newChildValue, s.getKey());
334                     }
335 
336                     String englishValue = null;
337                     if (zeroOutEnglish) {
338                         englishValue = "";
339                     }
340                     if (showEnglish && null != (englishValue = english.getStringValue(path))) {}
341 
342                     String statusClass =
343                             isAliased
344                                     ? (isInherited ? " class='ah'" : " class='a'")
345                                     : (isInherited ? " class='h'" : "");
346 
347                     //                    Level currentCoverage = coverageLevel.getLevel(path);
348                     //                    boolean hideCoverage = false;
349                     //                    if (requiredCoverage.compareTo(currentCoverage) < 0) {
350                     //                        hideCoverage = true;
351                     //                    }
352 
353                     boolean hide = isAliased || isInherited;
354                     if (!hide) {
355                         Relation<String, String> valuesToLocales =
356                                 pathHeaderToValuesToLocale.get(prettyPath);
357                         if (valuesToLocales == null) {
358                             pathHeaderToValuesToLocale.put(
359                                     prettyPath,
360                                     valuesToLocales =
361                                             Relation.of(
362                                                     new TreeMap<String, Set<String>>(),
363                                                     TreeSet.class));
364                         }
365                         valuesToLocales.put(lastValue + "→→" + value, locale);
366                     }
367                     pw.println(
368                             (hide ? "<tr class='xx'><td" : "<tr><td")
369                                     + statusClass
370                                     + ">"
371                                     + CldrUtility.getDoubleLinkedText(
372                                             Long.toHexString(StringId.getId(path)),
373                                             String.valueOf(++count))
374                                     + addPart(
375                                             oldParts == null ? null : oldParts.getSection(),
376                                             prettyPath.getSection())
377                                     + addPart(
378                                             oldParts == null ? null : oldParts.getPage(),
379                                             prettyPath.getPage())
380                                     + addPart(
381                                             oldParts == null ? null : oldParts.getHeader(),
382                                             prettyPath.getHeader())
383                                     + addPart(
384                                             oldParts == null ? null : oldParts.getCode(),
385                                             prettyPath.getCode())
386                                     // + "</td><td>" +
387                                     // TransliteratorUtilities.toHTML.transliterate(lastElement)
388                                     + showValue(showEnglish, englishValue, value, false)
389                                     + "</td>");
390                     boolean isExemplar = path.contains("/exemplar");
391                     showValue(pw, value, null, isExemplar);
392                     if (!childValueToLocales.keyValuesSet().isEmpty()) {
393                         for (Entry<String, Set<String>> x : childValueToLocales.keyValuesSet()) {
394                             showValue(pw, x.getKey(), x.getValue(), isExemplar);
395                         }
396                         pw.println(
397                                 "<td class='info'><a class='rightLink' target='CLDR-ST-DOCS' href='"
398                                         + CLDRURLS.CHARTS_URL
399                                         + "'>ⓘ</a></td>");
400                     }
401                     pw.println("</tr>");
402                     oldParts = prettyPath;
403                 }
404                 pw.println("</table><br><table>");
405                 pw.println(
406                         "<tr><td class='a'>Aliased items: </td><td>" + aliasedCount + "</td></tr>");
407                 pw.println(
408                         "<tr><td class='h'>Inherited items:</td><td>"
409                                 + inheritedCount
410                                 + "</td></tr>");
411                 if (skippedCount != 0)
412                     pw.println("<tr><td>Omitted items:</td><td>" + skippedCount + "</td></tr>");
413                 pw.println("</table>");
414 
415                 // pw.println("</body></html>");
416                 pw.println(headerAndFooter[1]);
417                 pw.close();
418             }
419             if (!TOO_BIG_FOR_GITHUB) {
420                 PrintWriter pw = FileUtilities.openUTF8Writer(targetDir, "all-changed.html");
421                 String[] headerAndFooter = new String[2];
422 
423                 getChartTemplate(
424                         "Locale Data Summary for ALL-CHANGED",
425                         ToolConstants.CHART_DISPLAY_VERSION,
426                         "",
427                         headerAndFooter,
428                         null,
429                         false);
430                 pw.println(headerAndFooter[0]);
431                 pw.println("<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\">");
432                 pw.println(
433                         "<tr>"
434                                 + "<th>Section</th>"
435                                 + "<th>Page</th>"
436                                 + "<th>Header</th>"
437                                 + "<th>Code</th>"
438                                 + "<th>Old</th>"
439                                 + "<th>Changed</th>"
440                                 + "<th>Locales</th>"
441                                 + "</tr>");
442                 for (Entry<PathHeader, Relation<String, String>> entry :
443                         pathHeaderToValuesToLocale.entrySet()) {
444                     PathHeader ph = entry.getKey();
445                     Set<Entry<String, Set<String>>> keyValuesSet = entry.getValue().keyValuesSet();
446                     String rowspan =
447                             keyValuesSet.size() == 1
448                                     ? ">"
449                                     : " rowSpan='" + keyValuesSet.size() + "'>";
450                     pw.append("<tr><td class='g'")
451                             .append(rowspan)
452                             .append(ph.getSectionId().toString())
453                             .append("</td><td class='g'")
454                             .append(rowspan)
455                             .append(ph.getPageId().toString())
456                             .append("</td><td class='g'")
457                             .append(rowspan)
458                             .append(ph.getHeader() == null ? "<i>n/a</i>" : ph.getHeader())
459                             .append("</td><td class='g'")
460                             .append(rowspan)
461                             .append(ph.getCode())
462                             .append("</td>");
463                     boolean addRow = false;
464                     for (Entry<String, Set<String>> s : keyValuesSet) {
465                         String value = s.getKey();
466                         int breakPoint = value.indexOf("→→");
467                         if (addRow) {
468                             pw.append("<tr>");
469                         }
470                         pw.append("<td>")
471                                 .append(DataShower.getPrettyValue(value.substring(0, breakPoint)))
472                                 .append("</td><td class='v'>")
473                                 .append(DataShower.getPrettyValue(value.substring(breakPoint + 2)))
474                                 .append("</td><td>")
475                                 .append(Joiner.on(", ").join(s.getValue()))
476                                 .append("</td></tr>")
477                                 .append(System.lineSeparator());
478                         addRow = true;
479                     }
480                 }
481                 pw.println(headerAndFooter[1]);
482                 pw.close();
483             }
484         } finally {
485             deltaTime = System.currentTimeMillis() - deltaTime;
486             System.out.println("Elapsed: " + deltaTime / 1000.0 + " seconds");
487             System.out.println("Done");
488         }
489     }
490 
491     public static void showValue(
492             PrintWriter pw, String value, Set<String> locales, boolean isExemplar) {
493         final boolean noLocales = locales == null || locales.isEmpty();
494         pw.println(
495                 "<td"
496                         + (isExemplar ? " style='max-width:20%'" : "")
497                         + (noLocales ? "" : " title='" + Joiner.on(", ").join(locales) + "'")
498                         + (value == null
499                                 ? "></i>n/a</i>"
500                                 : " class='v'"
501                                         + DataShower.getBidiStyle(value)
502                                         + ">"
503                                         + DataShower.getPrettyValue(value))
504                         + "</td>");
505     }
506 
507     private static String addPart(String oldPart, String newPart) {
508         String prefix;
509         if (newPart.equals(oldPart)) {
510             prefix = "</td><td class='n'>";
511         } else if (newPart.length() == 0) {
512             prefix = "</td><td>";
513         } else {
514             prefix = "</td><td class='g'>";
515         }
516         return prefix + TransliteratorUtilities.toHTML.transform(newPart);
517     }
518 
519     private static void getScripts() throws IOException {
520         Set<String> locales = cldrFactory.getAvailableLanguages();
521         Set<String> scripts = new TreeSet<>();
522         Map<String, Map<String, Set<String>>> script_name_locales = new TreeMap<>();
523         PrintWriter out = FileUtilities.openUTF8Writer(CLDRPaths.GEN_DIRECTORY, "scriptNames.txt");
524         for (Iterator<String> it = locales.iterator(); it.hasNext(); ) {
525             String locale = it.next();
526             System.out.println(locale);
527             CLDRFile file = cldrFactory.make(locale, false);
528             if (file.isNonInheriting()) continue;
529             String localeName = file.getName(locale);
530             getScripts(localeName, scripts);
531             if (!scripts.contains("Latn")) {
532                 out.println(locale + "\t" + english.getName(locale) + "\t" + localeName);
533             }
534             for (Iterator<String> it2 = UnicodeScripts.iterator(); it2.hasNext(); ) {
535                 String script = it2.next();
536                 if (script.equals("Latn")) continue;
537                 String name = file.getName(CLDRFile.SCRIPT_NAME, script);
538                 if (getScripts(name, scripts).contains(script)) {
539                     Map<String, Set<String>> names_locales = script_name_locales.get(script);
540                     if (names_locales == null)
541                         script_name_locales.put(script, names_locales = new TreeMap<>());
542                     Set<String> localeSet = names_locales.get(name);
543                     if (localeSet == null) names_locales.put(name, localeSet = new TreeSet<>());
544                     localeSet.add(getLocaleNameAndCode(locale));
545                 }
546             }
547         }
548         for (Iterator<String> it2 = UnicodeScripts.iterator(); it2.hasNext(); ) {
549             String script = it2.next();
550             Object names = script_name_locales.get(script);
551             out.println(
552                     script + "\t(" + english.getName(CLDRFile.SCRIPT_NAME, script) + ")\t" + names);
553         }
554         out.close();
555     }
556 
557     static Set<String> UnicodeScripts =
558             Collections.unmodifiableSet(
559                     new TreeSet<>(
560                             Arrays.asList(
561                                     new String[] {
562                                         "Arab", "Armn", "Bali", "Beng", "Bopo", "Brai", "Bugi",
563                                         "Buhd", "Cans", "Cher", "Copt", "Cprt", "Cyrl", "Deva",
564                                         "Dsrt", "Ethi", "Geor", "Glag", "Goth", "Grek", "Gujr",
565                                         "Guru", "Hang", "Hani", "Hano", "Hebr", "Hira", "Hrkt",
566                                         "Ital", "Kana", "Khar", "Khmr", "Knda", "Laoo", "Latn",
567                                         "Limb", "Linb", "Mlym", "Mong", "Mymr", "Nkoo", "Ogam",
568                                         "Orya", "Osma", "Phag", "Phnx", "Qaai", "Runr", "Shaw",
569                                         "Sinh", "Sylo", "Syrc", "Tagb", "Tale", "Talu", "Taml",
570                                         "Telu", "Tfng", "Tglg", "Thaa", "Thai", "Tibt", "Ugar",
571                                         "Xpeo", "Xsux", "Yiii"
572                                     })));
573 
574     private static Set<String> getScripts(String exemplars, Set<String> results) {
575         results.clear();
576         if (exemplars == null) return results;
577         for (UnicodeSetIterator it = new UnicodeSetIterator(new UnicodeSet().addAll(exemplars));
578                 it.next(); ) {
579             int cp = it.codepoint;
580             int script = UScript.getScript(cp);
581             results.add(UScript.getShortName(script));
582         }
583         return results;
584     }
585 
586     private static void showCollation(
587             Factory collationFactory, String locale, ExtractCollationRules collationRules) {
588         CLDRFile collationFile;
589         try {
590             collationFile = collationFactory.make(locale, false);
591         } catch (RuntimeException e) {
592             return; // skip
593         }
594         collationRules.set(collationFile);
595         for (Iterator<String> it = collationRules.iterator(); it.hasNext(); ) {
596             String key = it.next();
597             System.out.println(key + ": ");
598             String rules = collationRules.getRules(key);
599             System.out.println(rules);
600         }
601     }
602 
603     private static String showValue(
604             boolean showEnglish, String comparisonValue, String mainValue, boolean lastEquals) {
605         return !showEnglish
606                 ? ""
607                 : comparisonValue == null
608                         ? (lastEquals ? "</td><td>=" : "</td><td><i>n/a</i>")
609                         : comparisonValue.length() == 0
610                                 ? "</td><td>&nbsp;"
611                                 : comparisonValue.equals(mainValue)
612                                         ? "</td><td>="
613                                         : "</td><td class='e'"
614                                                 + DataShower.getBidiStyle(comparisonValue)
615                                                 + ">"
616                                                 + DataShower.getPrettyValue(comparisonValue);
617     }
618 
619     static DataShower dataShower = new DataShower();
620 
621     public static class DataShower {
622         static Transliterator toLatin = Transliterator.getInstance("any-latin");
623 
624         static UnicodeSet BIDI_R = new UnicodeSet("[[:Bidi_Class=R:][:Bidi_Class=AL:]]");
625 
626         static String getBidiStyle(String cellValue) {
627             return BIDI_R.containsSome(cellValue) ? " style='direction:rtl'" : "";
628         }
629 
630         public static String getPrettyValue(String textToInsert) {
631             String outValue = TransliteratorUtilities.toHTML.transliterate(textToInsert);
632             String transValue = textToInsert;
633             // String span = "";
634             try {
635                 transValue = toLatin.transliterate(textToInsert);
636             } catch (RuntimeException e) {
637             }
638             if (!transValue.equals(textToInsert)) {
639                 // WARNING: we use toXML in attributes
640                 outValue =
641                         "<span title='"
642                                 + TransliteratorUtilities.toXML.transliterate(transValue)
643                                 + "'>"
644                                 + outValue
645                                 + "</span>";
646             }
647             return outValue;
648         }
649     }
650 
651     private static String getNda(
652             Set<String> skipList,
653             Map<String, String> nonDistinguishingAttributes,
654             CLDRFile file,
655             String path,
656             String parentFullPath,
657             StringBuffer draftRef) {
658         draftRef.setLength(0);
659         if (parentFullPath != null && !parentFullPath.equals(path)) {
660             file.getNonDistinguishingAttributes(
661                     parentFullPath, nonDistinguishingAttributes, skipList);
662             if (nonDistinguishingAttributes.size() != 0) {
663                 String parentNda = "";
664                 for (Iterator<String> it = nonDistinguishingAttributes.keySet().iterator();
665                         it.hasNext(); ) {
666                     String key = it.next();
667                     String value = nonDistinguishingAttributes.get(key);
668                     if (key.equals("draft") && !value.equals("contributed")) {
669                         if (draftRef.length() != 0) draftRef.append(",");
670                         draftRef.append("d");
671                     } else if (key.equals("alt")) {
672                         if (draftRef.length() != 0) draftRef.append(",");
673                         draftRef.append("a");
674                     } else if (key.equals("references")) {
675                         if (draftRef.length() != 0) draftRef.append(",");
676                         draftRef.append(nonDistinguishingAttributes.get(key));
677                     } else {
678                         if (parentNda.length() != 0) parentNda += ", ";
679                         parentNda += key + "=" + nonDistinguishingAttributes.get(key);
680                     }
681                 }
682                 if (parentNda.length() != 0) {
683                     parentNda = parentNda.replaceAll("[/]", "/\u200B");
684                     parentNda = "[" + parentNda + "]";
685                 }
686                 return parentNda;
687             }
688         }
689         return "";
690     }
691 
692     private static void showLinks(PrintWriter pw, String locale) {
693         pw.print("<p>");
694         showLinks2(pw, locale);
695         pw.println("</p>");
696     }
697 
698     private static void showLinks2(PrintWriter pw, String locale) {
699         String parent = LocaleIDParser.getParent(locale);
700         if (parent != null) {
701             showLinks2(pw, parent);
702             pw.print(" &gt; ");
703         }
704         pw.println(getLinkedLocaleName(locale));
705     }
706 
707     private static void showChildren(PrintWriter pw, String locale) {
708         LanguageTagParser ltp = new LanguageTagParser();
709         TreeMap<String, String> nameToLocale = new TreeMap<>();
710         for (String sublocale : parentToChildren.get(locale)) {
711             String minimized = LIKELY.minimize(sublocale);
712             nameToLocale.put(
713                     getEnglishLocaleName(sublocale), minimized == null ? sublocale : minimized);
714         }
715 
716         boolean isRoot = locale.equals("root");
717         char lastFirstChar = 0;
718         boolean first = true;
719         for (Entry<String, String> nameAndCode : nameToLocale.entrySet()) {
720             String name = nameAndCode.getKey();
721             String localeCode = nameAndCode.getValue();
722             if (localeCode.equals(locale)) {
723                 continue;
724             }
725             char firstChar = name.charAt(0);
726             if (first) {
727                 pw.print(System.lineSeparator() + "<p style='margin-left:5em'>&gt; ");
728                 lastFirstChar = firstChar;
729                 first = false;
730             } else if (firstChar != lastFirstChar) {
731                 pw.print("</p>" + System.lineSeparator() + "<p style='margin-left:5em'> ");
732                 lastFirstChar = firstChar;
733             } else {
734                 pw.print(", ");
735             }
736             if (isRoot) {
737                 pw.print(getLinkedLocaleName(localeCode));
738             } else {
739                 pw.print(getLocaleMinusBaseAndCode(localeCode));
740             }
741         }
742         if (first) {
743             pw.println("</p>");
744         }
745     }
746 
747     public static String getLinkedLocaleName(String locale) {
748         return "<a href='"
749                 + locale
750                 + ".html'>"
751                 + getEnglishLocaleName(locale)
752                 + "</a> ["
753                 + locale
754                 + "]";
755     }
756 
757     public static String getEnglishLocaleName(String locale) {
758         return english.getName(locale, true, CLDRFile.SHORT_ALTS);
759     }
760 
761     private static String getLocaleNameAndCode(String locale) {
762         return getEnglishLocaleName(locale) + " [" + locale + "]";
763     }
764 
765     private static String getLocaleMinusBaseAndCode(String locale) {
766         String full = getEnglishLocaleName(locale);
767         int leftParen = full.indexOf('(');
768         if (leftParen >= 0) {
769             full = full.substring(leftParen + 1, full.lastIndexOf(')'));
770         }
771         return full + " [" + locale + "]";
772     }
773 
774     static final LikelySubtags LIKELY = new LikelySubtags();
775 
776     // public static SimpleDateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm",
777     // ULocale.ENGLISH);
778 
getChartTemplate( String title, String version, String header, String[] headerAndFooter, String indexTitle, boolean showDate)779     public static void getChartTemplate(
780             String title,
781             String version,
782             String header,
783             String[] headerAndFooter,
784             String indexTitle,
785             boolean showDate)
786             throws IOException {
787         if (version == null) {
788             version = ToolConstants.CHART_DISPLAY_VERSION;
789         }
790         VariableReplacer langTag =
791                 new VariableReplacer()
792                         .add("%title%", title)
793                         .add("%header%", header)
794                         .add("%index-title%", "Index")
795                         .add("%index%", "index.html")
796                         .add("%header%", header)
797                         .add("%version%", version)
798                         .add("%analytics%", Chart.AnalyticsID.CLDR.getScript())
799                         .add("%date%", showDate ? CldrUtility.isoFormatDateOnly(new Date()) : "");
800         if (indexTitle != null) {
801             langTag.add("%index-title%", indexTitle).add("%index%", "../index.html");
802         }
803         // "$" //
804         // + "Date" //
805         // + "$") // odd style to keep CVS from substituting
806         // isoDateFormat.format(new Date())
807         BufferedReader input = ToolUtilities.getUTF8Data("chart-template.html");
808         StringBuffer result = new StringBuffer();
809         while (true) {
810             String line = input.readLine();
811             if (line == null) break;
812             String langTagPattern = langTag.replace(line);
813             if (line.indexOf("%body%") >= 0) {
814                 headerAndFooter[0] = result.toString();
815                 result.setLength(0);
816                 continue;
817             }
818             result.append(langTagPattern).append(System.lineSeparator());
819         }
820         headerAndFooter[1] = result.toString();
821     }
822 }
823