1 package org.unicode.cldr.unittest; 2 3 import java.io.IOException; 4 import java.util.ArrayList; 5 import java.util.Arrays; 6 import java.util.Collection; 7 import java.util.HashMap; 8 import java.util.HashSet; 9 import java.util.LinkedHashMap; 10 import java.util.List; 11 import java.util.Map; 12 import java.util.Map.Entry; 13 import java.util.Set; 14 import java.util.TreeSet; 15 import java.util.stream.Collectors; 16 17 import org.unicode.cldr.test.ExampleGenerator; 18 import org.unicode.cldr.test.ExampleGenerator.UnitLength; 19 import org.unicode.cldr.util.CLDRConfig; 20 import org.unicode.cldr.util.CLDRFile; 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.GrammarInfo; 25 import org.unicode.cldr.util.GrammarInfo.CaseValues; 26 import org.unicode.cldr.util.GrammarInfo.GrammaticalFeature; 27 import org.unicode.cldr.util.GrammarInfo.GrammaticalScope; 28 import org.unicode.cldr.util.GrammarInfo.GrammaticalTarget; 29 import org.unicode.cldr.util.Pair; 30 import org.unicode.cldr.util.PathStarrer; 31 import org.unicode.cldr.util.SupplementalDataInfo; 32 import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo; 33 import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count; 34 import org.unicode.cldr.util.SupplementalDataInfo.PluralType; 35 import org.unicode.cldr.util.UnitPathType; 36 import org.unicode.cldr.util.With; 37 38 import com.google.common.collect.ImmutableSet; 39 import com.ibm.icu.dev.test.TestFmwk; 40 41 public class TestExampleGenerator extends TestFmwk { 42 43 boolean showTranslationPaths = CldrUtility.getProperty("TestExampleGenerator:showTranslationPaths", false); 44 45 private static final SupplementalDataInfo SDI = SupplementalDataInfo.getInstance(); 46 CLDRConfig info = CLDRConfig.getInstance(); 47 main(String[] args)48 public static void main(String[] args) { 49 new TestExampleGenerator().run(args); 50 } 51 testCurrency()52 public void testCurrency() { 53 String[][] tests = { 54 { 55 "fr", 56 "one", 57 "〖❬1,23 ❭value-one〗〖❬0,00 ❭value-one〗", 58 "〖❬1,23❭_❬dollar des États-Unis❭〗〖❬1,23❭_❬euro❭〗〖❬0,00❭_❬dollar des États-Unis❭〗〖❬0,00❭_❬euro❭〗" }, 59 { 60 "fr", 61 "other", 62 "〖❬2,34 ❭value-other〗〖❬3,45 ❭value-other〗", 63 "〖❬2,34❭_❬dollars des États-Unis❭〗〖❬2,34❭_❬euros❭〗〖❬3,45❭_❬dollars des États-Unis❭〗〖❬3,45❭_❬euros❭〗" }, 64 { "en", "one", "〖❬1 ❭Bermudan dollar〗", 65 "〖❬1❭ ❬US dollar❭〗〖❬1❭ ❬euro❭〗" }, 66 { "en", "other", 67 "〖❬1.23 ❭Bermudan dollars〗〖❬0.00 ❭Bermudan dollars〗", 68 "〖❬1.23❭ ❬US dollars❭〗〖❬1.23❭ ❬euros❭〗〖❬0.00❭ ❬US dollars❭〗〖❬0.00❭ ❬euros❭〗" }, }; 69 String sampleCurrencyPatternPrefix = "//ldml/numbers/currencyFormats[@numberSystem=\"latn\"]/unitPattern[@count=\""; 70 String sampleCurrencyPrefix = "//ldml/numbers/currencies/currency[@type=\"BMD\"]/displayName[@count=\""; 71 String sampleTemplateSuffix = "\"]"; 72 73 for (String[] row : tests) { 74 ExampleGenerator exampleGenerator = getExampleGenerator(row[0]); 75 String value = "value-" + row[1]; 76 77 String path = sampleCurrencyPrefix + row[1] + sampleTemplateSuffix; 78 String result = ExampleGenerator 79 .simplify(exampleGenerator.getExampleHtml(path, value), false); 80 assertEquals(row[0] + "-" + row[1] + "-BMD", row[2], result); 81 82 value = "{0}_{1}"; 83 path = sampleCurrencyPatternPrefix + row[1] + sampleTemplateSuffix; 84 result = ExampleGenerator 85 .simplify(exampleGenerator.getExampleHtml(path, value), false); 86 assertEquals(row[0] + "-" + row[1] + "-pat", row[3], result); 87 } 88 } 89 90 /** 91 * Only add to this if the example should NEVER appear. 92 * <br>WARNING - do not disable the test by putting in too broad a match. Make sure the paths are reasonably granular. 93 */ 94 static final Set<String> DELIBERATE_EXCLUDED_EXAMPLES = ImmutableSet.of( 95 "//ldml/layout/orientation/characterOrder", 96 "//ldml/layout/orientation/lineOrder", 97 "//ldml/characters/moreInformation", 98 "//ldml/numbers/symbols[@numberSystem=\"([^\"]*+)\"]/infinity", 99 "//ldml/numbers/symbols[@numberSystem=\"([^\"]*+)\"]/list", 100 "//ldml/numbers/symbols[@numberSystem=\"([^\"]*+)\"]/nan", 101 "//ldml/numbers/currencies/currency[@type=\"([^\"]*+)\"]/displayName", 102 "//ldml/localeDisplayNames/measurementSystemNames/measurementSystemName[@type=\"([^\"]*+)\"]", 103 // old format 104 "//ldml/numbers/symbols/infinity", 105 "//ldml/numbers/symbols/list", 106 "//ldml/numbers/symbols/nan", 107 "//ldml/posix/messages/nostr", 108 "//ldml/posix/messages/yesstr", 109 "//ldml/contextTransforms/contextTransformUsage[@type=\"([^\"]*+)\"]/contextTransform[@type=\"([^\"]*+)\"]", 110 "//ldml/characters/exemplarCharacters", 111 "//ldml/characters/exemplarCharacters[@type=\"([^\"]*+)\"]", 112 "//ldml/characters/parseLenients.*", 113 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/months/monthContext[@type=\"([^\"]*+)\"]/monthWidth[@type=\"([^\"]*+)\"]/month[@type=\"([^\"]*+)\"]", 114 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/days/dayContext[@type=\"([^\"]*+)\"]/dayWidth[@type=\"([^\"]*+)\"]/day[@type=\"([^\"]*+)\"]", 115 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/quarters/quarterContext[@type=\"([^\"]*+)\"]/quarterWidth[@type=\"([^\"]*+)\"]/quarter[@type=\"([^\"]*+)\"]", 116 "//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/displayName", 117 "//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/relative[@type=\"([^\"]*+)\"]", 118 "//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/relativeTime[@type=\"([^\"]*+)\"]/relativeTimePattern[@count=\"([^\"]*+)\"]", 119 "//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/relativePeriod", 120 "//ldml/dates/fields/field[@type=\"([^\"]*+)\"]/displayName[@alt=\"([^\"]*+)\"]", 121 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/cyclicNameSets/cyclicNameSet[@type=\"([^\"]*+)\"]/cyclicNameContext[@type=\"([^\"]*+)\"]/cyclicNameWidth[@type=\"([^\"]*+)\"]/cyclicName[@type=\"([^\"]*+)\"]", 122 123 "//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"([^\"]*+)\"]", 124 "//ldml/numbers/minimalPairs/ordinalMinimalPairs[@ordinal=\"([^\"]*+)\"]", 125 "//ldml/characters/parseLenients[@scope=\"([^\"]*+)\"][@level=\"([^\"]*+)\"]/parseLenient[@sample=\"([^\"]*+)\"]" 126 ); 127 // Only add to above if the example should NEVER appear. 128 129 /** 130 * Add to this if the example SHOULD appear, but we don't have it yet. 131 * <br>TODO Add later 132 */ 133 static final Set<String> TEMPORARY_EXCLUDED_EXAMPLES = ImmutableSet.of( 134 135 "//ldml/numbers/currencyFormats/currencySpacing/beforeCurrency/currencyMatch", 136 "//ldml/numbers/currencyFormats/currencySpacing/beforeCurrency/surroundingMatch", 137 "//ldml/numbers/currencyFormats/currencySpacing/beforeCurrency/insertBetween", 138 "//ldml/numbers/currencyFormats/currencySpacing/afterCurrency/currencyMatch", 139 "//ldml/numbers/currencyFormats/currencySpacing/afterCurrency/surroundingMatch", 140 "//ldml/numbers/currencyFormats/currencySpacing/afterCurrency/insertBetween", 141 "//ldml/numbers/currencyFormats/currencyPatternAppendISO", // TODO see CLDR-14831 142 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencySpacing/beforeCurrency/currencyMatch", 143 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencySpacing/beforeCurrency/surroundingMatch", 144 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencySpacing/beforeCurrency/insertBetween", 145 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencySpacing/afterCurrency/currencyMatch", 146 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencySpacing/afterCurrency/surroundingMatch", 147 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencySpacing/afterCurrency/insertBetween", 148 "//ldml/numbers/currencyFormats[@numberSystem=\"([^\"]*+)\"]/currencyPatternAppendISO", // TODO see CLDR-14831 149 150 "//ldml/localeDisplayNames/variants/variant[@type=\"([^\"]*+)\"]", 151 "//ldml/localeDisplayNames/keys/key[@type=\"([^\"]*+)\"]", 152 "//ldml/localeDisplayNames/types/type[@key=\"([^\"]*+)\"][@type=\"([^\"]*+)\"]", 153 "//ldml/localeDisplayNames/types/type[@key=\"([^\"]*+)\"][@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", 154 155 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNames/era[@type=\"([^\"]*+)\"]", 156 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraAbbr/era[@type=\"([^\"]*+)\"]", 157 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNarrow/era[@type=\"([^\"]*+)\"]", 158 159 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateFormats/dateFormatLength[@type=\"([^\"]*+)\"]/dateFormat[@type=\"([^\"]*+)\"]/datetimeSkeleton", 160 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/timeFormats/timeFormatLength[@type=\"([^\"]*+)\"]/timeFormat[@type=\"([^\"]*+)\"]/datetimeSkeleton", 161 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateFormats/dateFormatLength[@type=\"([^\"]*+)\"]/datetimeSkeleton", 162 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/timeFormats/timeFormatLength[@type=\"([^\"]*+)\"]/datetimeSkeleton", 163 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/appendItems/appendItem[@request=\"([^\"]*+)\"]", 164 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/intervalFormats/intervalFormatFallback", 165 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/intervalFormats/intervalFormatItem[@id=\"([^\"]*+)\"]/greatestDifference[@id=\"([^\"]*+)\"]", 166 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNames/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", 167 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraAbbr/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", 168 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/eras/eraNarrow/era[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", 169 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/months/monthContext[@type=\"([^\"]*+)\"]/monthWidth[@type=\"([^\"]*+)\"]/month[@type=\"([^\"]*+)\"][@yeartype=\"([^\"]*+)\"]", 170 "//ldml/dates/timeZoneNames/gmtZeroFormat", 171 172 "//ldml/numbers/minimumGroupingDigits", 173 "//ldml/numbers/symbols/timeSeparator", 174 "//ldml/numbers/symbols[@numberSystem=\"([^\"]*+)\"]/timeSeparator", 175 176 "//ldml/units/unitLength[@type=\"([^\"]*+)\"]/unit[@type=\"([^\"]*+)\"]/displayName", 177 "//ldml/units/unitLength[@type=\"([^\"]*+)\"]/unit[@type=\"([^\"]*+)\"]/perUnitPattern", 178 "//ldml/units/unitLength[@type=\"([^\"]*+)\"]/coordinateUnit/coordinateUnitPattern[@type=\"([^\"]*+)\"]", 179 "//ldml/units/unitLength[@type=\"([^\"]*+)\"]/coordinateUnit/displayName", 180 181 "//ldml/characterLabels/characterLabelPattern[@type=\"([^\"]*+)\"]", 182 "//ldml/characterLabels/characterLabelPattern[@type=\"([^\"]*+)\"][@count=\"([^\"]*+)\"]", 183 "//ldml/characterLabels/characterLabel[@type=\"([^\"]*+)\"]", 184 "//ldml/typographicNames/axisName[@type=\"([^\"]*+)\"]", 185 "//ldml/typographicNames/styleName[@type=\"([^\"]*+)\"][@subtype=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", 186 "//ldml/typographicNames/styleName[@type=\"([^\"]*+)\"][@subtype=\"([^\"]*+)\"]", 187 "//ldml/typographicNames/featureName[@type=\"([^\"]*+)\"]", 188 189 "//ldml/localeDisplayNames/subdivisions/subdivision[@type=\"([^\"]*+)\"]", 190 191 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/long/standard", // Error: (TestExampleGenerator.java:245) No background: <Coordinated Universal Time> 〖Coordinated Universal Time〗 192 193 "//ldml/personNames/nameOrderLocales[@order=\"([^\"]*+)\"]", // TODO CLDR-15384 194 "//ldml/personNames/foreignSpaceReplacement[@xml:space=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", // TODO CLDR-15384 195 "//ldml/personNames/foreignSpaceReplacement[@xml:space=\"([^\"]*+)\"]", // TODO CLDR-15384 196 "//ldml/personNames/foreignSpaceReplacement[@alt=\"([^\"]*+)\"]", // TODO CLDR-15384 197 "//ldml/personNames/foreignSpaceReplacement", // TODO CLDR-15384 198 "//ldml/personNames/initialPattern[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", // TODO CLDR-15384 199 "//ldml/personNames/initialPattern[@type=\"([^\"]*+)\"]", // TODO CLDR-15384 200 "//ldml/personNames/personName[@order=\"([^\"]*+)\"][@length=\"([^\"]*+)\"][@usage=\"([^\"]*+)\"][@formality=\"([^\"]*+)\"]/namePattern[@alt=\"([^\"]*+)\"]", // TODO CLDR-15384 201 "//ldml/personNames/sampleName[@item=\"([^\"]*+)\"]/nameField[@type=\"([^\"]*+)\"][@alt=\"([^\"]*+)\"]", // TODO CLDR-15384 202 "//ldml/personNames/sampleName[@item=\"([^\"]*+)\"]/nameField[@type=\"([^\"]*+)\"]" // TODO CLDR-15384 203 204 ); 205 // Add to above if the example SHOULD appear, but we don't have it yet. TODO Add later 206 207 208 /** 209 * Only add to this if the background should NEVER appear. 210 * <br>The background is used when the element is used as part of another format. 211 * <br>WARNING - do not disable the test by putting in too broad a match. Make sure the paths are reasonably granular. 212 */ 213 static final Set<String> DELIBERATE_OK_TO_MISS_BACKGROUND = ImmutableSet.of( 214 "//ldml/numbers/defaultNumberingSystem", 215 "//ldml/numbers/otherNumberingSystems/native", 216 // TODO fix formatting 217 "//ldml/characters/exemplarCharacters", 218 "//ldml/characters/exemplarCharacters[@type=\"([^\"]*+)\"]", 219 // TODO Add background 220 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateFormats/dateFormatLength[@type=\"([^\"]*+)\"]/dateFormat[@type=\"([^\"]*+)\"]/pattern[@type=\"([^\"]*+)\"]", 221 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/timeFormats/timeFormatLength[@type=\"([^\"]*+)\"]/timeFormat[@type=\"([^\"]*+)\"]/pattern[@type=\"([^\"]*+)\"]", 222 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/availableFormats/dateFormatItem[@id=\"([^\"]*+)\"]", 223 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/exemplarCity", 224 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/exemplarCity[@alt=\"([^\"]*+)\"]", 225 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/long/daylight", 226 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/short/generic", 227 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/short/standard", 228 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/short/daylight", 229 "//ldml/dates/timeZoneNames/metazone[@type=\"([^\"]*+)\"]/long/generic", 230 "//ldml/dates/timeZoneNames/metazone[@type=\"([^\"]*+)\"]/long/standard", 231 "//ldml/dates/timeZoneNames/metazone[@type=\"([^\"]*+)\"]/long/daylight", 232 "//ldml/units/durationUnit[@type=\"([^\"]*+)\"]/durationUnitPattern"); 233 // Only add to above if the background should NEVER appear. 234 235 236 /** 237 * Add to this if the background SHOULD appear, but we don't have them yet. 238 * <br> The background is used when the element is used as part of another format. 239 * <br> TODO Add later 240 */ 241 static final Set<String> TEMPORARY_OK_TO_MISS_BACKGROUND = ImmutableSet.of( 242 "//ldml/numbers/defaultNumberingSystem", 243 "//ldml/dates/calendars/calendar[@type=\"([^\"]*+)\"]/dateTimeFormats/availableFormats/dateFormatItem[@id=\"([^\"]*+)\"][@count=\"([^\"]*+)\"]", 244 "//ldml/dates/timeZoneNames/zone[@type=\"([^\"]*+)\"]/long/standard", 245 "//ldml/dates/timeZoneNames/metazone[@type=\"([^\"]*+)\"]/short/generic", 246 "//ldml/dates/timeZoneNames/metazone[@type=\"([^\"]*+)\"]/short/standard", 247 "//ldml/dates/timeZoneNames/metazone[@type=\"([^\"]*+)\"]/short/daylight", 248 "//ldml/personNames/personName[@order=\"([^\"]*+)\"][@length=\"([^\"]*+)\"][@formality=\"([^\"]*+)\"]/namePattern", 249 "//ldml/personNames/personName[@order=\"([^\"]*+)\"][@length=\"([^\"]*+)\"][@usage=\"([^\"]*+)\"][@formality=\"([^\"]*+)\"]/namePattern"); // CLDR-15384 250 // Add to above if the background SHOULD appear, but we don't have them yet. TODO Add later 251 TestAllPaths()252 public void TestAllPaths() { 253 ExampleGenerator exampleGenerator = getExampleGenerator("en"); 254 PathStarrer ps = new PathStarrer(); 255 Set<String> seen = new HashSet<>(); 256 CLDRFile cldrFile = exampleGenerator.getCldrFile(); 257 TreeSet<String> target = new TreeSet<>(cldrFile.getComparator()); 258 cldrFile.fullIterable().forEach(target::add); 259 for (String path : target) { 260 String plainStarred = ps.set(path); 261 String value = cldrFile.getStringValue(path); 262 if (value == null || path.endsWith("/alias") 263 || path.startsWith("//ldml/identity") 264 || DELIBERATE_EXCLUDED_EXAMPLES.contains(plainStarred)) { 265 continue; 266 } 267 if (TEMPORARY_EXCLUDED_EXAMPLES.contains(plainStarred)) { 268 if (logKnownIssue( 269 "Cldrbug:6342", 270 "Need an example for each path used in context: " + plainStarred)) { 271 continue; 272 } 273 continue; 274 } 275 String example = exampleGenerator.getExampleHtml(path, value); 276 String javaEscapedStarred = "\"" 277 + plainStarred.replace("\"", "\\\"") + "\","; 278 if (example == null) { 279 if (!seen.contains(javaEscapedStarred)) { 280 errln("No example:\t<" + value + ">\t" + javaEscapedStarred); 281 } 282 } else { 283 String simplified = ExampleGenerator.simplify(example, false); 284 285 if (simplified.contains("null")) { 286 if (true || !seen.contains(javaEscapedStarred)) { 287 // debug 288 exampleGenerator.getExampleHtml(path, value); 289 ExampleGenerator.simplify(example, false); 290 291 errln("'null' in message:\t<" + value + ">\t" 292 + simplified + "\t" + javaEscapedStarred); 293 // String example2 = 294 // exampleGenerator.getExampleHtml(path, value); // for 295 // debugging 296 } 297 } else if (!simplified.startsWith("〖")) { 298 if (!seen.contains(javaEscapedStarred)) { 299 errln("Funny HTML:\t<" + value + ">\t" + simplified 300 + "\t" + javaEscapedStarred); 301 } 302 } else if (!simplified.contains("❬") 303 && !DELIBERATE_OK_TO_MISS_BACKGROUND.contains(plainStarred)) { 304 if (!seen.contains(javaEscapedStarred)) { 305 306 if (TEMPORARY_OK_TO_MISS_BACKGROUND.contains(plainStarred) 307 && logKnownIssue( 308 "Cldrbug:6342", 309 "Make sure that background appears: " + simplified + "; " + plainStarred)) { 310 continue; 311 } 312 313 errln("No background:\t<" + value + ">\t" + simplified 314 + "\t" + javaEscapedStarred); 315 } 316 } 317 } 318 seen.add(javaEscapedStarred); 319 } 320 } 321 TestUnits()322 public void TestUnits() { 323 ExampleGenerator exampleGenerator = getExampleGenerator("en"); 324 checkValue("Duration hm", "〖5:37〗", exampleGenerator, 325 "//ldml/units/durationUnit[@type=\"hm\"]/durationUnitPattern"); 326 checkValue( 327 "Length m", 328 "〖❬1❭ meter〗", 329 exampleGenerator, 330 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"one\"]"); 331 checkValue( 332 "Length m", 333 "〖❬1.5❭ meters〗", 334 exampleGenerator, 335 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"other\"]"); 336 checkValue( 337 "Length m", 338 "〖❬1.5❭ m〗", 339 exampleGenerator, 340 "//ldml/units/unitLength[@type=\"short\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"other\"]"); 341 checkValue( 342 "Length m", 343 "〖❬1.5❭m〗", 344 exampleGenerator, 345 "//ldml/units/unitLength[@type=\"narrow\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"other\"]"); 346 347 // The following are to ensure that we properly generate an example when we have a non-winning value 348 checkValue( 349 "Length m", 350 "〖❬1.5❭ badmeter〗", 351 exampleGenerator, 352 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"other\"]", 353 "{0} badmeter"); 354 355 ExampleGenerator exampleGeneratorDe = getExampleGenerator("de"); 356 checkValue( 357 "Length m", 358 "〖❬1,5❭ badmeter〗〖❬Anstatt 1,5❭ badmeter❬ …❭〗〖❌ ❬… für 1,5❭ badmeter❬ …❭〗", 359 exampleGeneratorDe, 360 "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"length-meter\"]/unitPattern[@count=\"other\"][@case=\"genitive\"]", 361 "{0} badmeter"); 362 } 363 364 /** 365 * Check that the expected exampleGenerator example is produced for the parameters, with the value coming from the file. 366 */ checkValue(String message, String expected, ExampleGenerator exampleGenerator, String path)367 private void checkValue(String message, String expected, 368 ExampleGenerator exampleGenerator, String path) { 369 checkValue(message, expected, exampleGenerator, path, null); 370 } 371 372 /** 373 * Check that the expected exampleGenerator example is produced for the parameters 374 */ checkValue(String message, String expected, ExampleGenerator exampleGenerator, String path, String value)375 private void checkValue(String message, String expected, 376 ExampleGenerator exampleGenerator, String path, String value) { 377 final CLDRFile cldrFile = exampleGenerator.getCldrFile(); 378 value = value != null ? value : cldrFile.getStringValue(path); 379 String actual = exampleGenerator.getExampleHtml(path, value); 380 assertEquals(cldrFile.getLocaleID() + ": " + message, expected, 381 ExampleGenerator.simplify(actual, false)); 382 } 383 TestCompoundUnit()384 public void TestCompoundUnit() { 385 String[][] tests = { 386 { "per", "LONG", "one", "〖❬1 meter❭ per ❬second❭〗" }, 387 { "per", "SHORT", "one", "〖❬1 m❭/❬sec❭〗" }, 388 { "per", "NARROW", "one", "〖❬1m❭/❬s❭〗" }, 389 { "per", "LONG", "other", "〖❬1.5 meters❭ per ❬second❭〗" }, 390 { "per", "SHORT", "other", "〖❬1.5 m❭/❬sec❭〗" }, 391 { "per", "NARROW", "other", "〖❬1.5m❭/❬s❭〗" }, 392 { "times", "LONG", "one", "〖❬1 newton❭-❬meter❭〗" }, 393 { "times", "SHORT", "one", "〖❬1 N❭⋅❬m❭〗" }, 394 { "times", "NARROW", "one", "〖❬1N❭⋅❬m❭〗" }, 395 { "times", "LONG", "other", "〖❬1.5 newton❭-❬meters❭〗" }, 396 { "times", "SHORT", "other", "〖❬1.5 N❭⋅❬m❭〗" }, 397 { "times", "NARROW", "other", "〖❬1.5N❭⋅❬m❭〗" }, 398 }; 399 checkCompoundUnits("en", tests); 400 // reenable these after Arabic has meter translated 401 // String[][] tests2 = { 402 // {"LONG", "few", "〖❬1 meter❭ per ❬second❭〗"}, 403 // }; 404 // checkCompoundUnits("ar", tests2); 405 } 406 checkCompoundUnits(String locale, String[][] tests)407 private void checkCompoundUnits(String locale, String[][] tests) { 408 ExampleGenerator exampleGenerator = getExampleGenerator(locale); 409 for (String[] test : tests) { 410 String actual = exampleGenerator.handleCompoundUnit( 411 UnitLength.valueOf(test[1]), 412 test[0], 413 Count.valueOf(test[2])); 414 assertEquals("CompoundUnit", test[3], 415 ExampleGenerator.simplify(actual, true)); 416 } 417 } 418 TestTranslationPaths()419 public void TestTranslationPaths() { 420 for (String locale : Arrays.asList("en", "el", "ru")) { 421 CLDRFile cldrFile = CLDRConfig.getInstance().getCldrFactory().make(locale, true); 422 ExampleGenerator exampleGenerator = getExampleGenerator(locale); 423 424 for (UnitPathType pathType : UnitPathType.values()) { 425 for (String width : Arrays.asList("long", "short", "narrow")) { 426 if (pathType == UnitPathType.gender && !width.equals("long")) { 427 continue; 428 } 429 for (String unit : pathType.sampleShortUnitType) { 430 String path = pathType.getTranslationPath(cldrFile, width, unit, "one", "nominative", null); 431 String value = cldrFile.getStringValue(path); 432 if (value != null) { 433 String example = exampleGenerator.getExampleHtml(path, value); 434 if (assertNotNull(locale + "/" + path, example)) { 435 String simplified = ExampleGenerator.simplify(example, false); 436 if (showTranslationPaths) { 437 warnln(locale + ", " + width + ", " + pathType.toString() + " ==>" + simplified); 438 } 439 } else { 440 // for debugging 441 example = exampleGenerator.getExampleHtml(path, value); 442 } 443 } 444 } 445 } 446 } 447 } 448 } 449 TestCompoundUnit2()450 public void TestCompoundUnit2() { 451 String[][] tests = { 452 { "de", "LONG", "other", "Quadrat{0}", "〖❬1,5 ❭Quadrat❬meter❭〗" }, 453 454 { "en", "SHORT", "one", "z{0}", "〖❬1 ❭z❬m❭〗" }, 455 { "en", "LONG", "other", "zetta{0}", "〖❬1.5 ❭zetta❬meters❭〗" }, 456 457 { "en", "SHORT", "one", "{0}²", "〖❬1 m❭²〗" }, 458 { "en", "LONG", "other", "square {0}", "〖❬1.5 ❭square ❬meters❭〗" }, 459 460 { "de", "SHORT", "one", "z{0}", "〖❬1 ❭z❬m❭〗" }, 461 { "de", "LONG", "other", "Zetta{0}", "〖❬1,5 ❭Zetta❬meter❭〗" }, 462 463 { "de", "SHORT", "one", "{0}²", "〖❬1 m❭²〗" }, 464 { "de", "LONG", "other", "Quadrat{0}", "〖❬1,5 ❭Quadrat❬meter❭〗" }, 465 }; 466 for (String[] test : tests) { 467 468 ExampleGenerator exampleGenerator = getExampleGenerator(test[0]); 469 470 String actual = exampleGenerator.handleCompoundUnit1( 471 UnitLength.valueOf(test[1]), 472 Count.valueOf(test[2]), 473 test[3]); 474 assertEquals("CompoundUnit", test[4], 475 ExampleGenerator.simplify(actual, true)); 476 } 477 } 478 TestCompoundUnit3()479 public void TestCompoundUnit3() { 480 final Factory cldrFactory = CLDRConfig.getInstance().getCldrFactory(); 481 String[][] tests = { 482 // locale, path, value, expected-example 483 { "en", "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1", 484 "LOCALE", "〖square ❬meters❭〗" }, // 485 { "en", "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"one\"]", 486 "LOCALE", "〖❬1 ❭square ❬meter❭〗" }, // 487 { "en", "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"other\"]", 488 "LOCALE", "〖❬1.5 ❭square ❬meters❭〗" }, // 489 490 { "en", "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1", 491 "LOCALE", "〖❬m❭²〗" }, 492 { "en", "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"one\"]", 493 "LOCALE", "〖❬1m❭²〗" }, 494 { "en", "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"other\"]", 495 "LOCALE", "〖❬1.5m❭²〗" }, 496 497 // warning, french patterns has U+00A0 in them 498 { "fr", "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1", 499 "Square {0}", "〖Square ❬mètres❭〗" }, 500 { "fr", "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"one\"]", 501 "square {0}", "〖❬1,5 ❭square ❬mètre❭〗" }, 502 { "fr", "//ldml/units/unitLength[@type=\"long\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"other\"]", 503 "squares {0}", "〖❬3,5 ❭squares ❬mètres❭〗" }, 504 505 { "fr", "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1", 506 "LOCALE", "〖❬m❭²〗" }, 507 { "fr", "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"one\"]", 508 "LOCALE", "〖❬1,5m❭²〗" }, 509 { "fr", "//ldml/units/unitLength[@type=\"narrow\"]/compoundUnit[@type=\"power2\"]/compoundUnitPattern1[@count=\"other\"]", 510 "LOCALE", "〖❬3,5m❭²〗" }, 511 }; 512 513 int lineCount = 0; 514 for (String[] test : tests) { 515 516 final String localeID = test[0]; 517 final String xpath = test[1]; 518 String value = test[2]; 519 String expected = test[3]; 520 521 ExampleGenerator exampleGenerator = getExampleGenerator(localeID); 522 523 if (value.equals("LOCALE")) { 524 value = cldrFactory.make(localeID, true).getStringValue(xpath); 525 } 526 String actual = exampleGenerator.getExampleHtml(xpath, value); 527 assertEquals(++lineCount + ") " 528 + localeID 529 + ", CompoundUnit3", expected, 530 ExampleGenerator.simplify(actual, false)); 531 } 532 533 } 534 535 HashMap<String, ExampleGenerator> ExampleGeneratorCache = new HashMap<>(); 536 getExampleGenerator(String locale)537 private ExampleGenerator getExampleGenerator(String locale) { 538 ExampleGenerator result = ExampleGeneratorCache.get(locale); 539 if (result == null) { 540 final CLDRFile nativeCldrFile = info.getCLDRFile(locale, 541 true); 542 result = new ExampleGenerator(nativeCldrFile, info.getEnglish(), 543 CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 544 ExampleGeneratorCache.put(locale, result); 545 } 546 return result; 547 } 548 TestEllipsis()549 public void TestEllipsis() { 550 ExampleGenerator exampleGenerator = getExampleGenerator("it"); 551 String[][] tests = { { "initial", "〖…❬iappone❭〗" }, 552 { "medial", "〖❬Svizzer❭…❬iappone❭〗" }, 553 { "final", "〖❬Svizzer❭…〗" }, 554 { "word-initial", "〖… ❬Giappone❭〗" }, 555 { "word-medial", "〖❬Svizzera❭ … ❬Giappone❭〗" }, 556 { "word-final", "〖❬Svizzera❭ …〗" }, }; 557 for (String[] pair : tests) { 558 checkValue(exampleGenerator, "//ldml/characters/ellipsis[@type=\"" 559 + pair[0] + "\"]", pair[1]); 560 } 561 } 562 checkValue(ExampleGenerator exampleGenerator, String path, String expected)563 private void checkValue(ExampleGenerator exampleGenerator, String path, 564 String expected) { 565 String value = exampleGenerator.getCldrFile().getStringValue(path); 566 String result = ExampleGenerator.simplify( 567 exampleGenerator.getExampleHtml(path, value), false); 568 assertEquals("Ellipsis", expected, result); 569 } 570 simplify(String exampleHtml)571 public static String simplify(String exampleHtml) { 572 return ExampleGenerator.simplify(exampleHtml, false); 573 } 574 TestClip()575 public void TestClip() { 576 assertEquals("Clipping", "bc", ExampleGenerator.clip("abc", 1, 0)); 577 assertEquals("Clipping", "ab", ExampleGenerator.clip("abc", 0, 1)); 578 assertEquals("Clipping", "b\u0308c\u0308", 579 ExampleGenerator.clip("a\u0308b\u0308c\u0308", 1, 0)); 580 assertEquals("Clipping", "a\u0308b\u0308", 581 ExampleGenerator.clip("a\u0308b\u0308c\u0308", 0, 1)); 582 } 583 TestPaths()584 public void TestPaths() { 585 showCldrFile(info.getEnglish()); 586 showCldrFile(info.getCLDRFile("fr", true)); 587 } 588 TestMiscPatterns()589 public void TestMiscPatterns() { 590 ExampleGenerator exampleGenerator = getExampleGenerator("it"); 591 checkValue( 592 "At least", 593 "〖≥❬99❭〗", 594 exampleGenerator, 595 "//ldml/numbers/miscPatterns[@numberSystem=\"latn\"]/pattern[@type=\"atLeast\"]"); 596 checkValue("Range", "〖❬99❭-❬144❭〗", exampleGenerator, 597 "//ldml/numbers/miscPatterns[@numberSystem=\"latn\"]/pattern[@type=\"range\"]"); 598 // String actual = exampleGenerator.getExampleHtml( 599 // "//ldml/numbers/miscPatterns[@type=\"arab\"]/pattern[@type=\"atLeast\"]", 600 // "at least {0}", Zoomed.IN); 601 // assertEquals("Invalid format", 602 // "<div class='cldr_example'>at least 99</div>", actual); 603 } 604 TestPluralSamples()605 public void TestPluralSamples() { 606 ExampleGenerator exampleGenerator = getExampleGenerator("sv"); 607 String[][] tests = { 608 {"//ldml/units/unitLength[@type=\"short\"]/unit[@type=\"length-centimeter\"]/unitPattern[@count=\"one\"]", 609 "Number should be one", 610 "〖❬1❭ cm〗〖❬Jag tror att 1❭ cm❬ är tillräckligt.❭〗"}, 611 {"//ldml/numbers/minimalPairs/ordinalMinimalPairs[@ordinal=\"one\"]", 612 "Ordinal one", 613 "〖Ta ❬1❭:a svängen till höger〗〖❌ Ta ❬3❭:a svängen till höger〗"}, 614 {"//ldml/numbers/minimalPairs/ordinalMinimalPairs[@ordinal=\"other\"]", 615 "Ordinal other", 616 "〖Ta ❬3❭:e svängen till höger〗〖❌ Ta ❬1❭:e svängen till höger〗"}, 617 }; 618 for (String[] row : tests) { 619 String path = row[0]; 620 String message = row[1]; 621 String expected = row[2]; 622 checkValue(message, expected, exampleGenerator, path); 623 } 624 625 } 626 TestLocaleDisplayPatterns()627 public void TestLocaleDisplayPatterns() { 628 ExampleGenerator exampleGenerator = getExampleGenerator("it"); 629 String actual = exampleGenerator.getExampleHtml( 630 "//ldml/localeDisplayNames/localeDisplayPattern/localePattern", 631 "{0} [{1}]"); 632 assertEquals( 633 "localePattern example faulty", 634 "<div class='cldr_example'><span class='cldr_substituted'>uzbeco</span> [<span class='cldr_substituted'>Afghanistan</span>]</div>" 635 + "<div class='cldr_example'><span class='cldr_substituted'>uzbeco</span> [<span class='cldr_substituted'>arabo, Afghanistan</span>]</div>" 636 + "<div class='cldr_example'><span class='cldr_substituted'>uzbeco</span> [<span class='cldr_substituted'>arabo, Afghanistan, Cifre indo-arabe, Fuso orario: Ora Etiopia</span>]</div>", 637 actual); 638 actual = exampleGenerator 639 .getExampleHtml( 640 "//ldml/localeDisplayNames/localeDisplayPattern/localeSeparator", 641 "{0}. {1}"); 642 assertEquals( 643 "localeSeparator example faulty", 644 "<div class='cldr_example'><span class='cldr_substituted'>uzbeco (arabo</span>. <span class='cldr_substituted'>Afghanistan)</span></div>" 645 + "<div class='cldr_example'><span class='cldr_substituted'>uzbeco (arabo</span>. <span class='cldr_substituted'>Afghanistan</span>. <span class='cldr_substituted'>Cifre indo-arabe</span>. <span class='cldr_substituted'>Fuso orario: Ora Etiopia)</span></div>", 646 actual); 647 } 648 TestCurrencyFormats()649 public void TestCurrencyFormats() { 650 ExampleGenerator exampleGenerator = getExampleGenerator("it"); 651 String actual = simplify(exampleGenerator 652 .getExampleHtml( 653 "//ldml/numbers/currencyFormats[@numberSystem=\"latn\"]/currencyFormatLength/currencyFormat[@type=\"standard\"]/pattern[@type=\"standard\"]", 654 "¤ #0.00")); 655 assertEquals("Currency format example faulty", 656 "〖€ ❬1295,00❭〗〖-€ ❬1295,00❭〗", actual); 657 } 658 TestCurrencyFormatsWithContext()659 public void TestCurrencyFormatsWithContext() { 660 ExampleGenerator exampleGenerator = getExampleGenerator("he"); 661 String actual = simplify(exampleGenerator 662 .getExampleHtml( 663 "//ldml/numbers/currencyFormats[@numberSystem=\"latn\"]/currencyFormatLength/currencyFormat[@type=\"standard\"]/pattern[@type=\"standard\"]", 664 "#,##0.00 ¤;-#,##0.00 ¤")); 665 assertEquals("Currency format example faulty", 666 "【❬1,295❭.❬00❭ ₪〗【⃪❬1,295❭.❬00❭ ₪〗【-❬1,295❭.❬00❭ ₪〗【⃪-❬1,295❭.❬00❭ ₪〗【❬1,295❭.❬00❭ ILS〗【⃪❬1,295❭.❬00❭ ILS〗【-❬1,295❭.❬00❭ ILS〗【⃪-❬1,295❭.❬00❭ ILS〗", actual); 667 } 668 TestDateFormatsWithContext()669 public void TestDateFormatsWithContext() { 670 ExampleGenerator exampleGenerator = getExampleGenerator("ar"); 671 String actual = simplify(exampleGenerator 672 .getExampleHtml( 673 "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/dateFormats/dateFormatLength[@type=\"short\"]/dateFormat[@type=\"standard\"]/pattern[@type=\"standard\"]", 674 "d/M/y")); 675 assertEquals("Currency format example faulty", 676 "【٥/٩/١٩٩٩〗【⃪٥/٩/١٩٩٩〗", actual); 677 } 678 TestSymbols()679 public void TestSymbols() { 680 CLDRFile english = info.getEnglish(); 681 ExampleGenerator exampleGenerator = new ExampleGenerator(english, 682 english, CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 683 String actual = exampleGenerator 684 .getExampleHtml( 685 "//ldml/numbers/symbols[@numberSystem=\"latn\"]/superscriptingExponent", 686 "x"); 687 688 assertEquals( 689 "superscriptingExponent faulty", 690 "<div class='cldr_example'><span class='cldr_substituted'>1.23456789</span>x10<span class='cldr_substituted'><sup>5</sup></span></div>", 691 actual); 692 } 693 TestFallbackFormat()694 public void TestFallbackFormat() { 695 ExampleGenerator exampleGenerator = new ExampleGenerator( 696 info.getEnglish(), info.getEnglish(), 697 CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 698 String actual = exampleGenerator.getExampleHtml( 699 "//ldml/dates/timeZoneNames/fallbackFormat", "{1} [{0}]"); 700 assertEquals("fallbackFormat faulty", "〖❬Central Time❭ [❬Cancún❭]〗", 701 ExampleGenerator.simplify(actual, false)); 702 } 703 Test4897()704 public void Test4897() { 705 ExampleGenerator exampleGenerator = getExampleGenerator("it"); 706 for (String xpath : With.in(exampleGenerator.getCldrFile().iterator( 707 "//ldml/dates/timeZoneNames", 708 exampleGenerator.getCldrFile().getComparator()))) { 709 String value = exampleGenerator.getCldrFile().getStringValue(xpath); 710 String actual = exampleGenerator.getExampleHtml(xpath, value); 711 if (actual == null) { 712 if (!xpath.contains("singleCountries") 713 && !xpath.contains("gmtZeroFormat")) { 714 errln("Null value for " + value + "\t" + xpath); 715 // for debugging 716 exampleGenerator.getExampleHtml(xpath, value); 717 } 718 } else { 719 logln(actual + "\t" + value + "\t" + xpath); 720 } 721 } 722 } 723 Test4528()724 public void Test4528() { 725 String[][] testPairs = { 726 { 727 "//ldml/numbers/currencies/currency[@type=\"BMD\"]/displayName[@count=\"other\"]", 728 "〖❬1,23 ❭dollari delle Bermuda〗〖❬0,00 ❭dollari delle Bermuda〗" }, 729 { 730 "//ldml/numbers/currencyFormats[@numberSystem=\"latn\"]/unitPattern[@count=\"other\"]", 731 "〖❬1,23❭ ❬dollari statunitensi❭〗〖❬1,23❭ ❬euro❭〗〖❬0,00❭ ❬dollari statunitensi❭〗〖❬0,00❭ ❬euro❭〗" }, 732 { "//ldml/numbers/currencies/currency[@type=\"BMD\"]/symbol", 733 "〖❬123.456,79 ❭BMD〗" }, }; 734 735 ExampleGenerator exampleGenerator = getExampleGenerator("it"); 736 for (String[] testPair : testPairs) { 737 String xpath = testPair[0]; 738 String expected = testPair[1]; 739 String value = exampleGenerator.getCldrFile().getStringValue(xpath); 740 String actual = simplify(exampleGenerator.getExampleHtml(xpath, value)); 741 assertEquals("specifics", expected, actual); 742 } 743 } 744 Test4607()745 public void Test4607() { 746 String[][] testPairs = { 747 { 748 "//ldml/numbers/decimalFormats[@numberSystem=\"latn\"]/decimalFormatLength[@type=\"long\"]/decimalFormat[@type=\"standard\"]/pattern[@type=\"1000\"][@count=\"one\"]", 749 "<div class='cldr_example'><span class='cldr_substituted'>1</span> thousand</div>" }, 750 { 751 "//ldml/numbers/percentFormats[@numberSystem=\"latn\"]/percentFormatLength/percentFormat[@type=\"standard\"]/pattern[@type=\"standard\"]", 752 "<div class='cldr_example'><span class='cldr_substituted'>5</span>%</div>" 753 + "<div class='cldr_example'><span class='cldr_substituted'>12,345</span>,<span class='cldr_substituted'>679</span>%</div>" 754 + "<div class='cldr_example'>-<span class='cldr_substituted'>12,345</span>,<span class='cldr_substituted'>679</span>%</div>" } }; 755 final CLDRFile nativeCldrFile = info.getEnglish(); 756 ExampleGenerator exampleGenerator = new ExampleGenerator( 757 info.getEnglish(), info.getEnglish(), 758 CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 759 for (String[] testPair : testPairs) { 760 String xpath = testPair[0]; 761 String expected = testPair[1]; 762 String value = nativeCldrFile.getStringValue(xpath); 763 String actual = exampleGenerator.getExampleHtml(xpath, value); 764 assertEquals("specifics", expected, actual); 765 } 766 } 767 showCldrFile(final CLDRFile cldrFile)768 private void showCldrFile(final CLDRFile cldrFile) { 769 ExampleGenerator exampleGenerator = new ExampleGenerator(cldrFile, 770 info.getEnglish(), CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 771 checkPathValue( 772 exampleGenerator, 773 "//ldml/dates/calendars/calendar[@type=\"chinese\"]/dateFormats/dateFormatLength[@type=\"full\"]/dateFormat[@type=\"standard\"]/pattern[@type=\"standard\"][@draft=\"unconfirmed\"]", 774 "EEEE d MMMMl y'x'G", null); 775 776 for (String xpath : cldrFile.fullIterable()) { 777 if (xpath.endsWith("/alias")) { 778 continue; 779 } 780 String value = cldrFile.getStringValue(xpath); 781 checkPathValue(exampleGenerator, xpath, value, null); 782 // remove this, no longer used 783 // if (xpath.contains("count=\"one\"")) { 784 // String xpath2 = xpath.replace("count=\"one\"", "count=\"1\""); 785 // checkPathValue(exampleGenerator, xpath2, value, null); 786 // } 787 } 788 } 789 checkPathValue(ExampleGenerator exampleGenerator, String xpath, String value, String expected)790 private void checkPathValue(ExampleGenerator exampleGenerator, 791 String xpath, String value, String expected) { 792 Set<String> alreadySeen = new HashSet<>(); 793 try { 794 String text = exampleGenerator.getExampleHtml(xpath, value); 795 if (text == null) { 796 // skip 797 } else if (text.contains("Exception")) { 798 errln("getExampleHtml\t" + text); 799 } else if (!alreadySeen.contains(text)) { 800 if (text.contains("n/a")) { 801 if (text.contains("<")) { 802 errln("Text not quoted correctly:" + "\t" + text 803 + "\t" + xpath); 804 } 805 } 806 boolean skipLog = false; 807 if (expected != null) { 808 String simplified = ExampleGenerator.simplify(text, false); 809 // redo for debugging 810 text = exampleGenerator.getExampleHtml(xpath, value); 811 skipLog = !assertEquals("Example text for «" + value + "»", expected, simplified); 812 } 813 if (!skipLog) { 814 logln("getExampleHtml\t" + text + "\t" 815 + xpath); 816 } 817 alreadySeen.add(text); 818 } 819 } catch (Exception e) { 820 errln("getExampleHtml\t" + e.getMessage()); 821 } 822 823 try { 824 String text = exampleGenerator.getHelpHtml(xpath, value); 825 if (text == null) { 826 // skip 827 } else if (text.contains("Exception")) { 828 errln("getHelpHtml\t" + text); 829 } else { 830 logln("getExampleHtml(help)\t" + "\t" + text + "\t" + xpath); 831 } 832 } catch (Exception e) { 833 if (false) { 834 e.printStackTrace(); 835 } 836 errln("getHelpHtml\t" + e.getMessage()); 837 } 838 } 839 TestCompactPlurals()840 public void TestCompactPlurals() { 841 checkCompactExampleFor("de", Count.one, "〖❬1❭ Mio. €〗", "short", "currency", "000000"); 842 checkCompactExampleFor("de", Count.other, "〖❬2❭ Mio. €〗", "short", "currency", "000000"); 843 checkCompactExampleFor("de", Count.one, "〖❬12❭ Mio. €〗", "short", "currency", "0000000"); 844 checkCompactExampleFor("de", Count.other, "〖❬10❭ Mio. €〗", "short", "currency", "0000000"); 845 846 checkCompactExampleFor("cs", Count.many, "〖❬1,1❭ milionu〗", "long", "decimal", "000000"); 847 checkCompactExampleFor("pl", Count.other, "〖❬1,1❭ miliona〗", "long", "decimal", "000000"); 848 } 849 checkCompactExampleFor(String localeID, Count many, String expected, String longVsShort, String decimalVsCurrency, String zeros)850 private void checkCompactExampleFor(String localeID, Count many, 851 String expected, String longVsShort, String decimalVsCurrency, String zeros) { 852 CLDRFile cldrFile = info.getCLDRFile(localeID, true); 853 ExampleGenerator exampleGenerator = new ExampleGenerator(cldrFile, 854 info.getEnglish(), CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 855 String path = "//ldml/numbers/" 856 + decimalVsCurrency + "Formats[@numberSystem=\"latn\"]" 857 + "/" + decimalVsCurrency + "FormatLength[@type=\"" + longVsShort + "\"]" 858 + "/" + decimalVsCurrency + "Format[@type=\"standard\"]" 859 + "/pattern[@type=\"1" + zeros + "\"][@count=\"" + many + "\"]"; 860 checkPathValue(exampleGenerator, path, cldrFile.getStringValue(path), 861 expected); 862 } 863 864 //ldml/numbers/currencyFormats[@numberSystem="latn"]/currencyFormatLength[@type="short"]/currencyFormat[@type="standard"]/pattern[@type="1000"][@count="one"] 865 TestDayPeriods()866 public void TestDayPeriods() { 867 //checkDayPeriod("da", "format", "morning1", "〖05:00 – 10:00〗〖❬7:30❭ morgens〗"); 868 checkDayPeriod("zh", "format", "morning1", "〖05:00 – 08:00⁻〗〖清晨❬6:30❭〗"); 869 870 checkDayPeriod("de", "format", "morning1", "〖05:00 – 10:00⁻〗〖❬7:30 ❭morgens〗"); 871 checkDayPeriod("de", "stand-alone", "morning1", "〖05:00 – 10:00⁻〗"); 872 checkDayPeriod("de", "format", "morning2", "〖10:00 – 12:00⁻〗〖❬11:00 ❭vormittags〗"); 873 checkDayPeriod("de", "stand-alone", "morning2", "〖10:00 – 12:00⁻〗"); 874 checkDayPeriod("pl", "format", "morning1", "〖06:00 – 10:00⁻〗〖❬8:00 ❭rano〗"); 875 checkDayPeriod("pl", "stand-alone", "morning1", "〖06:00 – 10:00⁻〗"); 876 877 checkDayPeriod("en", "format", "night1", "〖00:00 – 06:00⁻; 21:00 – 24:00⁻〗〖❬3:00 ❭at night〗"); 878 checkDayPeriod("en", "stand-alone", "night1", "〖00:00 – 06:00⁻; 21:00 – 24:00⁻〗"); 879 880 checkDayPeriod("en", "format", "noon", "〖12:00〗〖❬12:00 ❭noon〗"); 881 checkDayPeriod("en", "format", "midnight", "〖00:00〗〖❬12:00 ❭midnight〗"); 882 checkDayPeriod("en", "format", "am", "〖00:00 – 12:00⁻〗〖❬6:00 ❭AM〗"); 883 checkDayPeriod("en", "format", "pm", "〖12:00 – 24:00⁻〗〖❬6:00 ❭PM〗"); 884 } 885 checkDayPeriod(String localeId, String type, String dayPeriodCode, String expected)886 private void checkDayPeriod(String localeId, String type, String dayPeriodCode, String expected) { 887 CLDRFile cldrFile = info.getCLDRFile(localeId, true); 888 ExampleGenerator exampleGenerator = new ExampleGenerator(cldrFile, info.getEnglish(), CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 889 String prefix = "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods/dayPeriodContext[@type=\""; 890 String suffix = "\"]/dayPeriodWidth[@type=\"wide\"]/dayPeriod[@type=\"" 891 + dayPeriodCode 892 + "\"]"; 893 String path = prefix + type + suffix; 894 checkPathValue(exampleGenerator, path, cldrFile.getStringValue(path), expected); 895 } 896 897 /** 898 * Test that getExampleHtml returns same output for same input regardless of 899 * order in which it is called with different inputs. 900 * 901 * Calling getExampleHtml with a particular path and value presumably should NOT depend on the 902 * history of paths and/or values it has been called with previously. 903 * 904 * We formerly got different examples for SPECIAL_PATH depending on whether an example was 905 * first gotten for USE_EVIL_PATH. 906 * 907 * Without EVIL_PATH, got right value for SPECIAL_PATH: 908 * <div class='cldr_example'><span class='cldr_substituted'>123 456,79 </span>€</div> 909 * 910 * With EVIL_PATH, got wrong value for SPECIAL_PATH: 911 * <div class='cldr_example'><span class='cldr_substituted'>123457 k </span>€</div> 912 * 913 * This was fixed by doing clone() before returning a DecimalFormat in ICUServiceBuilder. 914 * Reference: https://unicode-org.atlassian.net/browse/CLDR-13375. 915 * 916 * @throws IOException 917 */ TestExampleGeneratorConsistency()918 public void TestExampleGeneratorConsistency() throws IOException { 919 final String EVIL_PATH = "//ldml/numbers/currencyFormats/currencyFormatLength[@type=\"short\"]/currencyFormat[@type=\"standard\"]/pattern[@type=\"10000\"][@count=\"one\"]"; 920 final String SPECIAL_PATH = "//ldml/numbers/currencies/currency[@type=\"EUR\"]/symbol"; 921 final String EXPECTED = "123 456,79"; 922 923 final CLDRFile cldrFile = info.getCLDRFile("fr", true); 924 final ExampleGenerator eg = new ExampleGenerator(cldrFile, info.getEnglish(), CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY); 925 926 final String evilValue = cldrFile.getStringValue(EVIL_PATH); 927 final String specialValue = cldrFile.getStringValue(SPECIAL_PATH); 928 929 eg.getExampleHtml(EVIL_PATH, evilValue); 930 final String specialExample = eg.getExampleHtml(SPECIAL_PATH, specialValue); 931 932 if (!specialExample.contains(EXPECTED)) { 933 errln("Expected example to contain " + EXPECTED + "; got " + specialExample); 934 } 935 } 936 TestInflectedUnitExamples()937 public void TestInflectedUnitExamples() { 938 String[][] deTests = { 939 {"one", "accusative", "〖❬1❭ Tag〗〖❬… für 1❭ Tag❬ …❭〗〖❌ ❬Anstatt 1❭ Tag❬ …❭〗"}, 940 {"one", "dative", "〖❬1❭ Tag〗〖❬… mit 1❭ Tag❬ …❭〗〖❌ ❬Anstatt 1❭ Tag❬ …❭〗"}, 941 {"one", "genitive", "〖❬1❭ Tages〗〖❬Anstatt 1❭ Tages❬ …❭〗〖❌ ❬… für 1❭ Tages❬ …❭〗"}, 942 {"one", "nominative", "〖❬1❭ Tag〗〖❬1❭ Tag❬ kostet (kosten) € 3,50.❭〗〖❌ ❬Anstatt 1❭ Tag❬ …❭〗"}, 943 944 {"other", "accusative", "〖❬1,5❭ Tage〗〖❬… für 1,5❭ Tage❬ …❭〗〖❌ ❬… mit 1,5❭ Tage❬ …❭〗"}, 945 {"other", "dative", "〖❬1,5❭ Tagen〗〖❬… mit 1,5❭ Tagen❬ …❭〗〖❌ ❬… für 1,5❭ Tagen❬ …❭〗"}, 946 {"other", "genitive", "〖❬1,5❭ Tage〗〖❬Anstatt 1,5❭ Tage❬ …❭〗〖❌ ❬… mit 1,5❭ Tage❬ …❭〗"}, 947 {"other", "nominative", "〖❬1,5❭ Tage〗〖❬1,5❭ Tage❬ kostet (kosten) € 3,50.❭〗〖❌ ❬… mit 1,5❭ Tage❬ …❭〗"}, 948 }; 949 checkInflectedUnitExamples("de", deTests); 950 String[][] elTests = { 951 {"one", "accusative", "〖❬1❭ ημέρα〗〖❬… ανά 1❭ ημέρα❬ …❭〗〖❌ ❬… αξίας 1❭ ημέρα❬ …❭〗"}, 952 {"one", "genitive", "〖❬1❭ ημέρας〗〖❬… αξίας 1❭ ημέρας❬ …❭〗〖❌ ❬… ανά 1❭ ημέρας❬ …❭〗"}, 953 {"one", "nominative", "〖❬1❭ ημέρα〗〖❬Η απόσταση είναι 1❭ ημέρα❬ …❭〗〖❌ ❬… αξίας 1❭ ημέρα❬ …❭〗"}, 954 {"other", "accusative", "〖❬0,9❭ ημέρες〗〖❬… ανά 0,9❭ ημέρες❬ …❭〗〖❌ ❬… αξίας 0,9❭ ημέρες❬ …❭〗"}, 955 {"other", "genitive", "〖❬0,9❭ ημερών〗〖❬… αξίας 0,9❭ ημερών❬ …❭〗〖❌ ❬… ανά 0,9❭ ημερών❬ …❭〗"}, 956 {"other", "nominative", "〖❬0,9❭ ημέρες〗〖❬Η απόσταση είναι 0,9❭ ημέρες❬ …❭〗〖❌ ❬… αξίας 0,9❭ ημέρες❬ …❭〗"}, 957 }; 958 checkInflectedUnitExamples("el", elTests); 959 } 960 checkInflectedUnitExamples(final String locale, String[][] tests)961 private void checkInflectedUnitExamples(final String locale, String[][] tests) { 962 final CLDRFile cldrFile = info.getCLDRFile(locale, true); 963 ExampleGenerator exampleGenerator = getExampleGenerator(locale); 964 String pattern = "//ldml/units/unitLength[@type=\"long\"]/unit[@type=\"duration-day\"]/unitPattern[@count=\"COUNT\"][@case=\"CASE\"]"; 965 boolean showWorkingExamples = false; 966 for (String[] row : tests) { 967 String path = pattern.replace("COUNT", row[0]).replace("CASE", row[1]); 968 String expected = row[2]; 969 String value = cldrFile.getStringValue(path); 970 String actualRaw = exampleGenerator.getExampleHtml(path, value); 971 String actual = ExampleGenerator.simplify(actualRaw, false); 972 showWorkingExamples |= !assertEquals(row[0] + ", " + row[1], expected, actual); 973 } 974 975 // If a test fails, verbose will regenerate what the code thinks they should be. 976 // Review for correctness, and then replace the test cases 977 978 if (showWorkingExamples) { 979 System.out.println("## The following would satisfy the test, but check to make sure the expected values are all correct!"); 980 PluralInfo pluralInfo = SDI.getPlurals(PluralType.cardinal, locale); 981 GrammarInfo grammarInfo = SDI.getGrammarInfo(locale); 982 final Collection<String> grammaticalValues2 = grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalCase, GrammaticalScope.units); 983 984 for (Count plural : pluralInfo.getCounts()) { 985 for (String grammaticalCase : grammaticalValues2) { 986 String path = pattern.replace("COUNT", plural.toString()).replace("CASE", grammaticalCase); 987 String value = cldrFile.getStringValue(path); 988 String actualRaw = exampleGenerator.getExampleHtml(path, value); 989 String actual = ExampleGenerator.simplify(actualRaw, false); 990 System.out.println( 991 "{\"" + plural + "\", " 992 + "\"" + grammaticalCase + "\", " 993 + "\"" + actual + "\"},"); 994 } 995 } 996 } 997 } 998 TestMinimalPairExamples()999 public void TestMinimalPairExamples() { 1000 String[][] tests = { 1001 {"//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"one\"]", "〖❬1❭ Tag〗〖❌ ❬2❭ Tag〗"}, 1002 {"//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"other\"]", "〖❬2❭ Tage〗〖❌ ❬1❭ Tage〗"}, 1003 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"accusative\"]", "〖… für ❬1 metrische Pint❭ …〗〖❌ … für ❬1 metrischen Pint❭ …〗"}, 1004 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"dative\"]", "〖… mit ❬1 metrischen Pint❭ …〗〖❌ … mit ❬1 metrische Pint❭ …〗"}, 1005 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"genitive\"]", "〖Anstatt ❬1 metrischen Pints❭ …〗〖❌ Anstatt ❬1 metrische Pint❭ …〗"}, 1006 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"nominative\"]", "〖❬2 metrische Pints❭ kostet (kosten) € 3,50.〗〖❌ ❬1 metrische Pint❭ kostet (kosten) € 3,50.〗"}, 1007 {"//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"feminine\"]", "〖Die ❬Stunde❭ ist …〗〖❌ Die ❬Zentimeter❭ ist …〗"}, 1008 {"//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"masculine\"]", "〖Der ❬Zentimeter❭ ist …〗〖❌ Der ❬Stunde❭ ist …〗"}, 1009 {"//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"neuter\"]", "〖Das ❬Jahrhundert❭ ist …〗〖❌ Das ❬Stunde❭ ist …〗"}, 1010 }; 1011 checkMinimalPairExamples("de", tests); 1012 1013 String[][] elTests = { 1014 {"//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"one\"]", "〖❬1❭ ημέρα〗〖❌ ❬2❭ ημέρα〗"}, 1015 {"//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"other\"]", "〖❬2❭ ημέρες〗〖❌ ❬1❭ ημέρες〗"}, 1016 1017 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"accusative\"]", "〖… ανά ❬1 τόνο❭ …〗〖❌ … ανά ❬1 τόνου❭ …〗"}, 1018 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"genitive\"]", "〖… αξίας ❬1 τόνου❭ …〗〖❌ … αξίας ❬1 τόνο❭ …〗"}, 1019 {"//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"nominative\"]", "〖Η απόσταση είναι ❬2 τόνοι❭ …〗〖❌ Η απόσταση είναι ❬1 τόνο❭ …〗"}, 1020 1021 {"//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"feminine\"]", "〖Η ❬ημέρα❭ είναι〗〖❌ Η ❬αιώνας❭ είναι〗"}, 1022 {"//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"masculine\"]", "〖Ο ❬αιώνας❭ θα είναι〗〖❌ Ο ❬ημέρα❭ θα είναι〗"}, 1023 {"//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"neuter\"]", "〖Το ❬εκατοστό❭ ήταν〗〖❌ Το ❬ημέρα❭ ήταν〗"}, 1024 }; 1025 checkMinimalPairExamples("el", elTests); 1026 } 1027 checkMinimalPairExamples(final String locale, String[][] tests)1028 private void checkMinimalPairExamples(final String locale, String[][] tests) { 1029 final CLDRFile cldrFile = info.getCLDRFile(locale, true); 1030 ExampleGenerator exampleGenerator = getExampleGenerator(locale); 1031 boolean showWorkingExamples = false; 1032 for (String[] row : tests) { 1033 String path = row[0]; 1034 String expected = row[1]; 1035 String value = cldrFile.getStringValue(path); 1036 String actualRaw = exampleGenerator.getExampleHtml(path, value); 1037 String actual = ExampleGenerator.simplify(actualRaw, false); 1038 showWorkingExamples |= !assertEquals(row[0] + ", " + row[1], expected, actual); 1039 } 1040 1041 // If a test fails, verbose will regenerate what the code thinks they should be. 1042 // Review for correctness, and then replace the test cases 1043 1044 if (showWorkingExamples) { 1045 System.out.println("## The following would satisfy the test, but check to make sure the expected values are all correct!"); 1046 PluralInfo pluralInfo = SDI.getPlurals(PluralType.cardinal, locale); 1047 ArrayList<String> paths = new ArrayList<>(); 1048 1049 for (Count plural : pluralInfo.getCounts()) { 1050 paths.add("//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"" + plural + "\"]"); 1051 } 1052 GrammarInfo grammarInfo = SDI.getGrammarInfo(locale); 1053 for (String grammaticalValues : grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalCase, GrammaticalScope.units)) { 1054 paths.add("//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"" + grammaticalValues + "\"]"); 1055 } 1056 for (String grammaticalValues : grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalGender, GrammaticalScope.units)) { 1057 paths.add("//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"" + grammaticalValues + "\"]"); 1058 } 1059 for (String path : paths) { 1060 String value = cldrFile.getStringValue(path); 1061 String actualRaw = exampleGenerator.getExampleHtml(path, value); 1062 String actual = ExampleGenerator.simplify(actualRaw, false); 1063 System.out.println("{\"" + path.replace("\"", "\\\"") + "\", \"" + actual + "\"},"); 1064 } 1065 } 1066 } 1067 1068 /** Test the production of minimal pair examples, to make sure we get no exceptions. 1069 * If -v, then generates lines for spreadsheet survey 1070 */ TestListMinimalPairExamples()1071 public void TestListMinimalPairExamples() { 1072 Set<String> localesWithGrammar = SDI.hasGrammarInfo(); 1073 if (isVerbose()) { 1074 System.out.println("\nLC\tLocale\tType\tCode\tCurrent Pattern\tVerify this is correct!\tVerify this is wrong!"); 1075 } 1076 final String unused = "∅"; 1077 List<String> pluralSheet = new ArrayList(); 1078 for (String locale : localesWithGrammar) { 1079 final CLDRFile cldrFile = info.getCLDRFile(locale, true); 1080 ExampleGenerator exampleGenerator = getExampleGenerator(locale); 1081 1082 PluralInfo pluralInfo = SDI.getPlurals(PluralType.cardinal, cldrFile.getLocaleID()); 1083 Map<String, Pair<String,String>> paths = new LinkedHashMap<>(); 1084 1085 Set<Count> counts = pluralInfo.getCounts(); 1086 if (counts.size() > 1) { 1087 for (Count plural : counts) { 1088 paths.put("//ldml/numbers/minimalPairs/pluralMinimalPairs[@count=\"" + plural + "\"]", Pair.of("plural",plural.toString())); 1089 } 1090 } 1091 GrammarInfo grammarInfo = SDI.getGrammarInfo(locale); 1092 Collection<String> unitCases = grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalCase, GrammaticalScope.units); 1093 Collection<String> generalCasesRaw = grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalCase, GrammaticalScope.general); 1094 Collection<CaseValues> generalCases = generalCasesRaw.stream().map(x -> CaseValues.valueOf(x)).collect(Collectors.toCollection(TreeSet::new)); 1095 for (CaseValues unitCase0 : generalCases) { 1096 String unitCase = unitCase0.toString(); 1097 paths.put((unitCases.contains(unitCase) ? "" : unused) + "//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\"" + unitCase + "\"]", 1098 Pair.of("case",unitCase)); 1099 } 1100 Collection<String> unitGenders = grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalGender, GrammaticalScope.units); 1101 Collection<String> generalGenders = grammarInfo.get(GrammaticalTarget.nominal, GrammaticalFeature.grammaticalGender, GrammaticalScope.general); 1102 for (String unitGender : generalGenders) { 1103 paths.put((unitGenders.contains(unitGender) ? "" : unused) + "//ldml/numbers/minimalPairs/genderMinimalPairs[@gender=\"" + unitGender + "\"]", 1104 Pair.of("gender",unitGender)); 1105 } 1106 String localeName = CLDRConfig.getInstance().getEnglish().getName(locale); 1107 boolean pluralOnly = true; 1108 if (paths.isEmpty()) { 1109 pluralSheet.add(locale 1110 + "\t" + localeName 1111 + "\t" + "N/A" 1112 + "\t" + "N/A" 1113 + "\t" + "N/A" 1114 ); 1115 } else { 1116 for (Entry<String, Pair<String, String>> pathAndLabel : paths.entrySet()) { 1117 String path = pathAndLabel.getKey(); 1118 String label = pathAndLabel.getValue().getFirst(); 1119 String code = pathAndLabel.getValue().getSecond(); 1120 if (!label.equals("plural")) { 1121 pluralOnly = false; 1122 } 1123 } 1124 String lastLabel = ""; 1125 for (Entry<String, Pair<String, String>> pathAndLabel : paths.entrySet()) { 1126 String path = pathAndLabel.getKey(); 1127 String label = pathAndLabel.getValue().getFirst(); 1128 String code = pathAndLabel.getValue().getSecond(); 1129 String pattern = ""; 1130 String examples = ""; 1131 if (!label.equals(lastLabel)) { 1132 lastLabel = label; 1133 if (!pluralOnly) { 1134 if (isVerbose()) { 1135 System.out.println(); 1136 } 1137 } 1138 } 1139 if (path.startsWith(unused)) { 1140 pattern = " Not used with formatted units"; 1141 } else { 1142 pattern = cldrFile.getStringValue(path); 1143 if (pattern == null) { 1144 warnln("Missing ExampleGenerator html example for " + locale + "(" + localeName + "): " + path); 1145 continue; 1146 } 1147 String actualRaw = exampleGenerator.getExampleHtml(path, pattern); 1148 String actualSimplified = ExampleGenerator.simplify(actualRaw, false); 1149 examples = actualSimplified 1150 .replace("〗〖", "\t") 1151 .replace("〗", "") 1152 .replace("〖", "") 1153 ; 1154 List<String> exampleList = com.google.common.base.Splitter.on('\t').trimResults().splitToList(examples); 1155 final int exampleListSize = exampleList.size(); 1156 switch(exampleListSize) { 1157 case 2: // ok 1158 break; 1159 case 1: 1160 warnln("Expecting exactly 2 examples: " + exampleList + ", but got " + exampleListSize); 1161 break; 1162 default: 1163 errln("Expecting exactly 2 examples: " + exampleList + ", but got " + exampleListSize); 1164 break; 1165 } 1166 StringBuilder exampleBuffer = new StringBuilder(); 1167 for (String exampleItem : exampleList) { 1168 if (exampleItem.contains("❬null❭") || exampleItem.contains("❬n/a❭")) { 1169 boolean bad = (exampleItem.contains("❌")); 1170 exampleItem = " No unit available"; 1171 if (bad) { 1172 exampleItem = "❌ " + exampleItem; 1173 } 1174 } 1175 if (exampleBuffer.length() != 0) { 1176 exampleBuffer.append('\t'); 1177 } 1178 exampleBuffer.append(exampleItem); 1179 } 1180 examples = exampleBuffer.toString(); 1181 } 1182 String line = (locale 1183 + "\t" + localeName 1184 + "\t" + label 1185 + "\t" + code 1186 + "\t" + pattern 1187 + "\t" + examples); 1188 if (pluralOnly) { 1189 pluralSheet.add(line); 1190 } else { 1191 if (isVerbose()) { 1192 System.out.println(line); 1193 } 1194 } 1195 } 1196 } 1197 if (pluralOnly) { 1198 pluralSheet.add(""); 1199 } else if (isVerbose()) { 1200 System.out.println(); 1201 } 1202 } 1203 if (isVerbose()) { 1204 System.out.println("#################### Plural Only ###################"); 1205 for (String line : pluralSheet) { 1206 System.out.println(line); 1207 } 1208 } 1209 } 1210 } 1211