001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: Localization.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.tools;
009:
010: import java.util.*;
011:
012: import com.uwyn.rife.config.RifeConfig;
013: import com.uwyn.rife.resources.ResourceFinderClasspath;
014: import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.net.URL;
018: import java.net.URLConnection;
019: import java.text.MessageFormat;
020: import java.util.regex.Matcher;
021: import java.util.regex.Pattern;
022:
023: public class Localization {
024: public final static Pattern URL_PATTERN = Pattern
025: .compile("(?:\\s*(\\w+):((?!//)[^,]+)\\s*)|(?:\\s*([^,]+)\\s*)");
026:
027: private static HashMap<String, ResourceBundle> mResourceBundlesOpened = new HashMap<String, ResourceBundle>();
028: private static HashMap<String, Long> mResourceBundleModificationTimes = new HashMap<String, Long>();
029:
030: private static long sLastModificationCheck = 0;
031:
032: public static String extractLocalizedUrl(String url) {
033: if (null == url) {
034: return null;
035: }
036:
037: if (-1 == url.indexOf(":")) {
038: return url;
039: } else {
040: Matcher matcher = URL_PATTERN.matcher(url);
041: String localized_url = null;
042:
043: String default_lang = RifeConfig.Tools.getDefaultLanguage();
044: String fallback_url = null;
045:
046: String group_lang = null;
047: String group_url = null;
048: String group_fallback = null;
049: while (matcher.find()) {
050: if (3 == matcher.groupCount()) {
051: group_lang = matcher.group(1);
052: group_url = matcher.group(2);
053: group_fallback = matcher.group(3);
054:
055: if (group_fallback != null) {
056: fallback_url = group_fallback;
057: } else if (group_lang != null && group_url != null
058: && default_lang != null
059: && default_lang.equals(group_lang)) {
060: localized_url = group_url;
061: break;
062: }
063: }
064: }
065:
066: if (null == localized_url) {
067: if (null == fallback_url) {
068: localized_url = null;
069: } else {
070: localized_url = fallback_url;
071: }
072: }
073:
074: return localized_url;
075: }
076: }
077:
078: public static char getChar(String key) {
079: return getChar(null, key, null, null);
080: }
081:
082: public static char getChar(String key, String language) {
083: return getChar(null, key, language, null);
084: }
085:
086: public static char getChar(String key, String language,
087: String country) {
088: return getString(null, key, null, language, country).charAt(0);
089: }
090:
091: public static char getChar(String basename, String key,
092: String language, String country) {
093: return getString(basename, key, null, language, country)
094: .charAt(0);
095: }
096:
097: public static String getString(String key) {
098: return getString(null, key, null, null, null);
099: }
100:
101: public static String getString(String key, Object[] parameters) {
102: return getString(null, key, parameters, null, null);
103: }
104:
105: public static String getString(String key, String language) {
106: return getString(null, key, null, language, null);
107: }
108:
109: public static String getString(String key, Object[] parameters,
110: String language) {
111: return getString(null, key, parameters, language, null);
112: }
113:
114: public static String getString(String key, String language,
115: String country) {
116: return getString(null, key, null, language, country);
117: }
118:
119: public static String getString(String key, Object[] parameters,
120: String language, String country) {
121: return getString(null, key, parameters, language, country);
122: }
123:
124: public static String getString(String basename, String key,
125: String language, String country) {
126: return getString(basename, key, null, language, country);
127: }
128:
129: public static String getString(String basename, String key,
130: Object[] parameters, String language, String country) {
131: ResourceBundle resource_bundle = getResourceBundle(basename,
132: language, country);
133:
134: if (null != resource_bundle) {
135: String result = null;
136:
137: if (null == parameters) {
138: try {
139: result = resource_bundle.getString(key);
140: } catch (MissingResourceException e) {
141: return key;
142: }
143: } else {
144: String pattern_string = null;
145:
146: try {
147: pattern_string = resource_bundle.getString(key);
148: } catch (MissingResourceException e) {
149: return key;
150: }
151:
152: MessageFormat formatter = null;
153: formatter = new MessageFormat(pattern_string);
154: Locale locale = resource_bundle.getLocale();
155: if (locale != null) {
156: formatter.setLocale(locale);
157: }
158: result = formatter.format(parameters);
159: }
160:
161: return result;
162: } else {
163: return key;
164: }
165: }
166:
167: public static Locale getLocale() {
168: return getLocale(null, null);
169: }
170:
171: public static Locale getLocale(String language) {
172: return getLocale(language, null);
173: }
174:
175: public static Locale getLocale(String language, String country) {
176: if (null == language) {
177: language = RifeConfig.Tools.getDefaultLanguage();
178: }
179:
180: if (null == country) {
181: country = RifeConfig.Tools.getDefaultCountry();
182: }
183:
184: Locale locale = null;
185: if (null != language) {
186: if (null == country) {
187: locale = new Locale(language);
188: } else {
189: locale = new Locale(language, country);
190: }
191: }
192:
193: return locale;
194: }
195:
196: public static ResourceBundle getResourceBundle(String basename) {
197: return getResourceBundle(basename, null, null);
198: }
199:
200: public static ResourceBundle getResourceBundle(String basename,
201: String language) {
202: return getResourceBundle(basename, language, null);
203: }
204:
205: public static ResourceBundle getResourceBundle(String basename,
206: String language, String country) {
207: if (null == basename) {
208: basename = RifeConfig.Tools.getDefaultResourceBundle();
209: }
210:
211: Locale locale = getLocale(language, country);
212:
213: ResourceBundle result = getResourceBundle(basename, locale);
214: if (null == result) {
215: result = getResourceBundle(basename, Locale.ENGLISH);
216: }
217:
218: return result;
219: }
220:
221: public static ResourceBundle getResourceBundle(String basename,
222: Locale locale) {
223: ResourceBundle result = null;
224: if (null != locale) {
225: String most_detailed_candidate = basename
226: + locale.toString();
227:
228: // see if the resourcebundle reload is deactivated and thus fetch a previous copy without
229: // looking up the resource
230: if (!RifeConfig.Tools.getResourcebundleAutoReload()
231: || System.currentTimeMillis()
232: - sLastModificationCheck <= RifeConfig.Global
233: .getAutoReloadDelay()) {
234: result = mResourceBundlesOpened
235: .get(most_detailed_candidate);
236:
237: if (result != null) {
238: return result;
239: }
240: }
241:
242: if (RifeConfig.Tools.getResourcebundleAutoReload()) {
243: sLastModificationCheck = System.currentTimeMillis();
244: }
245:
246: // build the list of possible candidates
247: ArrayList<String> candidates = new ArrayList<String>();
248:
249: StringBuilder resource_bundle_id_buffer = new StringBuilder(
250: basename);
251:
252: candidates.add(basename);
253:
254: Locale default_locale = Locale.getDefault();
255: if (default_locale.getLanguage().length() > 0) {
256: resource_bundle_id_buffer.append("_");
257: resource_bundle_id_buffer.append(default_locale
258: .getLanguage());
259:
260: candidates.add(resource_bundle_id_buffer.toString());
261: }
262:
263: if (default_locale.getCountry().length() > 0) {
264: resource_bundle_id_buffer.append("_");
265: resource_bundle_id_buffer.append(default_locale
266: .getCountry());
267:
268: candidates.add(resource_bundle_id_buffer.toString());
269: }
270:
271: if (default_locale.getVariant().length() > 0) {
272: resource_bundle_id_buffer.append("_");
273: resource_bundle_id_buffer.append(default_locale
274: .getVariant());
275:
276: candidates.add(resource_bundle_id_buffer.toString());
277: }
278:
279: resource_bundle_id_buffer = new StringBuilder(basename);
280: if (locale.getLanguage().length() > 0) {
281: resource_bundle_id_buffer.append("_");
282: resource_bundle_id_buffer.append(locale.getLanguage());
283:
284: String candidate = resource_bundle_id_buffer.toString();
285: if (!candidates.contains(candidate)) {
286: candidates.add(candidate);
287: }
288: }
289:
290: if (locale.getCountry().length() > 0) {
291: resource_bundle_id_buffer.append("_");
292: resource_bundle_id_buffer.append(locale.getCountry());
293:
294: String candidate = resource_bundle_id_buffer.toString();
295: if (!candidates.contains(candidate)) {
296: candidates.add(candidate);
297: }
298: }
299:
300: if (locale.getVariant().length() > 0) {
301: resource_bundle_id_buffer.append("_");
302: resource_bundle_id_buffer.append(locale.getVariant());
303:
304: String candidate = resource_bundle_id_buffer.toString();
305: if (!candidates.contains(candidate)) {
306: candidates.add(candidate);
307: }
308: }
309:
310: while (candidates.size() > 0) {
311: String resource_bundle_id = candidates
312: .remove(candidates.size() - 1);
313: try {
314: // try to load the resource bundle as a class
315: Class resource_class = null;
316: try {
317: resource_class = Localization.class
318: .getClassLoader().loadClass(
319: resource_bundle_id);
320: } catch (ClassNotFoundException e) {
321: resource_class = null;
322: }
323:
324: if (resource_class != null) {
325: if (ResourceBundle.class
326: .isAssignableFrom(resource_class)) {
327: try {
328: result = (ResourceBundle) resource_class
329: .newInstance();
330:
331: return result;
332: } catch (IllegalAccessException e) {
333: resource_class = null;
334: result = null;
335: } catch (InstantiationException e) {
336: resource_class = null;
337: result = null;
338: }
339: }
340: }
341:
342: // try to load it as a properties file
343: resource_bundle_id = resource_bundle_id.replace(
344: '.', '/');
345:
346: // no previous result found or checks should be made to see if the modification time changed
347: String name = resource_bundle_id + ".properties";
348: URL resource = ResourceFinderClasspath
349: .getInstance().getResource(name);
350: if (resource != null) {
351: Long previous_modification = mResourceBundleModificationTimes
352: .get(most_detailed_candidate);
353:
354: long modification_time = -1;
355: if (RifeConfig.Tools
356: .getResourcebundleAutoReload()) {
357: try {
358: modification_time = ResourceFinderClasspath
359: .getInstance()
360: .getModificationTime(resource);
361: } catch (ResourceFinderErrorException e) {
362: // don't do anything, the modification time will simply be negative
363: }
364: }
365:
366: if (previous_modification != null
367: && modification_time <= previous_modification
368: .longValue()) {
369: result = mResourceBundlesOpened
370: .get(most_detailed_candidate);
371: } else {
372: try {
373: result = new ReloadingBundle(resource);
374:
375: mResourceBundleModificationTimes.put(
376: most_detailed_candidate,
377: modification_time);
378: mResourceBundlesOpened
379: .put(most_detailed_candidate,
380: result);
381: } catch (IOException e) {
382: result = null;
383: }
384: }
385: }
386: } catch (MissingResourceException e) {
387: result = null;
388: }
389:
390: if (result != null) {
391: return result;
392: }
393: }
394: }
395:
396: return null;
397: }
398: }
399:
400: class ReloadingBundle extends ResourceBundle {
401: private Properties mProperties = null;
402:
403: ReloadingBundle(URL resource) throws IOException {
404: mProperties = new Properties();
405: URLConnection connection = resource.openConnection();
406: connection.setUseCaches(false);
407: InputStream resourceAsStream = connection.getInputStream();
408: mProperties.load(resourceAsStream);
409: }
410:
411: protected Object handleGetObject(String key) {
412: return getProperties().get(key);
413: }
414:
415: protected Properties getProperties() {
416: return mProperties;
417: }
418:
419: public Enumeration getKeys() {
420: return Collections.enumeration(mProperties.keySet());
421: }
422: }
|