1 package org.unicode.cldr.util; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.util.Collections; 6 import java.util.HashMap; 7 import java.util.HashSet; 8 import java.util.List; 9 import java.util.Locale; 10 import java.util.Map; 11 import java.util.Set; 12 import java.util.TreeSet; 13 14 import com.ibm.icu.util.ICUUncheckedIOException; 15 16 /** 17 * List of locale IDs which are somehow 'special'. Parses SpecialLocales.txt 18 * 19 * @author srl 20 * 21 */ 22 public class SpecialLocales { 23 private static final String INCLUDE_SUBLOCALES = "*"; 24 25 public enum Type { 26 /** 27 * Locale may not be modified by user. 28 */ 29 readonly, 30 /** 31 * Locale may be modified by user. Contents aren't part of CLDR release and may change. 32 */ 33 scratch 34 }; 35 36 /** 37 * Get the type of this locale 38 * 39 * @param l 40 * @return a Type or null 41 */ 42 public static Type getType(CLDRLocale l) { 43 return getInstance().getTypeInternal(l); 44 } 45 46 /** 47 * Get all CLDRLocales matching this type. Does not include wildcard (*) sublocales. 48 * 49 * @param t 50 * @return a set, or null if none found 51 */ 52 public static Set<CLDRLocale> getByType(Type t) { 53 return getInstance().getByTypeInternal(t); 54 } 55 56 /** 57 * Get the comment on this locale. Strip out @ text. 58 * 59 * @param l 60 * @return string or null 61 */ 62 public static String getComment(CLDRLocale l) { 63 return getCommentRaw(l).replaceAll("@", ""); 64 } 65 66 /** 67 * Get the comment on this locale. Include "@locale" markers. 68 * 69 * @param l 70 * @return string or null 71 */ 72 public static String getCommentRaw(CLDRLocale l) { 73 return getInstance().getCommentInternal(l).replaceAll("@@", "@" + l.getBaseName()); 74 } 75 76 /** 77 * Singleton object 78 */ 79 private static SpecialLocales singleton = null; 80 81 /** 82 * Internal accessor. All access is via the static functions. 83 * @return 84 */ 85 private static synchronized SpecialLocales getInstance() { 86 if (singleton == null) { 87 singleton = new SpecialLocales(); 88 } 89 return singleton; 90 } 91 92 private Map<CLDRLocale, Type> specials = new HashMap<CLDRLocale, Type>(); 93 private Map<Type, Set<CLDRLocale>> types = new HashMap<Type, Set<CLDRLocale>>(); 94 private Map<CLDRLocale, String> comments = new HashMap<CLDRLocale, String>(); 95 private Set<CLDRLocale> specialsWildcards = new HashSet<CLDRLocale>(); 96 97 public Set<CLDRLocale> getByTypeInternal(Type t) { 98 return types.get(t); 99 } 100 101 public Type getTypeInternal(CLDRLocale l) { 102 l = findLocale(l, l); 103 return specials.get(l); 104 } 105 106 public String getCommentInternal(CLDRLocale l) { 107 l = findLocale(l, l); 108 return comments.get(l); 109 } 110 111 public CLDRLocale findLocale(CLDRLocale fromLocale, CLDRLocale origLocale) { 112 if (origLocale == fromLocale && specials.containsKey(origLocale)) { 113 return origLocale; // explicit locale - no search. 114 } 115 if (fromLocale == null) { 116 return origLocale; 117 } 118 if (specialsWildcards.contains(fromLocale)) { 119 return fromLocale; 120 } 121 return findLocale(fromLocale.getParent(), origLocale); 122 } 123 124 /** 125 * Internal constructor 126 */ 127 private SpecialLocales() { 128 // from StandardCodes.java 129 String line; 130 int ln = 0; 131 try { 132 BufferedReader lstreg = CldrUtility.getUTF8Data("SpecialLocales.txt"); 133 while (true) { 134 line = lstreg.readLine(); 135 ln++; 136 if (line == null) 137 break; 138 int commentPos = line.indexOf('#'); 139 if (commentPos >= 0) { 140 line = line.substring(0, commentPos); 141 } 142 line = line.trim(); 143 if (line.length() == 0) 144 continue; 145 List<String> stuff = CldrUtility.splitList(line, ';', true); 146 String id = (String) stuff.get(0); 147 boolean includeSublocs = (id.endsWith(INCLUDE_SUBLOCALES)); 148 if (includeSublocs) { 149 id = id.substring(0, id.length() - INCLUDE_SUBLOCALES.length()); 150 } 151 String type = (String) stuff.get(1); 152 String comment = (String) stuff.get(2); 153 Type t = null; 154 155 // verify that the locale is valid 156 CLDRLocale l = null; 157 try { 158 l = CLDRLocale.getInstance(id); 159 } catch (Exception e) { 160 throw new IllegalArgumentException("Invalid CLDRLocale in SpecialLocales.txt:" + ln + ": " + line); 161 } 162 163 // verify that the type is valid 164 try { 165 t = Type.valueOf(type.toLowerCase(Locale.ENGLISH)); 166 } catch (Exception e) { 167 throw new IllegalArgumentException("Invalid SpecialLocales.Type in SpecialLocales.txt:" + ln + ": " 168 + line); 169 } 170 171 Set<CLDRLocale> s = types.get(t); 172 if (s == null) { 173 s = new TreeSet<CLDRLocale>(); 174 types.put(t, s); 175 } 176 s.add(l); 177 specials.put(l, t); 178 if (includeSublocs) { 179 specialsWildcards.add(l); 180 } 181 if (!comment.isEmpty()) { 182 comments.put(l, comment); 183 } 184 if (false) { 185 System.out.println(SpecialLocales.class.getSimpleName() + ": locale " + l + ", includejSublocs=" + includeSublocs + ", type=" + t 186 + ", comment: " + comment); 187 } 188 } 189 } catch (IOException e) { 190 throw new ICUUncheckedIOException("Internal Error", e); 191 } 192 specials = Collections.unmodifiableMap(specials); 193 specialsWildcards = Collections.unmodifiableSet(specialsWildcards); 194 comments = Collections.unmodifiableMap(comments); 195 types = Collections.unmodifiableMap(types); 196 } 197 198 } 199