1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.util.i18n;
18
19 import static org.forgerock.util.Utils.isNullOrEmpty;
20
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.ResourceBundle;
25
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class PreferredLocales {
60
61 private static final Locale DEFAULT_RESOURCE_BUNDLE_LOCALE =
62 Locale.forLanguageTag(System.getProperty("org.forgerock.defaultBundleLocale", "en-US"));
63 private static final Logger logger = LoggerFactory.getLogger(PreferredLocales.class);
64
65 private final List<Locale> locales;
66 private final int numberLocales;
67
68
69
70
71
72 public PreferredLocales(List<Locale> locales) {
73 if (locales == null || locales.isEmpty()) {
74 locales = Collections.singletonList(Locale.ROOT);
75 }
76 this.locales = Collections.unmodifiableList(locales);
77 this.numberLocales = locales.size();
78 }
79
80
81
82
83 public PreferredLocales() {
84 this(null);
85 }
86
87
88
89
90
91 public Locale getPreferredLocale() {
92 return locales.get(0);
93 }
94
95
96
97
98
99 public List<Locale> getLocales() {
100 return locales;
101 }
102
103
104
105
106
107
108
109
110 public ResourceBundle getBundleInPreferredLocale(String bundleName, ClassLoader classLoader) {
111 logger.debug("Finding best {} bundle for locales {}", bundleName, locales);
112 for (int i = 0; i < numberLocales; i++) {
113 Locale locale = locales.get(i);
114 ResourceBundle candidate = ResourceBundle.getBundle(bundleName, locale, classLoader);
115 Locale candidateLocale = candidate.getLocale();
116 List<Locale> remainingLocales = locales.subList(i + 1, numberLocales);
117 if (matches(locale, candidateLocale, remainingLocales)) {
118 logger.debug("Returning {} bundle in {} locale", bundleName, candidateLocale);
119 return candidate;
120 }
121 if (candidateLocale.equals(Locale.ROOT)
122 && matches(locale, DEFAULT_RESOURCE_BUNDLE_LOCALE, remainingLocales)) {
123 return ResourceBundle.getBundle(bundleName, Locale.ROOT, classLoader);
124 }
125 }
126 logger.debug("Returning {} bundle in root locale", bundleName);
127 return ResourceBundle.getBundle(bundleName, Locale.ROOT, classLoader);
128 }
129
130
131
132
133
134
135
136
137
138
139 public static boolean matches(Locale requested, Locale candidate, List<Locale> remainingLocales) {
140 logger.trace("Checking candidate locale {} for match with requested {}", candidate, requested);
141 if (requested.equals(candidate)) {
142 return true;
143 }
144 if (candidate.equals(Locale.ROOT)) {
145 logger.trace("Rejecting root locale as it is the default. Requested {}", requested);
146 return false;
147 }
148 String language = candidate.getLanguage();
149 if (!requested.getLanguage().equals(language)) {
150 return false;
151 }
152 String country = candidate.getCountry();
153 String variant = candidate.getVariant();
154 if (!isNullOrEmpty(variant)
155 && remainingLocales.contains(new Locale(language, country, variant))) {
156 return false;
157 }
158 if ((!isNullOrEmpty(country) || !isNullOrEmpty(variant))
159 && remainingLocales.contains(new Locale(language, country))) {
160 return false;
161 }
162 if (remainingLocales.contains(new Locale(language))) {
163 return false;
164 }
165 return true;
166 }
167
168 }