Home | History | Annotate | Download | only in test
      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.regex.Pattern;
      9 
     10 import org.unicode.cldr.util.CLDRFile;
     11 import org.unicode.cldr.util.ICUServiceBuilder;
     12 import org.unicode.cldr.util.PatternCache;
     13 import org.unicode.cldr.util.SupplementalDataInfo;
     14 import org.unicode.cldr.util.XPathParts;
     15 
     16 import com.ibm.icu.impl.number.DecimalFormatProperties;
     17 import com.ibm.icu.text.CompactDecimalFormat;
     18 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
     19 import com.ibm.icu.text.DecimalFormat.PropertySetter;
     20 import com.ibm.icu.util.Currency;
     21 import com.ibm.icu.util.ULocale;
     22 
     23 @SuppressWarnings("deprecation")
     24 public class BuildIcuCompactDecimalFormat {
     25     private static boolean DEBUG = false;
     26     static SupplementalDataInfo sdi = SupplementalDataInfo.getInstance();
     27     static final int MINIMUM_ARRAY_LENGTH = 15;
     28     static final Pattern PATTERN = PatternCache.get("([^0,]*)([0]+)([.]0+)?([^0]*)");
     29     static final Pattern TYPE = PatternCache.get("1([0]*)");
     30 
     31     public enum CurrencyStyle {
     32         PLAIN, CURRENCY, LONG_CURRENCY, ISO_CURRENCY, UNIT
     33     }
     34 
     35     /**
     36      * JUST FOR DEVELOPMENT
     37      *
     38      * @param currencyStyle
     39      * @param currencyCode
     40      */
     41     public static final CompactDecimalFormat build(CLDRFile resolvedCldrFile,
     42         Set<String> debugCreationErrors, String[] debugOriginals,
     43         CompactStyle style, ULocale locale, CurrencyStyle currencyStyle, String currencyCodeOrUnit) {
     44 
     45         final Map<String, Map<String, String>> customData = new HashMap<String, Map<String, String>>();
     46 //        Map<String,String> inner = new HashMap<String,String>();
     47 //        inner.put("one", "0 qwerty");
     48 //        inner.put("other", "0 dvorak");
     49 //        customData.put("1000", inner);
     50 
     51 //        Map<String, String[][]> affixes = new HashMap<String, String[][]>();
     52 //        Map<String, String[]> unitPrefixes = new HashMap<String, String[]>();
     53 //
     54 //        // String[] prefix = new String[CompactDecimalFormat.MINIMUM_ARRAY_LENGTH];
     55 //        // String[] suffix = new String[CompactDecimalFormat.MINIMUM_ARRAY_LENGTH];
     56 //        long[] divisor = new long[MINIMUM_ARRAY_LENGTH];
     57 //        // get the pattern details from the locale
     58 //        PluralInfo pluralInfo = sdi.getPlurals(PluralType.cardinal, locale.toString());
     59 //
     60 //        // fix low numbers
     61 //        Set<String> canonicalKeywords = pluralInfo.getCanonicalKeywords();
     62 //        for (String key : canonicalKeywords) {
     63 //            String[][] affix = new String[MINIMUM_ARRAY_LENGTH][];
     64 //            for (int i = 0; i < 3; ++i) {
     65 //                affix[i] = new String[] { "", "" };
     66 //                divisor[i] = 1;
     67 //            }
     68 //            affixes.put(key, affix);
     69 //        }
     70 //        Matcher patternMatcher = PATTERN.matcher("");
     71 //        Matcher typeMatcher = TYPE.matcher("");
     72 //        XPathParts parts = new XPathParts();
     73         // for (String path :
     74         // With.in(resolvedCldrFile.iterator("//ldml/numbers/decimalFormats/decimalFormatLength[@type=\"short\"]/decimalFormat[@type=\"standard\"]/")))
     75         // {
     76         String prefix = currencyStyle == CurrencyStyle.PLAIN ? "//ldml/numbers/decimalFormats[@numberSystem=\"latn\"]/decimalFormatLength"
     77             : "//ldml/numbers/currencyFormats[@numberSystem=\"latn\"]/currencyFormatLength";
     78 
     79         Iterator<String> it = resolvedCldrFile.iterator(prefix);
     80 
     81         String styleString = style.toString().toLowerCase(Locale.ENGLISH);
     82         while (it.hasNext()) {
     83             String path = it.next();
     84             if (path.endsWith("/alias")) {
     85                 continue;
     86             }
     87             // String sourceLocale = resolvedCldrFile.getSourceLocaleID(path, null);
     88             // if ("root".equals(sourceLocale)) {
     89             // continue;
     90             // }
     91             // if (!path.contains("decimalFormatLength")) {
     92             // continue;
     93             // }
     94             XPathParts parts = XPathParts.getFrozenInstance(path);
     95             String stype = parts.getAttributeValue(3, "type");
     96             if (!styleString.equals(stype)) {
     97                 continue;
     98             }
     99             String type = parts.getAttributeValue(-1, "type");
    100             String key = parts.getAttributeValue(-1, "count");
    101             String pattern = resolvedCldrFile.getStringValue(path);
    102 
    103             /*
    104                     <pattern type="1000" count="one">0K</pattern>
    105              */
    106 
    107             add(customData, type, key, pattern);
    108 
    109 //            if (DEBUG && path.contains("miliony")) {
    110 //                System.out.println(key + ", " + path);
    111 //            }
    112 //            String[][] affix = affixes.get(key);
    113 //
    114 //            if (!typeMatcher.reset(type).matches()) {
    115 //                debugCreationErrors.add("type (" + type +
    116 //                    ") doesn't match expected " + TYPE.pattern());
    117 //                continue;
    118 //            }
    119 //
    120 //            String pattern = resolvedCldrFile.getStringValue(path);
    121 //
    122 //            int typeZeroCount = typeMatcher.end(1) - typeMatcher.start(1);
    123 //            // for debugging
    124 //            if (debugOriginals != null) {
    125 //                debugOriginals[typeZeroCount] = pattern;
    126 //            }
    127 //
    128 //            // special pattern for unused
    129 //            if (pattern.equals("0")) {
    130 //                affix[typeZeroCount] = new String[] { "", "" };
    131 //                divisor[typeZeroCount] = 1;
    132 //                continue;
    133 //            }
    134 //
    135 //            if (!patternMatcher.reset(pattern).matches()) {
    136 //                debugCreationErrors.add("pattern (" + pattern +
    137 //                    ") doesn't match expected " + PATTERN.pattern());
    138 //                continue;
    139 //            }
    140 //
    141 //            // HACK '.' just in case.
    142 //            affix[typeZeroCount] = new String[] {
    143 //                escape(patternMatcher.group(1).replace("'.'", ".")),
    144 //                escape(patternMatcher.group(4).replace("'.'", "."))
    145 //
    146 ////                patternMatcher.group(1).replace("'.'", "."),
    147 ////                patternMatcher.group(4).replace("'.'", ".")
    148 //                };
    149 //            if (DEBUG && key.equals("one")) {
    150 //                System.out.println(key + ", " + typeZeroCount + ", " + Arrays.asList(affix[typeZeroCount]));
    151 //            }
    152 //            int zeroCount = patternMatcher.end(2) - patternMatcher.start(2) - 1;
    153 //            divisor[typeZeroCount] = (long) Math.pow(10.0, typeZeroCount - zeroCount);
    154         }
    155 
    156         // DecimalFormat format = (DecimalFormat) (currencyStyle == CurrencyStyle.PLAIN
    157         // ? NumberFormat.getInstance(new ULocale(resolvedCldrFile.getLocaleID()))
    158         // : NumberFormat.getCurrencyInstance(new ULocale(resolvedCldrFile.getLocaleID())));
    159 
    160 //        ICUServiceBuilder builder = new ICUServiceBuilder().setCldrFile(resolvedCldrFile);
    161 ////        final DecimalFormat format = builder.getNumberFormat(1);
    162 //        switch (currencyStyle) {
    163 //        case PLAIN:
    164 //        default:
    165 //            break;
    166 //        case LONG_CURRENCY:
    167 //            // if the long form, modify the patterns
    168 //            CurrencyInfo names = new CurrencyInfo(resolvedCldrFile, canonicalKeywords,
    169 //                currencyCodeOrUnit, parts);
    170 //            if (!names.isEmpty()) {
    171 //                for (String count : canonicalKeywords) {
    172 //                    String unitPattern = names.getUnitPattern(count);
    173 //                    int pos = unitPattern.indexOf("{0}");
    174 //                    String prefixUnit = unitPattern.substring(0, pos);
    175 //                    String suffixUnit = unitPattern.substring(pos + 3);
    176 //                    String currencyName = names.getCurrencyName(count);
    177 //                    addPrefixSuffixInfo(unitPrefixes, count,
    178 //                        MessageFormat.format(prefixUnit, null, currencyName),
    179 //                        MessageFormat.format(suffixUnit, null, currencyName));
    180 //                }
    181 //                break;
    182 //            }
    183 //            // otherwise fallthru
    184 //        case CURRENCY:
    185 //            DecimalFormat format2 = builder.getCurrencyFormat(currencyCodeOrUnit);
    186 //            String prefix1 = format2.getPositivePrefix();
    187 //            String suffix2 = format2.getPositiveSuffix();
    188 //            for (String count : canonicalKeywords) {
    189 //                addPrefixSuffixInfo(unitPrefixes, count, prefix1, suffix2);
    190 //            }
    191 //            break;
    192 //        case ISO_CURRENCY:
    193 //            throw new IllegalArgumentException();
    194 //        case UNIT:
    195 //            String unit = currencyCodeOrUnit == null ? "mass-kilogram" : currencyCodeOrUnit;
    196 //            String otherValue = getUnitString(resolvedCldrFile, unit, "other");
    197 //            for (String count : canonicalKeywords) {
    198 //                String value = getUnitString(resolvedCldrFile, unit, count);
    199 //                if (value == null) {
    200 //                    value = otherValue;
    201 //                }
    202 //                int pos = value.indexOf("{0}");
    203 //                addPrefixSuffixInfo(unitPrefixes, count, value.substring(0, pos), value.substring(pos + 3));
    204 //            }
    205 //            break;
    206 //        }
    207 
    208         // DecimalFormat currencyFormat = new
    209         // ICUServiceBuilder().setCldrFile(resolvedCldrFile).getCurrencyFormat("USD");
    210         // for (String s : With.in(resolvedCldrFile.iterator("//ldml/numbers/currencyFormats/"))) {
    211         // System.out.println(s + "\t" + resolvedCldrFile.getStringValue(s));
    212         // }
    213         // DecimalFormat currencyFormat = new DecimalFormat(pattern);
    214         // do this by hand, because the DecimalFormat pattern parser does too much.
    215         // String pattern =
    216         // resolvedCldrFile.getWinningValue("//ldml/numbers/currencyFormats/currencyFormatLength/currencyFormat[@type=\"standard\"]/pattern[@type=\""
    217         // +
    218         // "standard" +
    219         // "\"]");
    220         // String[] currencyAffixes = new String[CompactDecimalFormat.AFFIX_SIZE];
    221         // String[] patterns = pattern.split(";");
    222         // final Matcher matcher = CURRENCY_PATTERN.matcher(patterns[0]);
    223         // if (!matcher.matches()) {
    224         // throw new IllegalArgumentException("Can't match currency pattern");
    225         // }
    226         // currencyAffixes[CompactDecimalFormat.POSITIVE_PREFIX] = matcher.group(1);
    227         // currencyAffixes[CompactDecimalFormat.POSITIVE_SUFFIX] = matcher.group(2);
    228         //
    229 //        if (DEBUG) {
    230 //            for (Entry<String, String[][]> keyList : affixes.entrySet()) {
    231 //                System.out.println("*\t" + keyList.getKey() + "\t" + CldrUtility.toString(keyList));
    232 //            }
    233 //        }
    234 
    235         // TODO fix to get right symbol for the count
    236         // String pattern = format.toPattern();
    237 
    238         // if (style == Style.LONG) {
    239         // pattern = pattern.replace("", "");
    240         // }
    241 
    242         // JCE 2017-03-28 - This constructor was removed in ICU 59.  Shane is working on a
    243         // workaround, but until one is done, we can't use it in its current state.
    244         // TODO: Put it back once the fix is in place, See Ticket #10166
    245         //        try {
    246 //            return new CompactDecimalFormat(
    247 //                pattern, format.getDecimalFormatSymbols(),
    248 //                style, pluralInfo.getPluralRules(),
    249 //                divisor, affixes, unitPrefixes,
    250 //                debugCreationErrors);
    251 //        } catch (Exception e) {
    252 //            debugCreationErrors.add(e.getMessage());
    253 //            return null;
    254 
    255         CompactDecimalFormat cdf = CompactDecimalFormat.getInstance(locale, style);
    256         ICUServiceBuilder builder = new ICUServiceBuilder().setCldrFile(resolvedCldrFile);
    257 
    258         cdf.setDecimalFormatSymbols(builder.getDecimalFormatSymbols("latn"));
    259         cdf.setProperties(new PropertySetter() {
    260             @Override
    261             public void set(DecimalFormatProperties props) {
    262                 props.setCompactCustomData(customData);
    263             }
    264         });
    265         return cdf;
    266 
    267 //        debugCreationErrors.add("Can't create due to lack of 'from scratch' constructor for CompactDecimalFormat");
    268 //        return null;
    269 //        }
    270         /*
    271          *                 divisor, prefixes, suffixes,
    272             unitPrefixes, unitSuffixes,
    273             currencyAffixes, new CompactDecimalFormatTest.MyCurrencySymbolDisplay(resolvedCldrFile),
    274             debugCreationErrors
    275 
    276          */
    277         //        CompactDecimalFormat cdf = new CompactDecimalFormat(
    278         //                "#,###.00",
    279         //                DecimalFormatSymbols.getInstance(new ULocale("fr")),
    280         //                CompactStyle.SHORT, PluralRules.createRules("one: j is 1 or f is 1"),
    281         //                divisors, affixes, null,
    282         //                debugCreationErrors
    283         //                );
    284 
    285     }
    286 
    287     private static <A, B, C> void add(Map<A, Map<B, C>> customData, A a, B b, C c) {
    288         Map<B, C> inner = customData.get(a);
    289         if (inner == null) {
    290             customData.put(a, inner = new HashMap<>());
    291         }
    292         inner.put(b, c);
    293     }
    294 
    295     private static String[] addPrefixSuffixInfo(Map<String, String[]> unitPrefixes, String count,
    296         final String prefix, final String suffix) {
    297         return unitPrefixes.put(count, new String[] { escape(prefix), escape(suffix) });
    298     }
    299 
    300     private static String escape(String prefix) {
    301         return prefix.isEmpty() ? prefix : "'" + prefix.replace("'", "''") + "'";
    302     }
    303 
    304     private static String getUnitString(CLDRFile resolvedCldrFile, String unit, String count) {
    305         return resolvedCldrFile.getStringValue("//ldml/units/unitLength[@type=\"short\"]/unit[@type=\""
    306             + unit + "\"]/unitPattern[@count=\"" +
    307             count +
    308             "\"]");
    309     }
    310 
    311     private static class CurrencyInfo {
    312         private HashMap<String, String> currencyNames = new HashMap<String, String>();
    313         private HashMap<String, String> unitPatterns = new HashMap<String, String>();
    314 
    315         CurrencyInfo(CLDRFile resolvedCldrFile, Set<String> canonicalKeywords, String currencyCode, XPathParts parts) {
    316             Iterator<String> it;
    317             it = resolvedCldrFile.iterator(
    318                 "//ldml/numbers/currencies/currency[@type=\"" +
    319                     currencyCode +
    320                     "\"]/displayName");
    321             // //ldml/numbers/currencies/currency[@type="SRD"]/symbol
    322             while (it.hasNext()) {
    323                 String path = it.next();
    324                 parts.set(path);
    325                 String key = parts.getAttributeValue(-1, "count");
    326                 if (key == null) {
    327                     key = "default";
    328                 }
    329                 currencyNames.put(key, resolvedCldrFile.getStringValue(path));
    330             }
    331 
    332             it = resolvedCldrFile.iterator(
    333                 "//ldml/numbers/currencyFormats/unitPattern");
    334             while (it.hasNext()) {
    335                 String path = it.next();
    336                 parts.set(path);
    337                 String key = parts.getAttributeValue(-1, "count");
    338                 unitPatterns.put(key, resolvedCldrFile.getStringValue(path));
    339             }
    340             // <displayName count="one" draft="contributed">evro</displayName>
    341             // flesh out missing
    342         }
    343 
    344         public boolean isEmpty() {
    345             return currencyNames.isEmpty();
    346         }
    347 
    348         String getUnitPattern(String count) {
    349             String result = unitPatterns.get(count);
    350             if (result == null) {
    351                 result = unitPatterns.get("other");
    352             }
    353             return result;
    354         }
    355 
    356         String getCurrencyName(String count) {
    357             String result = currencyNames.get(count);
    358             if (result != null) {
    359                 return result;
    360             }
    361             if (!count.equals("other")) {
    362                 result = currencyNames.get("other");
    363                 if (result != null) {
    364                     return result;
    365                 }
    366             }
    367             result = currencyNames.get("default");
    368             return result;
    369         }
    370     }
    371 
    372     // <currencyFormats numberSystem="latn">
    373     // <currencyFormatLength>
    374     // <currencyFormat>
    375     // <pattern>#,##0.00;(#,##0.00)</pattern>
    376     // </currencyFormat>
    377     // </currencyFormatLength>
    378     // <unitPattern count="one">{0} {1}</unitPattern>
    379     // <unitPattern count="other">{0} {1}</unitPattern>
    380     // </currencyFormats>
    381 
    382     static class MyCurrencySymbolDisplay {
    383         CLDRFile cldrFile;
    384 
    385         public MyCurrencySymbolDisplay(CLDRFile cldrFile) {
    386             this.cldrFile = cldrFile;
    387         }
    388 
    389         public String getName(Currency currency, int count) {
    390             final String currencyCode = currency.getCurrencyCode();
    391             if (count > 1) {
    392                 return currencyCode;
    393             }
    394             String prefix = "//ldml/numbers/currencies/currency[@type=\"" + currencyCode + "\"]/";
    395             String currencySymbol = cldrFile.getWinningValue(prefix + "symbol");
    396             return currencySymbol != null ? currencySymbol : currencyCode;
    397         }
    398     };
    399 
    400 }
    401