• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.HashSet;
6 import java.util.Set;
7 
8 import com.google.common.collect.ImmutableSet;
9 import com.ibm.icu.text.PluralRules;
10 
11 public class PluralRulesUtil {
12     /**
13      * Status of the keyword for the rules, given a set of explicit values.
14      */
15     public enum KeywordStatus {
16         /**
17          * The keyword is not valid for the rules.
18          */
19         INVALID,
20         /**
21          * The keyword is valid, but unused (it is covered by the explicit values).
22          */
23         SUPPRESSED,
24         /**
25          * The keyword is valid and used, but completely covered by the explicit values.
26          */
27         UNIQUE,
28         /**
29          * The keyword is valid, used, not suppressed, and has a finite set of values.
30          */
31         BOUNDED,
32         /**
33          * The keyword is valid but not bounded; there are indefinitely many matching values.
34          */
35         UNBOUNDED
36     }
37 
38     /**
39      * Find the status for the keyword, given a certain set of explicit values.
40      *
41      * @param rules
42      *            the PluralRules
43      * @param keyword
44      *            the particular keyword (call rules.getKeywords() to get the valid ones)
45      * @param offset
46      *            the offset used, or 0.0d if not. Internally, the offset is subtracted from each explicit value before
47      *            checking against the keyword values.
48      * @param explicits
49      *            a set of Doubles that are used explicitly (eg [=0], "[=1]"). May be empty or null.
50      * @param integerOnly
51      *            In circumstances where the values are known to be integers, this parameter can be set to true.
52      *            Examples: "There are 3 people in..." (integerOnly=true) vs. "There are 1.2 people per household
53      *            (integerOnly=false).
54      *            This may produce different results in languages where fractions have the same format as integers for
55      *            some keywords.
56      * @return the KeywordStatus
57      *         <p>
58      *         NOTE: For testing, this is a static with the first parameter being the rules. Those will disappear.
59      */
getKeywordStatus(PluralRules rules, String keyword, int offset, Set<Double> explicits, boolean integerOnly)60     public static KeywordStatus getKeywordStatus(PluralRules rules, String keyword, int offset, Set<Double> explicits,
61         boolean integerOnly) {
62         if (!rules.getKeywords().contains(keyword)) {
63             return KeywordStatus.INVALID;
64         }
65         Collection<Double> values = rules.getAllKeywordValues(keyword);
66         if (values == null) {
67             return KeywordStatus.UNBOUNDED;
68         }
69         int originalSize = values.size();
70 
71         // Quick check on whether there are multiple elements
72 
73         if (explicits == null) {
74             explicits = Collections.emptySet();
75         }
76         if (originalSize > explicits.size()) {
77             return originalSize == 1 ? KeywordStatus.UNIQUE : KeywordStatus.BOUNDED;
78         }
79 
80         // Compute if the quick test is insufficient.
81 
82         HashSet<Double> subtractedSet = new HashSet<>(values);
83         for (Double explicit : explicits) {
84             // int rounded = (int) Math.round(explicit*1000000);
85             subtractedSet.remove(explicit - offset);
86         }
87         if (subtractedSet.size() == 0) {
88             return KeywordStatus.SUPPRESSED;
89         }
90 
91         return originalSize == 1 ? KeywordStatus.UNIQUE : KeywordStatus.BOUNDED;
92     }
93 
94     /**
95      * Locales where 'many' is optional. TODO get ICU to add a method that determines if a plural keyword's rule
96      * is only true if the compact operand is set.
97      */
98     public static final ImmutableSet<String> LOCALES_WITH_OPTIONAL_MANY = ImmutableSet.of("fr", "it", "es", "pt", "pt_PT");
99 
100     // static final Map<String,Set<String>> locale2keywords = new HashMap<String,Set<String>>();
101     // static final Map<String,PluralRules> locale2pluralRules = new HashMap<String,PluralRules>();
102     // static final Set<Double> explicits = new HashSet<Double>();
103     // static {
104     // explicits.add(0.0d);
105     // explicits.add(1.0d);
106     // }
107     // public static Set<String> getCanonicalKeywords(String locale) {
108     // synchronized (locale2keywords) {
109     // Set<String> result = locale2keywords.get(locale);
110     // if (result != null) {
111     // return result;
112     // }
113     // // special caching because locales don't differ
114     // int pos = locale.indexOf('_');
115     // String lang = pos < 0 ? locale : locale.substring(0,pos);
116     // if (pos >= 0) {
117     // result = locale2keywords.get(locale);
118     // if (result != null) {
119     // locale2keywords.put(locale, result);
120     // return result;
121     // }
122     // }
123     // PluralInfo pluralInfo = SupplementalDataInfo.getInstance().getPlurals(SupplementalDataInfo.PluralType.cardinal,
124     // lang);
125     // PluralRules pluralRules = PluralRules.createRules(pluralInfo.getRules());
126     // locale2pluralRules.put(lang, pluralRules);
127     // result = new HashSet();
128     // for (String keyword : pluralRules.getKeywords()) {
129     // KeywordStatus status = getKeywordStatus(pluralRules, keyword, 0, explicits, true);
130     // if (status != KeywordStatus.SUPPRESSED) {
131     // result.add(keyword);
132     // }
133     // }
134     // result = Collections.unmodifiableSet(result);
135     // locale2keywords.put(locale, result);
136     // if (pos >= 0) {
137     // locale2keywords.put(lang, result);
138     // }
139     // return result;
140     // }
141     //
142     // }
143 }
144