1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.itracker.core.resources;
20
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.Map;
27 import java.util.MissingResourceException;
28 import java.util.ResourceBundle;
29 import java.util.Set;
30
31 import org.apache.log4j.Logger;
32 import org.itracker.model.Language;
33 import org.itracker.persistence.dao.NoSuchEntityException;
34 import org.itracker.services.exceptions.ITrackerDirtyResourceException;
35 import org.itracker.web.util.LoginUtilities;
36 import org.itracker.web.util.ServletContextUtils;
37
38
39
40
41
42
43
44
45 public class ITrackerResources {
46
47 private static final Logger logger = Logger
48 .getLogger(ITrackerResources.class);
49
50 public static final String RESOURCE_BUNDLE_NAME = "org.itracker.core.resources.ITracker";
51
52 public static final String DEFINED_LOCALES_KEY = "itracker.locales";
53
54 public static final String DEFAULT_LOCALE = "en_US";
55
56 public static final String BASE_LOCALE = "BASE";
57
58 public static final String NO_LOCALE = "ZZ_ZZ";
59
60 public static final String KEY_BASE_CUSTOMFIELD_TYPE = "itracker.web.generic.";
61
62 public static final String KEY_BASE_WORKFLOW_EVENT = "itracker.workflow.field.event.";
63
64 public static final String KEY_BASE_PROJECT_STATUS = "itracker.project.status.";
65
66 public static final String KEY_BASE_PERMISSION = "itracker.user.permission.";
67
68 public static final String KEY_BASE_PRIORITY = "itracker.script.priority.";
69
70 public static final String KEY_BASE_PRIORITY_LABEL = ".label";
71
72 public static final String KEY_BASE_PRIORITY_SIZE = "size";
73
74 public static final String KEY_BASE_RESOLUTION = "itracker.resolution.";
75
76 public static final String KEY_BASE_ISSUE_RELATION = "itracker.issuerelation.";
77
78 public static final String KEY_BASE_SEVERITY = "itracker.severity.";
79
80 public static final String KEY_BASE_STATUS = "itracker.status.";
81
82 public static final String KEY_BASE_USER_STATUS = "itracker.user.status.";
83
84 public static final String KEY_BASE_CUSTOMFIELD = "itracker.customfield.";
85
86 public static final String KEY_BASE_CUSTOMFIELD_OPTION = ".option.";
87
88 public static final String KEY_BASE_CUSTOMFIELD_LABEL = ".label";
89
90 public static final String KEY_BASE_LOCALE_NAME = "itracker.locale.name";
91
92 private static String defaultLocale = DEFAULT_LOCALE;
93
94 private static HashMap<String, Locale> locales = new HashMap<String, Locale>();
95
96 private static HashMap<Locale, ResourceBundle> languages = new HashMap<Locale, ResourceBundle>();
97
98 private static boolean initialized = false;
99
100 private static Object bundleLock = new Object();
101
102
103
104 public static Locale getLocale() {
105 return getLocale(getDefaultLocale());
106 }
107
108 public static Locale getLocale(String localeString) {
109
110
111
112
113 if (localeString == null || localeString.trim().equals("")) {
114 return getLocale(getDefaultLocale());
115 }
116
117 Locale locale = locales.get(localeString);
118 if (locale == null && localeString != null
119 && !localeString.trim().equals("")) {
120 try {
121 if (logger.isDebugEnabled()) {
122 logger.debug("Creating new locale for '" + localeString
123 + "'");
124 }
125 if (localeString.length() == 5) {
126 locale = new Locale(localeString.substring(0, 2),
127 localeString.substring(3));
128 } else if (localeString.length() == 2) {
129 locale = new Locale(localeString, "");
130 } else if (localeString.equals(BASE_LOCALE)) {
131 locale = new Locale("", "");
132 } else {
133
134 logger
135 .error("Invalid locale '"
136 + localeString
137 + "' specified. It must be either LN or LN_CN.");
138 throw new Exception("Invalid locale string");
139 }
140 } catch (Exception ex) {
141 if (!localeString.equals(getDefaultLocale())) {
142 logger.error("Failed creating new locale for '"
143 + localeString
144 + "' attempting for default locale '"
145 + getDefaultLocale() + "'", ex);
146 return getLocale(getDefaultLocale());
147 } else {
148 logger.error("Failed creating new default locale for '"
149 + getDefaultLocale()
150 + "' attempting for DEFAULT_LOCALE '"
151 + DEFAULT_LOCALE + "'", ex);
152 return getLocale(DEFAULT_LOCALE);
153 }
154 }
155 locales.put(localeString, locale);
156 }
157 return locale;
158 }
159
160 public static String getDefaultLocale() {
161 return (defaultLocale == null ? DEFAULT_LOCALE : defaultLocale);
162 }
163
164 public static void setDefaultLocale(String value) {
165 defaultLocale = value;
166 }
167
168 public static String getLocaleDN(String locale, Locale displayLocale) {
169 String name;
170 if (null == displayLocale) {
171 displayLocale = getLocale();
172 }
173 try {
174 name = getBundle(displayLocale).getString(
175 KEY_BASE_LOCALE_NAME + "." + locale);
176 } catch (RuntimeException e) {
177 name = getLocaleNativeName(getLocale(locale));
178 }
179
180 return name;
181 }
182
183 public static String getLocaleDN(Locale locale, Locale displayLocale) {
184
185 if (null == displayLocale) {
186 return getLocaleNativeName(displayLocale);
187 }
188 return getLocaleDN(locale.toString(), displayLocale);
189
190 }
191 public static String getLocaleFullDN(Locale locale, Locale displayLocale) {
192
193 if (null == locale) {
194 locale = new Locale("");
195 }
196 String fullName = getLocaleNativeName(locale);
197 if (null == displayLocale || locale.getLanguage().equals(displayLocale.getLanguage())) {
198 return fullName;
199 }
200 if (fullName.equals(locale.toString())) {
201 fullName = getLocaleDN(locale, displayLocale);
202 } else {
203 String localizedName = getLocaleDN(locale, displayLocale);
204 if (null != fullName && null != localizedName && !localizedName.trim().equals(fullName.trim())) {
205 return fullName.trim() + " (" + localizedName.trim() + ")";
206 } else if (null != localizedName) {
207 return localizedName.trim();
208 } else if (null != fullName) {
209 return fullName.trim();
210 }
211
212 }
213
214 return "Unknown: " + locale.toString();
215
216 }
217 public static String getLocaleNativeName(Locale locale) {
218 try {
219 return getString(KEY_BASE_LOCALE_NAME, locale);
220
221 } catch (MissingResourceException e) {
222 return locale.toString();
223
224 }
225 }
226
227 public static final Map<String, String> getLocaleNamesMap(Locale locale, Set<String> languageCodes,Map<String, List<String>> languagesMap ) {
228 Map<String, String> ret = new LinkedHashMap<String, String>();
229 for (String languageCode : languageCodes) {
230 List<String> languagelist = languagesMap.get(languageCode);
231
232 String name = getLocaleFullDN(ITrackerResources.getLocale(languageCode), locale);
233
234 ret.put(languageCode, name);
235 for (String languageitem : languagelist) {
236 name = getLocaleFullDN(ITrackerResources.getLocale(languageitem), locale);
237 ret.put(languageitem, name);
238 }
239
240 }
241 if (ret.size() == 0) {
242 ret.put(getDefaultLocale(), getLocaleNativeName(getLocale(getDefaultLocale())));
243 }
244 return ret;
245
246 }
247 public static ResourceBundle getBundle() {
248 return getBundle(getDefaultLocale());
249 }
250
251 public static ResourceBundle getBundle(String locale) {
252 if (locale == null || locale.equals("")) {
253 locale = getDefaultLocale();
254 }
255
256 return getBundle(getLocale(locale));
257 }
258
259 public static ResourceBundle getBundle(Locale locale) {
260 if (locale == null) {
261 locale = getLocale(getDefaultLocale());
262 }
263 ResourceBundle bundle = (ResourceBundle) languages.get(locale);
264 if (bundle == null) {
265 if (logger.isDebugEnabled()) {
266 logger.debug("getBundle: Loading new resource bundle for locale " + locale
267 + " from the database.");
268 }
269 List<Language> languageItems = ServletContextUtils
270 .getItrackerServices().getConfigurationService()
271 .getLanguage(locale);
272
273
274
275 bundle = ITrackerResourceBundle.loadBundle(locale, languageItems);
276 if (logger.isDebugEnabled()) {
277 logger.debug("getBundle: got loaded for locale " + locale
278 + " with items " + languageItems + " from the database.");
279 }
280 if (bundle != null) {
281 putBundle(locale, bundle);
282 } else if (!locale.toString().equals(getDefaultLocale())) {
283 bundle = getBundle(getLocale());
284 }
285 }
286
287 return bundle;
288 }
289
290 public static ResourceBundle getEditBundle(Locale locale) {
291 if (locale == null) {
292 locale = getLocale(getDefaultLocale());
293 }
294 ResourceBundle bundle = (ResourceBundle) languages.get(locale);
295 logger.debug("Loading new resource bundle for locale " + locale
296 + " from the database.");
297 List<Language> languageItems = ServletContextUtils
298 .getItrackerServices().getConfigurationService().getLanguage(
299 locale);
300 bundle = ITrackerResourceBundle.loadBundle(locale, languageItems);
301 if (bundle != null) {
302 putBundle(locale, bundle);
303 } else if (!locale.toString().equals(getDefaultLocale())) {
304 bundle = getBundle(getLocale());
305 }
306
307 return bundle;
308 }
309
310 public static void putBundle(Locale locale, ResourceBundle bundle) {
311 if (locale != null && bundle != null) {
312 synchronized (bundleLock) {
313 languages.put(locale, bundle);
314
315
316
317 String localeString = locale.toString();
318 if (localeString.length() == 5) {
319 localeString = localeString.substring(0, 2) + "_"
320 + localeString.substring(3).toUpperCase();
321 }
322 locales.put(localeString, locale);
323 }
324 }
325 }
326
327 static void setData(ITrackerResourceBundle bundle) {
328
329 List<Language> languageItems = ServletContextUtils
330 .getItrackerServices().getConfigurationService()
331 .getLanguage(bundle.getLocale());
332 bundle.setContents(languageItems);
333 }
334
335
336
337
338 public static void clearBundle(Locale locale) {
339 if (locale != null) {
340 synchronized (bundleLock) {
341 ResourceBundle bundle = languages.get(locale);
342
343
344
345 languages.remove(locale);
346 }
347 }
348 }
349
350
351
352
353
354 public static void clearBundles() {
355 synchronized (bundleLock) {
356
357 languages.clear();
358
359 }
360 }
361
362
363
364
365
366 public static void clearKeyFromBundles(String key, boolean markDirty) {
367 if (key != null) {
368 synchronized (bundleLock) {
369 for (Iterator<ResourceBundle> iter = languages.values()
370 .iterator(); iter.hasNext();) {
371 ((ITrackerResourceBundle) iter.next()).removeValue(key,
372 markDirty);
373 }
374 }
375 }
376 }
377
378 public static String getString(String key) {
379 return getString(key, getLocale(defaultLocale));
380 }
381
382 public static String getString(String key, String locale) {
383 if (key == null) {
384 return "";
385 }
386
387 if (locale == null || locale.equals("")) {
388 locale = getDefaultLocale();
389 }
390
391 return getString(key, getLocale(locale));
392 }
393
394 public static String getString(String key, Locale locale) {
395 if (key == null) {
396 return "";
397 }
398
399 if (locale == null) {
400 locale = getLocale(getDefaultLocale());
401 }
402 String val;
403 try {
404 try {
405
406
407
408 val = getBundle(locale).getString(key);
409 if (null != val) {
410
411
412
413
414
415 return val;
416 } else {
417 val = ITrackerResources.getString(key);
418
419
420
421
422
423 }
424 } catch (ITrackerDirtyResourceException idre) {
425
426
427
428
429 Language languageItem = ServletContextUtils
430 .getItrackerServices().getConfigurationService()
431 .getLanguageItemByKey(key, locale);
432 ResourceBundle bundle = getBundle(locale);
433 ((ITrackerResourceBundle) bundle)
434 .updateValue(languageItem);
435 val = bundle.getString(key);
436 }
437 return val;
438 } catch (NullPointerException ex) {
439 logger.error(
440 "Unable to get any resources. The requested locale was "
441 + locale, ex);
442 return "MISSING BUNDLE: " + locale;
443 } catch (MissingResourceException ex) {
444 logger.warn(
445 "MissingResourceException caught while retrieving translation key '"
446 + key + "' for locale " + locale, ex);
447 return "MISSING KEY: " + key;
448 } catch (NoSuchEntityException ex) {
449 logger.info("getString: not found " + key + " locale: " + locale,
450 ex);
451 try {
452 return getEditBundle(locale).getString(key);
453 } catch (Exception ex2) {
454 logger.warn(
455 "getString: caught while retrieving translation key '"
456 + key + "' for locale " + locale, ex2);
457 return "MISSING KEY: " + key;
458 }
459 }
460 }
461
462 public static String getString(String key, Object[] options) {
463 return getString(key, getLocale(getDefaultLocale()), options);
464 }
465
466 public static String getString(String key, String locale, Object[] options) {
467 return getString(key, getLocale(locale), options);
468 }
469
470 public static String getString(String key, Locale locale, Object[] options) {
471 String message = getString(key, locale);
472 return MessageFormat.format(message, options, locale);
473 }
474
475 public static String getString(String key, String locale, String option) {
476 String message = getString(key, locale);
477 return MessageFormat.format(message, new Object[] { option },
478 getLocale(locale));
479 }
480
481 public static String getString(String key, Locale locale, String option) {
482 String message = getString(key, locale);
483 return MessageFormat.format(message, new Object[] { option }, locale);
484 }
485
486 public static String getCheckForKey(String key)
487 throws MissingResourceException {
488 return getCheckForKey(key, getLocale());
489 }
490
491 public static String getCheckForKey(String key, Locale locale)
492 throws MissingResourceException {
493 try {
494 return getBundle(locale).getString(key);
495 } catch (ITrackerDirtyResourceException idre) {
496 return getString(key, locale);
497 } catch (NullPointerException ex) {
498 logger.error("Unable to get ResourceBundle for locale " + locale,
499 ex);
500 throw new MissingResourceException("MISSING LOCALE: " + locale,
501 "ITrackerResources", key);
502 }
503 }
504
505 public static boolean isLongString(String key) {
506 String value = getString(key);
507 if (value.length() > 80 || value.indexOf('\n') > 0) {
508 return true;
509 }
510 return false;
511 }
512
513 public static String escapeUnicodeString(String str, boolean escapeAll) {
514 if (str == null) {
515 return "";
516 }
517
518 StringBuffer sb = new StringBuffer();
519 for (int i = 0; i < str.length(); i++) {
520 char ch = str.charAt(i);
521 if (!escapeAll && ((ch >= 0x0020) && (ch <= 0x007e))) {
522 sb.append(ch);
523 } else {
524 sb.append('\\').append('u');
525 sb.append(encodeHex((ch >> 12) & 0xF));
526 sb.append(encodeHex((ch >> 8) & 0xF));
527 sb.append(encodeHex((ch >> 4) & 0xF));
528 sb.append(encodeHex(ch & 0xF));
529 }
530 }
531 return sb.toString();
532 }
533
534 public static String unescapeUnicodeString(String str) {
535 StringBuffer sb = new StringBuffer();
536
537 for (int i = 0; i < str.length();) {
538 char ch = str.charAt(i++);
539 if (ch == '\\') {
540 if (str.charAt(i++) == 'u') {
541 int value = 0;
542 for (int j = 0; j < 4; j++) {
543 value = (value << 4) + decodeHex(str.charAt(i++));
544 }
545 sb.append((char) value);
546 } else {
547 sb.append("\\" + str.charAt(i));
548 }
549 } else {
550 sb.append(ch);
551 }
552 }
553 return sb.toString();
554 }
555
556 public static final String HEXCHARS = "0123456789ABCDEF";
557
558 public static char encodeHex(int value) {
559 return HEXCHARS.charAt(value & 0xf);
560 }
561
562 public static int decodeHex(char ch) {
563 int value = -1;
564
565 if (ch >= '0' && ch <= '9') {
566 value = ch - '0';
567 } else if (ch >= 'a' && ch <= 'f') {
568 value = ch - 'a' + 10;
569 } else if (ch >= 'A' && ch <= 'F') {
570 value = ch - 'A' + 10;
571 }
572
573 return value;
574 }
575
576
577
578
579
580
581 public static boolean isInitialized() {
582 return initialized;
583 }
584
585 public static void setInitialized(boolean initialized) {
586 ITrackerResources.initialized = initialized;
587 }
588
589 public static String getParentLocale(String locale) {
590 String localeCode = locale;
591 if (localeCode == null) {
592 localeCode = getDefaultLocale();
593 } else if (localeCode.equals(getDefaultLocale())) {
594 localeCode = BASE_LOCALE;
595 } else {
596 Locale l = getLocale(locale);
597
598 if (!l.getVariant().equals("")) {
599 localeCode = l.getLanguage() + "_" + l.getCountry();
600 }
601 if (!l.getCountry().equals("")) {
602 localeCode = l.getLanguage();
603 }
604 if (!l.getLanguage().equals("")) {
605 localeCode = getDefaultLocale();
606 }
607 }
608 return localeCode;
609 }
610
611 }