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