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