< prev index next >

make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java

Print this page
rev 57965 : 8234347: "Turkey" meta time zone does not generate composed localized names
8236548: Localized time zone name inconsistency between English and other locales
Reviewed-by:
   1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.cldrconverter;
  27 
  28 import static build.tools.cldrconverter.Bundle.jreTimeZoneNames;
  29 import build.tools.cldrconverter.BundleGenerator.BundleType;
  30 import java.io.File;
  31 import java.io.IOException;
  32 import java.io.UncheckedIOException;
  33 import java.nio.file.*;
  34 import java.text.MessageFormat;
  35 import java.time.*;
  36 import java.util.*;
  37 import java.util.ResourceBundle.Control;
  38 import java.util.logging.Level;
  39 import java.util.logging.Logger;
  40 import java.util.stream.Collectors;
  41 import java.util.stream.IntStream;
  42 import java.util.stream.Stream;
  43 import javax.xml.parsers.SAXParser;
  44 import javax.xml.parsers.SAXParserFactory;
  45 import org.xml.sax.SAXNotRecognizedException;
  46 import org.xml.sax.SAXNotSupportedException;
  47 
  48 


  72     private static String WINZONES_SOURCE_FILE;
  73     private static String PLURALS_SOURCE_FILE;
  74     static String DESTINATION_DIR = "build/gensrc";
  75 
  76     static final String LOCALE_NAME_PREFIX = "locale.displayname.";
  77     static final String LOCALE_SEPARATOR = LOCALE_NAME_PREFIX + "separator";
  78     static final String LOCALE_KEYTYPE = LOCALE_NAME_PREFIX + "keytype";
  79     static final String LOCALE_KEY_PREFIX = LOCALE_NAME_PREFIX + "key.";
  80     static final String LOCALE_TYPE_PREFIX = LOCALE_NAME_PREFIX + "type.";
  81     static final String LOCALE_TYPE_PREFIX_CA = LOCALE_TYPE_PREFIX + "ca.";
  82     static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol.";
  83     static final String CURRENCY_NAME_PREFIX = "currency.displayname.";
  84     static final String CALENDAR_NAME_PREFIX = "calendarname.";
  85     static final String CALENDAR_FIRSTDAY_PREFIX = "firstDay.";
  86     static final String CALENDAR_MINDAYS_PREFIX = "minDays.";
  87     static final String TIMEZONE_ID_PREFIX = "timezone.id.";
  88     static final String EXEMPLAR_CITY_PREFIX = "timezone.excity.";
  89     static final String ZONE_NAME_PREFIX = "timezone.displayname.";
  90     static final String METAZONE_ID_PREFIX = "metazone.id.";
  91     static final String PARENT_LOCALE_PREFIX = "parentLocale.";

  92     static final String[] EMPTY_ZONE = {"", "", "", "", "", ""};






























  93 
  94     private static SupplementDataParseHandler handlerSuppl;
  95     private static LikelySubtagsParseHandler handlerLikelySubtags;
  96     private static WinZonesParseHandler handlerWinZones;
  97     static PluralsParseHandler handlerPlurals;
  98     static SupplementalMetadataParseHandler handlerSupplMeta;
  99     static NumberingSystemsParseHandler handlerNumbering;
 100     static MetaZonesParseHandler handlerMetaZones;
 101     static TimeZoneParseHandler handlerTimeZone;
 102     private static BundleGenerator bundleGenerator;
 103 
 104     // java.base module related
 105     static boolean isBaseModule = false;
 106     static final Set<Locale> BASE_LOCALES = new HashSet<>();
 107 
 108     // "parentLocales" map
 109     private static final Map<String, SortedSet<String>> parentLocalesMap = new HashMap<>();
 110     private static final ResourceBundle.Control defCon =
 111         ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
 112 


 669         return localeNames;
 670     }
 671 
 672     @SuppressWarnings("AssignmentToForLoopParameter")
 673     private static Map<String, Object> extractCurrencyNames(Map<String, Object> map, String id, String names)
 674             throws Exception {
 675         Map<String, Object> currencyNames = new TreeMap<>(KeyComparator.INSTANCE);
 676         for (String key : map.keySet()) {
 677             if (key.startsWith(CURRENCY_NAME_PREFIX)) {
 678                 currencyNames.put(key.substring(CURRENCY_NAME_PREFIX.length()), map.get(key));
 679             } else if (key.startsWith(CURRENCY_SYMBOL_PREFIX)) {
 680                 currencyNames.put(key.substring(CURRENCY_SYMBOL_PREFIX.length()), map.get(key));
 681             }
 682         }
 683         return currencyNames;
 684     }
 685 
 686     private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) {
 687         Map<String, Object> names = new HashMap<>();
 688 
 689         // Copy over missing time zone ids from JRE for English locale
 690         if (id.equals("en")) {
 691             Map<String[], String> jreMetaMap = new HashMap<>();
 692             jreTimeZoneNames.stream().forEach(e -> {
 693                 String tzid = (String)e[0];
 694                 String[] data = (String[])e[1];
 695 
 696                 if (map.get(TIMEZONE_ID_PREFIX + tzid) == null &&
 697                     handlerMetaZones.get(tzid) == null ||
 698                     handlerMetaZones.get(tzid) != null &&
 699                     map.get(METAZONE_ID_PREFIX + handlerMetaZones.get(tzid)) == null) {
 700 
 701                     // First, check the alias
 702                     String canonID = canonicalTZMap.get(tzid);
 703                     if (canonID != null && !tzid.equals(canonID)) {
 704                         Object value = map.get(TIMEZONE_ID_PREFIX + canonID);
 705                         if (value != null) {
 706                             names.put(tzid, value);
 707                             return;
 708                         } else {
 709                             String meta = handlerMetaZones.get(canonID);
 710                             if (meta != null) {
 711                                 value = map.get(METAZONE_ID_PREFIX + meta);
 712                                 if (value != null) {
 713                                     names.put(tzid, meta);
 714                                     return;
 715                                 }
 716                             }
 717                         }
 718                     }
 719 
 720                     // Check the CLDR meta key
 721                     Optional<Map.Entry<String, String>> cldrMeta =
 722                         handlerMetaZones.getData().entrySet().stream()
 723                             .filter(me ->
 724                                 Arrays.deepEquals(data,
 725                                     (String[])map.get(METAZONE_ID_PREFIX + me.getValue())))
 726                             .findAny();
 727                     cldrMeta.ifPresentOrElse(meta -> names.put(tzid, meta.getValue()), () -> {
 728                         // Check the JRE meta key, add if there is not.
 729                         Optional<Map.Entry<String[], String>> jreMeta =
 730                             jreMetaMap.entrySet().stream()
 731                                 .filter(jm -> Arrays.deepEquals(data, jm.getKey()))
 732                                 .findAny();
 733                         jreMeta.ifPresentOrElse(meta -> names.put(tzid, meta.getValue()), () -> {
 734                                 String metaName = "JRE_" + tzid.replaceAll("[/-]", "_");
 735                                 names.put(METAZONE_ID_PREFIX + metaName, data);
 736                                 names.put(tzid, metaName);
 737                         });
 738                     });
 739                 }
 740             });
 741         }
 742 
 743         getAvailableZoneIds().stream().forEach(tzid -> {
 744             // If the tzid is deprecated, get the data for the replacement id
 745             String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid))
 746                                    .orElse(tzid);
 747             Object data = map.get(TIMEZONE_ID_PREFIX + tzKey);
 748 
 749             if (data instanceof String[]) {






 750                 names.put(tzid, data);

 751             } else {
 752                 String meta = handlerMetaZones.get(tzKey);
 753                 if (meta != null) {
 754                     String metaKey = METAZONE_ID_PREFIX + meta;
 755                     data = map.get(metaKey);
 756                     if (data instanceof String[]) {
 757                         // Keep the metazone prefix here.
 758                         names.put(metaKey, data);
 759                         names.put(tzid, meta);
 760                     }
 761                 }
 762             }
 763         });
 764 
 765         // exemplar cities.
 766         Map<String, Object> exCities = map.entrySet().stream()
 767                 .filter(e -> e.getKey().startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX))
 768                 .collect(Collectors
 769                         .toMap(Map.Entry::getKey, Map.Entry::getValue));
 770         names.putAll(exCities);
 771 
 772         if (!id.equals("en") &&
 773             !names.isEmpty()) {
 774             // CLDR does not have UTC entry, so add it here.
 775             names.put("UTC", EMPTY_ZONE);
 776 
 777             // no metazone zones
 778             Arrays.asList(handlerMetaZones.get(MetaZonesParseHandler.NO_METAZONE_KEY)
 779                 .split("\\s")).stream()
 780                 .forEach(tz -> {
 781                     names.put(tz, EMPTY_ZONE);
 782                 });
 783         }
 784 







 785         return names;
 786     }
 787 
 788     /**
 789      * Extracts the language independent calendar data. Each of the two keys,
 790      * "firstDayOfWeek" and "minimalDaysInFirstWeek" has a string value consists of
 791      * one or multiple occurrences of:
 792      *  i: rg1 rg2 ... rgn;
 793      * where "i" is the data for the following regions (delimited by a space) after
 794      * ":", and ends with a ";".
 795      */
 796     private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) {
 797         Map<String, Object> calendarData = new LinkedHashMap<>();
 798         if (id.equals("root")) {
 799             calendarData.put("firstDayOfWeek",
 800                 IntStream.range(1, 8)
 801                     .mapToObj(String::valueOf)
 802                     .filter(d -> map.keySet().contains(CALENDAR_FIRSTDAY_PREFIX + d))
 803                     .map(d -> d + ": " + map.get(CALENDAR_FIRSTDAY_PREFIX + d))
 804                     .collect(Collectors.joining(";")));


   1 /*
   2  * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.cldrconverter;
  27 

  28 import build.tools.cldrconverter.BundleGenerator.BundleType;
  29 import java.io.File;
  30 import java.io.IOException;
  31 import java.io.UncheckedIOException;
  32 import java.nio.file.*;
  33 import java.text.MessageFormat;
  34 import java.time.*;
  35 import java.util.*;
  36 import java.util.ResourceBundle.Control;
  37 import java.util.logging.Level;
  38 import java.util.logging.Logger;
  39 import java.util.stream.Collectors;
  40 import java.util.stream.IntStream;
  41 import java.util.stream.Stream;
  42 import javax.xml.parsers.SAXParser;
  43 import javax.xml.parsers.SAXParserFactory;
  44 import org.xml.sax.SAXNotRecognizedException;
  45 import org.xml.sax.SAXNotSupportedException;
  46 
  47 


  71     private static String WINZONES_SOURCE_FILE;
  72     private static String PLURALS_SOURCE_FILE;
  73     static String DESTINATION_DIR = "build/gensrc";
  74 
  75     static final String LOCALE_NAME_PREFIX = "locale.displayname.";
  76     static final String LOCALE_SEPARATOR = LOCALE_NAME_PREFIX + "separator";
  77     static final String LOCALE_KEYTYPE = LOCALE_NAME_PREFIX + "keytype";
  78     static final String LOCALE_KEY_PREFIX = LOCALE_NAME_PREFIX + "key.";
  79     static final String LOCALE_TYPE_PREFIX = LOCALE_NAME_PREFIX + "type.";
  80     static final String LOCALE_TYPE_PREFIX_CA = LOCALE_TYPE_PREFIX + "ca.";
  81     static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol.";
  82     static final String CURRENCY_NAME_PREFIX = "currency.displayname.";
  83     static final String CALENDAR_NAME_PREFIX = "calendarname.";
  84     static final String CALENDAR_FIRSTDAY_PREFIX = "firstDay.";
  85     static final String CALENDAR_MINDAYS_PREFIX = "minDays.";
  86     static final String TIMEZONE_ID_PREFIX = "timezone.id.";
  87     static final String EXEMPLAR_CITY_PREFIX = "timezone.excity.";
  88     static final String ZONE_NAME_PREFIX = "timezone.displayname.";
  89     static final String METAZONE_ID_PREFIX = "metazone.id.";
  90     static final String PARENT_LOCALE_PREFIX = "parentLocale.";
  91     static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE";
  92     static final String[] EMPTY_ZONE = {"", "", "", "", "", ""};
  93     static final String META_ETCUTC_ZONE_NAME = "ETC_UTC";
  94 
  95     // Old 3-letter-id mappings for compatibility. Copied from sun.util.calendar.ZoneInfoFile.
  96     private static final String[][] oldMappings = new String[][] {
  97         { "ACT", "Australia/Darwin" },
  98         { "AET", "Australia/Sydney" },
  99         { "AGT", "America/Argentina/Buenos_Aires" },
 100         { "ART", "Africa/Cairo" },
 101         { "AST", "America/Anchorage" },
 102         { "BET", "America/Sao_Paulo" },
 103         { "BST", "Asia/Dhaka" },
 104         { "CAT", "Africa/Harare" },
 105         { "CNT", "America/St_Johns" },
 106         { "CST", "America/Chicago" },
 107         { "CTT", "Asia/Shanghai" },
 108         { "EAT", "Africa/Addis_Ababa" },
 109         { "ECT", "Europe/Paris" },
 110         { "IET", "America/Indiana/Indianapolis" },
 111         { "IST", "Asia/Kolkata" },
 112         { "JST", "Asia/Tokyo" },
 113         { "MIT", "Pacific/Apia" },
 114         { "NET", "Asia/Yerevan" },
 115         { "NST", "Pacific/Auckland" },
 116         { "PLT", "Asia/Karachi" },
 117         { "PNT", "America/Phoenix" },
 118         { "PRT", "America/Puerto_Rico" },
 119         { "PST", "America/Los_Angeles" },
 120         { "SST", "Pacific/Guadalcanal" },
 121         { "VST", "Asia/Ho_Chi_Minh" },
 122     };
 123 
 124     private static SupplementDataParseHandler handlerSuppl;
 125     private static LikelySubtagsParseHandler handlerLikelySubtags;
 126     private static WinZonesParseHandler handlerWinZones;
 127     static PluralsParseHandler handlerPlurals;
 128     static SupplementalMetadataParseHandler handlerSupplMeta;
 129     static NumberingSystemsParseHandler handlerNumbering;
 130     static MetaZonesParseHandler handlerMetaZones;
 131     static TimeZoneParseHandler handlerTimeZone;
 132     private static BundleGenerator bundleGenerator;
 133 
 134     // java.base module related
 135     static boolean isBaseModule = false;
 136     static final Set<Locale> BASE_LOCALES = new HashSet<>();
 137 
 138     // "parentLocales" map
 139     private static final Map<String, SortedSet<String>> parentLocalesMap = new HashMap<>();
 140     private static final ResourceBundle.Control defCon =
 141         ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
 142 


 699         return localeNames;
 700     }
 701 
 702     @SuppressWarnings("AssignmentToForLoopParameter")
 703     private static Map<String, Object> extractCurrencyNames(Map<String, Object> map, String id, String names)
 704             throws Exception {
 705         Map<String, Object> currencyNames = new TreeMap<>(KeyComparator.INSTANCE);
 706         for (String key : map.keySet()) {
 707             if (key.startsWith(CURRENCY_NAME_PREFIX)) {
 708                 currencyNames.put(key.substring(CURRENCY_NAME_PREFIX.length()), map.get(key));
 709             } else if (key.startsWith(CURRENCY_SYMBOL_PREFIX)) {
 710                 currencyNames.put(key.substring(CURRENCY_SYMBOL_PREFIX.length()), map.get(key));
 711             }
 712         }
 713         return currencyNames;
 714     }
 715 
 716     private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) {
 717         Map<String, Object> names = new HashMap<>();
 718 






















































 719         getAvailableZoneIds().stream().forEach(tzid -> {
 720             // If the tzid is deprecated, get the data for the replacement id
 721             String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid))
 722                                    .orElse(tzid);
 723             Object data = map.get(TIMEZONE_ID_PREFIX + tzKey);
 724 
 725             if (data instanceof String[]) {
 726                 // Hack for UTC. UTC is an alias to Etc/UTC in CLDR
 727                 if (tzid.equals("Etc/UTC") && !map.containsKey(TIMEZONE_ID_PREFIX + "UTC")) {
 728                     names.put(METAZONE_ID_PREFIX + META_ETCUTC_ZONE_NAME, data);
 729                     names.put(tzid, META_ETCUTC_ZONE_NAME);
 730                     names.put("UTC", META_ETCUTC_ZONE_NAME);
 731                 } else {
 732                     names.put(tzid, data);
 733                 }
 734             } else {
 735                 String meta = handlerMetaZones.get(tzKey);
 736                 if (meta != null) {
 737                     String metaKey = METAZONE_ID_PREFIX + meta;
 738                     data = map.get(metaKey);
 739                     if (data instanceof String[]) {
 740                         // Keep the metazone prefix here.
 741                         names.put(metaKey, data);
 742                         names.put(tzid, meta);
 743                     }
 744                 }
 745             }
 746         });
 747 
 748         // exemplar cities.
 749         Map<String, Object> exCities = map.entrySet().stream()
 750             .filter(e -> e.getKey().startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX))
 751             .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

 752         names.putAll(exCities);
 753 
 754         // If there's no UTC entry at this point, add an empty one
 755         if (!names.isEmpty() && !names.containsKey("UTC")) {
 756             names.putIfAbsent(METAZONE_ID_PREFIX + META_EMPTY_ZONE_NAME, EMPTY_ZONE);
 757             names.put("UTC", META_EMPTY_ZONE_NAME);







 758         }
 759 
 760         // Finally some compatibility stuff
 761         Arrays.stream(oldMappings)
 762             .filter(oldmap -> !names.containsKey(oldmap[0]) && names.containsKey(oldmap[1]))
 763             .forEach(oldmap -> {
 764                 names.put(oldmap[0], names.get(oldmap[1]));
 765             });
 766 
 767         return names;
 768     }
 769 
 770     /**
 771      * Extracts the language independent calendar data. Each of the two keys,
 772      * "firstDayOfWeek" and "minimalDaysInFirstWeek" has a string value consists of
 773      * one or multiple occurrences of:
 774      *  i: rg1 rg2 ... rgn;
 775      * where "i" is the data for the following regions (delimited by a space) after
 776      * ":", and ends with a ";".
 777      */
 778     private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) {
 779         Map<String, Object> calendarData = new LinkedHashMap<>();
 780         if (id.equals("root")) {
 781             calendarData.put("firstDayOfWeek",
 782                 IntStream.range(1, 8)
 783                     .mapToObj(String::valueOf)
 784                     .filter(d -> map.keySet().contains(CALENDAR_FIRSTDAY_PREFIX + d))
 785                     .map(d -> d + ": " + map.get(CALENDAR_FIRSTDAY_PREFIX + d))
 786                     .collect(Collectors.joining(";")));


< prev index next >