1 package org.unicode.cldr.test; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import java.util.Locale; 6 import java.util.Map; 7 import java.util.Set; 8 import java.util.TreeMap; 9 import java.util.regex.Pattern; 10 11 import org.unicode.cldr.util.CLDRFile; 12 import org.unicode.cldr.util.ICUServiceBuilder; 13 import org.unicode.cldr.util.PatternCache; 14 import org.unicode.cldr.util.SupplementalDataInfo; 15 import org.unicode.cldr.util.XPathParts; 16 17 import com.ibm.icu.impl.number.DecimalFormatProperties; 18 import com.ibm.icu.impl.number.PatternStringParser; 19 import com.ibm.icu.text.CompactDecimalFormat; 20 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle; 21 import com.ibm.icu.text.DecimalFormat; 22 import com.ibm.icu.text.DecimalFormat.PropertySetter; 23 import com.ibm.icu.text.PluralRules; 24 import com.ibm.icu.util.Currency; 25 import com.ibm.icu.util.ULocale; 26 27 @SuppressWarnings("deprecation") 28 public class BuildIcuCompactDecimalFormat { 29 static SupplementalDataInfo sdi = SupplementalDataInfo.getInstance(); 30 static final int MINIMUM_ARRAY_LENGTH = 15; 31 static final Pattern PATTERN = PatternCache.get("([^0,]*)([0]+)([.]0+)?([^0]*)"); 32 static final Pattern TYPE = PatternCache.get("1([0]*)"); 33 private static final boolean DEBUG = false; 34 35 public enum CurrencyStyle { 36 PLAIN, CURRENCY, LONG_CURRENCY, ISO_CURRENCY, UNIT 37 } 38 39 /** 40 * JUST FOR DEVELOPMENT 41 * 42 * @param currencyStyle 43 * @param currencyCode 44 */ build( CLDRFile resolvedCldrFile, Set<String> debugCreationErrors, String[] debugOriginals, CompactStyle style, ULocale locale, CurrencyStyle currencyStyle, String currencyCodeOrUnit)45 public static final CompactDecimalFormat build( 46 CLDRFile resolvedCldrFile, 47 Set<String> debugCreationErrors, String[] debugOriginals, 48 CompactStyle style, ULocale locale, CurrencyStyle currencyStyle, String currencyCodeOrUnit) { 49 50 // get the custom data from CLDR for use with the special setCompactCustomData 51 52 final Map<String, Map<String, String>> customData = buildCustomData(resolvedCldrFile, style, currencyStyle); 53 if (DEBUG) { 54 System.out.println("\nCustom Data:"); 55 customData.forEach((k, v) -> System.out.println("\t" + k + "\t" + v)); 56 } 57 58 // get the common CLDR data used for number/date/time formats 59 60 ICUServiceBuilder builder = new ICUServiceBuilder().setCldrFile(resolvedCldrFile); 61 62 DecimalFormat decimalFormat = currencyStyle == CurrencyStyle.PLAIN 63 ? builder.getNumberFormat(1) 64 : builder.getCurrencyFormat(currencyCodeOrUnit); 65 final String pattern = decimalFormat.toPattern(); 66 if (DEBUG) { 67 System.out.println("Pattern:\t" + pattern); 68 } 69 70 final PluralRules rules = SupplementalDataInfo.getInstance().getPlurals(locale.toString()).getPluralRules(); 71 72 // create a compact decimal format, and reset its data 73 74 CompactDecimalFormat cdf = CompactDecimalFormat.getInstance(locale, style); 75 cdf.setDecimalFormatSymbols(builder.getDecimalFormatSymbols("latn")); 76 77 cdf.setProperties(new PropertySetter() { 78 @Override 79 public void set(DecimalFormatProperties props) { 80 props.setCompactCustomData(customData); 81 PatternStringParser.parseToExistingProperties(pattern, props, PatternStringParser.IGNORE_ROUNDING_ALWAYS); 82 props.setPluralRules(rules); 83 } 84 }); 85 86 if (DEBUG) { 87 System.out.println("CompactDecimalFormat:\t" + cdf.toString().replace("}, ", "},\n\t")); 88 } 89 return cdf; 90 } 91 buildCustomData(CLDRFile resolvedCldrFile, CompactStyle style, CurrencyStyle currencyStyle)92 public static Map<String, Map<String, String>> buildCustomData(CLDRFile resolvedCldrFile, CompactStyle style, CurrencyStyle currencyStyle) { 93 94 final Map<String, Map<String, String>> customData = new TreeMap<>(); 95 96 String prefix = currencyStyle == CurrencyStyle.PLAIN 97 ? "//ldml/numbers/decimalFormats[@numberSystem=\"latn\"]/decimalFormatLength" 98 : "//ldml/numbers/currencyFormats[@numberSystem=\"latn\"]/currencyFormatLength"; 99 100 Iterator<String> it = resolvedCldrFile.iterator(prefix); 101 102 String styleString = style.toString().toLowerCase(Locale.ENGLISH); 103 while (it.hasNext()) { 104 String path = it.next(); 105 if (path.endsWith("/alias")) { 106 continue; 107 } 108 XPathParts parts = XPathParts.getFrozenInstance(path); 109 String stype = parts.getAttributeValue(3, "type"); 110 if (!styleString.equals(stype)) { 111 continue; 112 } 113 String type = parts.getAttributeValue(-1, "type"); 114 String key = parts.getAttributeValue(-1, "count"); 115 String pattern = resolvedCldrFile.getStringValue(path); 116 if (pattern.contentEquals("0")) { 117 continue; 118 } 119 120 /* 121 <pattern type="1000" count="one">0K</pattern> 122 */ 123 124 add(customData, type, key, pattern); 125 } 126 return customData; 127 } 128 add(Map<A, Map<B, C>> customData, A a, B b, C c)129 private static <A, B, C> void add(Map<A, Map<B, C>> customData, A a, B b, C c) { 130 Map<B, C> inner = customData.get(a); 131 if (inner == null) { 132 customData.put(a, inner = new HashMap<>()); 133 } 134 inner.put(b, c); 135 } 136 137 static class MyCurrencySymbolDisplay { 138 CLDRFile cldrFile; 139 MyCurrencySymbolDisplay(CLDRFile cldrFile)140 public MyCurrencySymbolDisplay(CLDRFile cldrFile) { 141 this.cldrFile = cldrFile; 142 } 143 getName(Currency currency, int count)144 public String getName(Currency currency, int count) { 145 final String currencyCode = currency.getCurrencyCode(); 146 if (count > 1) { 147 return currencyCode; 148 } 149 String prefix = "//ldml/numbers/currencies/currency[@type=\"" + currencyCode + "\"]/"; 150 String currencySymbol = cldrFile.getWinningValue(prefix + "symbol"); 151 return currencySymbol != null ? currencySymbol : currencyCode; 152 } 153 } 154 155 } 156