• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ShowPlurals()38     public ShowPlurals() {
39         supplementalDataInfo = CLDRConfig.getInstance().getSupplementalDataInfo();
40     }
41 
ShowPlurals(SupplementalDataInfo supplementalDataInfo)42     public ShowPlurals(SupplementalDataInfo supplementalDataInfo) {
43         this.supplementalDataInfo = supplementalDataInfo;
44     }
45 
printPlurals(CLDRFile english, String localeFilter, PrintWriter index, Factory factory)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 
appendBlanksForScrolling(final Appendable pw)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 
printPluralTable(CLDRFile english, String localeFilter, Appendable appendable, Factory factory)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 
getExamples(FixedDecimalSamples exampleList)223     private String getExamples(FixedDecimalSamples exampleList) {
224         return CollectionUtilities.join(exampleList.getSamples(), ", ") + (exampleList.bounded ? "" : ", …");
225     }
226 
getSample(FixedDecimal numb, String samplePattern, NumberFormat nf)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