Home | History | Annotate | Download | only in tool
      1 package org.unicode.cldr.tool;
      2 
      3 import java.io.IOException;
      4 import java.io.PrintWriter;
      5 import java.util.LinkedHashSet;
      6 import java.util.List;
      7 import java.util.Set;
      8 
      9 import org.unicode.cldr.tool.GeneratePluralRanges.RangeSample;
     10 import org.unicode.cldr.util.CLDRConfig;
     11 import org.unicode.cldr.util.CLDRFile;
     12 import org.unicode.cldr.util.CLDRURLS;
     13 import org.unicode.cldr.util.CldrUtility;
     14 import org.unicode.cldr.util.Factory;
     15 import org.unicode.cldr.util.LanguageTagCanonicalizer;
     16 import org.unicode.cldr.util.PluralSnapshot;
     17 import org.unicode.cldr.util.SupplementalDataInfo;
     18 import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo;
     19 import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count;
     20 import org.unicode.cldr.util.SupplementalDataInfo.PluralType;
     21 
     22 import com.ibm.icu.dev.util.CollectionUtilities;
     23 import com.ibm.icu.impl.Utility;
     24 import com.ibm.icu.text.NumberFormat;
     25 import com.ibm.icu.text.PluralRules;
     26 import com.ibm.icu.text.PluralRules.FixedDecimal;
     27 import com.ibm.icu.text.PluralRules.FixedDecimalSamples;
     28 import com.ibm.icu.util.ICUUncheckedIOException;
     29 import com.ibm.icu.util.ULocale;
     30 
     31 public class ShowPlurals {
     32 
     33     private static final String NO_PLURAL_DIFFERENCES = "<i>no plural differences</i>";
     34     private static final String NOT_AVAILABLE = "<i>Not available.<br>Please <a target='_blank' href='" + CLDRURLS.CLDR_NEWTICKET_URL
     35         + "'>file a ticket</a> to supply.</i>";
     36     final SupplementalDataInfo supplementalDataInfo;
     37 
     38     public ShowPlurals() {
     39         supplementalDataInfo = CLDRConfig.getInstance().getSupplementalDataInfo();
     40     }
     41 
     42     public ShowPlurals(SupplementalDataInfo supplementalDataInfo) {
     43         this.supplementalDataInfo = supplementalDataInfo;
     44     }
     45 
     46     public void printPlurals(CLDRFile english, String localeFilter, PrintWriter index, Factory factory) throws IOException {
     47         String section1 = "Rules";
     48         String section2 = "Comparison";
     49 
     50         final String title = "Language Plural Rules";
     51         final PrintWriter pw = new PrintWriter(new FormattedFileWriter(null, title, null, ShowLanguages.SUPPLEMENTAL_INDEX_ANCHORS));
     52 
     53         pw.append("<div style='margin-right:2em; margin-left:2em'>\n");
     54         ShowLanguages.showContents(pw, "rules", "Rules", "comparison", "Comparison");
     55 
     56         pw.append("<h2>" + CldrUtility.getDoubleLinkedText("rules", "1. " + section1) + "</h2>" + System.lineSeparator());
     57         pw.append("<div style='margin-right:2em; margin-left:2em'>\n");
     58         printPluralTable(english, localeFilter, pw, factory);
     59         pw.append("</div>\n");
     60 
     61         pw.append("<h2>" + CldrUtility.getDoubleLinkedText("comparison", "2. " + section2) + "</h2>" + System.lineSeparator());
     62         pw.append("<p style='text-align:left'>The plural forms are abbreviated by first letter, with 'x' for 'other'. "
     63             +
     64             "If values are made redundant by explicit 0 and 1, they are underlined. " +
     65             "The fractional and integral results are separated for clarity.</p>" + System.lineSeparator());
     66         pw.append("<div style='margin-right:2em; margin-left:2em'>\n");
     67         PluralSnapshot.writeTables(english, pw);
     68         pw.append("</div>\n");
     69         pw.append("</div>\n");
     70         appendBlanksForScrolling(pw);
     71         pw.close();
     72     }
     73 
     74     public void appendBlanksForScrolling(final Appendable pw) {
     75         try {
     76             pw.append(Utility.repeat("<br>", 100)).append(System.lineSeparator());
     77         } catch (IOException e) {
     78             throw new ICUUncheckedIOException(e);
     79         }
     80     }
     81 
     82     public void printPluralTable(CLDRFile english, String localeFilter,
     83         Appendable appendable, Factory factory) throws IOException {
     84 
     85         final TablePrinter tablePrinter = new TablePrinter()
     86             .setTableAttributes("class='dtf-table'")
     87             .addColumn("Name", "class='source'", null, "class='source'", true).setSortPriority(0).setHeaderAttributes("class='dtf-th'")
     88             .setCellAttributes("class='dtf-s'")
     89             .setBreakSpans(true).setRepeatHeader(true)
     90             .addColumn("Code", "class='source'", CldrUtility.getDoubleLinkMsg(), "class='source'", true).setHeaderAttributes("class='dtf-th'")
     91             .setCellAttributes("class='dtf-s'")
     92             .addColumn("Type", "class='source'", null, "class='source'", true).setHeaderAttributes("class='dtf-th'").setCellAttributes("class='dtf-s'")
     93             .setBreakSpans(true)
     94             .addColumn("Category", "class='target'", null, "class='target'", true).setHeaderAttributes("class='dtf-th'").setCellAttributes("class='dtf-s'")
     95             .setSpanRows(false)
     96             .addColumn("Examples", "class='target'", null, "class='target'", true).setHeaderAttributes("class='dtf-th'").setCellAttributes("class='dtf-s'")
     97             .addColumn("Minimal Pairs", "class='target'", null, "class='target'", true).setHeaderAttributes("class='dtf-th'").setCellAttributes("class='dtf-s'")
     98             .addColumn("Rules", "class='target'", null, "class='target' nowrap", true).setHeaderAttributes("class='dtf-th'").setCellAttributes("class='dtf-s'")
     99             .setSpanRows(false);
    100         PluralRulesFactory prf = PluralRulesFactory.getInstance(supplementalDataInfo);
    101         //Map<ULocale, PluralRulesFactory.SamplePatterns> samples = PluralRulesFactory.getLocaleToSamplePatterns();
    102         Set<String> cardinalLocales = supplementalDataInfo.getPluralLocales(PluralType.cardinal);
    103         Set<String> ordinalLocales = supplementalDataInfo.getPluralLocales(PluralType.ordinal);
    104         Set<String> all = new LinkedHashSet<String>(cardinalLocales);
    105         all.addAll(ordinalLocales);
    106 
    107         LanguageTagCanonicalizer canonicalizer = new LanguageTagCanonicalizer();
    108 
    109         for (String locale : supplementalDataInfo.getPluralLocales()) {
    110             if (localeFilter != null && !localeFilter.equals(locale) || locale.equals("root")) {
    111                 continue;
    112             }
    113             final String name = english.getName(locale);
    114             String canonicalLocale = canonicalizer.transform(locale);
    115             if (!locale.equals(canonicalLocale)) {
    116                 String redirect = "<i>=<a href='#" + canonicalLocale + "'>" + canonicalLocale + "</a></i>";
    117                 tablePrinter.addRow()
    118                     .addCell(name)
    119                     .addCell(locale)
    120                     .addCell(redirect)
    121                     .addCell(redirect)
    122                     .addCell(redirect)
    123                     .addCell(redirect)
    124                     .addCell(redirect)
    125                     .finishRow();
    126                 continue;
    127             }
    128 
    129             for (PluralType pluralType : PluralType.values()) {
    130                 if (pluralType == PluralType.ordinal && !ordinalLocales.contains(locale)
    131                     || pluralType == PluralType.cardinal && !cardinalLocales.contains(locale)) {
    132                     continue;
    133                 }
    134                 final PluralInfo plurals = supplementalDataInfo.getPlurals(pluralType, locale);
    135                 ULocale locale2 = new ULocale(locale);
    136                 final PluralMinimalPairs samplePatterns = PluralMinimalPairs.getInstance(locale2.toString());
    137                 //                    pluralType == PluralType.ordinal ? null
    138                 //                    : CldrUtility.get(samples, locale2);
    139                 NumberFormat nf = NumberFormat.getInstance(locale2);
    140 
    141                 String rules = plurals.getRules();
    142                 rules += rules.length() == 0 ? "other:<i>everything</i>" : ";other:<i>everything else</i>";
    143                 rules = rules.replace(":", "  ").replace(";", ";<br>");
    144                 PluralRules pluralRules = plurals.getPluralRules();
    145                 //final Map<PluralInfo.Count, String> typeToExamples = plurals.getCountToStringExamplesMap();
    146                 //final String examples = typeToExamples.get(type).toString().replace(";", ";<br>");
    147                 Set<Count> counts = plurals.getCounts();
    148                 for (PluralInfo.Count count : counts) {
    149                     String keyword = count.toString();
    150                     FixedDecimalSamples exampleList = pluralRules.getDecimalSamples(keyword, PluralRules.SampleType.INTEGER); // plurals.getSamples9999(count);
    151                     FixedDecimalSamples exampleList2 = pluralRules.getDecimalSamples(keyword, PluralRules.SampleType.DECIMAL);
    152                     if (exampleList == null) {
    153                         exampleList = exampleList2;
    154                         exampleList2 = null;
    155                     }
    156                     String examples = getExamples(exampleList);
    157                     if (exampleList2 != null) {
    158                         examples += "<br>" + getExamples(exampleList2);
    159                     }
    160                     String rule = pluralRules.getRules(keyword);
    161                     rule = rule != null ? rule.replace(":", "  ")
    162                         .replace(" and ", " and<br>&nbsp;&nbsp;")
    163                         .replace(" or ", " or<br>")
    164                         : counts.size() == 1 ? "<i>everything</i>"
    165                             : "<i>everything else</i>";
    166 
    167                     String sample = counts.size() == 1 ? NO_PLURAL_DIFFERENCES : NOT_AVAILABLE;
    168                     if (samplePatterns != null) {
    169                         String samplePattern = samplePatterns.get(pluralType.standardType, Count.valueOf(keyword)); // CldrUtility.get(samplePatterns.keywordToPattern, Count.valueOf(keyword));
    170                         if (samplePattern != null) {
    171                             FixedDecimal sampleDecimal = PluralInfo.getNonZeroSampleIfPossible(exampleList);
    172                             sample = getSample(sampleDecimal, samplePattern, nf);
    173                             if (exampleList2 != null) {
    174                                 sampleDecimal = PluralInfo.getNonZeroSampleIfPossible(exampleList2);
    175                                 sample += "<br>" + getSample(sampleDecimal, samplePattern, nf);
    176                             }
    177                         }
    178                     }
    179                     tablePrinter.addRow()
    180                         .addCell(name)
    181                         .addCell(locale)
    182                         .addCell(pluralType.toString())
    183                         .addCell(count.toString())
    184                         .addCell(examples.toString())
    185                         .addCell(sample)
    186                         .addCell(rule)
    187                         .finishRow();
    188                 }
    189             }
    190             List<RangeSample> rangeInfoList = null;
    191             try {
    192                 rangeInfoList = new GeneratePluralRanges(supplementalDataInfo).getRangeInfo(factory.make(locale, true));
    193             } catch (Exception e) {
    194             }
    195             if (rangeInfoList != null) {
    196                 for (RangeSample item : rangeInfoList) {
    197                     tablePrinter.addRow()
    198                         .addCell(name)
    199                         .addCell(locale)
    200                         .addCell("range")
    201                         .addCell(item.start + "+" + item.end)
    202                         .addCell(item.min + "" + item.max)
    203                         .addCell(item.resultExample.replace(". ", ".<br>"))
    204                         .addCell(item.start + " + " + item.end + "  " + item.result)
    205                         .finishRow();
    206                 }
    207             } else {
    208                 String message = supplementalDataInfo.getPlurals(PluralType.cardinal, locale).getCounts().size() == 1 ? NO_PLURAL_DIFFERENCES : NOT_AVAILABLE;
    209                 tablePrinter.addRow()
    210                     .addCell(name)
    211                     .addCell(locale)
    212                     .addCell("range")
    213                     .addCell("<i>n/a</i>")
    214                     .addCell("<i>n/a</i>")
    215                     .addCell(message)
    216                     .addCell("<i>n/a</i>")
    217                     .finishRow();
    218             }
    219         }
    220         appendable.append(tablePrinter.toTable()).append(System.lineSeparator());
    221     }
    222 
    223     private String getExamples(FixedDecimalSamples exampleList) {
    224         return CollectionUtilities.join(exampleList.getSamples(), ", ") + (exampleList.bounded ? "" : ", ");
    225     }
    226 
    227     private String getSample(FixedDecimal numb, String samplePattern, NumberFormat nf) {
    228         String sample;
    229         nf.setMaximumFractionDigits(numb.getVisibleDecimalDigitCount());
    230         nf.setMinimumFractionDigits(numb.getVisibleDecimalDigitCount());
    231         sample = samplePattern
    232             .replace('\u00A0', '\u0020')
    233             .replace("{0}", nf.format(numb.getSource()))
    234             .replace(". ", ".<br>");
    235         return sample;
    236     }
    237 
    238 }
    239