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