1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.springframework.extensions.surf.util;
20
21 import java.text.MessageFormat;
22 import java.util.Enumeration;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.ResourceBundle;
29 import java.util.Set;
30 import java.util.StringTokenizer;
31 import java.util.concurrent.locks.Lock;
32 import java.util.concurrent.locks.ReadWriteLock;
33 import java.util.concurrent.locks.ReentrantReadWriteLock;
34
35
36
37
38
39
40
41 public class I18NUtil
42 {
43
44
45
46 private static ThreadLocal<Locale> threadLocale = new ThreadLocal<Locale>();
47
48
49
50
51
52 private static ThreadLocal<Locale> threadContentLocale = new ThreadLocal<Locale>();
53
54
55
56
57 private static Set<String> resouceBundleBaseNames = new HashSet<String>();
58
59
60
61
62 private static Map<Locale, Set<String>> loadedResourceBundles = new HashMap<Locale, Set<String>>();
63
64
65
66
67 private static Map<Locale, Map<String, String>> cachedMessages = new HashMap<Locale, Map<String, String>>();
68
69
70
71
72 private static ReadWriteLock lock = new ReentrantReadWriteLock();
73 private static Lock readLock = lock.readLock();
74 private static Lock writeLock = lock.writeLock();
75
76
77
78
79
80
81 public static void setLocale(Locale locale)
82 {
83 threadLocale.set(locale);
84 }
85
86
87
88
89
90
91
92 public static Locale getLocale()
93 {
94 Locale locale = threadLocale.get();
95 if (locale == null)
96 {
97
98 locale = Locale.getDefault();
99 }
100 return locale;
101 }
102
103
104
105
106
107
108 public static void setContentLocale(Locale locale)
109 {
110 threadContentLocale.set(locale);
111 }
112
113
114
115
116
117
118
119 public static Locale getContentLocale()
120 {
121 Locale locale = threadContentLocale.get();
122 if (locale == null)
123 {
124
125 locale = getLocale();
126 }
127 return locale;
128 }
129
130
131
132
133
134
135
136 public static Locale getContentLocaleOrNull()
137 {
138 Locale locale = threadContentLocale.get();
139
140 return locale;
141 }
142
143
144
145
146
147
148
149
150
151
152
153 public static Locale getNearestLocale(Locale templateLocale, Set<Locale> options)
154 {
155 if (options.isEmpty())
156 {
157 return null;
158 }
159 else if (templateLocale == null)
160 {
161 for (Locale locale : options)
162 {
163 return locale;
164 }
165 }
166 else if (options.contains(templateLocale))
167 {
168 return templateLocale;
169 }
170
171 Set<Locale> remaining = new HashSet<Locale>(options);
172
173
174 Locale lastMatchingOption = null;
175 String templateLanguage = templateLocale.getLanguage();
176 if (templateLanguage != null && !templateLanguage.equals(""))
177 {
178 Iterator<Locale> iterator = remaining.iterator();
179 while (iterator.hasNext())
180 {
181 Locale option = iterator.next();
182 if (option != null && !templateLanguage.equals(option.getLanguage()))
183 {
184 iterator.remove();
185 }
186 else
187 {
188 lastMatchingOption = option;
189 }
190 }
191 }
192 if (remaining.isEmpty())
193 {
194 return null;
195 }
196 else if (remaining.size() == 1 && lastMatchingOption != null)
197 {
198 return lastMatchingOption;
199 }
200
201
202 lastMatchingOption = null;
203 String templateCountry = templateLocale.getCountry();
204 if (templateCountry != null && !templateCountry.equals(""))
205 {
206 Iterator<Locale> iterator = remaining.iterator();
207 while (iterator.hasNext())
208 {
209 Locale option = iterator.next();
210 if (option != null && !templateCountry.equals(option.getCountry()))
211 {
212
213
214
215 }
216 else
217 {
218 lastMatchingOption = option;
219 }
220 }
221 }
222
223
224
225
226
227 if (remaining.size() == 1 && lastMatchingOption != null)
228 {
229 return lastMatchingOption;
230 }
231 else
232 {
233
234
235
236
237 if(lastMatchingOption != null)
238 {
239 return lastMatchingOption;
240 }
241 else
242 {
243 for (Locale locale : remaining)
244 {
245 return locale;
246 }
247 }
248 }
249
250 throw new RuntimeException("Logic should not allow code to get here.");
251 }
252
253
254
255
256
257
258
259
260 public static Locale parseLocale(String localeStr)
261 {
262 if(localeStr == null)
263 {
264 return null;
265 }
266 Locale locale = Locale.getDefault();
267
268 StringTokenizer t = new StringTokenizer(localeStr, "_");
269 int tokens = t.countTokens();
270 if (tokens == 1)
271 {
272 locale = new Locale(t.nextToken());
273 }
274 else if (tokens == 2)
275 {
276 locale = new Locale(t.nextToken(), t.nextToken());
277 }
278 else if (tokens == 3)
279 {
280 locale = new Locale(t.nextToken(), t.nextToken(), t.nextToken());
281 }
282
283 return locale;
284 }
285
286
287
288
289
290
291
292
293
294
295 public static void registerResourceBundle(String bundleBaseName)
296 {
297 try
298 {
299 writeLock.lock();
300 resouceBundleBaseNames.add(bundleBaseName);
301 }
302 finally
303 {
304 writeLock.unlock();
305 }
306 }
307
308
309
310
311
312
313
314 public static String getMessage(String messageKey)
315 {
316 return getMessage(messageKey, getLocale());
317 }
318
319
320
321
322
323
324
325
326 public static String getMessage(String messageKey, Locale locale)
327 {
328 String message = null;
329 Map<String, String> props = getLocaleProperties(locale);
330 if (props != null)
331 {
332 message = props.get(messageKey);
333 }
334 return message;
335 }
336
337
338
339
340
341
342
343
344 public static String getMessage(String messageKey, Object ... params)
345 {
346 return getMessage(messageKey, getLocale(), params);
347 }
348
349
350
351
352
353
354
355
356
357 public static String getMessage(String messageKey, Locale locale, Object ... params)
358 {
359 String message = getMessage(messageKey, locale);
360 if (message != null && params != null)
361 {
362 message = MessageFormat.format(message, params);
363 }
364 return message;
365 }
366
367
368
369
370 public static Map<String, String> getAllMessages()
371 {
372 return getLocaleProperties(getLocale());
373 }
374
375
376
377
378 public static Map<String, String> getAllMessages(Locale locale)
379 {
380 return getLocaleProperties(locale);
381 }
382
383
384
385
386
387
388
389
390
391 private static Map<String, String> getLocaleProperties(Locale locale)
392 {
393 Set<String> loadedBundles = null;
394 Map<String, String> props = null;
395 int loadedBundleCount = 0;
396 try
397 {
398 readLock.lock();
399 loadedBundles = loadedResourceBundles.get(locale);
400 props = cachedMessages.get(locale);
401 loadedBundleCount = resouceBundleBaseNames.size();
402 }
403 finally
404 {
405 readLock.unlock();
406 }
407
408 if (loadedBundles == null)
409 {
410 try
411 {
412 writeLock.lock();
413 loadedBundles = new HashSet<String>();
414 loadedResourceBundles.put(locale, loadedBundles);
415 }
416 finally
417 {
418 writeLock.unlock();
419 }
420 }
421
422 if (props == null)
423 {
424 try
425 {
426 writeLock.lock();
427 props = new HashMap<String, String>();
428 cachedMessages.put(locale, props);
429 }
430 finally
431 {
432 writeLock.unlock();
433 }
434 }
435
436 if (loadedBundles.size() != loadedBundleCount)
437 {
438 try
439 {
440 writeLock.lock();
441 for (String resourceBundleBaseName : resouceBundleBaseNames)
442 {
443 if (loadedBundles.contains(resourceBundleBaseName) == false)
444 {
445 ResourceBundle resourcebundle = ResourceBundle.getBundle(resourceBundleBaseName, locale);
446 Enumeration<String> enumKeys = resourcebundle.getKeys();
447 while (enumKeys.hasMoreElements() == true)
448 {
449 String key = enumKeys.nextElement();
450 props.put(key, resourcebundle.getString(key));
451 }
452 loadedBundles.add(resourceBundleBaseName);
453 }
454 }
455 }
456 finally
457 {
458 writeLock.unlock();
459 }
460 }
461
462 return props;
463 }
464 }