blob: 0c14f1953662e1d3eca601af92bad0860768ed68 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2013, Google Inc. and International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package org.unicode.cldr.tool;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import org.unicode.cldr.util.CLDRConfig;
import org.unicode.cldr.util.Factory;
import org.unicode.cldr.util.Organization;
import org.unicode.cldr.util.PluralRanges;
import org.unicode.cldr.util.StandardCodes;
import org.unicode.cldr.util.SupplementalDataInfo;
import org.unicode.cldr.util.SupplementalDataInfo.PluralInfo.Count;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
import com.ibm.icu.text.PluralRules;
import com.ibm.icu.text.PluralRules.DecimalQuantitySamples;
import com.ibm.icu.text.PluralRules.DecimalQuantitySamplesRange;
import com.ibm.icu.text.PluralRules.PluralType;
import com.ibm.icu.text.PluralRules.SampleType;
/**
* Generate a spreadsheet that translators can use to pick the right plural range results,
* which we can then use to create the plural range rules.
* @author markdavis
*/
public class WritePluralRulesSpreadsheets {
// TODO rewrite to use Options, generate file instead of console.
public static String[] tests = { "or", "tk", "ps", "as", "sd" };
public static void main(String[] args) {
//writePluralChecklist(tests);
ranges();
}
static final SupplementalDataInfo supplemental = SupplementalDataInfo.getInstance();
static final Factory factory = ToolConfig.getToolInstance().getFullCldrFactory();
static final StandardCodes STD = StandardCodes.make();
private static void ranges() {
Multimap<Set<String>, String> missingMinimalPairs = HashMultimap.create();
System.out.println("Type\tCode\tName\tRange\tResult\tResult Example\tStart-Range Example\tEnd-Range Example");
Set<String> cldrLocales = // new TreeSet<>(Arrays.asList(tests));
new TreeSet<>(STD.getLocaleCoverageLocales(Organization.cldr));
cldrLocales.addAll(STD.getLocaleCoverageLocales(Organization.google));
cldrLocales.remove(StandardCodes.ALL_LOCALES); // '*' is not a real locale id.
writeRanges("Core", cldrLocales, missingMinimalPairs);
for (Entry<Set<String>, String> missing : missingMinimalPairs.entries()) {
Set<String> keywords = missing.getKey();
String locale = missing.getValue();
System.out.println("Missing Core\t" + getName(locale) + "\t" + keywords);
}
System.out.println();
missingMinimalPairs.clear();
TreeSet<String> localesWithPlurals = new TreeSet<>(supplemental.getPluralLocales(SupplementalDataInfo.PluralType.cardinal));
localesWithPlurals.removeAll(cldrLocales);
writeRanges("Other", localesWithPlurals, missingMinimalPairs);
for (Entry<Set<String>, String> missing : missingMinimalPairs.entries()) {
Set<String> keywords = missing.getKey();
String locale = missing.getValue();
System.out.println("Missing Other\t" + getName(locale) + "\t" + keywords);
}
}
private static void writePluralChecklist(String... locales) {
List<String> sampleStrings = Arrays.asList("0",
"0.1",
"0.2",
"0.9",
"1.9",
"1",
"1.0",
"1.2",
"2.0",
"2.1",
"0.00",
"0.01",
"0.10",
"0.11",
"0.02",
"1.00",
"1.10",
"1.11",
"1.02",
"2.00",
"2.01",
"2.9");
for (String locale : locales) {
if ("root".equals(locale) || locale.contains("_")) {
continue;
}
PluralRules rules = supplemental.getPlurals(locale).getPluralRules();
PluralMinimalPairs samplePatterns = PluralMinimalPairs.getInstance(locale);
if (samplePatterns.isEmpty(PluralType.CARDINAL)) {
continue;
}
Set<DecimalQuantity> samples = new TreeSet<>();
Set<String> keywords = rules.getKeywords();
// header
System.out.print(
locale
+ "\t" + "Number"
+ "\t" + "Cat."
+ "\t" + "Sample"
+ "\t" + "Replacement for Sample");
for (String keyword : keywords) {
System.out.print("\t" + Count.valueOf(keyword));
HashSet<Double> items = new HashSet<>(rules.getSamples(keyword, SampleType.INTEGER));
for (int i = 0; i < 5; ++i) {
items.add(i + 0d);
items.add(i + 10d);
items.add(i + 20d);
items.add(i + 100d);
items.add(i + 110d);
}
for (Double sample : items) {
DecimalQuantity fd = new DecimalQuantity_DualStorageBCD(sample);
samples.add(fd);
}
for (String sample : sampleStrings) {
DecimalQuantity dq = DecimalQuantity_DualStorageBCD.fromExponentString(sample);
samples.add(dq);
}
}
System.out.println();
for (DecimalQuantity number : samples) {
String cat = rules.select(number);
String sample = samplePatterns.get(PluralType.CARDINAL, Count.valueOf(cat));
System.out.print(
locale
+ "\t" + " " + number
+ "\t" + cat
+ "\t" + sample.replace("{0}", number.toString())
+ "\t" + "«replace if Sample wrong»");
for (String keyword : keywords) {
String sample2 = samplePatterns.get(PluralType.CARDINAL, Count.valueOf(keyword));
System.out.print("\t" + sample2.replace("{0}", number.toString()));
}
System.out.println();
}
System.out.println();
}
}
private static void writeRanges(String title, Set<String> locales, Multimap<Set<String>, String> missingMinimalPairs) {
for (String locale : locales) {
if ("root".equals(locale) || locale.contains("_")) {
continue;
}
PluralRules rules = supplemental.getPlurals(locale).getPluralRules();
String rangePattern;
try {
rangePattern = factory.make(locale, true).getStringValue("//ldml/numbers/miscPatterns[@numberSystem=\"latn\"]/pattern[@type=\"range\"]");
} catch (Exception e) {
missingMinimalPairs.put(rules.getKeywords(), locale);
continue;
}
PluralMinimalPairs samplePatterns = PluralMinimalPairs.getInstance(locale);
if (samplePatterns.isEmpty(PluralType.CARDINAL)) {
missingMinimalPairs.put(rules.getKeywords(), locale);
continue;
}
Set<String> keywords = rules.getKeywords();
PluralRanges pluralRanges = supplemental.getPluralRanges(locale);
for (String start : keywords) {
DecimalQuantity small = getSample(rules, start, null); // smallest
String startPattern = getSamplePattern(samplePatterns, start);
if (startPattern == null) {
throw new NullPointerException("no startPattern: get[Cardinal]SamplePattern(["+locale+"],"+start+") returned null"+
"- samplePatterns: " + samplePatterns.toString());
}
for (String end : keywords) {
DecimalQuantity large = getSample(rules, end, small); // smallest
if (large == null) {
continue;
}
String endPattern = getSamplePattern(samplePatterns, end);
if (endPattern == null) {
throw new NullPointerException("no endPattern: get[Cardinal]SamplePattern(["+locale+"],"+end+") returned null"+
"- samplePatterns: " + samplePatterns.toString());
}
String range = MessageFormat.format(rangePattern, small.toString(), large.toString());
Count rangeCount = pluralRanges == null ? null : pluralRanges.get(Count.valueOf(start), Count.valueOf(end));
String rangeCountPattern = rangeCount == null ? "<copy correct pattern>" : getSamplePattern(samplePatterns, rangeCount.toString());
System.out.println(title
+ "\t" + getName(locale)
+ "\t" + start + "—" + end
+ "\t" + (rangeCount == null ? "?" : rangeCount.toString())
+ "\t" + (rangeCountPattern.contains("{0}") ? rangeCountPattern.replace("{0}", range) : rangeCountPattern)
+ "\t" + (startPattern.contains("{0}") ? startPattern.replace("{0}", range) : "?")
+ "\t" + (endPattern.contains("{0}") ? endPattern.replace("{0}", range) : "?"));
}
}
System.out.println();
}
}
private static String getName(String missing) {
return missing + "\t" + CLDRConfig.getInstance().getEnglish().getName(missing);
}
private static String getSamplePattern(PluralMinimalPairs samplePatterns, String start) {
return samplePatterns.get(PluralType.CARDINAL, Count.valueOf(start));
}
private static DecimalQuantity getSample(PluralRules rules, String start, DecimalQuantity minimum) {
DecimalQuantity result = getSample(rules, start, SampleType.INTEGER, minimum);
DecimalQuantity result2 = getSample(rules, start, SampleType.DECIMAL, minimum);
if (result == null) {
return result2;
}
return result;
}
private static DecimalQuantity getSample(PluralRules rules, String start, SampleType sampleType, DecimalQuantity minimum) {
DecimalQuantitySamples samples = rules.getDecimalSamples(start, sampleType);
if (samples == null) {
return null;
}
Set<DecimalQuantitySamplesRange> samples2 = samples.getSamples();
if (samples2 == null) {
return null;
}
for (DecimalQuantitySamplesRange sample : samples2) {
if (minimum == null) {
return sample.start;
} else if (minimum.toDouble() < sample.start.toDouble()) {
return sample.start;
} else if (minimum.toDouble() < sample.end.toDouble()) {
return sample.end;
}
}
return null;
}
}