| package org.unicode.cldr.test; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.text.ChoiceFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.BitSet; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.unicode.cldr.tool.CLDRFileTransformer; |
| import org.unicode.cldr.tool.CLDRFileTransformer.LocaleTransform; |
| import org.unicode.cldr.tool.LikelySubtags; |
| import org.unicode.cldr.util.CLDRConfig; |
| import org.unicode.cldr.util.CLDRFile; |
| import org.unicode.cldr.util.CLDRLocale; |
| import org.unicode.cldr.util.CLDRPaths; |
| import org.unicode.cldr.util.CldrUtility; |
| import org.unicode.cldr.util.DayPeriodInfo; |
| import org.unicode.cldr.util.DayPeriodInfo.DayPeriod; |
| import org.unicode.cldr.util.Factory; |
| import org.unicode.cldr.util.ICUServiceBuilder; |
| import org.unicode.cldr.util.LanguageTagParser; |
| import org.unicode.cldr.util.Level; |
| import org.unicode.cldr.util.PathDescription; |
| import org.unicode.cldr.util.PatternCache; |
| import org.unicode.cldr.util.PluralSamples; |
| import org.unicode.cldr.util.SupplementalDataInfo; |
| import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo; |
| import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count; |
| import org.unicode.cldr.util.SupplementalDataInfo.PluralType; |
| import org.unicode.cldr.util.TimezoneFormatter; |
| import org.unicode.cldr.util.TransliteratorUtilities; |
| import org.unicode.cldr.util.XPathParts; |
| |
| import com.ibm.icu.impl.Row.R3; |
| import com.ibm.icu.text.BreakIterator; |
| import com.ibm.icu.text.DateFormat; |
| import com.ibm.icu.text.DateFormatSymbols; |
| import com.ibm.icu.text.DateTimePatternGenerator; |
| import com.ibm.icu.text.DecimalFormat; |
| import com.ibm.icu.text.DecimalFormatSymbols; |
| import com.ibm.icu.text.MessageFormat; |
| import com.ibm.icu.text.NumberFormat; |
| import com.ibm.icu.text.PluralRules; |
| import com.ibm.icu.text.PluralRules.FixedDecimal; |
| import com.ibm.icu.text.PluralRules.FixedDecimalRange; |
| import com.ibm.icu.text.PluralRules.FixedDecimalSamples; |
| import com.ibm.icu.text.PluralRules.SampleType; |
| import com.ibm.icu.text.SimpleDateFormat; |
| import com.ibm.icu.text.Transliterator; |
| import com.ibm.icu.util.Calendar; |
| import com.ibm.icu.util.TimeZone; |
| import com.ibm.icu.util.ULocale; |
| |
| /** |
| * Class to generate examples and help messages for the Survey tool (or console version). |
| * |
| * @author markdavis |
| * |
| */ |
| public class ExampleGenerator { |
| private static final String ALT_STAND_ALONE = "[@alt=\"stand-alone\"]"; |
| |
| private static final String EXEMPLAR_CITY_LOS_ANGELES = "//ldml/dates/timeZoneNames/zone[@type=\"America/Los_Angeles\"]/exemplarCity"; |
| |
| private static final boolean SHOW_ERROR = false; |
| |
| private static final Pattern URL_PATTERN = Pattern |
| .compile("http://[\\-a-zA-Z0-9]+(\\.[\\-a-zA-Z0-9]+)*([/#][\\-a-zA-Z0-9]+)*"); |
| |
| final static boolean DEBUG_SHOW_HELP = false; |
| |
| private static SupplementalDataInfo supplementalDataInfo; |
| private PathDescription pathDescription; |
| |
| private final static boolean CACHING = false; |
| |
| public final static double NUMBER_SAMPLE = 123456.789; |
| public final static double NUMBER_SAMPLE_WHOLE = 2345; |
| |
| public final static TimeZone ZONE_SAMPLE = TimeZone.getTimeZone("America/Indianapolis"); |
| public final static TimeZone GMT_ZONE_SAMPLE = TimeZone.getTimeZone("Etc/GMT"); |
| |
| public final static Date DATE_SAMPLE; |
| |
| private final static Date DATE_SAMPLE2; |
| private final static Date DATE_SAMPLE3; |
| private final static Date DATE_SAMPLE4; |
| |
| // private final static String EXEMPLAR_CITY = "Europe/Rome"; |
| |
| private String backgroundStart = "<span class='cldr_substituted'>"; |
| private String backgroundEnd = "</span>"; |
| |
| private static final String exampleStart = "<div class='cldr_example'>"; |
| private static final String exampleEnd = "</div>"; |
| private static final String startItalic = "<i>"; |
| private static final String endItalic = "</i>"; |
| private static final String startSup = "<sup>"; |
| private static final String endSup = "</sup>"; |
| |
| private static final String backgroundStartSymbol = "\uE234"; |
| private static final String backgroundEndSymbol = "\uE235"; |
| private static final String backgroundTempSymbol = "\uE236"; |
| private static final String exampleSeparatorSymbol = "\uE237"; |
| private static final String startItalicSymbol = "\uE238"; |
| private static final String endItalicSymbol = "\uE239"; |
| private static final String startSupSymbol = "\uE23A"; |
| private static final String endSupSymbol = "\uE23B"; |
| |
| private boolean verboseErrors = false; |
| |
| private Calendar calendar = Calendar.getInstance(ZONE_SAMPLE, ULocale.ENGLISH); |
| |
| static { |
| Calendar calendar = Calendar.getInstance(ZONE_SAMPLE, ULocale.ENGLISH); |
| calendar.set(1999, 8, 14, 13, 25, 59); // 1999-08-14 13:25:59 |
| DATE_SAMPLE = calendar.getTime(); |
| calendar.set(1999, 9, 27, 13, 25, 59); // 1999-09-27 13:25:59 |
| DATE_SAMPLE2 = calendar.getTime(); |
| |
| calendar.set(1999, 8, 14, 7, 0, 0); // 1999-08-14 07:00:00 |
| DATE_SAMPLE3 = calendar.getTime(); |
| calendar.set(1999, 8, 14, 23, 0, 0); // 1999-08-14 23:00:00 |
| DATE_SAMPLE4 = calendar.getTime(); |
| } |
| |
| private CLDRFile cldrFile; |
| |
| public CLDRFile getCldrFile() { |
| return cldrFile; |
| } |
| |
| private CLDRFile englishFile; |
| Matcher URLMatcher = URL_PATTERN.matcher(""); |
| |
| private Map<String, String> cache = new HashMap<String, String>(); |
| |
| private static final String NONE = "\uFFFF"; |
| |
| // Matcher skipMatcher = PatternCache.get( |
| // "/localeDisplayNames(?!" |
| // ).matcher(""); |
| private XPathParts parts = new XPathParts(); |
| |
| private ICUServiceBuilder icuServiceBuilder = new ICUServiceBuilder(); |
| |
| private PluralInfo pluralInfo; |
| |
| private PluralSamples patternExamples; |
| |
| /** |
| * For getting the end of the "background" style. Default is "</span>". 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 "</span>". It is |
| * used in composing patterns, so it can show the part that corresponds to the |
| * value. |
| * |
| * @return |
| */ |
| public void setBackgroundEnd(String backgroundEnd) { |
| this.backgroundEnd = backgroundEnd; |
| } |
| |
| /** |
| * For getting the "background" style. Default is "<span |
| * style='background-color: gray'>". 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 "<span |
| * style='background-color: gray'>". It is used in composing patterns, so it |
| * can show the part that corresponds to the value. |
| * |
| * @return |
| */ |
| 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 supplementalDataDirectory |
| */ |
| public ExampleGenerator(CLDRFile resolvedCldrFile, CLDRFile englishFile, String supplementalDataDirectory) { |
| if (!resolvedCldrFile.isResolved()) throw new IllegalArgumentException("CLDRFile must be resolved"); |
| if (!englishFile.isResolved()) throw new IllegalArgumentException("English CLDRFile must be resolved"); |
| cldrFile = resolvedCldrFile; |
| this.englishFile = englishFile; |
| synchronized (ExampleGenerator.class) { |
| if (supplementalDataInfo == null) { |
| supplementalDataInfo = SupplementalDataInfo.getInstance(supplementalDataDirectory); |
| } |
| } |
| icuServiceBuilder.setCldrFile(cldrFile); |
| |
| pluralInfo = supplementalDataInfo.getPlurals(PluralType.cardinal, cldrFile.getLocaleID()); |
| } |
| |
| public enum ExampleType { |
| NATIVE, ENGLISH |
| }; |
| |
| public static class ExampleContext { |
| private Collection<FixedDecimal> exampleCount; |
| |
| public void setExampleCount(Collection<FixedDecimal> exampleCount2) { |
| this.exampleCount = exampleCount2; |
| } |
| |
| public Collection<FixedDecimal> getExampleCount() { |
| return exampleCount; |
| } |
| } |
| |
| public String getExampleHtml(String xpath, String value) { |
| return getExampleHtml(xpath, value, null, null); |
| } |
| |
| /** |
| * Returns 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 Engish doesn't, but you want to return the best English |
| * example. <br> |
| * The result is valid HTML. |
| * |
| * @param xpath |
| * @return |
| */ |
| public String getExampleHtml(String xpath, String value, ExampleContext context, ExampleType type) { |
| if (value == null) { |
| return null; |
| } |
| String cacheKey; |
| String result = null; |
| try { |
| if (CACHING) { |
| cacheKey = xpath + "," + value; |
| result = cache.get(cacheKey); |
| if (result != null) { |
| if (result == NONE) { |
| return null; |
| } |
| return result; |
| } |
| } |
| // If generating examples for an inheritance marker, then we need to find the |
| // "real" value to generate from. |
| if (CldrUtility.INHERITANCE_MARKER.equals(value)) { |
| if (type.equals(ExampleType.ENGLISH)) { |
| value = englishFile.getConstructedBaileyValue(xpath, null, null); |
| } else { |
| value = cldrFile.getConstructedBaileyValue(xpath, null, null); |
| } |
| } |
| |
| // result is null at this point. Get the real value if we can. |
| parts.set(xpath); |
| if (parts.contains("dateRangePattern")) { // {0} - {1} |
| result = handleDateRangePattern(value, xpath); |
| } else if (parts.contains("timeZoneNames")) { |
| result = handleTimeZoneName(xpath, value); |
| } else if (parts.contains("localeDisplayNames")) { |
| result = handleDisplayNames(xpath, parts, value); |
| } else if (parts.contains("currency")) { |
| result = handleCurrency(xpath, value, context, type); |
| } else if (parts.contains("dayPeriods")) { |
| result = handleDayPeriod(xpath, value, context, type); |
| } else if (parts.contains("pattern") || parts.contains("dateFormatItem")) { |
| if (parts.contains("calendar")) { |
| result = handleDateFormatItem(xpath, value); |
| } else if (parts.contains("miscPatterns")) { |
| result = handleMiscPatterns(parts, value); |
| } else if (parts.contains("numbers")) { |
| if (parts.contains("currencyFormat")) { |
| result = handleCurrencyFormat(parts, value, type); |
| } else { |
| result = handleDecimalFormat(parts, value, type); |
| } |
| } |
| } 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, context, type); |
| } else if (parts.getElement(-2).equals("compoundUnit")) { |
| String count = CldrUtility.ifNull(parts.getAttributeValue(-1, "count"), "other"); |
| result = handleCompoundUnit(getUnitLength(), Count.valueOf(count), value); |
| } else if (parts.getElement(-1).equals("unitPattern")) { |
| String count = parts.getAttributeValue(-1, "count"); |
| result = handleFormatUnit(getUnitLength(), Count.valueOf(count), value); |
| } else if (parts.getElement(-1).equals("durationUnitPattern")) { |
| result = handleDurationUnit(value); |
| } else if (parts.contains("intervalFormats")) { |
| result = handleIntervalFormats(parts, xpath, value, context, type); |
| } 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 { |
| // didn't detect anything, return empty-handed |
| return null; |
| } |
| } catch (NullPointerException e) { |
| if (SHOW_ERROR) { |
| e.printStackTrace(); |
| } |
| return null; |
| } catch (RuntimeException e) { |
| String unchained = verboseErrors ? ("<br>" + finalizeBackground(unchainException(e))) : ""; |
| return "<i>Parsing error. " + finalizeBackground(e.getMessage()) + "</i>" + unchained; |
| } |
| |
| String test = parts.getElement(-1); |
| |
| //add transliteration if one exists |
| if (type == ExampleType.NATIVE && result != null) { |
| result = addTransliteration(result, value); |
| } |
| |
| result = finalizeBackground(result); |
| |
| if (CACHING) { |
| if (result == null) { |
| cache.put(cacheKey, NONE); |
| } else { |
| // fix HTML, cache |
| cache.put(cacheKey, result); |
| } |
| } |
| return result; |
| } |
| |
| private String handleDayPeriod(String xpath, String value, ExampleContext context, ExampleType type) { |
| //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<String> examples = new ArrayList<>(); |
| final String dayPeriodType = parts.getAttributeValue(5, "type"); |
| 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"); |
| |
| DayPeriod dayPeriod = DayPeriod.valueOf(periodString); |
| String periods = dayPeriodInfo.toString(dayPeriod); |
| examples.add(periods); |
| if ("format".equals(dayPeriodType)) { |
| if (value == null) { |
| value = "�"; |
| } |
| R3<Integer, Integer, Boolean> info = dayPeriodInfo.getFirstDayPeriodInfo(dayPeriod); |
| int time = (((info.get0() + info.get1()) % DayPeriodInfo.DAY_LIMIT) / 2); |
| //String calendar = parts.getAttributeValue(3, "type"); |
| String timeFormatString = icuServiceBuilder.formatDayPeriod(time, backgroundStartSymbol + value + backgroundEndSymbol); |
| examples.add(invertBackground(timeFormatString)); |
| } |
| return formatExampleList(examples.toArray(new String[examples.size()])); |
| } |
| |
| private UnitLength getUnitLength() { |
| return UnitLength.valueOf(parts.getAttributeValue(-3, "type").toUpperCase(Locale.ENGLISH)); |
| } |
| |
| private String handleFormatUnit(UnitLength unitLength, Count count, String value) { |
| FixedDecimal amount = getBest(count); |
| if (amount == null) { |
| return "n/a"; |
| } |
| DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(1); |
| return format(value, backgroundStartSymbol + numberFormat.format(amount) + backgroundEndSymbol); |
| } |
| |
| public String handleCompoundUnit(UnitLength unitLength, Count count, String value) { |
| /** |
| * <units> |
| <unitLength type="long"> |
| <alias source="locale" path="../unitLength[@type='short']"/> |
| </unitLength> |
| <unitLength type="short"> |
| <compoundUnit type="per"> |
| <unitPattern count="other">{0}/{1}</unitPattern> |
| </compoundUnit> |
| |
| * <compoundUnit type="per"> |
| <unitPattern count="one">{0}/{1}</unitPattern> |
| <unitPattern count="other">{0}/{1}</unitPattern> |
| </compoundUnit> |
| <unit type="length-m"> |
| <unitPattern count="one">{0} meter</unitPattern> |
| <unitPattern count="other">{0} meters</unitPattern> |
| </unit> |
| |
| */ |
| |
| // we want to get a number that works for the count passed in. |
| FixedDecimal amount = getBest(count); |
| if (amount == null) { |
| return "n/a"; |
| } |
| String unit1 = backgroundStartSymbol + getFormattedUnit("length-meter", unitLength, amount) + backgroundEndSymbol; |
| String unit2 = backgroundStartSymbol + getFormattedUnit("duration-second", unitLength, new FixedDecimal(1d, 0), "").trim() + backgroundEndSymbol; |
| // TODO fix hack |
| String form = this.pluralInfo.getPluralRules().select(amount); |
| String perPath = "//ldml/units/unitLength" + unitLength.typeString |
| + "/compoundUnit[@type=\"per\"]" |
| + "/compoundUnitPattern"; |
| //ldml/units/unitLength[@type="long"]/compoundUnit[@type="per"]/compoundUnitPattern |
| return format(getValueFromFormat(perPath, form), unit1, unit2); |
| } |
| |
| private FixedDecimal getBest(Count count) { |
| FixedDecimalSamples 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<FixedDecimalRange> samples2 = samples.getSamples(); |
| FixedDecimalRange range = samples2.iterator().next(); |
| return range.end; |
| } |
| |
| private String handleMiscPatterns(XPathParts parts2, 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); |
| } |
| } |
| |
| IntervalFormat intervalFormat = new IntervalFormat(); |
| |
| static Calendar generatingCalendar = Calendar.getInstance(ULocale.US); |
| |
| private static Date getDate(int year, int month, int date, int hour, int minute, int second, TimeZone zone) { |
| synchronized (generatingCalendar) { |
| generatingCalendar.setTimeZone(GMT_ZONE_SAMPLE); |
| generatingCalendar.set(year, month, date, hour, minute, second); |
| return generatingCalendar.getTime(); |
| } |
| } |
| |
| static Date FIRST_INTERVAL = getDate(2008, 1, 13, 5, 7, 9, GMT_ZONE_SAMPLE); |
| static Map<String, Date> SECOND_INTERVAL = CldrUtility.asMap(new Object[][] { |
| { "y", getDate(2009, 2, 14, 17, 8, 10, GMT_ZONE_SAMPLE) }, |
| { "M", getDate(2008, 2, 14, 17, 8, 10, GMT_ZONE_SAMPLE) }, |
| { "d", getDate(2008, 1, 14, 17, 8, 10, GMT_ZONE_SAMPLE) }, |
| { "a", getDate(2008, 1, 13, 17, 8, 10, GMT_ZONE_SAMPLE) }, |
| { "h", getDate(2008, 1, 13, 6, 8, 10, GMT_ZONE_SAMPLE) }, |
| { "m", getDate(2008, 1, 13, 5, 8, 10, GMT_ZONE_SAMPLE) } |
| }); |
| |
| private String handleIntervalFormats(XPathParts parts, String xpath, String value, |
| ExampleContext context, ExampleType type) { |
| 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"); |
| if (greatestDifference.equals("H")) greatestDifference = "h"; |
| // intervalFormatFallback |
| // //ldml/dates/calendars/calendar[@type="gregorian"]/dateTimeFormats/intervalFormats/intervalFormatItem[@id="yMd"]/greatestDifference[@id="y"] |
| // find where to split the value |
| intervalFormat.setPattern(value); |
| return intervalFormat.format(FIRST_INTERVAL, SECOND_INTERVAL.get(greatestDifference)); |
| } |
| |
| 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 |
| String listPatternType = parts.getAttributeValue(-2, "type"); |
| if (listPatternType == null || !listPatternType.contains("unit")) { |
| return handleRegularListPatterns(parts, value); |
| } else { |
| return handleDurationListPatterns(parts, value, UnitLength.from(listPatternType)); |
| } |
| } |
| |
| private String handleRegularListPatterns(XPathParts parts, String value) { |
| String patternType = parts.getAttributeValue(-1, "type"); |
| 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"); |
| String listPathFormat = "//ldml/listPatterns/listPattern/listPatternPart[@type=\"{0}\"]"; |
| return longListPatternExample( |
| listPathFormat, patternType, value, territory1, territory2, territory3, territory4); |
| } |
| |
| private String handleDurationListPatterns(XPathParts parts, String value, UnitLength unitWidth) { |
| String patternType = parts.getAttributeValue(-1, "type"); |
| 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); |
| String listPathFormat = "//ldml/listPatterns/listPattern" |
| + unitWidth.listTypeLength.typeString |
| + "/listPatternPart[@type=\"{0}\"]"; |
| return longListPatternExample( |
| listPathFormat, patternType, value, duration1, duration2, duration3, duration4); |
| } |
| |
| public enum ListTypeLength { |
| NORMAL(""), |
| UNIT_WIDE("[@type=\"unit\"]"), |
| UNIT_SHORT("[@type=\"unit-short\"]"), |
| UNIT_NARROW("[@type=\"unit-narrow\"]"); |
| final String typeString; |
| |
| ListTypeLength(String typeString) { |
| this.typeString = typeString; |
| } |
| } |
| |
| 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) { |
| if (listPatternType.equals("unit")) { |
| return UnitLength.LONG; |
| } else if (listPatternType.equals("unit-narrow")) { |
| return UnitLength.NARROW; |
| } else if (listPatternType.equals("unit-short")) { |
| return UnitLength.SHORT; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| |
| private String getFormattedUnit(String unitType, UnitLength unitWidth, FixedDecimal unitAmount) { |
| DecimalFormat numberFormat = icuServiceBuilder.getNumberFormat(1); |
| return getFormattedUnit(unitType, unitWidth, unitAmount, numberFormat.format(unitAmount)); |
| } |
| |
| private String getFormattedUnit(String unitType, UnitLength unitWidth, double unitAmount) { |
| return getFormattedUnit(unitType, unitWidth, new FixedDecimal(unitAmount)); |
| } |
| |
| private String getFormattedUnit(String unitType, UnitLength unitWidth, FixedDecimal 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); |
| } |
| |
| private String longListPatternExample(String listPathFormat, String patternType, String value, String territory1, String territory2, String territory3, |
| String territory4) { |
| String startPattern = getPattern(listPathFormat, "start", patternType, value); |
| String middlePattern = getPattern(listPathFormat, "middle", patternType, value); |
| String endPattern = getPattern(listPathFormat, "end", patternType, value); |
| |
| String example = format(startPattern, territory1, |
| format(middlePattern, territory2, format(endPattern, territory3, territory4))); |
| 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}\"]"; |
| // <ellipsis type="word-final">{0} …</ellipsis> |
| // <ellipsis type="word-initial">… {0}</ellipsis> |
| // <ellipsis type="word-medial">{0} … {1}</ellipsis> |
| 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"); |
| String result = format(value, setBackground(sdf.format(DATE_SAMPLE)), setBackground(zone)); |
| return result; |
| } |
| |
| class IntervalFormat { |
| 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) { |
| return firstFormat.format(earlier) + secondFormat.format(later); |
| } |
| |
| public IntervalFormat setPattern(String pattern) { |
| formatParser.set(pattern); |
| 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) { |
| // ULocale locale = new ULocale(this.icuServiceBuilder.getCldrFile().getLocaleID()); |
| // SimpleDateFormat df = new SimpleDateFormat(value.replace('h', 'H'), locale); |
| DateFormat df = this.icuServiceBuilder.getDateFormat("gregorian", value.replace('h', 'H')); |
| df.setTimeZone(TimeZone.GMT_ZONE); |
| long time = ((5 * 60 + 37) * 60 + 23) * 1000; |
| return df.format(new Date(time)); |
| } |
| |
| static final List<FixedDecimal> CURRENCY_SAMPLES = Arrays.asList( |
| new FixedDecimal(1.23), |
| new FixedDecimal(0), |
| new FixedDecimal(2.34), |
| new FixedDecimal(3.45), |
| new FixedDecimal(5.67), |
| new FixedDecimal(1) |
| ); |
| |
| private String formatCountValue(String xpath, XPathParts parts, String value, ExampleContext context, |
| ExampleType type) { |
| if (!parts.containsAttribute("count")) { // no examples for items that don't format |
| return null; |
| } |
| final PluralInfo plurals = supplementalDataInfo.getPlurals(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 = null; |
| final LinkedHashSet<FixedDecimal> exampleCount = new LinkedHashSet(); |
| exampleCount.addAll(CURRENCY_SAMPLES); |
| String countString = parts.getAttributeValue(-1, "count"); |
| if (countString == null) { |
| // count = Count.one; |
| 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); |
| |
| if (context != null) { |
| context.setExampleCount(exampleCount); |
| } |
| String result = ""; |
| DecimalFormat currencyFormat = icuServiceBuilder.getCurrencyFormat(unitType); |
| int decimalCount = currencyFormat.getMinimumFractionDigits(); |
| |
| // we will cycle until we have (at most) two examples. |
| Set<FixedDecimal> examplesSeen = new HashSet<FixedDecimal>(); |
| 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) { |
| int check = 0; |
| for (FixedDecimal 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) { |
| example = new FixedDecimal(example.getSource(), decimalCount); |
| } |
| // 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, type, unitType, isPattern, isCurrency, count, example); |
| // now add to list |
| result = addExampleResult(resultItem, result); |
| if (isPattern) { |
| String territory = getDefaultTerritory(type); |
| String currency = supplementalDataInfo.getDefaultCurrency(territory); |
| if (currency.equals(unitType)) { |
| currency = "EUR"; |
| if (currency.equals(unitType)) { |
| currency = "JAY"; |
| } |
| } |
| resultItem = formatCurrency(value, type, currency, isPattern, isCurrency, count, example); |
| // now add to list |
| result = addExampleResult(resultItem, result); |
| |
| } |
| if (--maxCount < 1) { |
| break main; |
| } |
| } |
| } |
| return result.isEmpty() ? null : result; |
| } |
| |
| static public void getStartEndSamples(PluralRules.FixedDecimalSamples samples, Set<FixedDecimal> target) { |
| if (samples != null) { |
| for (FixedDecimalRange item : samples.getSamples()) { |
| target.add(item.start); |
| target.add(item.end); |
| } |
| } |
| } |
| |
| private String formatCurrency(String value, ExampleType type, String unitType, final boolean isPattern, final boolean isCurrency, Count count, |
| FixedDecimal 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 = type != ExampleType.ENGLISH ? value : getUnitPattern(unitType, isCurrency, count); |
| } else { |
| unitPattern = getUnitPattern(unitType, isCurrency, count); |
| unitName = type != ExampleType.ENGLISH ? value : getUnitName(unitType, isCurrency, count); |
| } |
| |
| 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(example.getVisibleDecimalDigitCount()); |
| unitDecimalFormat.setMinimumFractionDigits(example.getVisibleDecimalDigitCount()); |
| |
| String formattedNumber = unitDecimalFormat.format(example.getSource()); |
| 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) { |
| if (resultToAddTo.length() != 0) { |
| resultToAddTo += exampleSeparatorSymbol; |
| } |
| resultToAddTo += resultItem; |
| return resultToAddTo; |
| } |
| |
| private String getUnitPattern(String unitType, final boolean isCurrency, Count count) { |
| String unitPattern; |
| String unitPatternPath = cldrFile.getCountPathWithFallback(isCurrency |
| ? "//ldml/numbers/currencyFormats/unitPattern" |
| : "//ldml/units/unit[@type=\"" + unitType + "\"]/unitPattern", |
| count, true); |
| unitPattern = cldrFile.getWinningValue(unitPatternPath); |
| return unitPattern; |
| } |
| |
| private String getUnitName(String unitType, final boolean isCurrency, Count count) { |
| String unitNamePath = cldrFile.getCountPathWithFallback(isCurrency |
| ? "//ldml/numbers/currencies/currency[@type=\"" + unitType + "\"]/displayName" |
| : "//ldml/units/unit[@type=\"" + unitType + "\"]/unitPattern", |
| count, true); |
| return unitNamePath == null ? unitType : cldrFile.getWinningValue(unitNamePath); |
| } |
| |
| private String handleNumberSymbol(XPathParts parts, String value) { |
| String symbolType = parts.getElement(-1); |
| String numberSystem = parts.getAttributeValue(2, "numberSystem"); // null if not present |
| int index = 1;// 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("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; |
| example = x.format(numberSample); |
| } 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(String xpath, 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; |
| } |
| 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 result; // fail, skip |
| } |
| } else { |
| String countryName = setBackground(cldrFile.getName(CLDRFile.TERRITORY_NAME, countryCode)); |
| boolean singleZone = !supplementalDataInfo.getMultizones().contains(countryCode); |
| // we show just country for singlezone countries |
| if (singleZone) { |
| result = countryName; |
| } else { |
| if (value == null) { |
| value = TimezoneFormatter.getFallbackName(timezone); |
| } |
| // otherwise we show the fallback with exemplar |
| String fallback = setBackground(cldrFile |
| .getWinningValue("//ldml/dates/timeZoneNames/fallbackFormat")); |
| // ldml/dates/timeZoneNames/zone[@type="America/Los_Angeles"]/exemplarCity |
| |
| result = format(fallback, value, countryName); |
| } |
| // format with "{0} Time" or equivalent. |
| String timeFormat = setBackground(cldrFile.getWinningValue("//ldml/dates/timeZoneNames/regionFormat")); |
| result = format(timeFormat, result); |
| } |
| } else if (parts.contains("zone")) { // {0} Time |
| result = value; |
| } 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 fallbackFormat = cldrFile.getWinningValue("//ldml/dates/timeZoneNames/fallbackFormat"); |
| String exemplarCity = cldrFile.getWinningValue("//ldml/dates/timeZoneNames/zone[@type=\"" |
| + timezone + "\"]/exemplarCity"); |
| if (exemplarCity == null) { |
| exemplarCity = timezone.substring(timezone.lastIndexOf('/') + 1).replace('_', ' '); |
| } |
| String countryName = cldrFile |
| .getWinningValue("//ldml/localeDisplayNames/territories/territory[@type=\"" + countryCode |
| + "\"]"); |
| boolean singleZone = !(supplementalDataInfo.getMultizones().contains(countryCode)); |
| |
| if (singleZone) { |
| result = setBackground(getMZTimeFormat() + " " + |
| format(regionFormat, countryName)); |
| } |
| else { |
| result = setBackground(getMZTimeFormat() + " " + |
| format(fallbackFormat, exemplarCity, 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 = supplementalData.resolveParsedMetazone(metazone_name,"001"); |
| 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(); |
| } |
| int MILLIS_PER_MINUTE = 1000 * 60; |
| int MILLIS_PER_HOUR = MILLIS_PER_MINUTE * 60; |
| int tm_hrs = tzOffset / MILLIS_PER_HOUR; |
| int tm_mins = (tzOffset % MILLIS_PER_HOUR) / 60000; // millis per minute |
| result = setBackground(getMZTimeFormat() + " " |
| + getGMTFormat(hourFormat, gmtFormat, tm_hrs, tm_mins)); |
| } |
| } |
| } |
| return result; |
| } |
| |
| private String handleDateFormatItem(String xpath, String value) { |
| |
| String fullpath = cldrFile.getFullXPath(xpath); |
| parts.set(fullpath); |
| |
| String calendar = parts.findAttributeValue("calendar", "type"); |
| |
| if (parts.contains("dateTimeFormat")) { |
| String dateFormatXPath = cldrFile.getWinningPath(xpath.replaceAll("dateTimeFormat", "dateFormat")); |
| String timeFormatXPath = cldrFile.getWinningPath(xpath.replaceAll("dateTimeFormat", "timeFormat")); |
| String dateFormatValue = cldrFile.getWinningValue(dateFormatXPath); |
| String timeFormatValue = cldrFile.getWinningValue(timeFormatXPath); |
| parts.set(cldrFile.getFullXPath(dateFormatXPath)); |
| String dateNumbersOverride = parts.findAttributeValue("pattern", "numbers"); |
| parts.set(cldrFile.getFullXPath(timeFormatXPath)); |
| String timeNumbersOverride = parts.findAttributeValue("pattern", "numbers"); |
| SimpleDateFormat df = icuServiceBuilder.getDateFormat(calendar, dateFormatValue, dateNumbersOverride); |
| SimpleDateFormat tf = icuServiceBuilder.getDateFormat(calendar, timeFormatValue, timeNumbersOverride); |
| df.setTimeZone(ZONE_SAMPLE); |
| tf.setTimeZone(ZONE_SAMPLE); |
| String dfResult = "'" + df.format(DATE_SAMPLE) + "'"; |
| String tfResult = "'" + tf.format(DATE_SAMPLE) + "'"; |
| SimpleDateFormat dtf = icuServiceBuilder.getDateFormat(calendar, |
| MessageFormat.format(value, (Object[]) new String[] { setBackground(tfResult), setBackground(dfResult) })); |
| return dtf.format(DATE_SAMPLE); |
| } 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) { |
| return sdf.format(DATE_SAMPLE); |
| } else { |
| List<String> examples = new ArrayList<String>(); |
| examples.add(sdf.format(DATE_SAMPLE3)); |
| examples.add(sdf.format(DATE_SAMPLE)); |
| examples.add(sdf.format(DATE_SAMPLE4)); |
| return formatExampleList(examples.toArray(new String[examples.size()])); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Creates examples for currency formats. |
| * |
| * @param value |
| * @return |
| */ |
| private String handleCurrencyFormat(XPathParts parts, String value, ExampleType type) { |
| |
| String territory = getDefaultTerritory(type); |
| |
| String currency = supplementalDataInfo.getDefaultCurrency(territory); |
| String checkPath = "//ldml/numbers/currencies/currency[@type=\"" + currency + "\"]/symbol"; |
| String currencySymbol = cldrFile.getWinningValue(checkPath); |
| 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; |
| String example = formatNumber(df, sampleAmount); |
| example = addExampleResult(formatNumber(df, -sampleAmount), example); |
| |
| return example; |
| } |
| |
| private String getDefaultTerritory(ExampleType type) { |
| CLDRLocale loc; |
| String territory = "US"; |
| if (ExampleType.NATIVE.equals(type)) { |
| loc = CLDRLocale.getInstance(cldrFile.getLocaleID()); |
| territory = loc.getCountry(); |
| if (territory == null || territory.length() == 0) { |
| loc = supplementalDataInfo.getDefaultContentFromBase(loc); |
| 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, ExampleType type) { |
| 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; |
| } |
| String example = formatNumber(numberFormat, sampleNum1); |
| example = addExampleResult(formatNumber(numberFormat, sampleNum2), example); |
| // have positive and negative |
| example = addExampleResult(formatNumber(numberFormat, -sampleNum2), example); |
| return example; |
| } |
| |
| private String formatCountDecimal(DecimalFormat numberFormat, String countValue) { |
| Count count = Count.valueOf(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 (TODO: 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<Count, Double> samples = patternExamples.getSamples(numDigits); |
| // int min = (int) Math.pow(10, numDigits - 1); |
| // int max = min * 10; |
| // Map<Count, Integer> examples = patternExamples.get(numDigits); |
| // if (examples == null) { |
| // patternExamples.put(numDigits, examples = new HashMap<Count, Integer>()); |
| // Set<Count> typesLeft = new HashSet<Count>(pluralInfo.getCountToExamplesMap().keySet()); |
| // // Add at most one example of each type. |
| // for (int i = min; i < max; ++i) { |
| // if (typesLeft.isEmpty()) break; |
| // Count type = Count.valueOf(pluralInfo.getPluralRules().select(i)); |
| // if (!typesLeft.contains(type)) continue; |
| // examples.put(type, i); |
| // typesLeft.remove(type); |
| // } |
| // // Add zero as an example only if there is no other option. |
| // if (min == 1) { |
| // Count type = Count.valueOf(pluralInfo.getPluralRules().select(0)); |
| // if (!examples.containsKey(type)) examples.put(type, 0); |
| // } |
| // } |
| return samples.get(count); |
| } |
| |
| private String handleCurrency(String xpath, String value, ExampleContext context, ExampleType type) { |
| 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; |
| 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, context, type); |
| } |
| return null; |
| } |
| |
| private String handleDateRangePattern(String value, String xpath) { |
| 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<String> locales = new ArrayList<String>(); |
| if (element.equals("localePattern")) { |
| locales.add("uz-AF"); |
| } |
| locales.add(element.equals("localeKeyTypePattern") ? |
| "uz-Arab@timezone=Africa/Addis_Ababa" : "uz-Arab-AF"); |
| locales.add("uz-Arab-AF@timezone=Africa/Addis_Ababa;numbers=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; |
| } else { |
| result = cldrFile.getConstructedBaileyValue(xpath, null, null); |
| } |
| } else { |
| value = setBackground(value); |
| List<String> examples = new ArrayList<String>(); |
| String nameType = parts.getElement(3); |
| |
| Map<String, String> 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))); |
| } else { |
| int x = 0; // debugging |
| } |
| if (isStandAloneValue || cldrFile.getStringValueWithBailey(xpath + ALT_STAND_ALONE) == null) { |
| // only do this if either it is a stand-alone form, |
| // or it isn't and there is no separate stand-alone form |
| String codePattern = cldrFile.getStringValueWithBailey("//ldml/localeDisplayNames/codePatterns/codePattern[@type=\"" + nameType + "\"]"); |
| examples.add(invertBackground(format(codePattern, value))); |
| } else { |
| int x = 0; // debugging |
| } |
| result = formatExampleList(examples.toArray(new String[examples.size()])); |
| } |
| } |
| 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; |
| } |
| |
| public String format(String format, Object... objects) { |
| if (format == null) return null; |
| return MessageFormat.format(format, objects); |
| } |
| |
| public static final String unchainException(Exception e) { |
| String stackStr = "[unknown stack]<br>"; |
| try { |
| StringWriter asString = new StringWriter(); |
| e.printStackTrace(new PrintWriter(asString)); |
| stackStr = "<pre>" + asString.toString() + "</pre>"; |
| } catch (Throwable tt) { |
| // ... |
| } |
| return stackStr; |
| } |
| |
| /** |
| * Put a background on an item, skipping enclosed patterns. |
| * |
| * @param sampleTerritory |
| * @return |
| */ |
| private String setBackground(String inputPattern) { |
| 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 patternToEmbed |
| * TODO |
| * @param sampleTerritory |
| * |
| * @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 patternToEmbed |
| * TODO |
| * @param sampleTerritory |
| * |
| * @return |
| */ |
| private String setBackgroundOnMatch(String inputPattern, Pattern patternToEmbed) { |
| Matcher m = patternToEmbed.matcher(inputPattern); |
| return m.replaceAll(backgroundStartSymbol + "$1" + backgroundEndSymbol); |
| } |
| |
| /** |
| * This adds the transliteration of a result in case it has one (i.e. sr_Cyrl -> sr_Latn). |
| * |
| * @param input |
| * string with special characters from setBackground. |
| * @param value |
| * value to be transliterated |
| * @return string with attached transliteration if there is one. |
| */ |
| private String addTransliteration(String input, String value) { |
| if (value == null) { |
| return input; |
| } |
| for (LocaleTransform localeTransform : LocaleTransform.values()) { |
| |
| String locale = cldrFile.getLocaleID(); |
| |
| if (!(localeTransform.getInputLocale().equals(locale))) { |
| continue; |
| } |
| |
| Factory factory = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*"); |
| CLDRFileTransformer transformer = new CLDRFileTransformer(factory, CLDRPaths.COMMON_DIRECTORY + "transforms/"); |
| Transliterator transliterator = transformer.loadTransliterator(localeTransform); |
| final String transliterated = transliterator.transliterate(value); |
| if (!transliterated.equals(value)) { |
| return backgroundStartSymbol + "[ " + transliterated + " ]" + backgroundEndSymbol + exampleSeparatorSymbol + input; |
| } |
| } |
| return input; |
| } |
| |
| /** |
| * 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. |
| * @param invert |
| * TODO |
| * @return string with HTML for the background. |
| */ |
| private String finalizeBackground(String input) { |
| return input == null |
| ? input |
| : exampleStart + |
| TransliteratorUtilities.toHTML.transliterate(input) |
| .replace(backgroundStartSymbol + backgroundEndSymbol, "") |
| // remove null runs |
| .replace(backgroundEndSymbol + backgroundStartSymbol, "") |
| // remove null runs |
| .replace(backgroundStartSymbol, backgroundStart) |
| .replace(backgroundEndSymbol, backgroundEnd) |
| .replace(exampleSeparatorSymbol, exampleEnd + exampleStart) |
| .replace(startItalicSymbol, startItalic) |
| .replace(endItalicSymbol, endItalic) |
| .replace(startSupSymbol, startSup) |
| .replace(endSupSymbol, endSup) |
| + exampleEnd; |
| } |
| |
| private String invertBackground(String input) { |
| if (input == null) { |
| return null; |
| } |
| input = input.replace(backgroundStartSymbol, backgroundTempSymbol) |
| .replace(backgroundEndSymbol, backgroundStartSymbol) |
| .replace(backgroundTempSymbol, backgroundEndSymbol); |
| |
| return backgroundStartSymbol + input + backgroundEndSymbol; |
| } |
| |
| public static final Pattern PARAMETER = PatternCache.get("(\\{[0-9]\\})"); |
| public static final Pattern PARAMETER_SKIP0 = PatternCache.get("(\\{[1-9]\\})"); |
| public static final Pattern ALL_DIGITS = PatternCache.get("(\\p{Nd}+(.\\p{Nd}+)?)"); |
| |
| /** |
| * 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> |
| * <br>For more information, see <a |
| * href='http://unicode.org/cldr/wiki?SurveyToolHelp/characters'>help</a>. <br> |
| * The result is valid HTML. Set listPlaceholders to true to include a |
| * HTML-formatted table of all placeholders required in the value.<br> |
| * 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, boolean listPlaceholders) { |
| |
| // lazy initialization |
| |
| if (pathDescription == null) { |
| Map<String, List<Set<String>>> starredPaths = new HashMap<String, List<Set<String>>>(); |
| Map<String, String> extras = new HashMap<String, String>(); |
| |
| this.pathDescription = new PathDescription(supplementalDataInfo, englishFile, extras, starredPaths, |
| PathDescription.ErrorHandling.CONTINUE); |
| |
| 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 = CLDRConfig.getInstance().getCoverageInfo().getCoverageLevel(xpath, cldrFile.getLocaleID()); |
| String description = pathDescription.getDescription(xpath, value, level, null); |
| if (description == null || description.equals("SKIP")) { |
| return null; |
| } |
| // http://cldr.org/translation/timezones |
| int start = 0; |
| StringBuilder buffer = new StringBuilder(); |
| while (URLMatcher.reset(description).find(start)) { |
| final String url = URLMatcher.group(); |
| buffer |
| .append(TransliteratorUtilities.toHTML.transliterate(description.substring(start, URLMatcher.start()))) |
| .append("<a target='CLDR-ST-DOCS' href='") |
| .append(url) |
| .append("'>") |
| .append(url) |
| .append("</a>"); |
| start = URLMatcher.end(); |
| } |
| buffer.append(TransliteratorUtilities.toHTML.transliterate(description.substring(start))); |
| |
| if (listPlaceholders) { |
| buffer.append(pathDescription.getPlaceholderDescription(xpath)); |
| } |
| |
| return buffer.toString(); |
| // return helpMessages.find(xpath); |
| // if (xpath.contains("/exemplarCharacters")) { |
| // result = "The standard exemplar characters are those used in customary writing ([a-z] for English; " |
| // + "the auxiliary characters are used in foreign words found in typical magazines, newspapers, &c.; " |
| // + "currency auxilliary characters are those used in currency symbols, like 'US$ 1,234'. "; |
| // } |
| // return result == null ? null : TransliteratorUtilities.toHTML.transliterate(result); |
| } |
| |
| public synchronized String getHelpHtml(String xpath, String value) { |
| return getHelpHtml(xpath, value, false); |
| } |
| |
| public static String simplify(String exampleHtml) { |
| return simplify(exampleHtml, false); |
| } |
| |
| public static String simplify(String exampleHtml, boolean internal) { |
| return exampleHtml == null ? null |
| : internal ? "〖" + exampleHtml |
| .replace("", "❬") |
| .replace("", "❭") + "〗" |
| : exampleHtml |
| .replace("<div class='cldr_example'>", "〖") |
| .replace("</div>", "〗") |
| .replace("<span class='cldr_substituted'>", "❬") |
| .replace("</span>", "❭"); |
| } |
| |
| HelpMessages helpMessages; |
| } |