• 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.ArrayList;
6 import java.util.Arrays;
7 import java.util.HashSet;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.Map.Entry;
11 import java.util.Set;
12 import java.util.TreeMap;
13 import java.util.TreeSet;
14 
15 import org.unicode.cldr.draft.FileUtilities;
16 import org.unicode.cldr.tool.Option.Options;
17 import org.unicode.cldr.util.CLDRConfig;
18 import org.unicode.cldr.util.CLDRFile;
19 import org.unicode.cldr.util.CLDRFile.DraftStatus;
20 import org.unicode.cldr.util.CLDRLocale;
21 import org.unicode.cldr.util.CLDRPaths;
22 import org.unicode.cldr.util.ChainedMap;
23 import org.unicode.cldr.util.ChainedMap.M3;
24 import org.unicode.cldr.util.ChainedMap.M4;
25 import org.unicode.cldr.util.Counter;
26 import org.unicode.cldr.util.Factory;
27 import org.unicode.cldr.util.LanguageTagParser;
28 import org.unicode.cldr.util.PathHeader;
29 import org.unicode.cldr.util.PathHeader.SectionId;
30 import org.unicode.cldr.util.SupplementalDataInfo;
31 
32 import com.google.common.base.Objects;
33 import com.ibm.icu.impl.Relation;
34 import com.ibm.icu.text.UnicodeSet;
35 
36 public class ShowRegionalVariants {
37     private static String MY_DIR;
38 
39     private static final boolean SKIP_SUPPRESSED_PATHS = true;
40 
41     private static final CLDRConfig CONFIG = CLDRConfig.getInstance();
42     private static final SupplementalDataInfo SUPPLEMENTAL_DATA_INFO = CONFIG.getSupplementalDataInfo();
43     private static final Factory FACTORY = CONFIG.getCldrFactory();
44     private static final CLDRFile ENGLISH = CONFIG.getEnglish();
45     private static final CLDRLocale ROOT = CLDRLocale.getInstance("root");
46     //private static final CLDRLocale en_US_POSIX = CLDRLocale.getInstance("en_US_POSIX");
47     private static final CLDRLocale SWISS_HIGH_GERMAN = CLDRLocale.getInstance("de_CH");
48 
49     final static Options myOptions = new Options();
50 
51     enum MyOptions {
52         targetDir(".*", CLDRPaths.GEN_DIRECTORY + "/regional/", "target output file."),;
53         // boilderplate
54         final Option option;
55 
MyOptions(String argumentPattern, String defaultArgument, String helpText)56         MyOptions(String argumentPattern, String defaultArgument, String helpText) {
57             option = myOptions.add(this, argumentPattern, defaultArgument, helpText);
58         }
59     }
60 
main(String[] args)61     public static void main(String[] args) throws IOException {
62         myOptions.parse(MyOptions.targetDir, args, true);
63 
64         MY_DIR = MyOptions.targetDir.option.getValue();
65 
66         Set<String> coverageLocales = CONFIG.getStandardCodes().getLocaleCoverageLocales("cldr");
67         Set<String> dc = new HashSet<>(SUPPLEMENTAL_DATA_INFO.getDefaultContentLocales());
68         Set<String> skipLocales = new HashSet<>(Arrays.asList("root", "en_US_POSIX", "sr_Latn"));
69 
70         Relation<CLDRLocale, CLDRLocale> parentToChildren = Relation.of(new TreeMap<CLDRLocale, Set<CLDRLocale>>(), TreeSet.class);
71         // first, collect all locales for lookup by parents.
72 
73         for (String locale : FACTORY.getAvailable()) {
74             if (skipLocales.contains(locale.toString())
75                 || dc.contains(locale.toString())) {
76                 continue;
77             }
78             CLDRLocale loc = CLDRLocale.getInstance(locale);
79 
80             if (!coverageLocales.contains(loc.getLanguage())) {
81                 continue;
82             }
83             CLDRLocale parent = null;
84             for (CLDRLocale current = loc;; current = parent) {
85                 parent = current.getParent();
86                 if (!dc.contains(parent.toString())) { // skip over default content
87                     break;
88                 }
89             }
90             if (ROOT.equals(parent)) {
91                 continue;
92             } else if ("root".equals(parent.toString())) {
93                 throw new IllegalArgumentException("CLDRLocale failure");
94             }
95             parentToChildren.put(parent, loc);
96         }
97 
98         // show inheritance
99         System.out.println("Locale Name\tCode\tRegion\tInherits from\tCode");
100         showInheritance(parentToChildren);
101 
102         // next find out the unique items in children
103         Relation<String, String> valueToAncestors = Relation.of(new LinkedHashMap<String, Set<String>>(), LinkedHashSet.class);
104 
105         int count = 0;
106 
107         try (
108             PrintWriter grandSummary = FileUtilities.openUTF8Writer(MY_DIR, "GrandSummary.txt");
109             PrintWriter summary = FileUtilities.openUTF8Writer(MY_DIR, "Summary.txt");
110             PrintWriter detailFile = FileUtilities.openUTF8Writer(MY_DIR, "details.txt");) {
111             grandSummary.println("Parent\tName\tTotal Diff Count\tChildren");
112             summary.println("Parent\tName\tDiff Count\tChild\tChild Name");
113             detailFile
114                 .println(
115                     "№\tBase\tParent Locales I\tParent Locales II\tChild Locales\tEnglish value\tParent value I\tParent value II\tChild value\tCorrected Child value\tComments\tFix Parent value?\tSection\tPage\tHeader\tCode");
116             PathHeader.Factory phf = PathHeader.getFactory(ENGLISH);
117             String lastBase = "";
118             for (Entry<CLDRLocale, Set<CLDRLocale>> item : parentToChildren.keyValuesSet()) {
119                 CLDRLocale parent = item.getKey();
120                 String base = parent.getLanguage();
121 
122                 CLDRFile parentFile = FACTORY.make(parent.toString(), true, DraftStatus.contributed);
123                 M4<PathHeader, String, CLDRLocale, Boolean> pathToValuesToLocales = ChainedMap.of(
124                     new TreeMap<PathHeader, Object>(),
125                     new TreeMap<String, Object>(),
126                     new TreeMap<CLDRLocale, Object>(),
127                     Boolean.class);
128 
129                 Counter<CLDRLocale> childDiffs = new Counter<>();
130 
131                 for (CLDRLocale child : item.getValue()) {
132                     //childDiffs.add(child, 0); // make sure it shows up
133                     String childString = child.toString();
134                     CLDRFile childFile = FACTORY.make(childString, false, DraftStatus.contributed);
135                     for (String path : childFile) {
136                         if (SKIP_SUPPRESSED_PATHS) {
137                             if (path.contains("/currency") && path.contains("/symbol")) {
138                                 continue;
139                             }
140                         }
141                         String childValue = childFile.getStringValue(path);
142                         if (childValue == null) {
143                             continue;
144                         }
145                         String parentValue = parentFile.getStringValue(path);
146                         if (parentValue == null) {
147                             parentValue = "∅∅∅";
148                         }
149                         if (!Objects.equal(childValue, parentValue)) {
150                             if (SKIP_SUPPRESSED_PATHS) {
151                                 if ("∅∅∅".equals(childValue) || "∅∅∅".equals(parentValue)) {
152                                     continue; // skip suppressed paths
153                                 }
154                             }
155                             if (parentValue != null) {
156                                 if (child.equals(SWISS_HIGH_GERMAN)) {
157                                     String norm = parentValue.replace("ß", "ss");
158                                     if (childValue.equals(norm)) {
159                                         continue;
160                                     }
161                                 } else if (base.equals("en")) {
162                                     if (sameExceptEnd(childValue, "re", parentValue, "er")
163                                         || sameExceptEnd(childValue, "res", parentValue, "ers")) {
164                                         continue;
165                                     }
166                                 }
167                             }
168                             PathHeader pheader = phf.fromPath(path);
169                             if (SectionId.Special == pheader.getSectionId()) {
170                                 continue;
171                             }
172                             pathToValuesToLocales.put(pheader, childValue, child, Boolean.TRUE);
173                             childDiffs.add(child, 1);
174                         }
175                     }
176                 }
177 
178                 long totalChildDiffs = childDiffs.getTotal();
179                 if (totalChildDiffs == 0) {
180                     continue;
181                 }
182 
183                 if (!base.equals(lastBase)) {
184                     detailFile.println();
185 //                    if (detailFile != null) {
186 //                        detailFile.close();
187 //                    }
188 //                    detailFile = FileUtilities.openUTF8Writer(MY_DIR, "detail-" + base + ".txt");
189 //                    detailFile.println("Section\tPage\tHeader\tCode\tLocales\tvalue\tParent Locales\tvalue\tParent Locales\tvalue");
190 //                    lastBase = base;
191                 }
192 
193                 grandSummary.println(parent + "\t" + ENGLISH.getName(parent.toString()) + "\t" + totalChildDiffs + "\t" + item.getValue());
194                 for (CLDRLocale s : childDiffs.getKeysetSortedByKey()) {
195                     long childDiffValue = childDiffs.get(s);
196                     if (childDiffValue == 0) {
197                         continue;
198                     }
199                     summary.println(parent + "\t" + ENGLISH.getName(parent.toString()) + "\t" + childDiffValue + "\t" + s + "\t"
200                         + ENGLISH.getName(s.toString()));
201                 }
202 
203                 ArrayList<CLDRFile> parentChain = new ArrayList<>();
204                 for (CLDRLocale current = parent;;) {
205                     parentChain.add(FACTORY.make(current.toString(), true));
206                     CLDRLocale grand = current.getParent();
207                     if (ROOT.equals(grand)) {
208                         break;
209                     }
210                     current = grand;
211                 }
212 
213                 for (PathHeader ph : pathToValuesToLocales.keySet()) {
214                     M3<String, CLDRLocale, Boolean> values = pathToValuesToLocales.get(ph);
215                     valueToAncestors.clear();
216                     for (String value : values.keySet()) {
217                         Set<CLDRLocale> childLocales = values.get(value).keySet();
218                         String englishValue = ENGLISH.getStringValue(ph.getOriginalPath());
219                         String originalPath = ph.getOriginalPath();
220                         for (CLDRFile grand : parentChain) {
221                             valueToAncestors.put(quote(grand.getStringValue(originalPath)), grand.getLocaleID());
222                         }
223                         Set<Entry<String, Set<String>>> keyValuesSet = valueToAncestors.keyValuesSet();
224                         final int countParents = keyValuesSet.size();
225                         if (countParents < 1 || countParents > 2) {
226                             throw new IllegalArgumentException("Too few/many parents");
227                         }
228 
229                         // // №  Base    Parent Locales I    Parent Locales II   Child Locales   English value   Parent value I  Parent value II Child value
230                         // Corrected Child value   Comments    Fix Parent value?   Section Page    Header  Code
231 
232                         detailFile.print(
233                             ++count
234                                 + "\t" + base);
235 
236                         for (Entry<String, Set<String>> entry : keyValuesSet) {
237                             detailFile.print("\t" + entry.getValue());
238                         }
239                         if (countParents == 1) {
240                             detailFile.print("\t");
241                         }
242                         detailFile.print(""
243                             + "\t" + childLocales
244                             + "\t" + quote(englishValue));
245                         for (Entry<String, Set<String>> entry : keyValuesSet) {
246                             detailFile.print("\t" + entry.getKey());
247                         }
248                         if (countParents == 1) {
249                             detailFile.print("\t");
250                         }
251                         detailFile.print(""
252                             + "\t" + quote(value)
253                             + "\t" + ""
254                             + "\t" + ""
255                             + "\t" + ""
256                             + "\t" + ph);
257                         detailFile.println();
258                     }
259                 }
260 
261             }
262         }
263         System.out.println("DONE");
264 //        if (detailFile != null) {
265 //            detailFile.close();
266 //        }
267     }
268 
showInheritance(Relation<CLDRLocale, CLDRLocale> parentToChildren)269     private static void showInheritance(Relation<CLDRLocale, CLDRLocale> parentToChildren) {
270         Set<CLDRLocale> values = parentToChildren.values();
271         Set<CLDRLocale> topParents = new TreeSet<>(parentToChildren.keySet());
272         topParents.removeAll(values);
273         showInheritance(topParents, "", parentToChildren);
274     }
275 
showInheritance(Set<CLDRLocale> topParents, String prefix, Relation<CLDRLocale, CLDRLocale> parentToChildren)276     private static void showInheritance(Set<CLDRLocale> topParents, String prefix, Relation<CLDRLocale, CLDRLocale> parentToChildren) {
277         for (CLDRLocale locale : topParents) {
278             String current = nameForLocale(locale) + "\t" + prefix;
279             System.out.println(current);
280             Set<CLDRLocale> newChildren = parentToChildren.get(locale);
281             if (newChildren == null) {
282                 continue;
283             }
284             showInheritance(newChildren, current, parentToChildren);
285         }
286     }
287 
288     static final LikelySubtags LS = new LikelySubtags();
289 
nameForLocale(CLDRLocale key)290     private static String nameForLocale(CLDRLocale key) {
291         String country = key.getCountry();
292         if (country.isEmpty()) {
293             String max = LS.maximize(key.toString());
294             LanguageTagParser ltp = new LanguageTagParser().set(max);
295             country = "(" + ltp.getRegion() + ")";
296         }
297         return ENGLISH.getName(key.toString(), false, CLDRFile.SHORT_ALTS) + "\t" + key + "\t" + country;
298     }
299 
sameExceptEnd(String childValue, String childEnding, String parentValue, String parentEnding)300     private static boolean sameExceptEnd(String childValue, String childEnding, String parentValue, String parentEnding) {
301         if (childValue.endsWith(childEnding)
302             && parentValue.endsWith(parentEnding)
303             && childValue.substring(0, childValue.length() - childEnding.length()).equals(
304                 parentValue.substring(0, parentValue.length() - parentEnding.length()))) {
305             return true;
306         }
307         return false;
308     }
309 
310     static final UnicodeSet SPREAD_SHEET_SENSITIVE = new UnicodeSet().add('=').add('+').add('0', '9');
311 
quote(String value)312     private static String quote(String value) {
313         if (value == null || value.isEmpty()) {
314             return "∅∅∅";
315         }
316         int first = value.codePointAt(0);
317         return SPREAD_SHEET_SENSITIVE.contains(first) ? "'" + value : value;
318     }
319 }
320