• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.ArrayList;
4 import java.util.EnumMap;
5 import java.util.EnumSet;
6 import java.util.HashMap;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Locale;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 import java.util.TreeMap;
13 
14 import org.unicode.cldr.util.ChainedMap.M3;
15 import org.unicode.cldr.util.DayPeriods.DayPeriod;
16 
17 import com.google.common.base.Splitter;
18 import com.ibm.icu.impl.Row.R3;
19 import com.ibm.icu.util.ULocale;
20 
21 public class DayPeriodConverter {
22     private static final boolean TO_CODE = true;
23 
24     // HACK TO SET UP DATA
25     // Will be replaced by real data table in the future
26 
27     static class DayInfo {
28         ULocale locale;
29         DayPeriods.DayPeriod[] data = new DayPeriod[24];
30         Map<DayPeriod, String> toNativeName = new EnumMap<DayPeriod, String>(DayPeriod.class);
31         Map<String, DayPeriod> toDayPeriod = new HashMap<String, DayPeriod>();
32 
33         @Override
toString()34         public String toString() {
35             String result = "make(\"" + locale + "\"";
36             DayPeriod lastDayPeriod = null;
37             for (int i = 0; i < 24; ++i) {
38                 DayPeriod dayPeriod = data[i];
39                 if (dayPeriod != lastDayPeriod) {
40                     result += ")\n.add(\""
41                         + dayPeriod
42                         + "\", \""
43                         + toNativeName.get(dayPeriod)
44                         + "\"";
45                     lastDayPeriod = dayPeriod;
46                 }
47                 result += ", " + i;
48             }
49             result += ")\n.build();\n";
50             /*
51             make("en")
52             .add("MORNING", "morning", 6, 7, 8, 9, 10, 11)
53             .add("AFTERNOON", "afternoon", 12, 13, 14, 15, 16, 17)
54             .add("EVENING", "evening", 18, 19, 20)
55             .add("NIGHT", "night", 0, 1, 2, 3, 4, 5, 21, 22, 23)
56             .build();
57              */
58             return result;
59         }
60 
toCldr()61         public String toCldr() {
62             String result = "\t\t<dayPeriodRules locales=\"" + locale + "\">\n";
63             DayPeriod lastDayPeriod = data[0];
64             int start = 0;
65             for (int i = 1; i < 24; ++i) {
66                 DayPeriod dayPeriod = data[i];
67                 if (dayPeriod != lastDayPeriod) {
68                     result = addPeriod(result, lastDayPeriod, start, i);
69                     lastDayPeriod = dayPeriod;
70                     start = i;
71                 }
72             }
73             result = addPeriod(result, lastDayPeriod, start, 24);
74             result += "\t\t</dayPeriodRules>";
75             return result;
76         }
77 
addPeriod(String result, DayPeriod dayPeriod, int start, int i)78         private String addPeriod(String result, DayPeriod dayPeriod, int start, int i) {
79             result += "\t\t\t<dayPeriodRule type=\""
80                 + dayPeriod.toString().toLowerCase(Locale.ENGLISH)
81                 + "\" from=\""
82                 + start + ":00"
83                 + "\" before=\""
84                 + i + ":00"
85                 + "\"/> <!-- " + toNativeName.get(dayPeriod)
86                 + " -->\n";
87             return result;
88         }
89     }
90 
91     static final Map<ULocale, DayInfo> DATA = new LinkedHashMap<>();
92     static {
93         for (String[] x : DayPeriodData.RAW_DATA) {
94             ULocale locale = new ULocale(x[0]);
95             int start = Integer.parseInt(x[1]);
96             DayPeriod dayPeriod = DayPeriod.valueOf(x[2]);
97             String nativeName = x[3].trim();
98             DayInfo data = DATA.get(locale);
99             if (data == null) {
DATA.put(locale, data = new DayInfo())100                 DATA.put(locale, data = new DayInfo());
101             }
102             data.locale = locale;
103             for (int i = start; i < 24; ++i) {
104                 data.data[i] = dayPeriod;
105             }
106             String old = data.toNativeName.get(dayPeriod);
107             if (old != null && !old.equals(nativeName)) {
108                 throw new IllegalArgumentException(locale + " inconsistent native name for "
109                     + dayPeriod + ", old: «" + old + "», new: «" + nativeName + "»");
110             }
111             DayPeriod oldDp = data.toDayPeriod.get(nativeName);
112             if (oldDp != null && oldDp != dayPeriod) {
113                 throw new IllegalArgumentException(locale + " inconsistent day periods for name «"
114                     + nativeName + "», old: " + oldDp + ", new: " + dayPeriod);
115             }
data.toDayPeriod.put(nativeName, dayPeriod)116             data.toDayPeriod.put(nativeName, dayPeriod);
data.toNativeName.put(dayPeriod, nativeName)117             data.toNativeName.put(dayPeriod, nativeName);
118         }
119     }
120 
main(String[] args)121     public static void main(String[] args) {
122         // generateFormat();
123         generateFieldNames();
124     }
125 
generateFieldNames()126     private static void generateFieldNames() {
127         SupplementalDataInfo sdi = CLDRConfig.getInstance().getSupplementalDataInfo();
128         Factory factory = CLDRConfig.getInstance().getFullCldrFactory();
129         EnumSet<DayPeriodInfo.DayPeriod> dayPeriodSet = EnumSet.noneOf(DayPeriodInfo.DayPeriod.class);
130 
131         String prefix = getPrefix("stand-alone");
132 
133         for (String locale : sdi.getDayPeriodLocales(DayPeriodInfo.Type.format)) {
134             ULocale uLocale = new ULocale(locale);
135             DayPeriodInfo dayPeriodInfo = sdi.getDayPeriods(DayPeriodInfo.Type.format, locale);
136             System.out.println("# " + locale);
137             dayPeriodSet.clear();
138             dayPeriodSet.addAll(dayPeriodInfo.getPeriods());
139             final boolean fieldType = false;
140             if (!fieldType) {
141                 //System.out.println("\t<dayPeriodContext type=\"stand-alone\">");
142                 //System.out.println("\t\t<dayPeriodWidth type=\"wide\">");
143                 CLDRFile cldrFile = factory.make(locale, false);
144                 for (String path : cldrFile) {
145                     if (path.endsWith("/alias")) {
146                         continue;
147                     }
148                     if (path.startsWith(prefix)) {
149                         XPathParts parts = XPathParts.getFrozenInstance(path);
150                         String width = parts.getAttributeValue(-2, "type");
151                         DayPeriodInfo.DayPeriod period = DayPeriodInfo.DayPeriod.fromString(parts.getAttributeValue(-1, "type"));
152                         String draft = parts.getAttributeValue(-1, "draft");
153                         //if (period != DayPeriodInfo.DayPeriod.am || period != DayPeriodInfo.DayPeriod.pm || width.equals("wide")) {
154                         System.out.println("#old: «" + cldrFile.getStringValue(path) + "»"
155                             + ", width: " + width
156                             + ", period: " + period
157                             + (draft == null ? "" : ", draft: " + draft));
158                         System.out.println("locale=" + locale
159                             + " ; action=delete"
160                             + " ; path=" + path);
161                         //}
162                     }
163                 }
164 
165 //                CLDRFile cldrFile = factory.make(locale, true);
166                 addOldDayPeriod(cldrFile, DayPeriodInfo.DayPeriod.am);
167                 addOldDayPeriod(cldrFile, DayPeriodInfo.DayPeriod.pm);
168             }
169             for (DayPeriodInfo.DayPeriod dayPeriod : dayPeriodSet) {
170                 if (fieldType) {
171                     String name = getNativeName(uLocale, dayPeriod);
172                     System.out.println("\t<field type=\"dayPeriod-" + dayPeriod + "\">");
173                     System.out.println("\t\t<displayName>" + name + "</displayName>");
174                     System.out.println("\t</field>");
175                 } else {
176                     String name = getNativeName(uLocale, dayPeriod);
177                     //System.out.println("\t\t\t<dayPeriod type=\"" + dayPeriod + "\">" + name + "</dayPeriod>");
178                     //ldml/dates/calendars/calendar[@type="gregorian"]/dayPeriods/dayPeriodContext[@type="format"]/dayPeriodWidth[@type="narrow"]/dayPeriod[@type="am"]
179 //                    String path = "//ldml/dates/calendars/calendar[@type=\"gregorian\"]/dayPeriods"
180 //                        + "/dayPeriodContext[@type=\"stand-alone\"]"
181 //                        + "/dayPeriodWidth[@type=\"wide\"]"
182 //                        + "/dayPeriod[@type=\"" + dayPeriod + "\"]";
183                     if (name != null) {
184                         showModLine(locale, dayPeriod, name, false);
185                     }
186                 }
187             }
188 //            if (!fieldType) {
189 //                System.out.println("\t\t</dayPeriodWidth>");
190 //                System.out.println("\t</dayPeriodContext>");
191 //            }
192             System.out.println();
193         }
194     }
195 
showModLine(String locale, DayPeriodInfo.DayPeriod dayPeriod, String name, boolean draft)196     private static void showModLine(String locale, DayPeriodInfo.DayPeriod dayPeriod, String name, boolean draft) {
197         String path = getPath("stand-alone", "wide", dayPeriod);
198         if (draft) {
199             path += "[@draft=\"provisional\"]";
200         }
201         System.out.println("locale=" + locale
202             + " ; action=add"
203             + " ; new_value=" + name
204             + " ; new_path=" + path);
205     }
206 
addOldDayPeriod(CLDRFile cldrFile, DayPeriodInfo.DayPeriod period)207     private static void addOldDayPeriod(CLDRFile cldrFile, DayPeriodInfo.DayPeriod period) {
208         String amString = cldrFile.getStringValue(getPath("format", "wide", period));
209         if (amString != null) {
210             String locale = cldrFile.getLocaleID();
211             showModLine(locale, period, amString, !locale.equals("root") && !locale.equals("en"));
212             //System.out.println("\t\t\t<dayPeriod type=\"" + period + "\">" + amString + "</dayPeriod>");
213         }
214     }
215 
getPath(String context, String width, DayPeriodInfo.DayPeriod dayPeriod)216     static String getPath(String context, String width, DayPeriodInfo.DayPeriod dayPeriod) {
217         return getPrefix(context)
218             + "/dayPeriodWidth[@type=\"" + width + "\"]"
219             + "/dayPeriod[@type=\"" + dayPeriod + "\"]";
220     }
221 
getPrefix(String context)222     private static String getPrefix(String context) {
223         return "//ldml/dates/calendars"
224             + "/calendar[@type=\"gregorian\"]"
225             + "/dayPeriods"
226             + "/dayPeriodContext[@type=\"" + context + "\"]";
227     }
228 
generateFormat()229     static void generateFormat() {
230         SupplementalDataInfo sdi = CLDRConfig.getInstance().getSupplementalDataInfo();
231         M3<ULocale, Integer, DayPeriodInfo.DayPeriod> allData = ChainedMap.of(new TreeMap(LanguageGroup.COMPARATOR), new TreeMap(),
232             DayPeriodInfo.DayPeriod.class);
233         for (String locale : sdi.getDayPeriodLocales(DayPeriodInfo.Type.selection)) {
234             ULocale ulocale = new ULocale(locale);
235             NoonMidnight nm = NoonMidnight.get(locale);
236             boolean hasNoon = nm != null && nm.noon != null;
237             boolean hasMidnight = nm != null && nm.midnight != null;
238             DayPeriodInfo data = sdi.getDayPeriods(DayPeriodInfo.Type.selection, locale);
239             if (hasMidnight) {
240                 allData.put(ulocale, 0, DayPeriodInfo.DayPeriod.midnight);
241             }
242             if (hasNoon) {
243                 allData.put(ulocale, 12 * DayPeriodInfo.HOUR, DayPeriodInfo.DayPeriod.noon);
244             }
245             int lastTime = -1;
246             DayPeriodInfo.DayPeriod lastPeriod = null;
247             for (int index = 0; index < data.getPeriodCount(); ++index) {
248                 R3<Integer, Boolean, DayPeriodInfo.DayPeriod> row = data.getPeriod(index);
249                 DayPeriodInfo.DayPeriod period = row.get2();
250                 int time = row.get0();
251                 if (!row.get1()) {
252                     time += 1;
253                 } else if (hasMidnight && time == 0) {
254                     time += 1;
255                 } else if (hasNoon) {
256                     if (time == 12 * DayPeriodInfo.HOUR) {
257                         time += 1;
258                     } else if (lastTime < 12 * DayPeriodInfo.HOUR && time > 12 * DayPeriodInfo.HOUR) {
259                         System.out.println(locale + ": Splitting " + lastTime + ", " + lastPeriod + ", " + time + ", " + period);
260                         allData.put(ulocale, 12 * DayPeriodInfo.HOUR + 1, lastPeriod);
261                     }
262                 }
263                 allData.put(ulocale, time, period);
264                 lastTime = time;
265                 lastPeriod = period;
266             }
267         }
268         for (Entry<ULocale, Map<Integer, org.unicode.cldr.util.DayPeriodInfo.DayPeriod>> entry : allData) {
269             ULocale locale = entry.getKey();
270             System.out.println("\t\t<dayPeriodRules locales=\"" + locale + "\">");
271             ArrayList<Entry<Integer, DayPeriodInfo.DayPeriod>> list = new ArrayList<>(entry.getValue().entrySet());
272             for (int i = 0; i < list.size(); ++i) {
273                 Entry<Integer, org.unicode.cldr.util.DayPeriodInfo.DayPeriod> item = list.get(i);
274                 //System.out.println(item.getKey() + " = " + item.getValue());
275                 DayPeriodInfo.DayPeriod dayPeriod = item.getValue();
276                 int start = item.getKey();
277                 int end = i + 1 == list.size() ? 24 * DayPeriodInfo.HOUR : list.get(i + 1).getKey();
278                 String startType = "from";
279                 if ((start & 1) != 0) {
280                     startType = "after";
281                 }
282                 start /= DayPeriodInfo.HOUR;
283                 end /= DayPeriodInfo.HOUR;
284                 System.out.println("\t\t\t<dayPeriodRule type=\""
285                     + dayPeriod.toString().toLowerCase(Locale.ENGLISH)
286                     + "\" "
287                     + (start == end ? "at=\"" + start
288                         : startType + "=\"" + start + ":00\" before=\"" + end)
289                     + ":00\"/>" +
290                     " <!-- " + getNativeName(locale, dayPeriod)
291                     + " -->");
292             }
293             System.out.println("\t\t</dayPeriodRules>");
294         }
295     }
296 
oldMain()297     void oldMain() {
298 //        SupplementalDataInfo sdi = CLDRConfig.getInstance().getSupplementalDataInfo();
299 //
300 //        for (String locale : sdi.getDayPeriodLocales(DayPeriodInfo.Type.selection)) {
301 //
302 //            StringBuilder result = new StringBuilder("\t\t<dayPeriodRules locales=\"" + locale + "\">\n";
303 //            for (int index = 0; index < data.getPeriodCount(); ++index) {
304 //                R3<Integer, Boolean, DayPeriodInfo.DayPeriod> periodData = data.getPeriod(index);
305 //                public String toCldr() {
306 //                    DayPeriod lastDayPeriod = data[0];
307 //                    int start = 0;
308 //                    for (int i = 1; i < 24; ++i) {
309 //                        DayPeriod dayPeriod = data[i];
310 //                        if (dayPeriod != lastDayPeriod) {
311 //                            result = addPeriod(result, lastDayPeriod, start, i);
312 //                            lastDayPeriod = dayPeriod;
313 //                            start = i;
314 //                        }
315 //                    }
316 //                    result = addPeriod(result, lastDayPeriod, start, 24);
317 //                    result += "\t\t</dayPeriodRules>";
318 //                    return result;
319 //                }
320 //
321 //                private String addPeriod(String result, DayPeriod dayPeriod, int start, int i) {
322 //                    result += "\t\t\t<dayPeriodRule type=\""
323 //                        + dayPeriod.toString().toLowerCase(Locale.ENGLISH)
324 //                        + "\" from=\""
325 //                        + start + ":00"
326 //                        + "\" before=\""
327 //                        + i + ":00"
328 //                        + "\"/> <!-- " + toNativeName.get(dayPeriod)
329 //                        + " -->\n";
330 //                    return result;
331 //                }
332 //
333 //            }
334 //            NoonMidnight nm = NoonMidnight.get(locale);
335 //
336 //            System.out.println(locale + "\t" + nm);
337 //        }
338     }
339 
340     static final ULocale ROOT2 = new ULocale("root");
341 
getNativeName(ULocale locale, DayPeriodInfo.DayPeriod dayPeriod)342     private static String getNativeName(ULocale locale, DayPeriodInfo.DayPeriod dayPeriod) {
343         NoonMidnight nm = NoonMidnight.get(locale.toString());
344         if (nm == null) {
345             return null;
346         }
347         if (dayPeriod == DayPeriodInfo.DayPeriod.noon) {
348             return CldrUtility.ifNull(nm.noon, "missing-" + dayPeriod);
349         } else if (dayPeriod == DayPeriodInfo.DayPeriod.midnight) {
350             return CldrUtility.ifNull(nm.midnight, "missing-" + dayPeriod);
351         }
352         if (locale.equals(ROOT2)) {
353             if (dayPeriod == DayPeriodInfo.DayPeriod.morning1) {
354                 return "am";
355             } else if (dayPeriod == DayPeriodInfo.DayPeriod.afternoon1) {
356                 return "pm";
357             }
358         }
359         DayInfo data = DATA.get(locale);
360         if (data == null) {
361             return "missing-" + dayPeriod;
362         }
363         DayPeriod otherDayPeriod = DayPeriod.valueOf(dayPeriod.toString().toUpperCase(Locale.ENGLISH));
364         return data.toNativeName.get(otherDayPeriod);
365     }
366 
writeOld()367     static void writeOld() {
368         System.out.println("\t<dayPeriodRuleSet type=\"selection\">");
369         for (Entry<ULocale, DayInfo> foo : DATA.entrySet()) {
370             check(foo.getKey(), foo.getValue());
371             System.out.println(foo.getValue().toCldr());
372         }
373         System.out.println("\t</dayPeriodRuleSet>");
374     }
375 
check(ULocale locale, DayInfo value)376     private static void check(ULocale locale, DayInfo value) {
377         check(locale, DayPeriod.MORNING1, DayPeriod.MORNING2, value);
378         check(locale, DayPeriod.AFTERNOON1, DayPeriod.AFTERNOON2, value);
379         check(locale, DayPeriod.EVENING1, DayPeriod.EVENING2, value);
380         check(locale, DayPeriod.NIGHT1, DayPeriod.NIGHT2, value);
381         DayPeriod lastDp = value.data[23];
382         for (DayPeriod dp : value.data) {
383             if (lastDp.compareTo(dp) > 0) {
384                 if ((lastDp == DayPeriod.NIGHT1 || lastDp == DayPeriod.NIGHT2) && dp == DayPeriod.MORNING1) {
385                 } else {
386                     throw new IllegalArgumentException(locale + " " + lastDp + " > " + dp);
387                 }
388             }
389             lastDp = dp;
390         }
391     }
392 
check(ULocale locale, DayPeriod morning1, DayPeriod morning2, DayInfo value)393     private static void check(ULocale locale, DayPeriod morning1, DayPeriod morning2, DayInfo value) {
394         if (value.toNativeName.containsKey(morning2) && !value.toNativeName.containsKey(morning1)) {
395             throw new IllegalArgumentException(locale + " Contains " + morning2 + ", but not " + morning1);
396         }
397     }
398 
399     static class NoonMidnight {
NoonMidnight(List<String> items)400         public NoonMidnight(List<String> items) {
401             locale = items.get(0);
402             midnight = CldrUtility.ifEqual(items.get(1), "N/A", null);
403             noon = CldrUtility.ifEqual(items.get(2), "N/A", null);
404         }
405 
406         final String locale;
407         final String noon;
408         final String midnight;
409 
get(String locale)410         static NoonMidnight get(String locale) {
411             return NOON_MIDNIGHT_MAP.get(locale);
412         }
413 
414         @Override
toString()415         public String toString() {
416             return locale + ", " + noon + ", " + midnight;
417         }
418 
419         static Map<String, NoonMidnight> NOON_MIDNIGHT_MAP = new HashMap<>();
420         static final String[] NOON_MIDNIGHT = {
421             "en|midnight|noon",
422             "af|middernag|N/A",
423             "nl|middernacht|N/A",
424             "de|Mitternacht|N/A",
425             "da|midnat|N/A",
426             "nb|midnatt|N/A",
427             "sv|midnatt|N/A",
428             "is|miðnætti|hádegi",
429             "pt|meia-noite|meio-dia",
430             "pt_PT|meia-noite|meio-dia",
431             "gl|medianoite|mediodía",
432             "es|medianoche|mediodía",
433             "es_419|medianoche|mediodía",
434             "ca|mitjanit|migdia",
435             "it|mezzanotte|mezzogiorno",
436             "ro|miezul nopții|amiază",
437             "fr|minuit|midi",
438             "fr-CA|minuit|midi",
439             "hr|ponoć|podne",
440             "bs|u ponoć|u podne",
441             "sr|поноћ|подне",
442             "sl|polnoč|poldne",
443             "cs|půlnoc|poledne",
444             "sk|polnoc|poludnie",
445             "pl|północ|południe",
446             "bg|полунощ|N/A",
447             "mk|на полноќ|напладне",
448             "ru|полночь|полдень",
449             "uk|північ|полудень",
450             "lt|vidurnaktis|vidurdienis",
451             "lv|pusnakts|pusdienlaiks",
452             "el|N/A|μεσημέρι",
453             "fa|نیمه‌شب|ظهر",
454             "hy|կեսգիշեր|կեսօր",
455             "ka|შუაღამე|შუადღე",
456             "sq|mesnatë|mesditë",
457             "ur|آدھی رات|N/A",
458             "hi|आधी रात|दोपहर",
459             "bn|N/A|N/A",
460             "gu|અડધી રાત|બપોર",
461             "mr|मध्यरात्री|मध्यान्ह",
462             "ne|मध्यरात|मध्यान्ह",
463             "pa|ਅੱਧੀ ਰਾਤ|ਦੁਪਹਿਰ",
464             "si|මැදියම|දවල්",
465             "ta|நள்ளிரவு|நன்பகல்",
466             "te|అర్థరాత్రి|మధ్యాహ్నం",
467             "ml|അർദ്ധരാത്രി|ഉച്ചയ്ക്ക്",
468             "kn|ಮಧ್ಯರಾತ್ರಿ|ಮಧ್ಯಾಹ್ನ",
469             "zh|半夜|中午",
470             "zh-TW|子夜|正午",
471             "zh-HK|深夜|中午",
472             "ja|真夜中|正午",
473             "ko|자정|정오",
474             "tr|gece yarısı|öğlen",
475             "az|gecəyarı|günorta",
476             "kk|түн жарымы|талтүс",
477             "ky|түн ортосу|чак түш",
478             "uz|yarim tun|tush",
479             "et|kesköö|keskpäev",
480             "fi|keskiyö|keskipäivä",
481             "hu|éjfél|dél",
482             "th|เที่ยงคืน|เที่ยง",
483             "lo|ທ່ຽງ​ຄືນ|​ທ່ຽງ",
484             "ar| منتصف الليل|ظهرا",
485             "he|חצות|N/A",
486             "id|tengah malam|tengah hari",
487             "ms|Tengah malam|Tengah hari",
488             "fil|hating-gabi|tangaling-tapat",
489             "vi|nửa đêm|trưa",
490             "km|អាធ្រាត្រ|ថ្ងៃ​ត្រង់",
491             "sw|saa sita za usiku|saa sita za mchana",
492             "zu|N/A|N/A",
493             "am|እኩለ ሌሊት|ቀትር",
494             "eu|gauerdia|eguerdia",
495             "mn|шөнө дунд|үд дунд",
496             "my|သန်းခေါင်ယံ|မွန်းတည့်",
497         };
498         static {
499             Splitter BAR = Splitter.on('|').trimResults();
500             for (String s : NOON_MIDNIGHT) {
501                 List<String> items = BAR.splitToList(s);
502                 NoonMidnight nm = new NoonMidnight(items);
503                 NOON_MIDNIGHT_MAP.put(items.get(0), nm);
504             }
505         }
506     }
507 }
508