1 /* 2 * Copyright (c) 2012, 2013, 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 java.io.File; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.util.Formatter; 32 import java.util.HashSet; 33 import java.util.Map; 34 import java.util.Set; 35 import java.util.SortedSet; 36 37 class ResourceBundleGenerator implements BundleGenerator { 38 @Override 39 public void generateBundle(String packageName, String baseName, String localeID, boolean useJava, 40 Map<String, ?> map, BundleType type) throws IOException { 41 String suffix = useJava ? ".java" : ".properties"; 42 String lang = CLDRConverter.getLanguageCode(localeID); 43 String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator 44 + packageName + File.separator + "resources" + File.separator + "cldr"; 45 if (lang.length() > 0) { 46 dirName = dirName + File.separator + lang; 47 packageName = packageName + ".resources.cldr." + lang; 48 } else { 49 packageName = packageName + ".resources.cldr"; 50 } 51 File dir = new File(dirName); 52 if (!dir.exists()) { 53 dir.mkdirs(); 54 } 55 File file = new File(dir, baseName + ("root".equals(localeID) ? "" : "_" + localeID) + suffix); 56 if (!file.exists()) { 57 file.createNewFile(); 58 } 59 CLDRConverter.info("\tWriting file " + file); 60 61 String encoding; 62 if (useJava) { 63 if (CLDRConverter.USE_UTF8) { 64 encoding = "utf-8"; 65 } else { 66 encoding = "us-ascii"; 67 } 68 } else { 72 Formatter fmt = null; 73 if (type == BundleType.TIMEZONE) { 74 fmt = new Formatter(); 75 Set<String> metaKeys = new HashSet<>(); 76 for (String key : map.keySet()) { 77 if (key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) { 78 String meta = key.substring(CLDRConverter.METAZONE_ID_PREFIX.length()); 79 String[] value; 80 value = (String[]) map.get(key); 81 fmt.format(" final String[] %s = new String[] {\n", meta); 82 for (String s : value) { 83 fmt.format(" \"%s\",\n", CLDRConverter.saveConvert(s, useJava)); 84 } 85 fmt.format(" };\n"); 86 metaKeys.add(key); 87 } 88 } 89 for (String key : metaKeys) { 90 map.remove(key); 91 } 92 } 93 94 try (PrintWriter out = new PrintWriter(file, encoding)) { 95 // Output copyright headers 96 out.println(CopyrightHeaders.getOpenJDKCopyright()); 97 out.println(CopyrightHeaders.getUnicodeCopyright()); 98 99 if (useJava) { 100 out.println("package sun." + packageName + ";\n"); 101 out.printf("import %s;\n\n", type.getPathName()); 102 out.printf("public class %s%s extends %s {\n", baseName, "root".equals(localeID) ? "" : "_" + localeID, type.getClassName()); 103 104 out.println(" @Override\n" + 105 " protected final Object[][] getContents() {"); 106 if (fmt != null) { 107 out.print(fmt.toString()); 108 } 109 out.println(" final Object[][] data = new Object[][] {"); 110 } 111 for (String key : map.keySet()) { 112 if (useJava) { 113 Object value = map.get(key); 114 if (value == null) { 115 CLDRConverter.warning("null value for " + key); 116 } else if (value instanceof String) { 117 if (type == BundleType.TIMEZONE) { 118 out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert((String) value, useJava)); 119 } else { 120 out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.saveConvert((String) value, useJava)); 121 } 122 } else if (value instanceof String[]) { 123 String[] values = (String[]) value; 124 out.println(" { \"" + key + "\",\n new String[] {"); 125 for (String s : values) { 126 out.println(" \"" + CLDRConverter.saveConvert(s, useJava) + "\","); 127 } 128 out.println(" }\n },"); 129 } else { 130 throw new RuntimeException("unknown value type: " + value.getClass().getName()); 131 } 132 } else { 133 out.println(key + "=" + CLDRConverter.saveConvert((String) map.get(key), useJava)); 134 } 135 } 136 if (useJava) { 137 out.println(" };\n return data;\n }\n}"); 138 } 139 } 140 } 141 142 private static final String METAINFO_CLASS = "CLDRLocaleDataMetaInfo"; 143 144 @Override 145 public void generateMetaInfo(Map<String, SortedSet<String>> metaInfo) throws IOException { 146 String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + 147 File.separator + "resources" + File.separator + "cldr" + File.separator + 148 "provider" + File.separator ; 149 File dir = new File(dirName); 150 if (!dir.exists()) { 151 dir.mkdirs(); 152 } 153 File file = new File(dir, METAINFO_CLASS + ".java"); 154 if (!file.exists()) { 155 file.createNewFile(); 156 } 157 CLDRConverter.info("Generating file " + file); 158 159 try (PrintWriter out = new PrintWriter(file, "us-ascii")) { 160 out.println(CopyrightHeaders.getOpenJDKCopyright()); 161 162 out.println("package sun.util.resources.cldr.provider;\n\n" 163 + "import java.util.ListResourceBundle;\n" 164 + "import sun.util.locale.provider.LocaleProviderAdapter;\n" 165 + "import sun.util.locale.provider.LocaleDataMetaInfo;\n"); 166 out.printf("public class %s extends ListResourceBundle implements LocaleDataMetaInfo {\n", METAINFO_CLASS); 167 out.println(" @Override\n" + 168 " protected final Object[][] getContents() {\n" + 169 " final Object[][] data = new Object[][] {"); 170 for (String key : metaInfo.keySet()) { 171 out.printf(" { \"%s\",\n", key); 172 out.printf(" \"%s\" },\n", toLocaleList(metaInfo.get(key))); 173 } 174 out.println(" };\n return data;\n }\n\n"); 175 176 out.println(" public LocaleProviderAdapter.Type getType() {\n" + 177 " return LocaleProviderAdapter.Type.CLDR;\n" + 178 " }\n\n"); 179 180 out.println(" public String availableLanguageTags(String category) {\n" + 181 " return getString(category);\n" + 182 " };\n}"); 183 } 184 } 185 186 private static String toLocaleList(SortedSet<String> set) { 187 StringBuilder sb = new StringBuilder(set.size() * 6); 188 for (String id : set) { 189 if (!"root".equals(id)) { 190 if (sb.length() > 0) { 191 sb.append(' '); 192 } 193 sb.append(id); 194 } 195 } 196 return sb.toString(); 197 } 198 } | 1 /* 2 * Copyright (c) 2012, 2015, 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 java.io.File; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.util.Formatter; 32 import java.util.HashSet; 33 import java.util.HashMap; 34 import java.util.LinkedHashMap; 35 import java.util.Map; 36 import java.util.Locale; 37 import java.util.Objects; 38 import java.util.Set; 39 import java.util.SortedSet; 40 41 class ResourceBundleGenerator implements BundleGenerator { 42 // preferred timezones - keeping compatibility with JDK1.1 3 letter abbreviations 43 private static final String[] preferredTZIDs = { 44 "America/Los_Angeles", 45 "America/Denver", 46 "America/Phoenix", 47 "America/Chicago", 48 "America/New_York", 49 "America/Indianapolis", 50 "Pacific/Honolulu", 51 "America/Anchorage", 52 "America/Halifax", 53 "America/Sitka", 54 "America/St_Johns", 55 "Europe/Paris", 56 // Although CLDR does not support abbreviated zones, handle "GMT" as a 57 // special case here, as it is specified in the javadoc. 58 "GMT", 59 "Africa/Casablanca", 60 "Asia/Jerusalem", 61 "Asia/Tokyo", 62 "Europe/Bucharest", 63 "Asia/Shanghai", 64 }; 65 66 // For duplicated values 67 private static final String META_VALUE_PREFIX = "metaValue_"; 68 69 @Override 70 public void generateBundle(String packageName, String baseName, String localeID, boolean useJava, 71 Map<String, ?> map, BundleType type) throws IOException { 72 String suffix = useJava ? ".java" : ".properties"; 73 String lang = CLDRConverter.getLanguageCode(localeID); 74 String ctry = CLDRConverter.getCountryCode(localeID); 75 String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator 76 + packageName + File.separator + "resources" + File.separator + "cldr"; 77 if (lang.length() > 0) { 78 if (CLDRConverter.isBaseModule ^ isBaseLocale(localeID)) { 79 return; 80 } 81 dirName = dirName + File.separator + lang + 82 (ctry != null && ctry.length() > 0 ? File.separator + ctry : ""); 83 packageName = packageName + ".resources.cldr." + lang + 84 (ctry != null && ctry.length() > 0 ? "." + ctry : ""); 85 } else { 86 if (!CLDRConverter.isBaseModule) { 87 return; 88 } 89 packageName = packageName + ".resources.cldr"; 90 } 91 File dir = new File(dirName); 92 if (!dir.exists()) { 93 dir.mkdirs(); 94 } 95 File file = new File(dir, baseName + ("root".equals(localeID) ? "" : "_" + localeID) + suffix); 96 if (!file.exists()) { 97 file.createNewFile(); 98 } 99 CLDRConverter.info("\tWriting file " + file); 100 101 String encoding; 102 if (useJava) { 103 if (CLDRConverter.USE_UTF8) { 104 encoding = "utf-8"; 105 } else { 106 encoding = "us-ascii"; 107 } 108 } else { 112 Formatter fmt = null; 113 if (type == BundleType.TIMEZONE) { 114 fmt = new Formatter(); 115 Set<String> metaKeys = new HashSet<>(); 116 for (String key : map.keySet()) { 117 if (key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) { 118 String meta = key.substring(CLDRConverter.METAZONE_ID_PREFIX.length()); 119 String[] value; 120 value = (String[]) map.get(key); 121 fmt.format(" final String[] %s = new String[] {\n", meta); 122 for (String s : value) { 123 fmt.format(" \"%s\",\n", CLDRConverter.saveConvert(s, useJava)); 124 } 125 fmt.format(" };\n"); 126 metaKeys.add(key); 127 } 128 } 129 for (String key : metaKeys) { 130 map.remove(key); 131 } 132 133 // Make it preferred ordered 134 LinkedHashMap<String, Object> newMap = new LinkedHashMap<>(); 135 for (String preferred : preferredTZIDs) { 136 if (map.containsKey(preferred)) { 137 newMap.put(preferred, map.remove(preferred)); 138 } else if ("GMT".equals(preferred) && 139 metaKeys.contains(CLDRConverter.METAZONE_ID_PREFIX+preferred)) { 140 newMap.put(preferred, preferred); 141 } 142 } 143 newMap.putAll(map); 144 map = newMap; 145 } else { 146 // generic reduction of duplicated values 147 Map<String, Object> newMap = null; 148 for (String key : map.keySet()) { 149 Object val = map.get(key); 150 String metaVal = null; 151 152 for (Map.Entry<String, ?> entry : map.entrySet()) { 153 String k = entry.getKey(); 154 if (!k.equals(key) && 155 Objects.deepEquals(val, entry.getValue()) && 156 !(Objects.nonNull(newMap) && newMap.containsKey(k))) { 157 if (Objects.isNull(newMap)) { 158 newMap = new HashMap<>(); 159 fmt = new Formatter(); 160 } 161 162 if (Objects.isNull(metaVal)) { 163 metaVal = META_VALUE_PREFIX + key.replaceAll("\\.", "_"); 164 165 if (val instanceof String[]) { 166 fmt.format(" final String[] %s = new String[] {\n", metaVal); 167 for (String s : (String[])val) { 168 fmt.format(" \"%s\",\n", CLDRConverter.saveConvert(s, useJava)); 169 } 170 fmt.format(" };\n"); 171 } else { 172 fmt.format(" final String %s = \"%s\";\n", metaVal, CLDRConverter.saveConvert((String)val, useJava)); 173 } 174 } 175 176 newMap.put(k, metaVal); 177 } 178 } 179 180 if (Objects.nonNull(metaVal)) { 181 newMap.put(key, metaVal); 182 } 183 } 184 185 if (Objects.nonNull(newMap)) { 186 for (String key : map.keySet()) { 187 newMap.putIfAbsent(key, map.get(key)); 188 } 189 map = newMap; 190 } 191 } 192 193 try (PrintWriter out = new PrintWriter(file, encoding)) { 194 // Output copyright headers 195 out.println(CopyrightHeaders.getOpenJDKCopyright()); 196 out.println(CopyrightHeaders.getUnicodeCopyright()); 197 198 if (useJava) { 199 out.println("package sun." + packageName + ";\n"); 200 out.printf("import %s;\n\n", type.getPathName()); 201 out.printf("public class %s%s extends %s {\n", baseName, "root".equals(localeID) ? "" : "_" + localeID, type.getClassName()); 202 203 out.println(" @Override\n" + 204 " protected final Object[][] getContents() {"); 205 if (fmt != null) { 206 out.print(fmt.toString()); 207 } 208 out.println(" final Object[][] data = new Object[][] {"); 209 } 210 for (String key : map.keySet()) { 211 if (useJava) { 212 Object value = map.get(key); 213 if (value == null) { 214 CLDRConverter.warning("null value for " + key); 215 } else if (value instanceof String) { 216 if (type == BundleType.TIMEZONE || 217 ((String)value).startsWith(META_VALUE_PREFIX)) { 218 out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert((String) value, useJava)); 219 } else { 220 out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.saveConvert((String) value, useJava)); 221 } 222 } else if (value instanceof String[]) { 223 String[] values = (String[]) value; 224 out.println(" { \"" + key + "\",\n new String[] {"); 225 for (String s : values) { 226 out.println(" \"" + CLDRConverter.saveConvert(s, useJava) + "\","); 227 } 228 out.println(" }\n },"); 229 } else { 230 throw new RuntimeException("unknown value type: " + value.getClass().getName()); 231 } 232 } else { 233 out.println(key + "=" + CLDRConverter.saveConvert((String) map.get(key), useJava)); 234 } 235 } 236 if (useJava) { 237 out.println(" };\n return data;\n }\n}"); 238 } 239 } 240 } 241 242 @Override 243 public void generateMetaInfo(Map<String, SortedSet<String>> metaInfo) throws IOException { 244 String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + 245 File.separator + 246 (CLDRConverter.isBaseModule ? "cldr" + File.separator + File.separator : 247 "resources" + File.separator + "cldr" + File.separator + "provider" + File.separator); 248 File dir = new File(dirName); 249 if (!dir.exists()) { 250 dir.mkdirs(); 251 } 252 String className = 253 (CLDRConverter.isBaseModule ? "CLDRBaseLocaleDataMetaInfo" : 254 "CLDRLocaleDataMetaInfo_" + 255 CLDRConverter.DESTINATION_DIR.substring(CLDRConverter.DESTINATION_DIR.lastIndexOf('/')+1) 256 .replaceAll("\\.", "_")); 257 File file = new File(dir, className + ".java"); 258 if (!file.exists()) { 259 file.createNewFile(); 260 } 261 CLDRConverter.info("Generating file " + file); 262 263 try (PrintWriter out = new PrintWriter(file, "us-ascii")) { 264 out.println(CopyrightHeaders.getOpenJDKCopyright()); 265 266 out.println((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" : 267 "package sun.util.resources.cldr.provider;\n\n") 268 + "import java.util.HashMap;\n" 269 + "import java.util.Map;\n" 270 + "import java.util.ListResourceBundle;\n" 271 + "import sun.util.locale.provider.LocaleProviderAdapter;\n" 272 + "import sun.util.locale.provider.LocaleDataMetaInfo;\n"); 273 out.printf("public class %s extends ListResourceBundle implements LocaleDataMetaInfo {\n", className); 274 out.println(" @Override\n" + 275 " protected final Object[][] getContents() {\n" + 276 " final Object[][] data = new Object[][] {"); 277 for (String key : metaInfo.keySet()) { 278 out.printf(" { \"%s\",\n", key); 279 out.printf(" \"%s\" },\n", 280 toLocaleList(key.equals("FormatData") ? metaInfo.get("AvailableLocales") : 281 metaInfo.get(key), 282 key.startsWith(CLDRConverter.PARENT_LOCALE_PREFIX))); 283 } 284 out.println(" };\n return data;\n }\n\n"); 285 286 out.println(" @Override\n" + 287 " public LocaleProviderAdapter.Type getType() {\n" + 288 " return LocaleProviderAdapter.Type.CLDR;\n" + 289 " }\n\n"); 290 291 out.println(" @Override\n" + 292 " public String availableLanguageTags(String category) {\n" + 293 " return getString(category);\n" + 294 " };\n\n"); 295 296 if (CLDRConverter.isBaseModule) { 297 out.printf(" public Map<String, String> parentLocales() {\n" + 298 " Map<String, String> ret = new HashMap<>();\n" + 299 " keySet().stream()\n" + 300 " .filter(key -> key.startsWith(\"%s\"))\n" + 301 " .forEach(key -> ret.put(key.substring(%d), getString(key)));\n" + 302 " return ret.isEmpty() ? null : ret;\n" + 303 " };\n}", 304 CLDRConverter.PARENT_LOCALE_PREFIX, 305 CLDRConverter.PARENT_LOCALE_PREFIX.length()); 306 } else { 307 out.println("}"); 308 } 309 } 310 } 311 312 private static final Locale.Builder LOCALE_BUILDER = new Locale.Builder(); 313 private static boolean isBaseLocale(String localeID) { 314 localeID = localeID.replaceAll("-", "_"); 315 // ignore script here 316 Locale locale = LOCALE_BUILDER 317 .clear() 318 .setLanguage(CLDRConverter.getLanguageCode(localeID)) 319 .setRegion(CLDRConverter.getCountryCode(localeID)) 320 .build(); 321 return CLDRConverter.BASE_LOCALES.contains(locale); 322 } 323 324 private static String toLocaleList(SortedSet<String> set, boolean all) { 325 StringBuilder sb = new StringBuilder(set.size() * 6); 326 for (String id : set) { 327 if (!"root".equals(id)) { 328 if (!all && CLDRConverter.isBaseModule ^ isBaseLocale(id)) { 329 continue; 330 } 331 if (sb.length() > 0) { 332 sb.append(' '); 333 } 334 sb.append(id); 335 } 336 } 337 return sb.toString(); 338 } 339 } |