• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.ArrayList;
4 import java.util.Set;
5 
6 /**
7  * Normalize and validate sets of locales. This class was split off from UserRegistry.java with
8  * the goal of encapsulation to support refactoring and implementation of new features such as
9  * warning a Manager who tries to assign to a Vetter unknown locales or locales that are not
10  * covered by their organization.
11  *
12  * A single locale may be represented by a string like "fr_CA" for Canadian French, or by
13  * a CLDRLocale object.
14  *
15  * A set of locales related to a particular Survey Tool user is compactly represented by a single string
16  * like "am fr_CA zh" (meaning "Amharic, Canadian French, and Chinese"). Survey Tool uses this compact
17  * representation for storage in the user database, and for browser inputting/editing forms, etc.
18  *
19  * Otherwise the preferred representation is a LocaleSet, which encapsulates a Set<CLDRLocale> along
20  * with special handling for isAllLocales.
21  */
22 public class LocaleNormalizer {
23 
24     /**
25      * Special constant for specifying access to no locales. Used with intlocs (not with locale access)
26      */
27     public static final String NO_LOCALES = "none";
28 
29     /**
30      * Special String constant for specifying access to all locales.
31      */
32     public static final String ALL_LOCALES = "*";
33 
isAllLocales(String localeList)34     public static boolean isAllLocales(String localeList) {
35         return (localeList != null) && (localeList.contains(ALL_LOCALES) || localeList.trim().equals("all"));
36     }
37 
38     /**
39      * Special LocaleSet constant for specifying access to all locales.
40      */
41     public static final LocaleSet ALL_LOCALES_SET = new LocaleSet(true);
42 
43     /**
44      * The actual set of locales used by CLDR. For Survey Tool, this may be set by SurveyMain during initialization.
45      * It is used for validation so it should not simply be ALL_LOCALES_SET.
46      */
47     private static LocaleSet knownLocales = null;
48 
setKnownLocales(Set<CLDRLocale> localeListSet)49     public static void setKnownLocales(Set<CLDRLocale> localeListSet) {
50         knownLocales = new LocaleSet();
51         knownLocales.addAll(localeListSet);
52     }
53 
54     /**
55      * Normalize the given locale-list string, removing invalid/duplicate locale names,
56      * and saving error/warning messages in this LocaleNormalizer object
57      *
58      * @param list the String like "zh  aa test123"
59      * @return the normalized string like "aa zh"
60      */
normalize(String list)61     public String normalize(String list) {
62         return norm(this, list, null);
63     }
64 
65     /**
66      * Normalize the given locale-list string, removing invalid/duplicate locale names
67      *
68      * Do not report any errors or warnings
69      *
70      * @param list the String like "zh  aa test123"
71      * @return the normalized string like "aa zh"
72      */
normalizeQuietly(String list)73     public static String normalizeQuietly(String list) {
74         return norm(null, list, null);
75     }
76 
77     /**
78      * Normalize the given locale-list string, removing invalid/duplicate locale names,
79      * and saving error/warning messages in this LocaleNormalizer object
80      *
81      * @param list the String like "zh  aa test123"
82      * @param orgLocaleSet the locales covered by a particular organization,
83      *        used as a filter unless null or ALL_LOCALES_SET
84      * @return the normalized string like "aa zh"
85      */
normalizeForSubset(String list, LocaleSet orgLocaleSet)86     public String normalizeForSubset(String list, LocaleSet orgLocaleSet) {
87         return norm(this, list, orgLocaleSet);
88     }
89 
90     /**
91      * Normalize the given locale-list string, removing invalid/duplicate locale names
92      *
93      * Always filter out unknown locales.
94      * If orgLocaleSet isn't null, filter out locales missing from it.
95      *
96      * This is static and has an optional LocaleNormalizer parameter that enables saving
97      * warning/error messages that can be shown to the user.
98      *
99      * @param locNorm the object to be filled in with warning/error messages, if not null
100      * @param list the String like "zh  aa test123"
101      * @param orgLocaleSet the locales covered by a particular organization,
102      *        used as a filter unless null or ALL_LOCALES_SET
103      * @return the normalized string like "aa zh"
104      */
norm(LocaleNormalizer locNorm, String list, LocaleSet orgLocaleSet)105     private static String norm(LocaleNormalizer locNorm, String list, LocaleSet orgLocaleSet) {
106         if (list == null) {
107             return "";
108         }
109         list = list.trim();
110         if (list.isEmpty() || NO_LOCALES.equals(list)) {
111             return "";
112         }
113         if (isAllLocales(list)) {
114             return ALL_LOCALES;
115         }
116         final LocaleSet locSet = setFromString(locNorm, list, orgLocaleSet);
117         return locSet.toString();
118     }
119 
120     private ArrayList<String> messages = null;
121 
addMessage(String s)122     private void addMessage(String s) {
123         if (messages == null) {
124             messages = new ArrayList<>();
125         }
126         messages.add(s);
127     }
128 
hasMessage()129     public boolean hasMessage() {
130         return messages != null && !messages.isEmpty();
131     }
132 
getMessagePlain()133     public String getMessagePlain() {
134         return String.join("\n", messages);
135     }
136 
getMessageHtml()137     public String getMessageHtml() {
138         return String.join("<br />\n", messages);
139     }
140 
setFromStringQuietly(String locales, LocaleSet orgLocaleSet)141     public static LocaleSet setFromStringQuietly(String locales, LocaleSet orgLocaleSet) {
142         return setFromString(null, locales, orgLocaleSet);
143     }
144 
setFromString(LocaleNormalizer locNorm, String localeList, LocaleSet orgLocaleSet)145     private static LocaleSet setFromString(LocaleNormalizer locNorm, String localeList, LocaleSet orgLocaleSet) {
146         if (isAllLocales(localeList)) {
147             if (orgLocaleSet == null || orgLocaleSet.isAllLocales()) {
148                 return ALL_LOCALES_SET;
149             }
150             return intersectKnownWithOrgLocales(orgLocaleSet);
151         }
152         final LocaleSet newSet = new LocaleSet();
153         if (localeList == null || (localeList = localeList.trim()).length() == 0) {
154             return newSet;
155         }
156         final String[] array = localeList.split("[, \t\u00a0\\s]+"); // whitespace
157         for (String s : array) {
158             CLDRLocale locale = CLDRLocale.getInstance(s);
159             if (knownLocales == null || knownLocales.contains(locale)) {
160                 if (orgLocaleSet == null || orgLocaleSet.containsLocaleOrParent(locale)) {
161                     newSet.add(locale);
162                 } else if (locNorm != null) {
163                     locNorm.addMessage("Outside org. coverage: " + locale.getBaseName());
164                 }
165             } else if (locNorm != null) {
166                 locNorm.addMessage("Unknown: " + locale.getBaseName());
167             }
168         }
169         return newSet;
170     }
171 
intersectKnownWithOrgLocales(LocaleSet orgLocaleSet)172     private static LocaleSet intersectKnownWithOrgLocales(LocaleSet orgLocaleSet) {
173         if (knownLocales == null) {
174             final LocaleSet orgSetCopy = new LocaleSet();
175             orgSetCopy.addAll(orgLocaleSet.getSet());
176             return orgSetCopy;
177         }
178         final LocaleSet intersection = new LocaleSet();
179         for (CLDRLocale locale : knownLocales.getSet()) {
180             if (orgLocaleSet.containsLocaleOrParent(locale)) {
181                 intersection.add(locale);
182             }
183         }
184         return intersection;
185     }
186 }
187