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