• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.tool;
2 
3 import java.util.Arrays;
4 import java.util.Collections;
5 import java.util.Date;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.TreeSet;
11 
12 import org.unicode.cldr.util.Builder;
13 import org.unicode.cldr.util.LanguageTagParser;
14 import org.unicode.cldr.util.LanguageTagParser.OutputOption;
15 import org.unicode.cldr.util.SupplementalDataInfo;
16 import org.unicode.cldr.util.SupplementalDataInfo.BasicLanguageData;
17 import org.unicode.cldr.util.SupplementalDataInfo.BasicLanguageData.Type;
18 import org.unicode.cldr.util.SupplementalDataInfo.CurrencyDateInfo;
19 import org.unicode.cldr.util.SupplementalDataInfo.PopulationData;
20 
21 import com.ibm.icu.impl.Row;
22 import com.ibm.icu.impl.Row.R2;
23 
24 public class LikelySubtags {
25     static final boolean DEBUG = true;
26     static final String TAG_SEPARATOR = "_";
27 
28     private Map<String, String> toMaximized;
29     private boolean favorRegion = false;
30     private static SupplementalDataInfo supplementalDataInfo;
31     private static Map<String, String> currencyToLikelyTerritory;
32     private static final Object SYNC = new Object();
33 
34     /**
35      * Create the likely subtags.
36      *
37      * @param toMaximized
38      */
LikelySubtags(Map<String, String> toMaximized)39     public LikelySubtags(Map<String, String> toMaximized) {
40         loadStaticVariables();
41         if (this.toMaximized == null) {
42             this.toMaximized = supplementalDataInfo.getLikelySubtags();
43         } else {
44             this.toMaximized = toMaximized;
45         }
46     }
47 
loadStaticVariables()48     private static void loadStaticVariables() {
49         if (supplementalDataInfo != null && currencyToLikelyTerritory != null) {
50             return;
51         }
52         synchronized(SYNC) {
53             supplementalDataInfo = SupplementalDataInfo.getInstance();
54             currencyToLikelyTerritory = new HashMap<>();
55             Date now = new Date();
56             Set<Row.R2<Double, String>> sorted = new TreeSet<>();
57             for (String territory : supplementalDataInfo.getTerritoriesWithPopulationData()) {
58                 PopulationData pop = supplementalDataInfo.getPopulationDataForTerritory(territory);
59                 double population = pop.getPopulation();
60                 sorted.add(Row.of(-population, territory));
61             }
62             for (R2<Double, String> item : sorted) {
63                 String territory = item.get1();
64                 Set<CurrencyDateInfo> targetCurrencyInfo = supplementalDataInfo.getCurrencyDateInfo(territory);
65                 if (targetCurrencyInfo == null) {
66                     continue;
67                 }
68                 for (CurrencyDateInfo cdi : targetCurrencyInfo) {
69                     String currency = cdi.getCurrency();
70                     if (!currencyToLikelyTerritory.containsKey(currency) && cdi.getStart().before(now)
71                         && cdi.getEnd().after(now) && cdi.isLegalTender()) {
72                         currencyToLikelyTerritory.put(currency, territory);
73                     }
74                 }
75             }
76         }
77     }
78 
79     /**
80      * Create the likely subtags.
81      *
82      * @param toMaximized
83      */
LikelySubtags()84     public LikelySubtags() {
85         this(null);
86     }
87 
isFavorRegion()88     public boolean isFavorRegion() {
89         return favorRegion;
90     }
91 
setFavorRegion(boolean favorRegion)92     public LikelySubtags setFavorRegion(boolean favorRegion) {
93         this.favorRegion = favorRegion;
94         return this;
95     }
96 
getToMaximized()97     public Map<String, String> getToMaximized() {
98         return toMaximized;
99     }
100 
setToMaximized(Map<String, String> toMaximized)101     public LikelySubtags setToMaximized(Map<String, String> toMaximized) {
102         this.toMaximized = toMaximized;
103         return this;
104     }
105 
maximize(String languageTag, Map<String, String> toMaximized)106     public static String maximize(String languageTag, Map<String, String> toMaximized) {
107         return new LikelySubtags(toMaximized).maximize(languageTag);
108     }
109 
minimize(String input, Map<String, String> toMaximized, boolean favorRegion)110     public static String minimize(String input, Map<String, String> toMaximized, boolean favorRegion) {
111         return new LikelySubtags(toMaximized).setFavorRegion(favorRegion).minimize(input);
112     }
113 
114     // TODO Old, crufty code, needs reworking.
maximize(String languageTag)115     public synchronized String maximize(String languageTag) {
116         if (languageTag == null) {
117             return null;
118         }
119         LanguageTagParser ltp = new LanguageTagParser();
120         if (DEBUG && languageTag.equals("es" + TAG_SEPARATOR + "Hans" + TAG_SEPARATOR + "CN")) {
121             System.out.print(""); // debug
122         }
123         // clean up the input by removing Zzzz, ZZ, and changing "" into und.
124         ltp.set(languageTag);
125         return maximize(ltp);
126     }
127 
maximize(LanguageTagParser ltp)128     private String maximize(LanguageTagParser ltp) {
129         String language = ltp.getLanguage();
130         String region = ltp.getRegion();
131         String script = ltp.getScript();
132         List<String> variants = ltp.getVariants();
133         Map<String, String> extensions = ltp.getExtensions();
134         Map<String, String> localeExtensions = ltp.getLocaleExtensions();
135 
136         if (language.equals("")) {
137             ltp.setLanguage(language = "und");
138         }
139         if (script.equals("Zzzz")) {
140             ltp.setScript(script = "");
141         }
142         if (region.equals("ZZ")) {
143             ltp.setRegion(region = "");
144         }
145         if (variants.size() != 0) {
146             ltp.setVariants(Collections.<String> emptySet());
147         }
148         if (extensions.size() != 0) {
149             ltp.setExtensions(Collections.<String, String> emptyMap());
150         }
151         if (localeExtensions.size() != 0) {
152             ltp.setExtensions(Collections.<String, String> emptyMap());
153         }
154 
155         // check whole
156         String result = toMaximized.get(ltp.toString());
157         if (result != null) {
158             return ltp.set(result)
159                 .setVariants(variants)
160                 .setExtensions(extensions)
161                 .setLocaleExtensions(localeExtensions)
162                 .toString();
163         }
164 
165         boolean noLanguage = language.equals("und");
166         boolean noScript = script.isEmpty();
167         boolean noRegion = region.isEmpty();
168 
169         // not efficient, but simple to match spec.
170         for (String region2 : noRegion ? Arrays.asList(region) : Arrays.asList(region, "")) {
171             ltp.setRegion(region2);
172             for (String script2 : noScript ? Arrays.asList(script) : Arrays.asList(script, "")) {
173                 ltp.setScript(script2);
174 
175                 result = toMaximized.get(ltp.toString());
176                 if (result != null) {
177                     ltp.set(result);
178                     if (!noLanguage) {
179                         ltp.setLanguage(language);
180                     }
181                     if (!noScript) {
182                         ltp.setScript(script);
183                     }
184                     if (!noRegion) {
185                         ltp.setRegion(region);
186                     }
187                     return ltp.setVariants(variants)
188                         .setExtensions(extensions)
189                         .setLocaleExtensions(localeExtensions)
190                         .toString();
191                 }
192             }
193         }
194 
195         // now check und_script
196         if (!noScript) {
197             ltp.setLanguage("und");
198             ltp.setScript(script);
199             result = toMaximized.get(ltp.toString());
200             if (result != null) {
201                 ltp.set(result);
202                 if (!noLanguage) {
203                     ltp.setLanguage(language);
204                 }
205                 if (!noScript) {
206                     ltp.setScript(script);
207                 }
208                 if (!noRegion) {
209                     ltp.setRegion(region);
210                 }
211                 return ltp.setVariants(variants)
212                     .setExtensions(extensions)
213                     .setLocaleExtensions(localeExtensions)
214                     .toString();
215             }
216         }
217 
218         return null; // couldn't maximize
219     }
220 
221     // TODO, optimize if needed by adding private routine that maximizes a LanguageTagParser instead of multiple parsings
222     // TODO Old, crufty code, needs reworking.
minimize(String input)223     public String minimize(String input) {
224         return minimize(input, OutputOption.ICU_LCVARIANT);
225     }
226 
minimize(String input, OutputOption oo)227     public synchronized String minimize(String input, OutputOption oo) {
228         String maximized = maximize(input, toMaximized);
229         if (maximized == null) {
230             return null;
231         }
232         if (DEBUG && maximized.equals("sr" + TAG_SEPARATOR + "Latn" + TAG_SEPARATOR + "RS")) {
233             System.out.print(""); // debug
234         }
235         LanguageTagParser ltp = new LanguageTagParser().set(maximized);
236         String language = ltp.getLanguage();
237         String region = ltp.getRegion();
238         String script = ltp.getScript();
239 
240         // handle variants
241         List<String> variants = ltp.getVariants();
242         Map<String, String> extensions = ltp.getExtensions();
243         Map<String, String> localeExtensions = ltp.getLocaleExtensions();
244 
245         String maximizedCheck = maximized;
246         if (!variants.isEmpty() || !extensions.isEmpty() || !localeExtensions.isEmpty()) {
247             maximizedCheck = ltp.toLSR();
248         }
249         // try building up from shorter to longer, and find the first that matches
250         // could be more optimized, but for this code we want simplest
251         String[] trials = { language,
252             language + TAG_SEPARATOR + (favorRegion ? region : script),
253             language + TAG_SEPARATOR + (!favorRegion ? region : script) };
254         for (String trial : trials) {
255             String newMaximized = maximize(trial, toMaximized);
256             if (maximizedCheck.equals(newMaximized)) {
257                 if (variants.isEmpty() && extensions.isEmpty() && localeExtensions.isEmpty()) {
258                     return trial;
259                 }
260                 return ltp.set(trial)
261                     .setVariants(variants)
262                     .setExtensions(extensions)
263                     .setLocaleExtensions(extensions)
264                     .toString(oo);
265             }
266         }
267         return maximized;
268     }
269 
270     static final Map<String, String> EXTRA_SCRIPTS = Builder.with(new HashMap<String, String>())
271         .on("crs", "pcm", "tlh").put("Latn")
272         .freeze();
273 
getLikelyScript(String code)274     public String getLikelyScript(String code) {
275         String max = this.maximize(code);
276 
277         String script = null;
278         if (max != null) {
279             script = new LanguageTagParser().set(max).getScript();
280         } else {
281             Map<Type, BasicLanguageData> data = supplementalDataInfo.getBasicLanguageDataMap(code);
282             if (data != null) {
283                 for (BasicLanguageData item : data.values()) {
284                     Set<String> scripts = item.getScripts();
285                     if (scripts == null || scripts.size() == 0) continue;
286                     script = scripts.iterator().next();
287                     Type type = item.getType();
288                     if (type == Type.primary) {
289                         break;
290                     }
291                 }
292             }
293             if (script == null) {
294                 script = EXTRA_SCRIPTS.get(code);
295                 if (script == null) {
296                     script = "Zzzz";
297                 }
298             }
299         }
300         return script;
301     }
302 
getLikelyTerritoryFromCurrency(String code)303     public String getLikelyTerritoryFromCurrency(String code) {
304         return currencyToLikelyTerritory.get(code);
305     }
306 }
307