1 package org.unicode.cldr.tool; 2 3 import com.ibm.icu.text.UTF16; 4 import com.ibm.icu.util.ICUUncheckedIOException; 5 import com.ibm.icu.util.ULocale; 6 import java.io.IOException; 7 import java.util.Collections; 8 import java.util.LinkedHashSet; 9 import java.util.Locale; 10 import java.util.Map; 11 import java.util.Set; 12 import java.util.TreeMap; 13 import org.unicode.cldr.util.CldrUtility; 14 import org.unicode.cldr.util.CldrUtility.LineHandler; 15 import org.unicode.cldr.util.StandardCodes; 16 17 public class CountryCodeConverter { 18 19 private static final boolean SHOW_SKIP = CldrUtility.getProperty("SHOW_SKIP", false); 20 21 private static Map<String, String> nameToCountryCode = 22 new TreeMap<>(new UTF16.StringComparator(true, true, 0)); 23 private static Set<String> parseErrors = new LinkedHashSet<>(); 24 getCodeFromName(String display, boolean showMissing)25 public static String getCodeFromName(String display, boolean showMissing) { 26 return getCodeFromName(display, showMissing, null); 27 } 28 29 /** 30 * @param display 31 * @param showMissing 32 * @param missing will contain a list of missing names (if showMissing is true) 33 * @return 34 */ getCodeFromName(String display, boolean showMissing, Set<String> missing)35 public static String getCodeFromName(String display, boolean showMissing, Set<String> missing) { 36 String trial = display.trim().toLowerCase(Locale.ENGLISH); 37 if (trial.startsWith("\"") && trial.endsWith("\"")) { 38 trial = trial.substring(1, trial.length() - 2); 39 } 40 if (trial.startsWith("the ")) { 41 trial = trial.substring(4); 42 } 43 String result = nameToCountryCode.get(trial); 44 if ("skip".equals(result)) { 45 return null; 46 } 47 if (result == null) { 48 trial = reverseComma(display); 49 if (trial != null) { 50 result = nameToCountryCode.get(trial); 51 // if (result != null) { 52 // addName(trial, result); 53 // } 54 } 55 } 56 if (result == null && (showMissing || SHOW_SKIP)) { 57 System.err.println( 58 "ERROR: CountryCodeConverter missing code for " 59 + display 60 + ".\n" 61 + "To fix: add to external/alternate_country_names.txt a line such as:\n" 62 + "\t<code>;\t<name>;\t" 63 + display); 64 if (missing != null) { 65 missing.add(display); 66 } 67 } 68 return result; 69 } 70 names()71 public static Set<String> names() { 72 return nameToCountryCode.keySet(); 73 } 74 reverseComma(String display)75 private static String reverseComma(String display) { 76 String trial; 77 trial = null; 78 int comma = display.indexOf(','); 79 if (comma >= 0) { 80 trial = display.substring(comma + 1).trim() + " " + display.substring(0, comma).trim(); 81 } 82 return trial; 83 } 84 85 static { 86 try { loadNames()87 loadNames(); 88 } catch (IOException e) { 89 throw new ICUUncheckedIOException(e); 90 } 91 } 92 loadNames()93 static void loadNames() throws IOException { 94 for (String country : ULocale.getISOCountries()) { 95 addName(ULocale.getDisplayCountry("und-" + country, "en"), country); 96 } 97 StandardCodes sc = StandardCodes.make(); 98 Set<String> goodAvailableCodes = sc.getGoodAvailableCodes("territory"); 99 100 for (String country : goodAvailableCodes) { 101 String description = sc.getFullData("territory", country).get(0); 102 if (country.equals("057")) continue; 103 addName(description, country); 104 } 105 CldrUtility.handleFile( 106 "external/alternate_country_names.txt", new MyHandler(goodAvailableCodes)); 107 nameToCountryCode = CldrUtility.protectCollection(nameToCountryCode); 108 parseErrors = Collections.unmodifiableSet(parseErrors); 109 } 110 111 static class MyHandler implements LineHandler { 112 private Set<String> goodAvailableCodes; 113 MyHandler(Set<String> goodAvailableCodes)114 public MyHandler(Set<String> goodAvailableCodes) { 115 this.goodAvailableCodes = goodAvailableCodes; 116 } 117 118 @Override handle(String line)119 public boolean handle(String line) { 120 if (line.trim().length() == 0 || line.trim().startsWith("#")) { 121 return true; // don't show skips, ignore comment lines 122 } 123 String[] pieces = line.split(";"); 124 String country = pieces[0].trim(); 125 if (!goodAvailableCodes.contains(country)) { 126 // TODO- ? 127 } 128 // Note: field 1 is ignored. 129 130 addName(pieces[2].trim(), country); 131 return true; 132 } 133 } 134 addName(String key, String code)135 static void addName(String key, String code) { 136 addName2(key, code); 137 String trial = reverseComma(key); 138 if (trial != null) { 139 addName2(trial, code); 140 } 141 } 142 addName2(String key, String code)143 private static void addName2(String key, String code) { 144 key = key.toLowerCase(Locale.ENGLISH); 145 if (key.startsWith("the ")) { 146 key = key.substring(4); 147 } 148 String old = nameToCountryCode.get(key); 149 if (old != null && !code.equals(old)) { 150 System.err.println("Conflict!!" + key + "\t" + old + "\t" + code); 151 return; 152 } 153 nameToCountryCode.put(key, code); 154 } 155 getParseErrors()156 public static Set<String> getParseErrors() { 157 return parseErrors; 158 } 159 } 160