1 package org.unicode.cldr.tool; 2 3 import com.ibm.icu.text.ListFormatter; 4 import com.ibm.icu.util.ICUUncheckedIOException; 5 import com.ibm.icu.util.ULocale; 6 import java.io.IOException; 7 import java.io.OutputStream; 8 import java.io.OutputStreamWriter; 9 import java.io.Writer; 10 import java.util.Arrays; 11 import java.util.stream.Collectors; 12 import org.unicode.cldr.test.CheckCLDR; 13 import org.unicode.cldr.test.TestCache.TestResultBundle; 14 import org.unicode.cldr.tool.FormattedFileWriter.Anchors; 15 import org.unicode.cldr.util.CLDRConfig; 16 import org.unicode.cldr.util.CLDRFile; 17 import org.unicode.cldr.util.CLDRURLS; 18 import org.unicode.cldr.util.Factory; 19 import org.unicode.cldr.util.PathHeader; 20 import org.unicode.cldr.util.SupplementalDataInfo; 21 import org.unicode.cldr.util.VoterReportStatus.ReportId; 22 23 /** 24 * To add a new chart, subclass this, and add the subclass to {@link 25 * ShowLanguages.printLanguageData()}. There isn't much documentation, so best to look at a simple 26 * subclass to see how it works. 27 * 28 * @author markdavis 29 */ 30 public abstract class Chart { 31 public static final CLDRConfig CONFIG = CLDRConfig.getInstance(); 32 public static final SupplementalDataInfo SDI = CONFIG.getSupplementalDataInfo(); 33 public static final CLDRFile ENGLISH = CONFIG.getEnglish(); 34 public static final String LS = System.lineSeparator(); 35 36 public static final String PREV_CHART_VERSION_DIRECTORY = 37 ToolConstants.getBaseDirectory(ToolConstants.PREV_CHART_VERSION); 38 public static final String CHART_VERSION_DIRECTORY = 39 ToolConstants.getBaseDirectory(ToolConstants.CHART_VERSION); 40 41 public static final String GITHUB_ROOT = CLDRURLS.CLDR_REPO_MAIN; 42 public static final String LDML_SPEC = "https://unicode.org/reports/tr35/"; 43 dataScrapeMessage(String specPart, String testFile, String... dataFiles)44 public static String dataScrapeMessage(String specPart, String testFile, String... dataFiles) { 45 final String dataFileList = 46 dataFiles.length == 0 47 ? null 48 : ListFormatter.getInstance(ULocale.ENGLISH) 49 .format( 50 Arrays.asList(dataFiles).stream() 51 .map(dataFile -> Chart.dataFileLink(dataFile)) 52 .collect(Collectors.toSet())); 53 54 return "<p>" 55 + "<b>Warning:</b> Do not scrape this chart for production data.\n" 56 + "Instead, for the meaning of the fields and data consult the " 57 + Chart.ldmlSpecLink(specPart) 58 + (dataFileList == null 59 ? "" 60 : ", and for machine-readable source data, access " + dataFileList) 61 + (testFile == null ? "" : ", and for test data, access " + dataFileLink(testFile)) 62 + ".</p>\n"; 63 } 64 dataFileLink(String dataFile)65 private static String dataFileLink(String dataFile) { 66 return "<a href='" 67 + GITHUB_ROOT 68 + dataFile 69 + "' target='" 70 + dataFile 71 + "'>" 72 + dataFile 73 + "</a>"; 74 } 75 ldmlSpecLink(String specPart)76 public static String ldmlSpecLink(String specPart) { 77 return "<a href='" 78 + LDML_SPEC 79 + (specPart == null ? "" : specPart) 80 + "' target='units.xml'>LDML specification</a>"; 81 } 82 83 /** 84 * null means a string will be constructed from the title. Otherwise a real file name (no html 85 * extension). 86 * 87 * @return 88 */ getFileName()89 public String getFileName() { 90 return null; 91 } 92 93 /** 94 * Show Date? 95 * 96 * @return 97 */ getExplanation()98 public String getExplanation() { 99 return null; 100 } 101 102 /** 103 * Short explanation that will go just after the title/dates. 104 * 105 * @return 106 */ getShowDate()107 public boolean getShowDate() { 108 return true; 109 } 110 111 /** 112 * Directory for the file to go into. 113 * 114 * @return 115 */ getDirectory()116 public abstract String getDirectory(); 117 118 /** 119 * Short title for page. Will appear at the top, and in the window title, and in the index. 120 * 121 * @return 122 */ getTitle()123 public abstract String getTitle(); 124 125 /** 126 * Work 127 * 128 * @param pw 129 * @throws IOException 130 */ writeContents(FormattedFileWriter pw)131 public void writeContents(FormattedFileWriter pw) throws IOException { 132 writeContents(pw.getStringWriter()); 133 } 134 135 /** 136 * Helper function to use the default factory. Not for use within SurveyTool. 137 * 138 * @param pw 139 * @throws IOException 140 */ writeContents(Writer pw)141 public void writeContents(Writer pw) throws IOException { 142 writeContents(pw, CLDRConfig.getInstance().getCldrFactory()); 143 } 144 writeContents(OutputStream output, Factory factory)145 public void writeContents(OutputStream output, Factory factory) throws IOException { 146 try (final Writer w = new OutputStreamWriter(output); ) { 147 writeContents(w, factory); 148 } 149 } 150 151 /** 152 * Do the work of generating the chart. 153 * 154 * @param pw 155 * @param factory 156 * @throws IOException 157 */ writeContents(Writer pw, Factory factory)158 public void writeContents(Writer pw, Factory factory) throws IOException { 159 // TODO: this should be an abstract function. 160 throw new IllegalArgumentException("Not implemented yet"); 161 } 162 163 /** 164 * extended function with some additional parameters subclasses may optionally implement this. 165 */ writeContents( Writer pw, Factory factory, TestResultBundle bundle, CheckCLDR.SubtypeToURLProvider urlProvider)166 public void writeContents( 167 Writer pw, 168 Factory factory, 169 TestResultBundle bundle, 170 CheckCLDR.SubtypeToURLProvider urlProvider) 171 throws IOException { 172 this.writeContents(pw, factory); 173 } 174 175 private static final class AnalyticsHelper { 176 private static final AnalyticsHelper INSTANCE = new AnalyticsHelper(); 177 178 public final String str; 179 AnalyticsHelper()180 AnalyticsHelper() { 181 str = 182 ToolUtilities.getUTF8Data("analytics.html") 183 .lines() 184 .collect(Collectors.joining("\n")); 185 } 186 } 187 188 public enum AnalyticsID { 189 CLDR("G-BPN1D3SEJM"), 190 ICU("G-06PL1DM20S"), 191 ICU_GUIDE("UA-7670256-1"), 192 UNICODE("G-GC4HXC4GVQ"), 193 UNICODE_UTILITY("G-0M7Q5QLZPV"); 194 public final String id; 195 AnalyticsID(String id)196 private AnalyticsID(String id) { 197 this.id = id; 198 } 199 getScript()200 public String getScript() { 201 return AnalyticsHelper.INSTANCE.str.replaceAll("TAG_ID", id); 202 } 203 } 204 writeChart(Anchors anchors)205 public final void writeChart(Anchors anchors) { 206 try (FormattedFileWriter x = 207 new FormattedFileWriter(getFileName(), getTitle(), getExplanation(), anchors); ) { 208 x.setDirectory(getDirectory()); 209 x.setShowDate(getShowDate()); 210 writeContents(x); 211 } catch (IOException e) { 212 throw new ICUUncheckedIOException(e); 213 } 214 } 215 getTsvDir(String targetDir, String topicName)216 public static String getTsvDir(String targetDir, String topicName) { 217 String target = targetDir.replaceAll(topicName, "tsv"); 218 if (target.equals(targetDir)) { 219 throw new IllegalArgumentException("Can't make TSV directory from " + targetDir); 220 } 221 return target; 222 } 223 getFixLinkFromPath(CLDRFile cldrFile, String path)224 public String getFixLinkFromPath(CLDRFile cldrFile, String path) { 225 String result = PathHeader.getLinkedView(CLDRConfig.getInstance().urls(), cldrFile, path); 226 return result == null ? "" : result; 227 } 228 229 /** 230 * Attempt to allocate the Chart that goes along with this report Also see {@link 231 * org.unicode.cldr.util.VoterReportStatus.ReportId} and keep up to date 232 */ forReport(final ReportId report, final String locale)233 public static Chart forReport(final ReportId report, final String locale) { 234 switch (report) { 235 case personnames: 236 return new ChartPersonName(locale); 237 default: 238 return null; 239 } 240 } 241 } 242