1
20 package org.crosswire.common.util;
21
22 import java.text.MessageFormat;
23 import java.util.HashMap;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.MissingResourceException;
27 import java.util.ResourceBundle;
28
29 import org.crosswire.common.icu.NumberShaper;
30 import org.crosswire.jsword.internationalisation.LocaleProviderManager;
31 import org.slf4j.LoggerFactory;
32
33
41 public class MsgBase {
42
45 protected MsgBase() {
46 this.shaper = new NumberShaper();
47 }
48
49
56 public String lookup(String key, Object... params) {
57 String rawMessage = obtainString(key);
58 if (params.length == 0) {
59 return shaper.shape(rawMessage);
60 }
61
62 rawMessage = rawMessage.replaceAll("'", "''");
64
65 return shaper.shape(MessageFormat.format(rawMessage, params));
66 }
67
68 private String obtainString(String key) {
69 try {
70 if (getLocalisedResources() != null) {
71 return getLocalisedResources().getString(key);
72 }
73 } catch (MissingResourceException ex) {
74 log.error("Missing resource: Locale={} name={} package={}", LocaleProviderManager.getLocale(), key, getClass().getName());
75 }
76
77 return key;
78 }
79
80 private ResourceBundle getLocalisedResources() {
81 Class<? extends MsgBase> implementingClass = getClass();
82 String className = implementingClass.getName();
83 String shortClassName = ClassUtil.getShortClassName(className);
84
85 Locale currentUserLocale = LocaleProviderManager.getLocale();
86 Map<String, ResourceBundle> localisedResourceMap = getLazyLocalisedResourceMap(currentUserLocale);
87
88 ResourceBundle resourceBundle = localisedResourceMap.get(className);
89 if (resourceBundle == null) {
90 resourceBundle = getResourceBundleForClass(implementingClass, className, shortClassName, currentUserLocale, localisedResourceMap);
91 }
92
93 if (resourceBundle == null) {
95 resourceBundle = getResourceBundleForClass(implementingClass, className, shortClassName, Locale.ENGLISH, localisedResourceMap);
96 }
97
98 if (resourceBundle == null) {
100 log.error("Missing resources: Locale={} class={}", currentUserLocale, className);
101 throw new MissingResourceException("Unable to find the language resources.", className, shortClassName);
102 }
103 return resourceBundle;
104 }
105
106
116 private ResourceBundle getResourceBundleForClass(Class<? extends MsgBase> implementingClass, String className, String shortClassName, Locale currentUserLocale, Map<String, ResourceBundle> localisedResourceMap) {
117 ResourceBundle resourceBundle;
118 synchronized (MsgBase.class) {
119 resourceBundle = localisedResourceMap.get(className);
120 if (resourceBundle == null) {
121 try {
122 resourceBundle = ResourceBundle.getBundle(shortClassName, currentUserLocale, CWClassLoader.instance(implementingClass));
123 localisedResourceMap.put(className, resourceBundle);
124 } catch (MissingResourceException ex) {
125 log.warn("Assuming key is the default message {}", className);
126 }
127 }
128 }
129 return resourceBundle;
130 }
131
132
138 private Map<String, ResourceBundle> getLazyLocalisedResourceMap(Locale currentUserLocale) {
139 Map<String, ResourceBundle> localisedResourceMap = localeToResourceMap.get(currentUserLocale);
140 if (localisedResourceMap == null) {
141 synchronized (MsgBase.class) {
142 localisedResourceMap = localeToResourceMap.get(currentUserLocale);
143 if (localisedResourceMap == null) {
144 localisedResourceMap = new HashMap<String, ResourceBundle>(512);
145 localeToResourceMap.put(currentUserLocale, localisedResourceMap);
146 }
147 }
148 }
149 return localisedResourceMap;
150 }
151
152 private static Map<Locale, Map<String, ResourceBundle>> localeToResourceMap = new HashMap<Locale, Map<String, ResourceBundle>>();
153
154
155 private NumberShaper shaper;
156
157
160 private static final org.slf4j.Logger log = LoggerFactory.getLogger(MsgBase.class);
161 }
162