subdivisionIdToName;
-
- private String creationTime = null; // only used if DEBUG_EXAMPLE_GENERATOR
-
- private final IntervalFormat intervalFormat = new IntervalFormat();
-
- private PathDescription pathDescription;
-
- /**
- * True if this ExampleGenerator is especially for generating "English" examples, false if it is
- * for generating "native" examples.
- */
- private final boolean typeIsEnglish;
-
- /** True if this ExampleGenerator is for RTL locale. */
- private final boolean isRTL;
-
- HelpMessages helpMessages;
-
- public CLDRFile getCldrFile() {
- return cldrFile;
- }
-
- /**
- * For this (locale-specific) ExampleGenerator, clear the cached examples for any paths whose
- * examples might depend on the winning value of the given path, since the winning value of the
- * given path has changed.
- *
- * @param xpath the path whose winning value has changed
- * Called by TestCache.updateExampleGeneratorCache
- */
- public void updateCache(String xpath) {
- exCache.update(xpath);
- if (ICUServiceBuilder.ISB_CAN_CLEAR_CACHE) {
- icuServiceBuilder.clearCache();
- }
- }
-
- /**
- * For getting the end of the "background" style. Default is "". It is used in composing
- * patterns, so it can show the part that corresponds to the value.
- *
- * @return
- */
- public String getBackgroundEnd() {
- return backgroundEnd;
- }
-
- /**
- * For setting the end of the "background" style. Default is "". It is used in composing
- * patterns, so it can show the part that corresponds to the value.
- */
- public void setBackgroundEnd(String backgroundEnd) {
- this.backgroundEnd = backgroundEnd;
- }
-
- /**
- * For getting the "background" style. Default is "". It is
- * used in composing patterns, so it can show the part that corresponds to the value.
- *
- * @return
- */
- public String getBackgroundStart() {
- return backgroundStart;
- }
-
- /**
- * For setting the "background" style. Default is "". It is
- * used in composing patterns, so it can show the part that corresponds to the value.
- */
- public void setBackgroundStart(String backgroundStart) {
- this.backgroundStart = backgroundStart;
- }
-
- /**
- * Set the verbosity level of internal errors. For example, setVerboseErrors(true) will cause
- * full stack traces to be shown in some cases.
- */
- public void setVerboseErrors(boolean verbosity) {
- this.verboseErrors = verbosity;
- }
-
- /**
- * Create an Example Generator. If this is shared across threads, it must be synchronized.
- *
- * @param resolvedCldrFile
- * @param englishFile
- */
- public ExampleGeneratorOld(CLDRFile resolvedCldrFile, CLDRFile englishFile) {
- if (!resolvedCldrFile.isResolved()) {
- throw new IllegalArgumentException("CLDRFile must be resolved");
- }
- if (!englishFile.isResolved()) {
- throw new IllegalArgumentException("English CLDRFile must be resolved");
- }
- cldrFile = resolvedCldrFile;
- final String localeId = cldrFile.getLocaleID();
- subdivisionIdToName = EmojiSubdivisionNames.getSubdivisionIdToName(localeId);
- pluralInfo = supplementalDataInfo.getPlurals(PluralType.cardinal, localeId);
- grammarInfo =
- supplementalDataInfo.getGrammarInfo(localeId); // getGrammarInfo can return null
- this.englishFile = englishFile;
- this.typeIsEnglish = (resolvedCldrFile == englishFile);
- icuServiceBuilder.setCldrFile(cldrFile);
-
- bestMinimalPairSamples = new BestMinimalPairSamples(cldrFile, icuServiceBuilder, false);
-
- String characterOrder = cldrFile.getStringValue("//ldml/layout/orientation/characterOrder");
- this.isRTL = (characterOrder != null && characterOrder.equals("right-to-left"));
-
- if (DEBUG_EXAMPLE_GENERATOR) {
- creationTime =
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
- .format(Calendar.getInstance().getTime());
- System.out.println(
- "π§β Created new ExampleGenerator for loc " + localeId + " at " + creationTime);
- }
- }
-
- /**
- * Get an example string, in html, if there is one for this path, otherwise null. For use in the
- * survey tool, an example might be returned *even* if there is no value in the locale. For
- * example, the locale might have a path that English doesn't, but you want to return the best
- * English example.
- * The result is valid HTML.
- *
- * If generating examples for an inheritance marker, use the "real" inherited value to
- * generate from. Do this BEFORE accessing the cache, which doesn't use INHERITANCE_MARKER.
- *
- * @param xpath the path; e.g., "//ldml/dates/timeZoneNames/fallbackFormat"
- * @param value the value; e.g., "{1} [{0}]"; not necessarily the winning value
- * @return the example HTML, or null
- */
- public String getExampleHtml(String xpath, String value) {
- return getExampleHtmlExtended(xpath, value, false /* nonTrivial */);
- }
-
- /**
- * Same as getExampleHtml but return null if the result would simply be the given value plus
- * some markup
- *
- *
For example, for path = //ldml/localeDisplayNames/languages/language[@type="nl_BE"] and
- * value = "Flemish", getExampleHtml returns "
Flemish
", which is
- * trivial. Maybe there is some context in which such trivial examples are useful -- if not,
- * getExampleHtml should be revised to be the same as getNonTrivialExampleHtml and there won't
- * be a need for this distinct method.
- *
- * @param xpath the path; e.g., "//ldml/dates/timeZoneNames/fallbackFormat"
- * @param value the value; e.g., "{1} [{0}]"; not necessarily the winning value
- * @return the example HTML, or null
- */
- public String getNonTrivialExampleHtml(String xpath, String value) {
- return getExampleHtmlExtended(xpath, value, true /* nonTrivial */);
- }
-
- private String getExampleHtmlExtended(String xpath, String value, boolean nonTrivial) {
- if (value == null || xpath == null || xpath.endsWith("/alias")) {
- return null;
- }
- String result;
- try {
- if (CldrUtility.INHERITANCE_MARKER.equals(value)) {
- value = cldrFile.getBaileyValue(xpath, null, null);
- if (value == null) {
- /*
- * This can happen for some paths, such as
- * //ldml/dates/timeZoneNames/metazone[@type="Mawson"]/short/daylight
- */
- return null;
- }
- }
- ExampleCache.ExampleCacheItem cacheItem = exCache.new ExampleCacheItem(xpath, value);
- result = cacheItem.getExample();
- if (result != null) {
- return result;
- }
- result = constructExampleHtml(xpath, value, nonTrivial);
- cacheItem.putExample(result);
- } catch (RuntimeException e) {
- e.printStackTrace();
- String unchained =
- verboseErrors ? ("
" + finalizeBackground(unchainException(e))) : "";
- result = "Parsing error. " + finalizeBackground(e.getMessage()) + "" + unchained;
- }
- return result;
- }
-
- /**
- * Do the main work of getExampleHtml given that the result was not found in the cache.
- *
- * @param xpath the path; e.g., "//ldml/dates/timeZoneNames/fallbackFormat"
- * @param value the value; e.g., "{1} [{0}]"; not necessarily the winning value
- * @param nonTrivial true if we should avoid returning a trivial example (just value wrapped in
- * markup)
- * @return the example HTML, or null
- */
- private String constructExampleHtml(String xpath, String value, boolean nonTrivial) {
- String result = null;
- boolean showContexts =
- isRTL || BIDI_MARKS.containsSome(value); // only used for certain example types
- /*
- * Need getInstance, not getFrozenInstance here: some functions such as handleNumberSymbol
- * expect to call functions like parts.addRelative which throw exceptions if parts is frozen.
- */
- XPathParts parts = XPathParts.getFrozenInstance(xpath).cloneAsThawed();
- if (parts.contains("dateRangePattern")) { // {0} - {1}
- result = handleDateRangePattern(value);
- } else if (parts.contains("timeZoneNames")) {
- result = handleTimeZoneName(parts, value);
- } else if (parts.contains("localeDisplayNames")) {
- result = handleDisplayNames(xpath, parts, value);
- } else if (parts.contains("currency")) {
- result = handleCurrency(xpath, parts, value);
- } else if (parts.contains("dayPeriods")) {
- result = handleDayPeriod(parts, value);
- } else if (parts.contains("monthContext")) {
- result = handleDateSymbol(parts, value);
- } else if (parts.contains("pattern") || parts.contains("dateFormatItem")) {
- if (parts.contains("calendar")) {
- result = handleDateFormatItem(xpath, value, showContexts);
- } else if (parts.contains("miscPatterns")) {
- result = handleMiscPatterns(parts, value);
- } else if (parts.contains("numbers")) {
- if (parts.contains("currencyFormat")) {
- result = handleCurrencyFormat(parts, value, showContexts);
- } else {
- result = handleDecimalFormat(parts, value, showContexts);
- }
- }
- } else if (parts.contains("minimumGroupingDigits")) {
- result = handleMinimumGrouping(parts, value);
- } else if (parts.getElement(2).contains("symbols")) {
- result = handleNumberSymbol(parts, value);
- } else if (parts.contains("defaultNumberingSystem")
- || parts.contains("otherNumberingSystems")) {
- result = handleNumberingSystem(value);
- } else if (parts.contains("currencyFormats") && parts.contains("unitPattern")) {
- result = formatCountValue(xpath, parts, value);
- } else if (parts.getElement(-1).equals("compoundUnitPattern")) {
- result = handleCompoundUnit(parts);
- } else if (parts.getElement(-1).equals("compoundUnitPattern1")
- || parts.getElement(-1).equals("unitPrefixPattern")) {
- result = handleCompoundUnit1(parts, value);
- } else if (parts.getElement(-2).equals("unit")
- && (parts.getElement(-1).equals("unitPattern")
- || parts.getElement(-1).equals("displayName"))) {
- result = handleFormatUnit(parts, value);
- } else if (parts.getElement(-1).equals("perUnitPattern")) {
- result = handleFormatPerUnit(value);
- } else if (parts.getElement(-2).equals("minimalPairs")) {
- result = handleMinimalPairs(parts, value);
- } else if (parts.getElement(-1).equals("durationUnitPattern")) {
- result = handleDurationUnit(value);
- } else if (parts.contains("intervalFormats")) {
- result = handleIntervalFormats(parts, value);
- } else if (parts.getElement(1).equals("delimiters")) {
- result = handleDelimiters(parts, xpath, value);
- } else if (parts.getElement(1).equals("listPatterns")) {
- result = handleListPatterns(parts, value);
- } else if (parts.getElement(2).equals("ellipsis")) {
- result = handleEllipsis(parts.getAttributeValue(-1, "type"), value);
- } else if (parts.getElement(-1).equals("monthPattern")) {
- result = handleMonthPatterns(parts, value);
- } else if (parts.getElement(-1).equals("appendItem")) {
- result = handleAppendItems(parts, value);
- } else if (parts.getElement(-1).equals("annotation")) {
- result = handleAnnotationName(parts, value);
- } else if (parts.getElement(-1).equals("characterLabel")) {
- result = handleLabel(parts, value);
- } else if (parts.getElement(-1).equals("characterLabelPattern")) {
- result = handleLabelPattern(parts, value);
- } else if (parts.getElement(1).equals("personNames")) {
- result = handlePersonName(parts, value);
- } else if (parts.getElement(-1).equals("exemplarCharacters")
- || parts.getElement(-1).equals("parseLenient")) {
- result = handleUnicodeSet(parts, xpath, value);
- }
-
- // Handle the outcome
- if (result != null) {
- if (nonTrivial && value.equals(result)) {
- result = null;
- } else {
- result = finalizeBackground(result);
- }
- }
- return result;
- }
-
- // Note: may want to change to locale's order; if so, these would be instance fields
- static final SimpleUnicodeSetFormatter SUSF =
- new SimpleUnicodeSetFormatter(SimpleUnicodeSetFormatter.BASIC_COLLATOR);
- static final SimpleUnicodeSetFormatter SUSFNS =
- new SimpleUnicodeSetFormatter(
- SimpleUnicodeSetFormatter.BASIC_COLLATOR,
- CodePointEscaper.FORCE_ESCAPE_WITH_NONSPACING);
- static final String LRM = "\u200E";
- static final UnicodeSet NEEDS_LRM = new UnicodeSet("[:BidiClass=R:]").freeze();
- private static final boolean SHOW_NON_SPACING_IN_UNICODE_SET = true;
-
- /**
- * Add examples for UnicodeSets. First, show a hex format of non-spacing marks if there are any,
- * then show delta to the winning value if there are any.
- */
- private String handleUnicodeSet(XPathParts parts, String xpath, String value) {
- ArrayList examples = new ArrayList<>();
- UnicodeSet valueSet;
- try {
- valueSet = new UnicodeSet(value);
- } catch (Exception e) {
- return null;
- }
- String winningValue = cldrFile.getWinningValue(xpath);
- if (!winningValue.equals(value)) {
- // show delta
- final UnicodeSet winningSet = new UnicodeSet(winningValue);
- UnicodeSet value_minus_winning = new UnicodeSet(valueSet).removeAll(winningSet);
- UnicodeSet winning_minus_value = new UnicodeSet(winningSet).removeAll(valueSet);
- if (!value_minus_winning.isEmpty()) {
- examples.add(LRM + ADDS + " " + SUSF.format(value_minus_winning));
- }
- if (!winning_minus_value.isEmpty()) {
- examples.add(LRM + SUBTRACTS + " " + SUSF.format(winning_minus_value));
- }
- }
- if (parts.containsAttributeValue("type", "auxiliary")) {
- LanguageTagParser ltp = new LanguageTagParser();
- String ltpScript = ltp.set(cldrFile.getLocaleID()).getResolvedScript();
- UnicodeSet exemplars = ScriptToExemplars.getExemplars(ltpScript);
- UnicodeSet main = cldrFile.getExemplarSet(ExemplarType.main, WinningChoice.WINNING);
- UnicodeSet mainAndAux = new UnicodeSet(main).addAll(valueSet);
- if (!mainAndAux.containsAll(exemplars)) {
- examples.add(
- LRM
- + HINTS
- + " "
- + SUSF.format(new UnicodeSet(exemplars).removeAll(mainAndAux)));
- }
- }
- if (SHOW_NON_SPACING_IN_UNICODE_SET
- && valueSet.containsSome(CodePointEscaper.FORCE_ESCAPE)) {
- for (String nsm : new UnicodeSet(valueSet).retainAll(CodePointEscaper.FORCE_ESCAPE)) {
- examples.add(CodePointEscaper.toExample(nsm.codePointAt(0)));
- }
- }
- examples.add(setBackground(INTERNAL) + valueSet.toPattern(false)); // internal format
- return formatExampleList(examples);
- }
-
- /**
- * Holds a map and an object that are relatively expensive to build, so we don't want to do that
- * on each call. TODO clean up the synchronization model.
- */
- private static class PersonNamesCache implements ExampleCache.ClearableCache {
- Map sampleNames = null;
- PersonNameFormatter personNameFormatter = null;
-
- @Override
- public void clear() {
- sampleNames = null;
- personNameFormatter = null;
- }
-
- Map getSampleNames(CLDRFile cldrFile) {
- synchronized (this) {
- if (sampleNames == null) {
- sampleNames = PersonNameFormatter.loadSampleNames(cldrFile);
- }
- return sampleNames;
- }
- }
-
- PersonNameFormatter getPersonNameFormatter(CLDRFile cldrFile) {
- synchronized (this) {
- if (personNameFormatter == null) {
- personNameFormatter = new PersonNameFormatter(cldrFile);
- }
- return personNameFormatter;
- }
- }
-
- @Override
- public String toString() {
- return "["
- + (sampleNames == null ? "" : Joiner.on('\n').join(sampleNames.entrySet()))
- + ", "
- + (personNameFormatter == null ? "" : personNameFormatter.toString())
- + "]";
- }
- }
-
- /** Register the cache, so that it gets cleared when any of the paths change */
- PersonNamesCache personNamesCache =
- exCache.registerCache(
- new PersonNamesCache(),
- "//ldml/personNames/sampleName[@item=\"*\"]/nameField[@type=\"*\"]",
- "//ldml/personNames/initialPattern[@type=\"*\"]",
- "//ldml/personNames/foreignSpaceReplacement",
- "//ldml/personNames/nativeSpaceReplacement",
- "//ldml/personNames/personName[@order=\"*\"][@length=\"*\"][@usage=\"*\"][@formality=\"*\"]/namePattern");
-
- private static final Function BACKGROUND_TRANSFORM =
- x -> backgroundStartSymbol + x + backgroundEndSymbol;
-
- private String handlePersonName(XPathParts parts, String value) {
- // ldml/personNames/personName[@order="givenFirst"][@length="long"][@usage="addressing"][@style="formal"]/namePattern => {prefix} {surname}
- String debugState = "start";
- try {
- FormatParameters formatParameters =
- new FormatParameters(
- PersonNameFormatter.Order.from(parts.getAttributeValue(2, "order")),
- PersonNameFormatter.Length.from(parts.getAttributeValue(2, "length")),
- PersonNameFormatter.Usage.from(parts.getAttributeValue(2, "usage")),
- PersonNameFormatter.Formality.from(
- parts.getAttributeValue(2, "formality")));
-
- List examples = null;
- final CLDRFile cldrFile2 = getCldrFile();
- switch (parts.getElement(2)) {
- case "nameOrderLocales":
- examples = new ArrayList<>();
- for (String localeId : PersonNameFormatter.SPLIT_SPACE.split(value)) {
- final String name =
- localeId.equals("und")
- ? "Β«any otherΒ»"
- : cldrFile2.getName(localeId);
- examples.add(localeId + " = " + name);
- }
- break;
- case "initialPattern":
- return null;
- case "sampleName":
- return null;
- case "personName":
- examples = new ArrayList<>();
- Map sampleNames =
- personNamesCache.getSampleNames(cldrFile2);
- PersonNameFormatter personNameFormatter =
- personNamesCache.getPersonNameFormatter(cldrFile2);
-
- // We might need the alt, however: String alt = parts.getAttributeValue(-1,
- // "alt");
-
- boolean lastIsNative = false;
- for (Entry
- typeAndSampleNameObject : sampleNames.entrySet()) {
- NamePattern namePattern = NamePattern.from(0, value); // get the first one
- final boolean isNative = typeAndSampleNameObject.getKey().isNative();
- if (isNative != lastIsNative) {
- final String title =
- isNative
- ? "π¨ Native name and script:"
- : "π§ Foreign name and native script:";
- examples.add(startItalicSymbol + title + endItalicSymbol);
- lastIsNative = isNative;
- }
- debugState = " haveHeaderLine = new Output<>(false);
-
- if (!script.equals("Latn")) {
- formatSampleName(formatParameters, englishFile, examples, haveHeaderLine);
- }
- if (!script.equals("Cyrl")) {
- formatSampleName(
- formatParameters, PersonNameScripts.Cyrl, examples, haveHeaderLine);
- }
- if (!script.equals("Jpan")) {
- formatSampleName(
- formatParameters, PersonNameScripts.Jpan, examples, haveHeaderLine);
- }
- break;
- }
- return formatExampleList(examples);
- } catch (Exception e) {
- StringBuffer stackTrace;
- try (StringWriter sw = new StringWriter();
- PrintWriter p = new PrintWriter(sw)) {
- e.printStackTrace(p);
- stackTrace = sw.getBuffer();
- } catch (Exception e2) {
- stackTrace = new StringBuffer("internal error");
- }
- return "Internal error: " + e.getMessage() + "\n" + debugState + "\n" + stackTrace;
- }
- }
-
- enum PersonNameScripts {
- Latn,
- Cyrl,
- Jpan
- }
-
- public void formatSampleName(
- FormatParameters formatParameters,
- PersonNameScripts script,
- List examples,
- Output haveHeaderLine) {
- switch (script) {
- case Cyrl:
- if (cyrillicFile == null) {
- cyrillicFile = CLDRConfig.getInstance().getCldrFactory().make("uk", true);
- }
- formatSampleName(formatParameters, cyrillicFile, examples, haveHeaderLine);
- break;
- case Jpan:
- if (japanFile == null) {
- japanFile = CLDRConfig.getInstance().getCldrFactory().make("ja", true);
- }
- formatSampleName(formatParameters, japanFile, examples, haveHeaderLine);
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- public void formatSampleName(
- FormatParameters formatParameters,
- final CLDRFile cldrFile2,
- List examples,
- Output haveHeaderLine) {
- PersonNameFormatter formatter2 = new PersonNameFormatter(cldrFile2);
- Map sampleNames2 =
- PersonNameFormatter.loadSampleNames(cldrFile2);
- SimpleNameObject sampleName =
- getBestAvailable(
- sampleNames2,
- PersonNameFormatter.SampleType.nativeFull,
- PersonNameFormatter.SampleType.nativeGGS);
- if (sampleName != null) {
- String result2 =
- formatter2.format(
- new PersonNameFormatter.TransformingNameObject(
- sampleName, BACKGROUND_TRANSFORM),
- formatParameters);
- if (result2 != null) {
- if (!haveHeaderLine.value) {
- haveHeaderLine.value = Boolean.TRUE;
- examples.add(
- startItalicSymbol + "π₯ Foreign name and script:" + endItalicSymbol);
- }
- examples.add(result2);
- }
- }
- }
-
- private SimpleNameObject getBestAvailable(
- Map sampleNamesMap,
- PersonNameFormatter.SampleType... sampleTypes) {
- for (PersonNameFormatter.SampleType sampleType : sampleTypes) {
- SimpleNameObject result = sampleNamesMap.get(sampleType);
- if (result != null) {
- return result;
- }
- }
- return null;
- }
-
- private String handleLabelPattern(XPathParts parts, String value) {
- if ("category-list".equals(parts.getAttributeValue(-1, "type"))) {
- List examples = new ArrayList<>();
- CLDRFile cfile = getCldrFile();
- SimpleFormatter initialPattern = SimpleFormatter.compile(setBackground(value));
- String path = CLDRFile.getKey(CLDRFile.TERRITORY_NAME, "FR");
- String regionName = cfile.getStringValue(path);
- String flagName =
- cfile.getStringValue("//ldml/characterLabels/characterLabel[@type=\"flag\"]");
- examples.add(
- invertBackground(
- EmojiConstants.getEmojiFromRegionCodes("FR")
- + " β "
- + initialPattern.format(flagName, regionName)));
- return formatExampleList(examples);
- }
- return null;
- }
-
- private String handleLabel(XPathParts parts, String value) {
- // "//ldml/characterLabels/characterLabel[@type=\"" + typeAttributeValue + "\"]"
- switch (parts.getAttributeValue(-1, "type")) {
- case "flag":
- {
- String value2 = backgroundStartSymbol + value + backgroundEndSymbol;
- CLDRFile cfile = getCldrFile();
- List examples = new ArrayList<>();
- SimpleFormatter initialPattern =
- SimpleFormatter.compile(
- cfile.getStringValue(
- "//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]"));
- addFlag(value2, "FR", cfile, initialPattern, examples);
- addFlag(value2, "CN", cfile, initialPattern, examples);
- addSubdivisionFlag(value2, "gbeng", initialPattern, examples);
- addSubdivisionFlag(value2, "gbsct", initialPattern, examples);
- addSubdivisionFlag(value2, "gbwls", initialPattern, examples);
- return formatExampleList(examples);
- }
- case "keycap":
- {
- String value2 = backgroundStartSymbol + value + backgroundEndSymbol;
- List examples = new ArrayList<>();
- CLDRFile cfile = getCldrFile();
- SimpleFormatter initialPattern =
- SimpleFormatter.compile(
- cfile.getStringValue(
- "//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]"));
- examples.add(invertBackground(initialPattern.format(value2, "1")));
- examples.add(invertBackground(initialPattern.format(value2, "10")));
- examples.add(invertBackground(initialPattern.format(value2, "#")));
- return formatExampleList(examples);
- }
- default:
- return null;
- }
- }
-
- private void addFlag(
- String value2,
- String isoRegionCode,
- CLDRFile cfile,
- SimpleFormatter initialPattern,
- List examples) {
- String path = CLDRFile.getKey(CLDRFile.TERRITORY_NAME, isoRegionCode);
- String regionName = cfile.getStringValue(path);
- examples.add(
- invertBackground(
- EmojiConstants.getEmojiFromRegionCodes(isoRegionCode)
- + " β "
- + initialPattern.format(value2, regionName)));
- }
-
- private void addSubdivisionFlag(
- String value2,
- String isoSubdivisionCode,
- SimpleFormatter initialPattern,
- List examples) {
- String subdivisionName = subdivisionIdToName.get(isoSubdivisionCode);
- if (subdivisionName == null) {
- subdivisionName = isoSubdivisionCode;
- }
- examples.add(
- invertBackground(
- EmojiConstants.getEmojiFromSubdivisionCodes(isoSubdivisionCode)
- + " β "
- + initialPattern.format(value2, subdivisionName)));
- }
-
- private String handleAnnotationName(XPathParts parts, String value) {
- // ldml/annotations/annotation[@cp="π¦°"][@type="tts"]
- // skip anything but the name
- if (!"tts".equals(parts.getAttributeValue(-1, "type"))) {
- return null;
- }
- String cp = parts.getAttributeValue(-1, "cp");
- if (cp == null || cp.isEmpty()) {
- return null;
- }
- Set examples = new LinkedHashSet<>();
- int first = cp.codePointAt(0);
- switch (first) {
- case 0x1F46A: // πͺ U+1F46A FAMILY
- examples.add(formatGroup(value, "π¨βπ©βπ§βπ¦", "π¨", "π©", "π§", "π¦"));
- examples.add(formatGroup(value, "π©βπ©βπ¦", "π©", "π©", "π¦"));
- break;
- case 0x1F48F: // π U+1F48F KISS π©π¨
- examples.add(formatGroup(value, "π©ββ€οΈβπβπ¨", "π©", "π¨"));
- examples.add(formatGroup(value, "π©ββ€οΈβπβπ©", "π©", "π©"));
- break;
- case 0x1F491: // π U+1F491 COUPLE WITH HEART
- examples.add(formatGroup(value, "π©ββ€οΈβπ¨", "π©", "π¨"));
- examples.add(formatGroup(value, "π©ββ€οΈβπ©", "π©", "π©"));
- break;
- default:
- boolean isSkin = EmojiConstants.MODIFIERS.contains(first);
- if (isSkin || EmojiConstants.HAIR.contains(first)) {
- String value2 = backgroundStartSymbol + value + backgroundEndSymbol;
- CLDRFile cfile = getCldrFile();
- String skin = "π½";
- String hair = "π¦°";
- String skinName = getEmojiName(cfile, skin);
- String hairName = getEmojiName(cfile, hair);
- if (hairName == null) {
- hair = "[missing]";
- }
- SimpleFormatter initialPattern =
- SimpleFormatter.compile(
- cfile.getStringValue(
- "//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]"));
- SimpleFormatter listPattern =
- SimpleFormatter.compile(
- cfile.getStringValue(
- "//ldml/listPatterns/listPattern[@type=\"unit-short\"]/listPatternPart[@type=\"2\"]"));
-
- hair = EmojiConstants.JOINER_STRING + hair;
- formatPeople(
- cfile,
- first,
- isSkin,
- value2,
- "π©",
- skin,
- skinName,
- hair,
- hairName,
- initialPattern,
- listPattern,
- examples);
- formatPeople(
- cfile,
- first,
- isSkin,
- value2,
- "π¨",
- skin,
- skinName,
- hair,
- hairName,
- initialPattern,
- listPattern,
- examples);
- }
- break;
- }
- return formatExampleList(examples);
- }
-
- private String getEmojiName(CLDRFile cfile, String skin) {
- return cfile.getStringValue(
- "//ldml/annotations/annotation[@cp=\"" + skin + "\"][@type=\"tts\"]");
- }
-
- // ldml/listPatterns/listPattern[@type="standard-short"]/listPatternPart[@type="2"]
- private String formatGroup(String value, String sourceEmoji, String... components) {
- CLDRFile cfile = getCldrFile();
- SimpleFormatter initialPattern =
- SimpleFormatter.compile(
- cfile.getStringValue(
- "//ldml/characterLabels/characterLabelPattern[@type=\"category-list\"]"));
- String value2 = backgroundEndSymbol + value + backgroundStartSymbol;
- String[] names = new String[components.length];
- int i = 0;
- for (String component : components) {
- names[i++] = getEmojiName(cfile, component);
- }
- return backgroundStartSymbol
- + sourceEmoji
- + " β "
- + initialPattern.format(
- value2,
- longListPatternExample(
- EmojiConstants.COMPOSED_NAME_LIST.getPath(), "n/a", "n/a2", names));
- }
-
- private void formatPeople(
- CLDRFile cfile,
- int first,
- boolean isSkin,
- String value2,
- String person,
- String skin,
- String skinName,
- String hair,
- String hairName,
- SimpleFormatter initialPattern,
- SimpleFormatter listPattern,
- Collection examples) {
- String cp;
- String personName = getEmojiName(cfile, person);
- StringBuilder emoji = new StringBuilder(person).appendCodePoint(first);
- cp = UTF16.valueOf(first);
- cp = isSkin ? cp : EmojiConstants.JOINER_STRING + cp;
- examples.add(
- person + cp + " β " + invertBackground(initialPattern.format(personName, value2)));
- emoji.setLength(0);
- emoji.append(personName);
- if (isSkin) {
- skinName = value2;
- skin = cp;
- } else {
- hairName = value2;
- hair = cp;
- }
- examples.add(
- person
- + skin
- + hair
- + " β "
- + invertBackground(
- listPattern.format(
- initialPattern.format(personName, skinName), hairName)));
- }
-
- private String handleDayPeriod(XPathParts parts, String value) {
- // ldml/dates/calendars/calendar[@type="gregorian"]/dayPeriods/dayPeriodContext[@type="format"]/dayPeriodWidth[@type="wide"]/dayPeriod[@type="morning1"]
- // ldml/dates/calendars/calendar[@type="gregorian"]/dayPeriods/dayPeriodContext[@type="stand-alone"]/dayPeriodWidth[@type="wide"]/dayPeriod[@type="morning1"]
- List examples = new ArrayList<>();
- final String dayPeriodType = parts.getAttributeValue(5, "type");
- if (dayPeriodType == null) {
- return null; // formerly happened for some "/alias" paths
- }
- org.unicode.cldr.util.DayPeriodInfo.Type aType =
- dayPeriodType.equals("format")
- ? DayPeriodInfo.Type.format
- : DayPeriodInfo.Type.selection;
- DayPeriodInfo dayPeriodInfo =
- supplementalDataInfo.getDayPeriods(aType, cldrFile.getLocaleID());
- String periodString = parts.getAttributeValue(-1, "type");
- if (periodString == null) {
- return null; // formerly happened for some "/alias" paths
- }
- DayPeriod dayPeriod = DayPeriod.valueOf(periodString);
- String periods = dayPeriodInfo.toString(dayPeriod);
- examples.add(periods);
- if ("format".equals(dayPeriodType)) {
- if (value == null) {
- value = "οΏ½";
- }
- R3 info = dayPeriodInfo.getFirstDayPeriodInfo(dayPeriod);
- if (info != null) {
- int time = (((info.get0() + info.get1()) % DayPeriodInfo.DAY_LIMIT) / 2);
- String timeFormatString =
- icuServiceBuilder.formatDayPeriod(
- time, backgroundStartSymbol + value + backgroundEndSymbol);
- examples.add(invertBackground(timeFormatString));
- }
- }
- return formatExampleList(examples.toArray(new String[0]));
- }
-
- private String handleDateSymbol(XPathParts parts, String value) {
- // Currently only called for month names, can expand in the future to handle other symbols.
- // The idea is to show format months in a yMMMM?d date format, and stand-alone months in a
- // yMMMM? format.
- String length = parts.findAttributeValue("monthWidth", "type"); // wide, abbreviated, narrow
- if (length.equals("narrow")) {
- return null; // no examples for narrow
- }
- String context = parts.findAttributeValue("monthContext", "type"); // format, stand-alone
- String calendarId =
- parts.findAttributeValue("calendar", "type"); // gregorian, islamic, hebrew, ...
- String monthNumId =
- parts.findAttributeValue("month", "type"); // 1-based: 1, 2, 3, ... 12 or 13
-
- final String[] skeletons = {"yMMMMd", "yMMMd", "yMMMM", "yMMM"};
- int skeletonIndex = (length.equals("wide")) ? 0 : 1;
- if (!context.equals("format")) {
- skeletonIndex += 2;
- }
- String checkPath =
- "//ldml/dates/calendars/calendar[@type=\""
- + calendarId
- + "\"]/dateTimeFormats/availableFormats/dateFormatItem[@id=\""
- + skeletons[skeletonIndex]
- + "\"]";
- String dateFormat = cldrFile.getWinningValue(checkPath);
- if (dateFormat == null || dateFormat.indexOf("MMM") < 0) {
- // If we do not have the desired width (might be missing for MMMM) or
- // the desired format does not have alpha months (in some locales liks 'cs'
- // skeletons for MMM have pattern with M), then try the other width for same
- // context by adjusting skeletonIndex.
- skeletonIndex = (length.equals("wide")) ? skeletonIndex + 1 : skeletonIndex - 1;
- checkPath =
- "//ldml/dates/calendars/calendar[@type=\""
- + calendarId
- + "\"]/dateTimeFormats/availableFormats/dateFormatItem[@id=\""
- + skeletons[skeletonIndex]
- + "\"]";
- dateFormat = cldrFile.getWinningValue(checkPath);
- }
- if (dateFormat == null) {
- return null;
- }
- SimpleDateFormat sdf = icuServiceBuilder.getDateFormat(calendarId, dateFormat);
- sdf.setTimeZone(ZONE_SAMPLE);
- DateFormatSymbols dfs = sdf.getDateFormatSymbols();
- // We do not know whether dateFormat is using MMMM, MMM, LLLL or LLL so
- // override all of them in our DateFormatSymbols. The DATE_SAMPLE is for
- // month 9 "September", offset of 8 in the months arrays, so override that.
- String[] monthNames = dfs.getMonths(DateFormatSymbols.FORMAT, DateFormatSymbols.WIDE);
- monthNames[8] = value;
- dfs.setMonths(monthNames, DateFormatSymbols.FORMAT, DateFormatSymbols.WIDE);
- monthNames = dfs.getMonths(DateFormatSymbols.FORMAT, DateFormatSymbols.ABBREVIATED);
- monthNames[8] = value;
- dfs.setMonths(monthNames, DateFormatSymbols.FORMAT, DateFormatSymbols.ABBREVIATED);
- monthNames = dfs.getMonths(DateFormatSymbols.STANDALONE, DateFormatSymbols.WIDE);
- monthNames[8] = value;
- dfs.setMonths(monthNames, DateFormatSymbols.STANDALONE, DateFormatSymbols.WIDE);
- monthNames = dfs.getMonths(DateFormatSymbols.STANDALONE, DateFormatSymbols.ABBREVIATED);
- monthNames[8] = value;
- dfs.setMonths(monthNames, DateFormatSymbols.STANDALONE, DateFormatSymbols.ABBREVIATED);
- sdf.setDateFormatSymbols(dfs);
- return sdf.format(DATE_SAMPLE);
- }
-
- private String handleMinimalPairs(XPathParts parts, String minimalPattern) {
- List examples = new ArrayList<>();
-
- Output output = new Output<>();
- String count;
- String otherCount;
- String sample;
- String sampleBad;
- String locale = getCldrFile().getLocaleID();
-
- switch (parts.getElement(-1)) {
- case "ordinalMinimalPairs": // ldml/numbers/minimalPairs/ordinalMinimalPairs[@count="one"]
- count = parts.getAttributeValue(-1, "ordinal");
- sample =
- bestMinimalPairSamples.getPluralOrOrdinalSample(
- PluralType.ordinal,
- count); // Pick a unit that exhibits the most variation
- otherCount = getOtherCount(locale, PluralType.ordinal, count);
- sampleBad =
- bestMinimalPairSamples.getPluralOrOrdinalSample(
- PluralType.ordinal,
- otherCount); // Pick a unit that exhibits the most variation
- break;
-
- case "pluralMinimalPairs": // ldml/numbers/minimalPairs/pluralMinimalPairs[@count="one"]
- count = parts.getAttributeValue(-1, "count");
- sample =
- bestMinimalPairSamples.getPluralOrOrdinalSample(
- PluralType.cardinal,
- count); // Pick a unit that exhibits the most variation
- otherCount = getOtherCount(locale, PluralType.cardinal, count);
- sampleBad =
- bestMinimalPairSamples.getPluralOrOrdinalSample(
- PluralType.cardinal,
- otherCount); // Pick a unit that exhibits the most variation
- break;
-
- case "caseMinimalPairs": // ldml/numbers/minimalPairs/caseMinimalPairs[@case="accusative"]
- String gCase = parts.getAttributeValue(-1, "case");
- sample =
- bestMinimalPairSamples.getBestUnitWithCase(
- gCase, output); // Pick a unit that exhibits the most variation
- sampleBad = getOtherCase(sample);
- break;
-
- case "genderMinimalPairs": // ldml/numbers/minimalPairs/genderMinimalPairs[@gender="feminine"]
- String gender = parts.getAttributeValue(-1, "gender");
- sample = bestMinimalPairSamples.getBestUnitWithGender(gender, output);
- String otherGender = getOtherGender(gender);
- sampleBad = bestMinimalPairSamples.getBestUnitWithGender(otherGender, output);
- break;
- default:
- return null;
- }
- String formattedUnit =
- format(minimalPattern, backgroundStartSymbol + sample + backgroundEndSymbol);
- examples.add(formattedUnit);
- if (sampleBad == null) {
- sampleBad = "n/a";
- }
- formattedUnit =
- format(minimalPattern, backgroundStartSymbol + sampleBad + backgroundEndSymbol);
- examples.add(EXAMPLE_OF_INCORRECT + formattedUnit);
- return formatExampleList(examples);
- }
-
- private String getOtherGender(String gender) {
- if (gender == null || grammarInfo == null) {
- return null;
- }
- Collection unitGenders =
- grammarInfo.get(
- GrammaticalTarget.nominal,
- GrammaticalFeature.grammaticalGender,
- GrammaticalScope.units);
- for (String otherGender : unitGenders) {
- if (!gender.equals(otherGender)) {
- return otherGender;
- }
- }
- return null;
- }
-
- private String getOtherCase(String sample) {
- if (sample == null) {
- return null;
- }
- Collection unitCases =
- grammarInfo.get(
- GrammaticalTarget.nominal,
- GrammaticalFeature.grammaticalCase,
- GrammaticalScope.units);
- Output output = new Output<>();
- for (String otherCase : unitCases) {
- String sampleBad =
- bestMinimalPairSamples.getBestUnitWithCase(
- otherCase, output); // Pick a unit that exhibits the most variation
- if (!sample.equals(sampleBad)) { // caution: sampleBad may be null
- return sampleBad;
- }
- }
- return null;
- }
-
- private static String getOtherCount(String locale, PluralType ordinal, String count) {
- String otherCount = null;
- if (!Objects.equals(count, "other")) {
- otherCount = "other";
- } else {
- PluralInfo rules = SupplementalDataInfo.getInstance().getPlurals(ordinal, locale);
- Set counts = rules.getAdjustedCountStrings();
- for (String tryCount : counts) {
- if (!tryCount.equals("other")) {
- otherCount = tryCount;
- break;
- }
- }
- }
- return otherCount;
- }
-
- private UnitLength getUnitLength(XPathParts parts) {
- return UnitLength.valueOf(parts.getAttributeValue(-3, "type").toUpperCase(Locale.ENGLISH));
- }
-
- private String handleFormatUnit(XPathParts parts, String unitPattern) {
- // Sample:
- // //ldml/units/unitLength[@type="long"]/unit[@type="duration-day"]/unitPattern[@count="one"][@case="accusative"]
-
- String longUnitId = parts.getAttributeValue(-2, "type");
- final String shortUnitId = UNIT_CONVERTER.getShortId(longUnitId);
- if (UnitConverter.HACK_SKIP_UNIT_NAMES.contains(shortUnitId)) {
- return null;
- }
-
- List examples = new ArrayList<>();
- if (parts.getElement(-1).equals("unitPattern")) {
- String count = parts.getAttributeValue(-1, "count");
- DecimalQuantity amount = getBest(Count.valueOf(count));
- if (amount != null) {
- addFormattedUnits(examples, parts, unitPattern, shortUnitId, amount);
- }
- }
- // add related units
- Map relatedUnits =
- UNIT_CONVERTER.getRelatedExamples(
- shortUnitId, UnitConverter.getExampleUnitSystems(cldrFile.getLocaleID()));
- String unitSystem = null;
- boolean first = true;
- for (Entry relatedUnitInfo : relatedUnits.entrySet()) {
- if (unitSystem == null) {
- Set systems = UNIT_CONVERTER.getSystemsEnum(shortUnitId);
- unitSystem = UnitSystem.getSystemsDisplay(systems);
- }
- Rational relatedValue = relatedUnitInfo.getKey();
- String relatedUnit = relatedUnitInfo.getValue();
- Set systems = UNIT_CONVERTER.getSystemsEnum(relatedUnit);
- String relation = "β‘";
- String relatedValueDisplay = relatedValue.toString(FormatStyle.approx);
- if (relatedValueDisplay.startsWith("~")) {
- relation = "β";
- relatedValueDisplay = relatedValueDisplay.substring(1);
- }
- if (first) {
- if (!examples.isEmpty()) {
- examples.add(""); // add blank line
- }
- first = false;
- }
- examples.add(
- String.format(
- "1 %s%s %s %s %s%s",
- shortUnitId,
- unitSystem,
- relation,
- relatedValueDisplay,
- relatedUnit,
- UnitSystem.getSystemsDisplay(systems)));
- }
- return formatExampleList(examples);
- }
-
- /**
- * Handles paths like:
- * //ldml/units/unitLength[@type="long"]/unit[@type="volume-fluid-ounce-imperial"]/unitPattern[@count="other"]
- */
- public void addFormattedUnits(
- List examples,
- XPathParts parts,
- String unitPattern,
- final String shortUnitId,
- DecimalQuantity amount) {
- /*
- * PluralRules.FixedDecimal is deprecated, but deprecated in ICU is
- * also used to mark internal methods (which are OK for us to use in CLDR).
- */
- DecimalFormat numberFormat;
- String formattedAmount;
- numberFormat = icuServiceBuilder.getNumberFormat(1);
- formattedAmount = numberFormat.format(amount.toBigDecimal());
- examples.add(
- format(unitPattern, backgroundStartSymbol + formattedAmount + backgroundEndSymbol));
-
- if (parts.getElement(-2).equals("unit")) {
- if (unitPattern != null) {
- String gCase = parts.getAttributeValue(-1, "case");
- if (gCase == null) {
- gCase = GrammaticalFeature.grammaticalCase.getDefault(null);
- }
- Collection unitCaseInfo = null;
- if (grammarInfo != null) {
- unitCaseInfo =
- grammarInfo.get(
- GrammaticalTarget.nominal,
- GrammaticalFeature.grammaticalCase,
- GrammaticalScope.units);
- }
- String minimalPattern =
- cldrFile.getStringValue(
- "//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\""
- + gCase
- + "\"]");
- if (minimalPattern != null) {
- String composed =
- format(
- unitPattern,
- backgroundStartSymbol + formattedAmount + backgroundEndSymbol);
- examples.add(
- backgroundStartSymbol
- + format(
- minimalPattern,
- backgroundEndSymbol + composed + backgroundStartSymbol)
- + backgroundEndSymbol);
- // get contrasting case
- if (unitCaseInfo != null && !unitCaseInfo.isEmpty()) {
- String constrastingCase =
- getConstrastingCase(unitPattern, gCase, unitCaseInfo, parts);
- if (constrastingCase != null) {
- minimalPattern =
- cldrFile.getStringValue(
- "//ldml/numbers/minimalPairs/caseMinimalPairs[@case=\""
- + constrastingCase
- + "\"]");
- composed =
- format(
- unitPattern,
- backgroundStartSymbol
- + formattedAmount
- + backgroundEndSymbol);
- examples.add(
- EXAMPLE_OF_INCORRECT
- + backgroundStartSymbol
- + format(
- minimalPattern,
- backgroundEndSymbol
- + composed
- + backgroundStartSymbol)
- + backgroundEndSymbol);
- }
- } else {
- examples.add(EXAMPLE_OF_CAUTION + "οΈNo Case Minimal Pair available yetοΈ");
- }
- }
- }
- }
- }
-
- private String getConstrastingCase(
- String unitPattern, String gCase, Collection unitCaseInfo, XPathParts parts) {
- for (String otherCase : unitCaseInfo) {
- if (otherCase.equals(gCase)) {
- continue;
- }
- parts.putAttributeValue(-1, "case", "nominative".equals(otherCase) ? null : otherCase);
- String otherValue = cldrFile.getStringValue(parts.toString());
- if (otherValue != null && !otherValue.equals(unitPattern)) {
- return otherCase;
- }
- }
- return null;
- }
-
- private String handleFormatPerUnit(String value) {
- DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(1);
- return format(value, backgroundStartSymbol + numberFormat.format(1) + backgroundEndSymbol);
- }
-
- public String handleCompoundUnit(XPathParts parts) {
- UnitLength unitLength = getUnitLength(parts);
- String compoundType = parts.getAttributeValue(-2, "type");
- Count count =
- Count.valueOf(CldrUtility.ifNull(parts.getAttributeValue(-1, "count"), "other"));
- return handleCompoundUnit(unitLength, compoundType, count);
- }
-
- @SuppressWarnings("deprecation")
- public String handleCompoundUnit(UnitLength unitLength, String compoundType, Count count) {
- /*
- *
-
-
-
-
-
- {0}/{1}
-
-
- *
- {0}/{1}
- {0}/{1}
-
-
- {0} meter
- {0} meters
-
-
- */
-
- // we want to get a number that works for the count passed in.
- DecimalQuantity amount = getBest(count);
- if (amount == null) {
- return "n/a";
- }
- DecimalQuantity oneValue = DecimalQuantity_DualStorageBCD.fromExponentString("1");
-
- String unit1mid;
- String unit2mid;
- switch (compoundType) {
- default:
- return "n/a";
- case "per":
- unit1mid = getFormattedUnit("length-meter", unitLength, amount);
- unit2mid = getFormattedUnit("duration-second", unitLength, oneValue, "");
- break;
- case "times":
- unit1mid =
- getFormattedUnit(
- "force-newton",
- unitLength,
- oneValue,
- icuServiceBuilder.getNumberFormat(1).format(amount.toBigDecimal()));
- unit2mid = getFormattedUnit("length-meter", unitLength, amount, "");
- break;
- }
- String unit1 = backgroundStartSymbol + unit1mid.trim() + backgroundEndSymbol;
- String unit2 = backgroundStartSymbol + unit2mid.trim() + backgroundEndSymbol;
-
- String form = this.pluralInfo.getPluralRules().select(amount);
- // we rebuild a path, because we may have changed it.
- String perPath = makeCompoundUnitPath(unitLength, compoundType, "compoundUnitPattern");
- return format(getValueFromFormat(perPath, form), unit1, unit2);
- }
-
- public String handleCompoundUnit1(XPathParts parts, String compoundPattern) {
- UnitLength unitLength = getUnitLength(parts);
- String pathCount = parts.getAttributeValue(-1, "count");
- if (pathCount == null) {
- return handleCompoundUnit1Name(unitLength, compoundPattern);
- } else {
- return handleCompoundUnit1(unitLength, Count.valueOf(pathCount), compoundPattern);
- }
- }
-
- private String handleCompoundUnit1Name(UnitLength unitLength, String compoundPattern) {
- String pathFormat =
- "//ldml/units/unitLength"
- + unitLength.typeString
- + "/unit[@type=\"{0}\"]/displayName";
-
- String meterFormat = getValueFromFormat(pathFormat, "length-meter");
-
- String modFormat =
- combinePrefix(meterFormat, compoundPattern, unitLength == UnitLength.LONG);
-
- return removeEmptyRuns(modFormat);
- }
-
- public String handleCompoundUnit1(UnitLength unitLength, Count count, String compoundPattern) {
-
- // we want to get a number that works for the count passed in.
- DecimalQuantity amount = getBest(count);
- if (amount == null) {
- return "n/a";
- }
- DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(1);
-
- @SuppressWarnings("deprecation")
- String form1 = this.pluralInfo.getPluralRules().select(amount);
-
- String pathFormat =
- "//ldml/units/unitLength"
- + unitLength.typeString
- + "/unit[@type=\"{0}\"]/unitPattern[@count=\"{1}\"]";
-
- // now pick up the meter pattern
-
- String meterFormat = getValueFromFormat(pathFormat, "length-meter", form1);
-
- // now combine them
-
- String modFormat =
- combinePrefix(meterFormat, compoundPattern, unitLength == UnitLength.LONG);
-
- return removeEmptyRuns(format(modFormat, numberFormat.format(amount.toBigDecimal())));
- }
-
- // TODO, pass in unitLength instead of last parameter, and do work in Units.combinePattern.
-
- public String combinePrefix(
- String unitFormat, String inCompoundPattern, boolean lowercaseUnitIfNoSpaceInCompound) {
- // mark the part except for the {0} as foreground
- String compoundPattern =
- backgroundEndSymbol
- + inCompoundPattern.replace(
- "{0}", backgroundStartSymbol + "{0}" + backgroundEndSymbol)
- + backgroundStartSymbol;
-
- String modFormat =
- Units.combinePattern(unitFormat, compoundPattern, lowercaseUnitIfNoSpaceInCompound);
-
- return backgroundStartSymbol + modFormat + backgroundEndSymbol;
- }
-
- // ldml/units/unitLength[@type="long"]/compoundUnit[@type="per"]/compoundUnitPattern
- public String makeCompoundUnitPath(
- UnitLength unitLength, String compoundType, String patternType) {
- return "//ldml/units/unitLength"
- + unitLength.typeString
- + "/compoundUnit[@type=\""
- + compoundType
- + "\"]"
- + "/"
- + patternType;
- }
-
- @SuppressWarnings("deprecation")
- private DecimalQuantity getBest(Count count) {
- DecimalQuantitySamples samples =
- pluralInfo.getPluralRules().getDecimalSamples(count.name(), SampleType.DECIMAL);
- if (samples == null) {
- samples =
- pluralInfo.getPluralRules().getDecimalSamples(count.name(), SampleType.INTEGER);
- }
- if (samples == null) {
- return null;
- }
- Set samples2 = samples.getSamples();
- DecimalQuantitySamplesRange range = samples2.iterator().next();
- return range.end;
- }
-
- private String handleMiscPatterns(XPathParts parts, String value) {
- DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(0);
- String start = backgroundStartSymbol + numberFormat.format(99) + backgroundEndSymbol;
- if ("range".equals(parts.getAttributeValue(-1, "type"))) {
- String end = backgroundStartSymbol + numberFormat.format(144) + backgroundEndSymbol;
- return format(value, start, end);
- } else {
- return format(value, start);
- }
- }
-
- private String handleIntervalFormats(XPathParts parts, String value) {
- if (!parts.getAttributeValue(3, "type").equals("gregorian")) {
- return null;
- }
- if (parts.getElement(6).equals("intervalFormatFallback")) {
- SimpleDateFormat dateFormat = new SimpleDateFormat();
- String fallbackFormat = invertBackground(setBackground(value));
- return format(
- fallbackFormat,
- dateFormat.format(FIRST_INTERVAL),
- dateFormat.format(SECOND_INTERVAL.get("y")));
- }
- String greatestDifference = parts.getAttributeValue(-1, "id");
- /*
- * Choose an example interval suitable for the symbol. If testing years, use an interval
- * of more than one year, and so forth. For the purpose of choosing the interval,
- * "H" is equivalent to "h", and so forth; map to a symbol that occurs in SECOND_INTERVAL.
- */
- if (greatestDifference.equals("H")) { // Hour [0-23]
- greatestDifference = "h"; // Hour [1-12]
- } else if (greatestDifference.equals("B") // flexible day periods
- || greatestDifference.equals("b")) { // am, pm, noon, midnight
- greatestDifference = "a"; // AM, PM
- }
- // intervalFormatFallback
- // //ldml/dates/calendars/calendar[@type="gregorian"]/dateTimeFormats/intervalFormats/intervalFormatItem[@id="yMd"]/greatestDifference[@id="y"]
- // find where to split the value
- intervalFormat.setPattern(parts, value);
- Date later = SECOND_INTERVAL.get(greatestDifference);
- if (later == null) {
- /*
- * This may still happen for some less-frequently used symbols such as "Q" (Quarter),
- * if they ever occur in the data.
- * Reference: https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
- * For now, such paths do not get examples.
- */
- return null;
- }
- return intervalFormat.format(FIRST_INTERVAL, later);
- }
-
- private String handleDelimiters(XPathParts parts, String xpath, String value) {
- String lastElement = parts.getElement(-1);
- final String[] elements = {
- "quotationStart", "alternateQuotationStart",
- "alternateQuotationEnd", "quotationEnd"
- };
- String[] quotes = new String[4];
- String baseXpath = xpath.substring(0, xpath.lastIndexOf('/'));
- for (int i = 0; i < quotes.length; i++) {
- String currElement = elements[i];
- if (lastElement.equals(currElement)) {
- quotes[i] = backgroundStartSymbol + value + backgroundEndSymbol;
- } else {
- quotes[i] = cldrFile.getWinningValue(baseXpath + '/' + currElement);
- }
- }
- String example =
- cldrFile.getStringValue(
- "//ldml/localeDisplayNames/types/type[@key=\"calendar\"][@type=\"gregorian\"]");
- // NOTE: the example provided here is partially in English because we don't
- // have a translated conversational example in CLDR.
- return invertBackground(
- format("{0}They said {1}" + example + "{2}.{3}", (Object[]) quotes));
- }
-
- private String handleListPatterns(XPathParts parts, String value) {
- // listPatternType is either "duration" or null/other list
- String listPatternType = parts.getAttributeValue(-2, "type");
- if (listPatternType == null || !listPatternType.contains("unit")) {
- return handleRegularListPatterns(parts, value, ListTypeLength.from(listPatternType));
- } else {
- return handleDurationListPatterns(parts, value, UnitLength.from(listPatternType));
- }
- }
-
- private String handleRegularListPatterns(
- XPathParts parts, String value, ListTypeLength listTypeLength) {
- String patternType = parts.getAttributeValue(-1, "type");
- if (patternType == null) {
- return null; // formerly happened for some "/alias" paths
- }
- String pathFormat = "//ldml/localeDisplayNames/territories/territory[@type=\"{0}\"]";
- String territory1 = getValueFromFormat(pathFormat, "CH");
- String territory2 = getValueFromFormat(pathFormat, "JP");
- if (patternType.equals("2")) {
- return invertBackground(format(setBackground(value), territory1, territory2));
- }
- String territory3 = getValueFromFormat(pathFormat, "EG");
- String territory4 = getValueFromFormat(pathFormat, "CA");
- return longListPatternExample(
- listTypeLength.getPath(),
- patternType,
- value,
- territory1,
- territory2,
- territory3,
- territory4);
- }
-
- private String handleDurationListPatterns(
- XPathParts parts, String value, UnitLength unitWidth) {
- String patternType = parts.getAttributeValue(-1, "type");
- if (patternType == null) {
- return null; // formerly happened for some "/alias" paths
- }
- String duration1 = getFormattedUnit("duration-day", unitWidth, 4);
- String duration2 = getFormattedUnit("duration-hour", unitWidth, 2);
- if (patternType.equals("2")) {
- return invertBackground(format(setBackground(value), duration1, duration2));
- }
- String duration3 = getFormattedUnit("duration-minute", unitWidth, 37);
- String duration4 = getFormattedUnit("duration-second", unitWidth, 23);
- return longListPatternExample(
- unitWidth.listTypeLength.getPath(),
- patternType,
- value,
- duration1,
- duration2,
- duration3,
- duration4);
- }
-
- public enum UnitLength {
- LONG(ListTypeLength.UNIT_WIDE),
- SHORT(ListTypeLength.UNIT_SHORT),
- NARROW(ListTypeLength.UNIT_NARROW);
- final String typeString;
- final ListTypeLength listTypeLength;
-
- UnitLength(ListTypeLength listTypeLength) {
- typeString = "[@type=\"" + name().toLowerCase(Locale.ENGLISH) + "\"]";
- this.listTypeLength = listTypeLength;
- }
-
- public static UnitLength from(String listPatternType) {
- switch (listPatternType) {
- case "unit":
- return UnitLength.LONG;
- case "unit-narrow":
- return UnitLength.NARROW;
- case "unit-short":
- return UnitLength.SHORT;
- default:
- throw new IllegalArgumentException();
- }
- }
- }
-
- private String getFormattedUnit(
- String unitType, UnitLength unitWidth, DecimalQuantity unitAmount) {
- DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(1);
- return getFormattedUnit(
- unitType, unitWidth, unitAmount, numberFormat.format(unitAmount.toBigDecimal()));
- }
-
- private String getFormattedUnit(String unitType, UnitLength unitWidth, double unitAmount) {
- return getFormattedUnit(
- unitType, unitWidth, new DecimalQuantity_DualStorageBCD(unitAmount));
- }
-
- @SuppressWarnings("deprecation")
- private String getFormattedUnit(
- String unitType,
- UnitLength unitWidth,
- DecimalQuantity unitAmount,
- String formattedUnitAmount) {
- String form = this.pluralInfo.getPluralRules().select(unitAmount);
- String pathFormat =
- "//ldml/units/unitLength"
- + unitWidth.typeString
- + "/unit[@type=\"{0}\"]/unitPattern[@count=\"{1}\"]";
- return format(getValueFromFormat(pathFormat, unitType, form), formattedUnitAmount);
- }
-
- // ldml/listPatterns/listPattern/listPatternPart[@type="2"] β And
- // ldml/listPatterns/listPattern[@type="standard-short"]/listPatternPart[@type="2"] Short And
- // ldml/listPatterns/listPattern[@type="or"]/listPatternPart[@type="2"] or list
- // ldml/listPatterns/listPattern[@type="unit"]/listPatternPart[@type="2"]
- // ldml/listPatterns/listPattern[@type="unit-short"]/listPatternPart[@type="2"]
- // ldml/listPatterns/listPattern[@type="unit-narrow"]/listPatternPart[@type="2"]
-
- private String longListPatternExample(
- String listPathFormat, String patternType, String value, String... items) {
- String doublePattern = getPattern(listPathFormat, "2", patternType, value);
- String startPattern = getPattern(listPathFormat, "start", patternType, value);
- String middlePattern = getPattern(listPathFormat, "middle", patternType, value);
- String endPattern = getPattern(listPathFormat, "end", patternType, value);
- /*
- * DateTimePatternGenerator.FormatParser is deprecated, but deprecated in ICU is
- * also used to mark internal methods (which are OK for us to use in CLDR).
- */
- @SuppressWarnings("deprecation")
- ListFormatter listFormatter =
- new ListFormatter(doublePattern, startPattern, middlePattern, endPattern);
- String example = listFormatter.format((Object[]) items);
- return invertBackground(example);
- }
-
- /**
- * Helper method for handleListPatterns. Returns the pattern to be used for a specified pattern
- * type.
- *
- * @param pathFormat
- * @param pathPatternType
- * @param valuePatternType
- * @param value
- * @return
- */
- private String getPattern(
- String pathFormat, String pathPatternType, String valuePatternType, String value) {
- return valuePatternType.equals(pathPatternType)
- ? setBackground(value)
- : getValueFromFormat(pathFormat, pathPatternType);
- }
-
- private String getValueFromFormat(String format, Object... arguments) {
- return cldrFile.getWinningValue(format(format, arguments));
- }
-
- public String handleEllipsis(String type, String value) {
- String pathFormat = "//ldml/localeDisplayNames/territories/territory[@type=\"{0}\"]";
- // {0} β¦
- // β¦ {0}
- // {0} β¦ {1}
- String territory1 = getValueFromFormat(pathFormat, "CH");
- String territory2 = getValueFromFormat(pathFormat, "JP");
- // if it isn't a word, break in the middle
- if (!type.contains("word")) {
- territory1 = clip(territory1, 0, 1);
- territory2 = clip(territory2, 1, 0);
- }
- if (type.contains("initial")) {
- territory1 = territory2;
- }
- return invertBackground(format(setBackground(value), territory1, territory2));
- }
-
- public static String clip(String text, int clipStart, int clipEnd) {
- BreakIterator bi = BreakIterator.getCharacterInstance();
- bi.setText(text);
- for (int i = 0; i < clipStart; ++i) {
- bi.next();
- }
- int start = bi.current();
- bi.last();
- for (int i = 0; i < clipEnd; ++i) {
- bi.previous();
- }
- int end = bi.current();
- return start >= end ? text : text.substring(start, end);
- }
-
- /**
- * Handle miscellaneous calendar patterns.
- *
- * @param parts
- * @param value
- * @return
- */
- private String handleMonthPatterns(XPathParts parts, String value) {
- String calendar = parts.getAttributeValue(3, "type");
- String context = parts.getAttributeValue(5, "type");
- String month = "8";
- if (!context.equals("numeric")) {
- String width = parts.getAttributeValue(6, "type");
- String xpath =
- "//ldml/dates/calendars/calendar[@type=\"{0}\"]/months/monthContext[@type=\"{1}\"]/monthWidth[@type=\"{2}\"]/month[@type=\"8\"]";
- month = getValueFromFormat(xpath, calendar, context, width);
- }
- return invertBackground(format(setBackground(value), month));
- }
-
- private String handleAppendItems(XPathParts parts, String value) {
- String request = parts.getAttributeValue(-1, "request");
- if (!"Timezone".equals(request)) {
- return null;
- }
- String calendar = parts.getAttributeValue(3, "type");
-
- SimpleDateFormat sdf =
- icuServiceBuilder.getDateFormat(calendar, 0, DateFormat.MEDIUM, null);
- String zone = cldrFile.getStringValue("//ldml/dates/timeZoneNames/gmtZeroFormat");
- return format(value, setBackground(sdf.format(DATE_SAMPLE)), setBackground(zone));
- }
-
- private class IntervalFormat {
- @SuppressWarnings("deprecation")
- DateTimePatternGenerator.FormatParser formatParser =
- new DateTimePatternGenerator.FormatParser();
-
- SimpleDateFormat firstFormat = new SimpleDateFormat();
- SimpleDateFormat secondFormat = new SimpleDateFormat();
- StringBuilder first = new StringBuilder();
- StringBuilder second = new StringBuilder();
- BitSet letters = new BitSet();
-
- public String format(Date earlier, Date later) {
- if (earlier == null || later == null) {
- return null;
- }
- if (later.compareTo(earlier) < 0) {
- /*
- * Swap so earlier is earlier than later.
- * This is necessary for "G" (Era) given the current FIRST_INTERVAL, SECOND_INTERVAL
- */
- Date tmp = earlier;
- earlier = later;
- later = tmp;
- }
- return firstFormat.format(earlier) + secondFormat.format(later);
- }
-
- @SuppressWarnings("deprecation")
- public IntervalFormat setPattern(XPathParts parts, String pattern) {
- if (formatParser == null || pattern == null) {
- return this;
- }
- try {
- formatParser.set(pattern);
- } catch (NullPointerException e) {
- /*
- * This has been observed to occur, within ICU, for unknown reasons.
- */
- System.err.println(
- "Caught NullPointerException in IntervalFormat.setPattern, pattern = "
- + pattern);
- e.printStackTrace();
- return null;
- }
- first.setLength(0);
- second.setLength(0);
- boolean doFirst = true;
- letters.clear();
-
- for (Object item : formatParser.getItems()) {
- if (item instanceof DateTimePatternGenerator.VariableField) {
- char c = item.toString().charAt(0);
- if (letters.get(c)) {
- doFirst = false;
- } else {
- letters.set(c);
- }
- if (doFirst) {
- first.append(item);
- } else {
- second.append(item);
- }
- } else {
- if (doFirst) {
- first.append(formatParser.quoteLiteral((String) item));
- } else {
- second.append(formatParser.quoteLiteral((String) item));
- }
- }
- }
- String calendar = parts.findAttributeValue("calendar", "type");
- firstFormat = icuServiceBuilder.getDateFormat(calendar, first.toString());
- firstFormat.setTimeZone(GMT_ZONE_SAMPLE);
-
- secondFormat = icuServiceBuilder.getDateFormat(calendar, second.toString());
- secondFormat.setTimeZone(GMT_ZONE_SAMPLE);
- return this;
- }
- }
-
- private String handleDurationUnit(String value) {
- DateFormat df = this.icuServiceBuilder.getDateFormat("gregorian", value.replace('h', 'H'));
- df.setTimeZone(TimeZone.GMT_ZONE);
- long time = ((5 * 60 + 37) * 60 + 23) * 1000;
- try {
- return df.format(new Date(time));
- } catch (IllegalArgumentException e) {
- // e.g., Illegal pattern character 'o' in "aΙabaΖoΖo m:ss"
- return null;
- }
- }
-
- @SuppressWarnings("deprecation")
- private String formatCountValue(String xpath, XPathParts parts, String value) {
- if (!parts.containsAttribute("count")) { // no examples for items that don't format
- return null;
- }
- final PluralInfo plurals =
- supplementalDataInfo.getPlurals(PluralType.cardinal, cldrFile.getLocaleID());
- PluralRules pluralRules = plurals.getPluralRules();
-
- String unitType = parts.getAttributeValue(-2, "type");
- if (unitType == null) {
- unitType = "USD"; // sample for currency pattern
- }
- final boolean isPattern = parts.contains("unitPattern");
- final boolean isCurrency = !parts.contains("units");
-
- Count count;
- final LinkedHashSet exampleCount = new LinkedHashSet<>(CURRENCY_SAMPLES);
- String countString = parts.getAttributeValue(-1, "count");
- if (countString == null) {
- return null;
- } else {
- try {
- count = Count.valueOf(countString);
- } catch (Exception e) {
- return null; // counts like 0
- }
- }
-
- // we used to just get the samples for the given keyword, but that doesn't work well any
- // more.
- getStartEndSamples(
- pluralRules.getDecimalSamples(countString, SampleType.INTEGER), exampleCount);
- getStartEndSamples(
- pluralRules.getDecimalSamples(countString, SampleType.DECIMAL), exampleCount);
-
- String result = "";
- DecimalFormat currencyFormat = icuServiceBuilder.getCurrencyFormat(unitType);
- int decimalCount = currencyFormat.getMinimumFractionDigits();
-
- // Unless/until DecimalQuantity overrides hashCode() or implements Comparable, we
- // should use a concrete collection type for examplesSeen for which .contains() only
- // relies on DecimalQuantity.equals() . The reason is that the default hashCode()
- // implementation for DecimalQuantity may return false when .equals() returns true.
- Collection examplesSeen = new ArrayList<>();
-
- // we will cycle until we have (at most) two examples.
- int maxCount = 2;
- main:
- // If we are a currency, we will try to see if we can set the decimals to match.
- // but if nothing works, we will just use a plain sample.
- for (int phase = 0; phase < 2; ++phase) {
- for (DecimalQuantity example : exampleCount) {
- // we have to first see whether we have a currency. If so, we have to see if the
- // count works.
-
- if (isCurrency && phase == 0) {
- DecimalQuantity_DualStorageBCD newExample =
- new DecimalQuantity_DualStorageBCD();
- newExample.copyFrom(example);
- newExample.setMinFraction(decimalCount);
- example = newExample;
- }
- // skip if we've done before (can happen because of the currency reset)
- if (examplesSeen.contains(example)) {
- continue;
- }
- examplesSeen.add(example);
- // skip if the count isn't appropriate
- if (!pluralRules.select(example).equals(count.toString())) {
- continue;
- }
-
- if (value == null) {
- String fallbackPath = cldrFile.getCountPathWithFallback(xpath, count, true);
- value = cldrFile.getStringValue(fallbackPath);
- }
- String resultItem;
-
- resultItem = formatCurrency(value, unitType, isPattern, isCurrency, count, example);
- // now add to list
- result = addExampleResult(resultItem, result);
- if (isPattern) {
- String territory = getDefaultTerritory();
- String currency = supplementalDataInfo.getDefaultCurrency(territory);
- if (currency.equals(unitType)) {
- currency = "EUR";
- if (currency.equals(unitType)) {
- currency = "JAY";
- }
- }
- resultItem =
- formatCurrency(value, currency, isPattern, isCurrency, count, example);
- // now add to list
- result = addExampleResult(resultItem, result);
- }
- if (--maxCount < 1) {
- break main;
- }
- }
- }
- return result.isEmpty() ? null : result;
- }
-
- @SuppressWarnings("deprecation")
- public static void getStartEndSamples(
- DecimalQuantitySamples samples, Set target) {
- if (samples != null) {
- for (DecimalQuantitySamplesRange item : samples.getSamples()) {
- target.add(item.start);
- target.add(item.end);
- }
- }
- }
-
- @SuppressWarnings("deprecation")
- private String formatCurrency(
- String value,
- String unitType,
- final boolean isPattern,
- final boolean isCurrency,
- Count count,
- DecimalQuantity example) {
- String resultItem;
- {
- // If we have a pattern, get the unit from the count
- // If we have a unit, get the pattern from the count
- // English is special; both values are retrieved based on the count.
- String unitPattern;
- String unitName;
- if (isPattern) {
- // //ldml/numbers/currencies/currency[@type="USD"]/displayName
- unitName = getUnitName(unitType, isCurrency, count);
- unitPattern = typeIsEnglish ? getUnitPattern(unitType, isCurrency, count) : value;
- } else {
- unitPattern = getUnitPattern(unitType, isCurrency, count);
- unitName = typeIsEnglish ? getUnitName(unitType, isCurrency, count) : value;
- }
-
- if (isPattern) {
- unitPattern = setBackground(unitPattern);
- } else {
- unitPattern = setBackgroundExceptMatch(unitPattern, PARAMETER_SKIP0);
- }
-
- MessageFormat unitPatternFormat = new MessageFormat(unitPattern);
-
- // get the format for the currency
- // TODO fix this for special currency overrides
-
- DecimalFormat unitDecimalFormat = icuServiceBuilder.getNumberFormat(1); // decimal
- unitDecimalFormat.setMaximumFractionDigits((int) example.getPluralOperand(Operand.v));
- unitDecimalFormat.setMinimumFractionDigits((int) example.getPluralOperand(Operand.v));
-
- String formattedNumber = unitDecimalFormat.format(example.toDouble());
- unitPatternFormat.setFormatByArgumentIndex(0, unitDecimalFormat);
- resultItem = unitPattern.replace("{0}", formattedNumber).replace("{1}", unitName);
-
- if (isPattern) {
- resultItem = invertBackground(resultItem);
- }
- }
- return resultItem;
- }
-
- private String addExampleResult(String resultItem, String resultToAddTo) {
- return addExampleResult(resultItem, resultToAddTo, false);
- }
-
- private String addExampleResult(String resultItem, String resultToAddTo, boolean showContexts) {
- if (!showContexts) {
- if (resultToAddTo.length() != 0) {
- resultToAddTo += exampleSeparatorSymbol;
- }
- resultToAddTo += resultItem;
- } else {
- resultToAddTo +=
- exampleStartAutoSymbol
- + resultItem
- + exampleEndSymbol; // example in neutral context
- resultToAddTo +=
- exampleStartRTLSymbol + resultItem + exampleEndSymbol; // example in RTL context
- }
- return resultToAddTo;
- }
-
- private String getUnitPattern(String unitType, final boolean isCurrency, Count count) {
- return cldrFile.getStringValue(
- isCurrency
- ? "//ldml/numbers/currencyFormats/unitPattern" + countAttribute(count)
- : "//ldml/units/unit[@type=\""
- + unitType
- + "\"]/unitPattern"
- + countAttribute(count));
- }
-
- private String getUnitName(String unitType, final boolean isCurrency, Count count) {
- return cldrFile.getStringValue(
- isCurrency
- ? "//ldml/numbers/currencies/currency[@type=\""
- + unitType
- + "\"]/displayName"
- + countAttribute(count)
- : "//ldml/units/unit[@type=\""
- + unitType
- + "\"]/unitPattern"
- + countAttribute(count));
- }
-
- public String countAttribute(Count count) {
- return "[@count=\"" + count + "\"]";
- }
-
- private String handleMinimumGrouping(XPathParts parts, String value) {
- String numberSystem = cldrFile.getWinningValue("//ldml/numbers/defaultNumberingSystem");
- String checkPath =
- "//ldml/numbers/decimalFormats[@numberSystem=\""
- + numberSystem
- + "\"]/decimalFormatLength/decimalFormat[@type=\"standard\"]/pattern[@type=\"standard\"]";
- String decimalFormat = cldrFile.getWinningValue(checkPath);
- DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(decimalFormat, numberSystem);
- numberFormat.setMinimumGroupingDigits(Integer.parseInt(value));
-
- double sampleNum1 = 543.21;
- double sampleNum2 = 6543.21;
- double sampleNum3 = 76543.21;
- String example = "";
- example = addExampleResult(formatNumber(numberFormat, sampleNum1), example);
- example = addExampleResult(formatNumber(numberFormat, sampleNum2), example);
- example = addExampleResult(formatNumber(numberFormat, sampleNum3), example);
- return example;
- }
-
- private String handleNumberSymbol(XPathParts parts, String value) {
- String symbolType = parts.getElement(-1);
- String numberSystem = parts.getAttributeValue(2, "numberSystem"); // null if not present
- int index; // dec/percent/sci
- double numberSample = NUMBER_SAMPLE;
- String originalValue = cldrFile.getWinningValue(parts.toString());
- boolean isSuperscripting = false;
- if (symbolType.equals("decimal") || symbolType.equals("group")) {
- index = 1;
- } else if (symbolType.equals("minusSign")) {
- index = 1;
- numberSample = -numberSample;
- } else if (symbolType.equals("percentSign")) {
- // For the perMille symbol, we reuse the percent example.
- index = 2;
- numberSample = 0.23;
- } else if (symbolType.equals("perMille")) {
- // For the perMille symbol, we reuse the percent example.
- index = 2;
- numberSample = 0.023;
- originalValue =
- cldrFile.getWinningValue(parts.addRelative("../percentSign").toString());
- } else if (symbolType.equals("approximatelySign")) {
- // Substitute the approximately symbol in for the minus sign.
- index = 1;
- numberSample = -numberSample;
- originalValue = cldrFile.getWinningValue(parts.addRelative("../minusSign").toString());
- } else if (symbolType.equals("exponential") || symbolType.equals("plusSign")) {
- index = 3;
- } else if (symbolType.equals("superscriptingExponent")) {
- index = 3;
- isSuperscripting = true;
- } else {
- // We don't need examples for standalone symbols, i.e. infinity and nan.
- // We don't have an example for the list symbol either.
- return null;
- }
- DecimalFormat x = icuServiceBuilder.getNumberFormat(index, numberSystem);
- String example;
- String formattedValue;
- if (isSuperscripting) {
- DecimalFormatSymbols symbols = x.getDecimalFormatSymbols();
- char[] digits = symbols.getDigits();
- x.setDecimalFormatSymbols(symbols);
- x.setNegativeSuffix(endSupSymbol + x.getNegativeSuffix());
- x.setPositiveSuffix(endSupSymbol + x.getPositiveSuffix());
- x.setExponentSignAlwaysShown(false);
-
- // Don't set the exponent directly because future examples for items
- // will be affected as well.
- originalValue = symbols.getExponentSeparator();
- formattedValue =
- backgroundEndSymbol
- + value
- + digits[1]
- + digits[0]
- + backgroundStartSymbol
- + startSupSymbol;
- } else {
- x.setExponentSignAlwaysShown(true);
- formattedValue = backgroundEndSymbol + value + backgroundStartSymbol;
- }
- example = x.format(numberSample);
- example = example.replace(originalValue, formattedValue);
- return backgroundStartSymbol + example + backgroundEndSymbol;
- }
-
- private String handleNumberingSystem(String value) {
- NumberFormat x = icuServiceBuilder.getGenericNumberFormat(value);
- x.setGroupingUsed(false);
- return x.format(NUMBER_SAMPLE_WHOLE);
- }
-
- private String handleTimeZoneName(XPathParts parts, String value) {
- String result = null;
- if (parts.contains("exemplarCity")) {
- // ldml/dates/timeZoneNames/zone[@type="America/Los_Angeles"]/exemplarCity
- String timezone = parts.getAttributeValue(3, "type");
- String countryCode = supplementalDataInfo.getZone_territory(timezone);
- if (countryCode == null) {
- if (value == null) {
- result = timezone.substring(timezone.lastIndexOf('/') + 1).replace('_', ' ');
- } else {
- result = value; // trivial -- is this beneficial?
- }
- return result;
- }
- if (countryCode.equals("001")) {
- // GMT code, so format.
- try {
- String hourOffset = timezone.substring(timezone.contains("+") ? 8 : 7);
- int hours = Integer.parseInt(hourOffset);
- result = getGMTFormat(null, null, hours);
- } catch (RuntimeException e) {
- return null; // fail, skip
- }
- } else {
- result = setBackground(cldrFile.getName(CLDRFile.TERRITORY_NAME, countryCode));
- }
- } else if (parts.contains("zone")) { // {0} Time
- result = value; // trivial -- is this beneficial?
- } else if (parts.contains("regionFormat")) { // {0} Time
- result = format(value, setBackground(cldrFile.getName(CLDRFile.TERRITORY_NAME, "JP")));
- result =
- addExampleResult(
- format(
- value,
- setBackground(
- cldrFile.getWinningValue(EXEMPLAR_CITY_LOS_ANGELES))),
- result);
- } else if (parts.contains("fallbackFormat")) { // {1} ({0})
- String central =
- setBackground(
- cldrFile.getWinningValue(
- "//ldml/dates/timeZoneNames/metazone[@type=\"America_Central\"]/long/generic"));
- String cancun =
- setBackground(
- cldrFile.getWinningValue(
- "//ldml/dates/timeZoneNames/zone[@type=\"America/Cancun\"]/exemplarCity"));
- result = format(value, cancun, central);
- } else if (parts.contains("gmtFormat")) { // GMT{0}
- result = getGMTFormat(null, value, -8);
- } else if (parts.contains("hourFormat")) { // +HH:mm;-HH:mm
- result = getGMTFormat(value, null, -8);
- } else if (parts.contains("metazone")
- && !parts.contains("commonlyUsed")) { // Metazone string
- if (value != null && value.length() > 0) {
- result = getMZTimeFormat() + " " + value;
- } else {
- // TODO check for value
- if (parts.contains("generic")) {
- String metazone_name = parts.getAttributeValue(3, "type");
- String timezone =
- supplementalDataInfo.getZoneForMetazoneByRegion(metazone_name, "001");
- String countryCode = supplementalDataInfo.getZone_territory(timezone);
- String regionFormat =
- cldrFile.getWinningValue("//ldml/dates/timeZoneNames/regionFormat");
- String countryName =
- cldrFile.getWinningValue(
- "//ldml/localeDisplayNames/territories/territory[@type=\""
- + countryCode
- + "\"]");
- result =
- setBackground(
- getMZTimeFormat() + " " + format(regionFormat, countryName));
- } else {
- String gmtFormat =
- cldrFile.getWinningValue("//ldml/dates/timeZoneNames/gmtFormat");
- String hourFormat =
- cldrFile.getWinningValue("//ldml/dates/timeZoneNames/hourFormat");
- String metazone_name = parts.getAttributeValue(3, "type");
- String tz_string =
- supplementalDataInfo.getZoneForMetazoneByRegion(metazone_name, "001");
- TimeZone currentZone = TimeZone.getTimeZone(tz_string);
- int tzOffset = currentZone.getRawOffset();
- if (parts.contains("daylight")) {
- tzOffset += currentZone.getDSTSavings();
- }
- long tm_hrs = tzOffset / DateConstants.MILLIS_PER_HOUR;
- long tm_mins =
- (tzOffset % DateConstants.MILLIS_PER_HOUR)
- / DateConstants.MILLIS_PER_MINUTE;
- result =
- setBackground(
- getMZTimeFormat()
- + " "
- + getGMTFormat(
- hourFormat,
- gmtFormat,
- (int) tm_hrs,
- (int) tm_mins));
- }
- }
- }
- return result;
- }
-
- @SuppressWarnings("deprecation")
- private String handleDateFormatItem(String xpath, String value, boolean showContexts) {
- // Get here if parts contains "calendar" and either of "pattern", "dateFormatItem"
-
- String fullpath = cldrFile.getFullXPath(xpath);
- XPathParts parts = XPathParts.getFrozenInstance(fullpath);
- String calendar = parts.findAttributeValue("calendar", "type");
-
- if (parts.contains("dateTimeFormat")) { // date-time combining patterns
- // ldml/dates/calendars/calendar[@type="*"]/dateTimeFormats/dateTimeFormatLength[@type="*"]/dateTimeFormat[@type="standard"]/pattern[@type="standard"]
- // ldml/dates/calendars/calendar[@type="*"]/dateTimeFormats/dateTimeFormatLength[@type="*"]/dateTimeFormat[@type="atTime"]/pattern[@type="standard"]
- String formatType =
- parts.findAttributeValue("dateTimeFormat", "type"); // "standard" or "atTime"
- String length =
- parts.findAttributeValue(
- "dateTimeFormatLength", "type"); // full, long, medium, short
-
- // For all types, show
- // - date (of same length) with a single full time, or long time (abbreviated zone) if
- // the date is short
- // - date (of same length) with a single short time
- // For the standard patterns, add
- // - date (of same length) with a short time range
- // - relative date with a short time range
- // For the atTime patterns, add
- // - relative date with a single short time
-
- // ldml/dates/calendars/calendar[@type="*"]/dateFormats/dateFormatLength[@type="*"]/dateFormat[@type="standard"]/pattern[@type="standard"]
- // ldml/dates/calendars/calendar[@type="*"]/dateFormats/dateFormatLength[@type="*"]/dateFormat[@type="standard"]/pattern[@type="standard"][@numbers="*"]
- String dateFormatXPath = // Get standard dateFmt for same calendar & length as this
- // dateTimePattern
- cldrFile.getWinningPath(
- xpath.replaceAll("dateTimeFormat", "dateFormat")
- .replaceAll("atTime", "standard"));
-
- String dateFormatValue = cldrFile.getWinningValue(dateFormatXPath);
- parts = XPathParts.getFrozenInstance(cldrFile.getFullXPath(dateFormatXPath));
- String dateNumbersOverride = parts.findAttributeValue("pattern", "numbers");
- SimpleDateFormat df =
- icuServiceBuilder.getDateFormat(calendar, dateFormatValue, dateNumbersOverride);
- df.setTimeZone(ZONE_SAMPLE);
-
- // ldml/dates/calendars/calendar[@type="*"]/timeFormats/timeFormatLength[@type="*"]/timeFormat[@type="standard"]/pattern[@type="standard"]
- // ldml/dates/calendars/calendar[@type="*"]/timeFormats/timeFormatLength[@type="*"]/timeFormat[@type="standard"]/pattern[@type="standard"][@numbers="*"] // not currently used
- String timeFormatXPathForPrefix =
- cldrFile.getWinningPath(xpath.replaceAll("dateTimeFormat", "timeFormat"));
- int tfLengthOffset = timeFormatXPathForPrefix.indexOf("timeFormatLength");
- if (tfLengthOffset < 0) {
- return "";
- }
- String timeFormatXPathPrefix = timeFormatXPathForPrefix.substring(0, tfLengthOffset);
- String timeLongerFormatXPath =
- (!length.equals("short"))
- ? timeFormatXPathPrefix.concat(
- "timeFormatLength[@type=\"full\"]/timeFormat[@type=\"standard\"]/pattern[@type=\"standard\"]")
- : timeFormatXPathPrefix.concat(
- "timeFormatLength[@type=\"long\"]/timeFormat[@type=\"standard\"]/pattern[@type=\"standard\"]");
- String timeShortFormatXPath =
- timeFormatXPathPrefix.concat(
- "timeFormatLength[@type=\"short\"]/timeFormat[@type=\"standard\"]/pattern[@type=\"standard\"]");
-
- String timeFormatValue = cldrFile.getWinningValue(timeLongerFormatXPath);
- parts = XPathParts.getFrozenInstance(cldrFile.getFullXPath(timeLongerFormatXPath));
- String timeNumbersOverride = parts.findAttributeValue("pattern", "numbers");
- SimpleDateFormat tlf =
- icuServiceBuilder.getDateFormat(calendar, timeFormatValue, timeNumbersOverride);
- tlf.setTimeZone(ZONE_SAMPLE);
-
- timeFormatValue = cldrFile.getWinningValue(timeShortFormatXPath);
- parts = XPathParts.getFrozenInstance(cldrFile.getFullXPath(timeShortFormatXPath));
- timeNumbersOverride = parts.findAttributeValue("pattern", "numbers");
- SimpleDateFormat tsf =
- icuServiceBuilder.getDateFormat(calendar, timeFormatValue, timeNumbersOverride);
- tsf.setTimeZone(ZONE_SAMPLE);
-
- // ldml/dates/fields/field[@type="day"]/relative[@type="0"] // "today"
- String relativeDayXPath =
- cldrFile.getWinningPath(
- "//ldml/dates/fields/field[@type=\"day\"]/relative[@type=\"0\"]");
- String relativeDayValue = cldrFile.getWinningValue(relativeDayXPath);
-
- List examples = new ArrayList<>();
-
- String dfResult = df.format(DATE_SAMPLE);
- String tlfResult = tlf.format(DATE_SAMPLE);
- String tsfResult = tsf.format(DATE_SAMPLE); // DATE_SAMPLE is in the afternoon
-
- // Handle date plus a single full time.
- // We need to process the dateTimePattern as a date pattern (not only a message format)
- // so
- // we handle it with SimpleDateFormat, plugging the date and time formats in as literal
- // text.
- SimpleDateFormat dtf =
- icuServiceBuilder.getDateFormat(
- calendar,
- MessageFormat.format(
- value,
- (Object[])
- new String[] {
- setBackground("'" + tlfResult + "'"),
- setBackground("'" + dfResult + "'")
- }));
- examples.add(dtf.format(DATE_SAMPLE));
-
- // Handle date plus a single short time.
- dtf =
- icuServiceBuilder.getDateFormat(
- calendar,
- MessageFormat.format(
- value,
- (Object[])
- new String[] {
- setBackground("'" + tsfResult + "'"),
- setBackground("'" + dfResult + "'")
- }));
- examples.add(dtf.format(DATE_SAMPLE));
-
- if (!formatType.contentEquals("atTime")) {
- // Examples for standard pattern
-
- // Create a time range (from morning to afternoon, using short time formats). For
- // simplicity we format
- // using the intervalFormatFallback pattern (should be reasonable for time range
- // morning to evening).
- int dtfLengthOffset = xpath.indexOf("dateTimeFormatLength");
- if (dtfLengthOffset > 0) {
- String intervalFormatFallbackXPath =
- xpath.substring(0, dtfLengthOffset)
- .concat("intervalFormats/intervalFormatFallback");
- String intervalFormatFallbackValue =
- cldrFile.getWinningValue(intervalFormatFallbackXPath);
- String tsfAMResult = tsf.format(DATE_SAMPLE3); // DATE_SAMPLE3 is in the morning
- String timeRange = format(intervalFormatFallbackValue, tsfAMResult, tsfResult);
-
- // Handle date plus short time range
- dtf =
- icuServiceBuilder.getDateFormat(
- calendar,
- MessageFormat.format(
- value,
- (Object[])
- new String[] {
- setBackground("'" + timeRange + "'"),
- setBackground("'" + dfResult + "'")
- }));
- examples.add(dtf.format(DATE_SAMPLE));
-
- // Handle relative date plus short time range
- dtf =
- icuServiceBuilder.getDateFormat(
- calendar,
- MessageFormat.format(
- value,
- (Object[])
- new String[] {
- setBackground("'" + timeRange + "'"),
- setBackground("'" + relativeDayValue + "'")
- }));
- examples.add(dtf.format(DATE_SAMPLE));
- }
- } else {
- // Examples for atTime pattern
-
- // Handle relative date plus a single short time.
- dtf =
- icuServiceBuilder.getDateFormat(
- calendar,
- MessageFormat.format(
- value,
- (Object[])
- new String[] {
- setBackground("'" + tsfResult + "'"),
- setBackground("'" + relativeDayValue + "'")
- }));
- examples.add(dtf.format(DATE_SAMPLE));
- }
-
- return formatExampleList(examples.toArray(new String[0]));
- } else {
- String id = parts.findAttributeValue("dateFormatItem", "id");
- if ("NEW".equals(id) || value == null) {
- return startItalicSymbol + "n/a" + endItalicSymbol;
- } else {
- String numbersOverride = parts.findAttributeValue("pattern", "numbers");
- SimpleDateFormat sdf =
- icuServiceBuilder.getDateFormat(calendar, value, numbersOverride);
- sdf.setTimeZone(ZONE_SAMPLE);
- String defaultNumberingSystem =
- cldrFile.getWinningValue("//ldml/numbers/defaultNumberingSystem");
- String timeSeparator =
- cldrFile.getWinningValue(
- "//ldml/numbers/symbols[@numberSystem='"
- + defaultNumberingSystem
- + "']/timeSeparator");
- DateFormatSymbols dfs = sdf.getDateFormatSymbols();
- dfs.setTimeSeparatorString(timeSeparator);
- sdf.setDateFormatSymbols(dfs);
- if (id == null || id.indexOf('B') < 0) {
- // Standard date/time format, or availableFormat without dayPeriod
- if (value.contains("MMM") || value.contains("LLL")) {
- // alpha month, do not need context examples
- return sdf.format(DATE_SAMPLE);
- } else {
- // Use contextExamples if showContexts T
- String example =
- showContexts
- ? exampleStartHeaderSymbol
- + contextheader
- + exampleEndSymbol
- : "";
- example = addExampleResult(sdf.format(DATE_SAMPLE), example, showContexts);
- return example;
- }
- } else {
- List examples = new ArrayList<>();
- examples.add(sdf.format(DATE_SAMPLE3));
- examples.add(sdf.format(DATE_SAMPLE));
- examples.add(sdf.format(DATE_SAMPLE4));
- return formatExampleList(examples.toArray(new String[0]));
- }
- }
- }
- }
-
- // Simple check whether the currency symbol has letters on one or both sides
- private boolean symbolIsLetters(String currencySymbol, boolean onBothSides) {
- int len = currencySymbol.length();
- if (len == 0) {
- return false;
- }
- int limitChar = currencySymbol.codePointAt(0);
- if (UCharacter.isLetter(limitChar)) {
- if (!onBothSides) {
- return true;
- }
- } else if (onBothSides) {
- return false;
- }
- if (len > 1) {
- limitChar = currencySymbol.codePointAt(len - 1);
- return UCharacter.isLetter(limitChar);
- }
- return false;
- }
-
- /**
- * Creates examples for currency formats.
- *
- * @param value
- * @return
- */
- private String handleCurrencyFormat(XPathParts parts, String value, boolean showContexts) {
-
- String example =
- showContexts ? exampleStartHeaderSymbol + contextheader + exampleEndSymbol : "";
- String territory = getDefaultTerritory();
-
- String currency = supplementalDataInfo.getDefaultCurrency(territory);
- String checkPath = "//ldml/numbers/currencies/currency[@type=\"" + currency + "\"]/symbol";
- String currencySymbol = cldrFile.getWinningValue(checkPath);
- String altValue = parts.getAttributeValue(-1, "alt");
- boolean altAlpha = (altValue != null && altValue.equals("alphaNextToNumber"));
- if (altAlpha && !symbolIsLetters(currencySymbol, true)) {
- // If this example is for alt="alphaNextToNumber" and the default currency symbol
- // does not have letters on both sides, need to use a fully alphabetic one.
- currencySymbol = currency;
- }
-
- String numberSystem = parts.getAttributeValue(2, "numberSystem"); // null if not present
-
- DecimalFormat df =
- icuServiceBuilder.getCurrencyFormat(currency, currencySymbol, numberSystem);
- df.applyPattern(value);
-
- String countValue = parts.getAttributeValue(-1, "count");
- if (countValue != null) {
- return formatCountDecimal(df, countValue);
- }
-
- double sampleAmount = 1295.00;
- example = addExampleResult(formatNumber(df, sampleAmount), example, showContexts);
- example = addExampleResult(formatNumber(df, -sampleAmount), example, showContexts);
-
- if (showContexts && !altAlpha) {
- // If this example is not for alt="alphaNextToNumber", then if the currency symbol
- // above has letters (strong dir) add another example with non-letter symbol
- // (weak or neutral), or vice versa
- if (symbolIsLetters(currencySymbol, false)) {
- currency = "EUR";
- checkPath = "//ldml/numbers/currencies/currency[@type=\"" + currency + "\"]/symbol";
- currencySymbol = cldrFile.getWinningValue(checkPath);
- } else {
- currencySymbol = currency;
- }
- df = icuServiceBuilder.getCurrencyFormat(currency, currencySymbol, numberSystem);
- df.applyPattern(value);
- example = addExampleResult(formatNumber(df, sampleAmount), example, showContexts);
- example = addExampleResult(formatNumber(df, -sampleAmount), example, showContexts);
- }
-
- return example;
- }
-
- private String getDefaultTerritory() {
- CLDRLocale loc;
- String territory = "US";
- if (!typeIsEnglish) {
- loc = CLDRLocale.getInstance(cldrFile.getLocaleID());
- territory = loc.getCountry();
- if (territory == null || territory.length() == 0) {
- loc = supplementalDataInfo.getDefaultContentFromBase(loc);
- if (loc != null) {
- territory = loc.getCountry();
- if (territory.equals("001") && loc.getLanguage().equals("ar")) {
- territory =
- "EG"; // Use Egypt as territory for examples in ar locale, since its
- // default content is ar_001.
- }
- }
- }
- if (territory == null || territory.length() == 0) {
- territory = "US";
- }
- }
- return territory;
- }
-
- /**
- * Creates examples for decimal formats.
- *
- * @param value
- * @return
- */
- private String handleDecimalFormat(XPathParts parts, String value, boolean showContexts) {
- String example =
- showContexts ? exampleStartHeaderSymbol + contextheader + exampleEndSymbol : "";
- String numberSystem = parts.getAttributeValue(2, "numberSystem"); // null if not present
- DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(value, numberSystem);
- String countValue = parts.getAttributeValue(-1, "count");
- if (countValue != null) {
- return formatCountDecimal(numberFormat, countValue);
- }
-
- double sampleNum1 = 5.43;
- double sampleNum2 = NUMBER_SAMPLE;
- if (parts.getElement(4).equals("percentFormat")) {
- sampleNum1 = 0.0543;
- }
- example = addExampleResult(formatNumber(numberFormat, sampleNum1), example, showContexts);
- example = addExampleResult(formatNumber(numberFormat, sampleNum2), example, showContexts);
- // have positive and negative
- example = addExampleResult(formatNumber(numberFormat, -sampleNum2), example, showContexts);
- return example;
- }
-
- private String formatCountDecimal(DecimalFormat numberFormat, String countValue) {
- Count count;
- try {
- count = Count.valueOf(countValue);
- } catch (Exception e) {
- String locale = getCldrFile().getLocaleID();
- PluralInfo pluralInfo = supplementalDataInfo.getPlurals(locale);
- count =
- pluralInfo.getCount(
- DecimalQuantity_DualStorageBCD.fromExponentString(countValue));
- }
- Double numberSample = getExampleForPattern(numberFormat, count);
- if (numberSample == null) {
- // Ideally, we would suppress the value in the survey tool.
- // However, until we switch over to the ICU samples, we are not guaranteed
- // that "no samples" means "can't occur". So we manufacture something.
- int digits = numberFormat.getMinimumIntegerDigits();
- numberSample = (double) Math.round(1.2345678901234 * Math.pow(10, digits - 1));
- }
- String temp = String.valueOf(numberSample);
- int fractionLength = temp.endsWith(".0") ? 0 : temp.length() - temp.indexOf('.') - 1;
- if (fractionLength != numberFormat.getMaximumFractionDigits()) {
- numberFormat = (DecimalFormat) numberFormat.clone(); // for safety
- numberFormat.setMinimumFractionDigits(fractionLength);
- numberFormat.setMaximumFractionDigits(fractionLength);
- }
- return formatNumber(numberFormat, numberSample);
- }
-
- private String formatNumber(DecimalFormat format, double value) {
- String example = format.format(value);
- return setBackgroundOnMatch(example, ALL_DIGITS);
- }
-
- /**
- * Calculates a numerical example to use for the specified pattern using brute force (there
- * should be a more elegant way to do this).
- *
- * @param format
- * @param count
- * @return
- */
- private Double getExampleForPattern(DecimalFormat format, Count count) {
- if (patternExamples == null) {
- patternExamples = PluralSamples.getInstance(cldrFile.getLocaleID());
- }
- int numDigits = format.getMinimumIntegerDigits();
- Map samples = patternExamples.getSamples(numDigits);
- if (samples == null) {
- return null;
- }
- return samples.get(count);
- }
-
- private String handleCurrency(String xpath, XPathParts parts, String value) {
- String currency = parts.getAttributeValue(-2, "type");
- String fullPath = cldrFile.getFullXPath(xpath, false);
- if (parts.contains("symbol")) {
- if (fullPath != null && fullPath.contains("[@choice=\"true\"]")) {
- ChoiceFormat cf = new ChoiceFormat(value);
- value = cf.format(NUMBER_SAMPLE);
- }
- String result;
- if (value == null) {
- throw new NullPointerException(
- cldrFile.getSourceLocation(fullPath)
- + ": "
- + cldrFile.getLocaleID()
- + ": "
- + ": Error: no currency symbol for "
- + currency);
- }
- DecimalFormat x = icuServiceBuilder.getCurrencyFormat(currency, value);
- result = x.format(NUMBER_SAMPLE);
- result =
- setBackground(result)
- .replace(value, backgroundEndSymbol + value + backgroundStartSymbol);
- return result;
- } else if (parts.contains("displayName")) {
- return formatCountValue(xpath, parts, value);
- }
- return null;
- }
-
- private String handleDateRangePattern(String value) {
- String result;
- SimpleDateFormat dateFormat = icuServiceBuilder.getDateFormat("gregorian", 2, 0);
- result =
- format(
- value,
- setBackground(dateFormat.format(DATE_SAMPLE)),
- setBackground(dateFormat.format(DATE_SAMPLE2)));
- return result;
- }
-
- /**
- * @param elementToOverride the element that is to be overridden
- * @param element the overriding element
- * @param value the value to override element with
- * @return
- */
- private String getLocaleDisplayPattern(String elementToOverride, String element, String value) {
- final String localeDisplayPatternPath = "//ldml/localeDisplayNames/localeDisplayPattern/";
- if (elementToOverride.equals(element)) {
- return value;
- } else {
- return cldrFile.getWinningValue(localeDisplayPatternPath + elementToOverride);
- }
- }
-
- private String handleDisplayNames(String xpath, XPathParts parts, String value) {
- String result = null;
- if (parts.contains("codePatterns")) {
- // ldml/localeDisplayNames/codePatterns/codePattern[@type="language"]
- // ldml/localeDisplayNames/codePatterns/codePattern[@type="script"]
- // ldml/localeDisplayNames/codePatterns/codePattern[@type="territory"]
- String type = parts.getAttributeValue(-1, "type");
- result =
- format(
- value,
- setBackground(
- type.equals("language")
- ? "ace"
- : type.equals("script")
- ? "Avst"
- : type.equals("territory") ? "057" : "CODE"));
- } else if (parts.contains("localeDisplayPattern")) {
- // ldml/localeDisplayNames/localeDisplayPattern/localePattern
- // ldml/localeDisplayNames/localeDisplayPattern/localeSeparator
- // ldml/localeDisplayNames/localeDisplayPattern/localeKeyTypePattern
- String element = parts.getElement(-1);
- value = setBackground(value);
- String localeKeyTypePattern =
- getLocaleDisplayPattern("localeKeyTypePattern", element, value);
- String localePattern = getLocaleDisplayPattern("localePattern", element, value);
- String localeSeparator = getLocaleDisplayPattern("localeSeparator", element, value);
-
- List locales = new ArrayList<>();
- if (element.equals("localePattern")) {
- locales.add("uz-AF");
- }
- locales.add(
- element.equals("localeKeyTypePattern") ? "uz-Arab-u-tz-etadd" : "uz-Arab-AF");
- locales.add("uz-Arab-AF-u-tz-etadd-nu-arab");
- String[] examples = new String[locales.size()];
- for (int i = 0; i < locales.size(); i++) {
- examples[i] =
- invertBackground(
- cldrFile.getName(
- locales.get(i),
- false,
- localeKeyTypePattern,
- localePattern,
- localeSeparator));
- }
- result = formatExampleList(examples);
- } else if (parts.contains("languages")
- || parts.contains("scripts")
- || parts.contains("territories")) {
- // ldml/localeDisplayNames/languages/language[@type="ar"]
- // ldml/localeDisplayNames/scripts/script[@type="Arab"]
- // ldml/localeDisplayNames/territories/territory[@type="CA"]
- String type = parts.getAttributeValue(-1, "type");
- if (type.contains("_")) {
- if (value != null && !value.equals(type)) {
- result = value; // trivial -- is this beneficial?
- } else {
- result = cldrFile.getBaileyValue(xpath, null, null);
- }
- } else {
- value = setBackground(value);
- List examples = new ArrayList<>();
- String nameType = parts.getElement(3);
-
- Map likely = supplementalDataInfo.getLikelySubtags();
- String alt = parts.getAttributeValue(-1, "alt");
- boolean isStandAloneValue = "stand-alone".equals(alt);
- if (!isStandAloneValue) {
- // only do this if the value is not a stand-alone form
- String tag = "language".equals(nameType) ? type : "und_" + type;
- String max = LikelySubtags.maximize(tag, likely);
- if (max == null) {
- return null;
- }
- LanguageTagParser ltp = new LanguageTagParser().set(max);
- String languageName = null;
- String scriptName = null;
- String territoryName = null;
- if (nameType.equals("language")) {
- languageName = value;
- } else if (nameType.equals("script")) {
- scriptName = value;
- } else {
- territoryName = value;
- }
- if (languageName == null) {
- languageName =
- cldrFile.getStringValueWithBailey(
- CLDRFile.getKey(CLDRFile.LANGUAGE_NAME, ltp.getLanguage()));
- if (languageName == null) {
- languageName =
- cldrFile.getStringValueWithBailey(
- CLDRFile.getKey(CLDRFile.LANGUAGE_NAME, "en"));
- }
- if (languageName == null) {
- languageName = ltp.getLanguage();
- }
- }
- if (scriptName == null) {
- scriptName =
- cldrFile.getStringValueWithBailey(
- CLDRFile.getKey(CLDRFile.SCRIPT_NAME, ltp.getScript()));
- if (scriptName == null) {
- scriptName =
- cldrFile.getStringValueWithBailey(
- CLDRFile.getKey(CLDRFile.SCRIPT_NAME, "Latn"));
- }
- if (scriptName == null) {
- scriptName = ltp.getScript();
- }
- }
- if (territoryName == null) {
- territoryName =
- cldrFile.getStringValueWithBailey(
- CLDRFile.getKey(CLDRFile.TERRITORY_NAME, ltp.getRegion()));
- if (territoryName == null) {
- territoryName =
- cldrFile.getStringValueWithBailey(
- CLDRFile.getKey(CLDRFile.TERRITORY_NAME, "US"));
- }
- if (territoryName == null) {
- territoryName = ltp.getRegion();
- }
- }
- languageName =
- languageName
- .replace('(', '[')
- .replace(')', ']')
- .replace('οΌ', 'οΌ»')
- .replace('οΌ', 'οΌ½');
- scriptName =
- scriptName
- .replace('(', '[')
- .replace(')', ']')
- .replace('οΌ', 'οΌ»')
- .replace('οΌ', 'οΌ½');
- territoryName =
- territoryName
- .replace('(', '[')
- .replace(')', ']')
- .replace('οΌ', 'οΌ»')
- .replace('οΌ', 'οΌ½');
-
- String localePattern =
- cldrFile.getStringValueWithBailey(
- "//ldml/localeDisplayNames/localeDisplayPattern/localePattern");
- String localeSeparator =
- cldrFile.getStringValueWithBailey(
- "//ldml/localeDisplayNames/localeDisplayPattern/localeSeparator");
- String scriptTerritory = format(localeSeparator, scriptName, territoryName);
- if (!nameType.equals("script")) {
- examples.add(
- invertBackground(
- format(localePattern, languageName, territoryName)));
- }
- if (!nameType.equals("territory")) {
- examples.add(
- invertBackground(format(localePattern, languageName, scriptName)));
- }
- examples.add(
- invertBackground(format(localePattern, languageName, scriptTerritory)));
- }
- Output pathWhereFound;
- if (isStandAloneValue
- || cldrFile.getStringValueWithBailey(
- xpath + ALT_STAND_ALONE,
- pathWhereFound = new Output<>(),
- null)
- == null
- || !pathWhereFound.value.contains(ALT_STAND_ALONE)) {
- // only do this if either it is a stand-alone form,
- // or it isn't and there is no separate stand-alone form
- // the extra check after the == null is to make sure that we don't have sideways
- // inheritance
- String codePattern =
- cldrFile.getStringValueWithBailey(
- "//ldml/localeDisplayNames/codePatterns/codePattern[@type=\""
- + nameType
- + "\"]");
- examples.add(invertBackground(format(codePattern, value)));
- }
- result = formatExampleList(examples.toArray(new String[0]));
- }
- }
- return result;
- }
-
- private String formatExampleList(String[] examples) {
- String result = examples[0];
- for (int i = 1, len = examples.length; i < len; i++) {
- result = addExampleResult(examples[i], result);
- }
- return result;
- }
-
- /**
- * Return examples formatted as string, with null returned for null or empty examples.
- *
- * @param examples
- * @return
- */
- private String formatExampleList(Collection examples) {
- if (examples == null || examples.isEmpty()) {
- return null;
- }
- String result = "";
- boolean first = true;
- for (String example : examples) {
- if (first) {
- result = example;
- first = false;
- } else {
- result = addExampleResult(example, result);
- }
- }
- return result;
- }
-
- public static String format(String format, Object... objects) {
- if (format == null) return null;
- return MessageFormat.format(format, objects);
- }
-
- public static String unchainException(Exception e) {
- String stackStr = "[unknown stack]
";
- try {
- StringWriter asString = new StringWriter();
- e.printStackTrace(new PrintWriter(asString));
- stackStr = "" + asString + "
";
- } catch (Throwable tt) {
- // ...
- }
- return stackStr;
- }
-
- /**
- * Put a background on an item, skipping enclosed patterns.
- *
- * @param inputPattern
- * @return
- */
- private String setBackground(String inputPattern) {
- if (inputPattern == null) {
- return "?";
- }
- Matcher m = PARAMETER.matcher(inputPattern);
- return backgroundStartSymbol
- + m.replaceAll(backgroundEndSymbol + "$1" + backgroundStartSymbol)
- + backgroundEndSymbol;
- }
-
- /**
- * Put a background on an item, skipping enclosed patterns, except for {0}
- *
- * @param input
- * @param patternToEmbed
- * @return
- */
- private String setBackgroundExceptMatch(String input, Pattern patternToEmbed) {
- Matcher m = patternToEmbed.matcher(input);
- return backgroundStartSymbol
- + m.replaceAll(backgroundEndSymbol + "$1" + backgroundStartSymbol)
- + backgroundEndSymbol;
- }
-
- /**
- * Put a background on an item, skipping enclosed patterns, except for {0}
- *
- * @param inputPattern
- * @param patternToEmbed
- * @return
- */
- private String setBackgroundOnMatch(String inputPattern, Pattern patternToEmbed) {
- Matcher m = patternToEmbed.matcher(inputPattern);
- return m.replaceAll(backgroundStartSymbol + "$1" + backgroundEndSymbol);
- }
-
- /**
- * This is called just before we return a result. It fixes the special characters that were
- * added by setBackground.
- *
- * @param input string with special characters from setBackground.
- * @return string with HTML for the background.
- */
- private String finalizeBackground(String input) {
- if (input == null) {
- return null;
- }
- String coreString =
- TransliteratorUtilities.toHTML
- .transliterate(input)
- .replace(backgroundStartSymbol + backgroundEndSymbol, "")
- // remove null runs
- .replace(backgroundEndSymbol + backgroundStartSymbol, "")
- // remove null runs
- .replace(backgroundStartSymbol, backgroundStart)
- .replace(backgroundEndSymbol, backgroundEnd)
- .replace(backgroundAutoStartSymbol, backgroundAutoStart)
- .replace(backgroundAutoEndSymbol, backgroundAutoEnd)
- .replace(exampleSeparatorSymbol, exampleEnd + exampleStart)
- .replace(exampleStartAutoSymbol, exampleStartAuto)
- .replace(exampleStartRTLSymbol, exampleStartRTL)
- .replace(exampleStartHeaderSymbol, exampleStartHeader)
- .replace(exampleEndSymbol, exampleEnd)
- .replace(startItalicSymbol, startItalic)
- .replace(endItalicSymbol, endItalic)
- .replace(startSupSymbol, startSup)
- .replace(endSupSymbol, endSup);
- // If we are not showing context, we use exampleSeparatorSymbol between examples,
- // and then need to add the initial exampleStart and final exampleEnd.
- return (input.contains(exampleStartAutoSymbol))
- ? coreString
- : exampleStart + coreString + exampleEnd;
- }
-
- private String invertBackground(String input) {
- return input == null
- ? null
- : backgroundStartSymbol
- + input.replace(backgroundStartSymbol, backgroundTempSymbol)
- .replace(backgroundEndSymbol, backgroundStartSymbol)
- .replace(backgroundTempSymbol, backgroundEndSymbol)
- + backgroundEndSymbol;
- }
-
- private String removeEmptyRuns(String input) {
- return input.replace(backgroundStartSymbol + backgroundEndSymbol, "")
- .replace(backgroundEndSymbol + backgroundStartSymbol, "");
- }
-
- /**
- * Utility to format using a gmtHourString, gmtFormat, and an integer hours. We only need the
- * hours because that's all the TZDB IDs need. Should merge this eventually into
- * TimeZoneFormatter and call there.
- *
- * @param gmtHourString
- * @param gmtFormat
- * @param hours
- * @return
- */
- private String getGMTFormat(String gmtHourString, String gmtFormat, int hours) {
- return getGMTFormat(gmtHourString, gmtFormat, hours, 0);
- }
-
- private String getGMTFormat(String gmtHourString, String gmtFormat, int hours, int minutes) {
- boolean hoursBackground = false;
- if (gmtHourString == null) {
- hoursBackground = true;
- gmtHourString = cldrFile.getWinningValue("//ldml/dates/timeZoneNames/hourFormat");
- }
- if (gmtFormat == null) {
- hoursBackground = false; // for the hours case
- gmtFormat =
- setBackground(cldrFile.getWinningValue("//ldml/dates/timeZoneNames/gmtFormat"));
- }
- String[] plusMinus = gmtHourString.split(";");
-
- SimpleDateFormat dateFormat =
- icuServiceBuilder.getDateFormat("gregorian", plusMinus[hours >= 0 ? 0 : 1]);
- dateFormat.setTimeZone(ZONE_SAMPLE);
- calendar.set(1999, 9, 27, Math.abs(hours), minutes, 0); // 1999-09-13 13:25:59
- Date sample = calendar.getTime();
- String hourString = dateFormat.format(sample);
- if (hoursBackground) {
- hourString = setBackground(hourString);
- }
- String result = format(gmtFormat, hourString);
- return result;
- }
-
- private String getMZTimeFormat() {
- String timeFormat =
- cldrFile.getWinningValue(
- "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/timeFormats/timeFormatLength[@type=\"short\"]/timeFormat[@type=\"standard\"]/pattern[@type=\"standard\"]");
- if (timeFormat == null) {
- timeFormat = "HH:mm";
- }
- // the following is <= because the TZDB inverts the hours
- SimpleDateFormat dateFormat = icuServiceBuilder.getDateFormat("gregorian", timeFormat);
- dateFormat.setTimeZone(ZONE_SAMPLE);
- calendar.set(1999, 9, 13, 13, 25, 59); // 1999-09-13 13:25:59
- Date sample = calendar.getTime();
- String result = dateFormat.format(sample);
- return result;
- }
-
- /**
- * Return a help string, in html, that should be shown in the Zoomed view. Presumably at the end
- * of each help section is something like:
- * <br>For more information, see help.
- * The result is valid HTML. Set listPlaceholders to true to include a HTML-formatted table of
- * all placeholders required in the value.
- * TODO: add more help, and modify to get from property or xml file for easy modification.
- *
- * @return null if none available.
- */
- public synchronized String getHelpHtml(String xpath, String value) {
- // lazy initialization
- if (pathDescription == null) {
- Map>> starredPaths = new HashMap<>();
- Map extras = new HashMap<>();
-
- this.pathDescription =
- new PathDescription(
- supplementalDataInfo,
- englishFile,
- extras,
- starredPaths,
- PathDescription.ErrorHandling.CONTINUE);
-
- if (helpMessages == null) {
- helpMessages = new HelpMessages("test_help_messages.html");
- }
- }
-
- // now get the description
-
- Level level = CONFIG.getCoverageInfo().getCoverageLevel(xpath, cldrFile.getLocaleID());
- String description = pathDescription.getDescription(xpath, value, null);
- if (description == null || description.equals("SKIP")) {
- return null;
- }
- int start = 0;
- StringBuilder buffer = new StringBuilder();
-
- Matcher URLMatcher = URL_PATTERN.matcher("");
- while (URLMatcher.reset(description).find(start)) {
- final String url = URLMatcher.group();
- buffer.append(
- TransliteratorUtilities.toHTML.transliterate(
- description.substring(start, URLMatcher.start())))
- .append("")
- .append(url)
- .append("");
- start = URLMatcher.end();
- }
- buffer.append(TransliteratorUtilities.toHTML.transliterate(description.substring(start)));
- if (AnnotationUtil.pathIsAnnotation(xpath)) {
- XPathParts emoji = XPathParts.getFrozenInstance(xpath);
- String cp = emoji.getAttributeValue(-1, "cp");
- String minimal = Utility.hex(cp).replace(',', '_').toLowerCase(Locale.ROOT);
- buffer.append(
- "
");
- }
- return buffer.toString();
- }
-
- public static String simplify(String exampleHtml) {
- return simplify(exampleHtml, false);
- }
-
- public static String simplify(String exampleHtml, boolean internal) {
- if (exampleHtml == null) {
- return null;
- }
- if (internal) {
- return "γ"
- + exampleHtml
- .replace(backgroundStartSymbol, "β¬")
- .replace(backgroundEndSymbol, "β")
- + "γ";
- }
- int startIndex = exampleHtml.indexOf(exampleStartHeader);
- if (startIndex >= 0) {
- int endIndex = exampleHtml.indexOf(exampleEnd, startIndex);
- if (endIndex > startIndex) {
- // remove header for context examples
- endIndex += exampleEnd.length();
- String head = exampleHtml.substring(0, startIndex);
- String tail = exampleHtml.substring(endIndex);
- exampleHtml = head + tail;
- }
- }
- return exampleHtml
- .replace("", "γ")
- .replace("
", "γ")
- .replace("
", "γβͺ")
- .replace("
", "γ")
- .replace("
", "β¬")
- .replace("", "β");
- }
-}
diff --git a/tools/cldr-code/src/test/java/org/unicode/cldr/unittest/TestExampleGenerator.java b/tools/cldr-code/src/test/java/org/unicode/cldr/unittest/TestExampleGenerator.java
index 2a57bb1f2e6..8b2652c160e 100644
--- a/tools/cldr-code/src/test/java/org/unicode/cldr/unittest/TestExampleGenerator.java
+++ b/tools/cldr-code/src/test/java/org/unicode/cldr/unittest/TestExampleGenerator.java
@@ -9,7 +9,6 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import com.ibm.icu.dev.test.TestFmwk;
-import com.ibm.icu.util.ULocale;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -29,7 +28,6 @@
import org.unicode.cldr.test.CheckCLDR.StatusAction;
import org.unicode.cldr.test.ExampleGenerator;
import org.unicode.cldr.test.ExampleGenerator.UnitLength;
-import org.unicode.cldr.test.ExampleGeneratorOld;
import org.unicode.cldr.unittest.TestCheckCLDR.DummyPathValueInfo;
import org.unicode.cldr.util.CLDRConfig;
import org.unicode.cldr.util.CLDRFile;
@@ -2079,50 +2077,4 @@ private String getResult(String starredPath, String attr) {
public String sampleAttrAndValue(PathStarrer ps, final String separator, String value) {
return ps.getAttributesString(separator) + "βΒ«" + value + "Β»";
}
-
- PathHeader.Factory phf = PathHeader.getFactory(null);
-
- private boolean isValidPath(String xpath, ULocale locale) {
- PathHeader ph = phf.fromPath(xpath);
- if (ph == null) {
- return false;
- }
- if (ph.getSurveyToolStatus() == PathHeader.SurveyToolStatus.DEPRECATED) {
- return false;
- }
- if (ph.getSurveyToolStatus() == PathHeader.SurveyToolStatus.HIDE
- || ph.getSurveyToolStatus() == PathHeader.SurveyToolStatus.READ_ONLY) {
- return false;
- }
-
- if (SDI.getCoverageValue(xpath, locale.getBaseName())
- > org.unicode.cldr.util.Level.COMPREHENSIVE.getLevel()) {
- return false;
- }
- return true;
- }
-
- public void TestRefactoring() {
- for (final String loc : info.getCldrFactory().getAvailable()) {
- CLDRFile resolvedCldrFile = info.getCLDRFile(loc, true);
- CLDRFile unresolvedCldrFile = info.getCLDRFile(loc, false);
- ExampleGenerator exampleGenerator = getExampleGenerator(loc);
- ExampleGeneratorOld exampleGeneratorOld =
- new ExampleGeneratorOld(resolvedCldrFile, info.getEnglish());
- for (String path : unresolvedCldrFile) {
- if (isValidPath(path, loc)) {
- String value = unresolvedCldrFile.getStringValue(path);
- String oldExample = exampleGeneratorOld.getExampleHtml(path, value);
- String newExample = exampleGenerator.getExampleHtml(path, value);
- assertEquals(
- "Ensure same example pre/post refactoring for locale: "
- + loc
- + "and path: "
- + path,
- oldExample,
- newExample);
- }
- }
- }
- }
}