001: // Copyright (c) 2004 Sun Microsystems Inc., All Rights Reserved.
002:
003: /*
004: * StringTranslator.java
005: *
006: * SUN PROPRIETARY/CONFIDENTIAL.
007: * This software is the proprietary information of Sun Microsystems, Inc.
008: * Use is subject to license terms.
009: *
010: */
011: package com.sun.jbi.common;
012:
013: import com.sun.jbi.StringTranslator;
014:
015: import java.text.MessageFormat;
016:
017: import java.util.Locale;
018: import java.util.ResourceBundle;
019: import java.util.logging.Logger;
020:
021: /**
022: * This is the implementation of the String Translator, which provides services for
023: * internationalization of messages to all services running inside the JBI environment.
024: *
025: * @author Mark S White
026: */
027: public class StringTranslatorImpl implements StringTranslator {
028: /**
029: * Logger name
030: */
031: private static final String LOGGER_NAME = "com.sun.jbi.common.i18n";
032:
033: /**
034: * Unqualified name for resource bundles.
035: */
036: public static final String RESOURCE_BUNDLE_NAME = "LocalStrings";
037:
038: /**
039: * Log message for creation of new instance.
040: */
041: private static final String LOG_NEW_INSTANCE = "New StringTranslator for package {0}, classLoader is {1}";
042:
043: /**
044: * Log message for locale.
045: */
046: private static final String LOG_CURRENT_LOCALE = "Current locale is {0}";
047:
048: /**
049: * Log message for failure loading resource bundle.
050: */
051: private static final String LOG_UNABLE_TO_LOAD_BUNDLE = "Unable to load resource bundle {0} for locale {1}: {2}";
052:
053: /**
054: * Log message for using alternate resource bundle.
055: */
056: private static final String LOG_USING_BUNDLE = "Using resource bundle for locale {0} instead.";
057:
058: /**
059: * Log message for using fallback resource bundle to look up a message.
060: */
061: private static final String LOG_TRANSLATION_USING_FALLBACK = "No translation for key={0} found in resource bundle for locale {1}, "
062: + "using locale {2} instead.";
063:
064: /**
065: * Log message for no translation available for a message key in any resource bundle.
066: */
067: private static final String LOG_NO_TRANSLATION_FOR_KEY = "No translation for key={0} found in any resource bundle. "
068: + "Insert data is [{1}].";
069:
070: /**
071: * Log message for no translation available for a message key in a particular
072: * resource bundle.
073: */
074: private static final String LOG_NO_TRANSLATION_FOR_KEY_IN_BUNDLE = "No translation for key={0} found in resource bundle for locale {1}. "
075: + "Insert data is [{2}].";
076:
077: /**
078: * Message text used when no translation is available for a message key.
079: */
080: private static final String MSG_NO_TRANSLATION = "No translation available for message with key={0} and inserts=[{1}].";
081:
082: /**
083: * Logger for this instance
084: */
085: private Logger mLog;
086:
087: /**
088: * ResourceBundle for a single package name.
089: */
090: private ResourceBundle mResourceBundle;
091:
092: /**
093: * The default locale at the time this StringTranslator was created.
094: */
095: private Locale mDefaultLocale;
096:
097: /**
098: * Fallback ResourceBundle for a single package name. This is used only when the
099: * default locale is something other than Locale.US. In that case, this is the
100: * bundle for Locale.US for looking up messages that are not found in the default
101: * locale.
102: */
103: private ResourceBundle mFallbackBundle;
104:
105: /**
106: * Constructor. This loads the Resource Bundle for the current locale, and if the
107: * current locale is not Locale.US, it loads the Resource Bundle for Locale.US and
108: * stores it as the backup for string lookup.
109: *
110: * @param packageName - the name of the package that contains the resource bundle.
111: * @param classLoader - the class loader to be used for loading the resource bundle.
112: * If this parameter is null, the current class loader is used.
113: */
114: StringTranslatorImpl(String packageName, ClassLoader classLoader) {
115: mLog = Logger.getLogger(LOGGER_NAME);
116: mLog.fine(MessageFormat.format(LOG_NEW_INSTANCE, new Object[] {
117: packageName, classLoader }));
118:
119: String bundleName = packageName + "." + RESOURCE_BUNDLE_NAME;
120: mDefaultLocale = Locale.getDefault();
121: mLog.finer(MessageFormat.format(LOG_CURRENT_LOCALE,
122: new Object[] { mDefaultLocale }));
123:
124: // Always load the bundle for english
125: mFallbackBundle = null;
126:
127: ResourceBundle englishBundle = null;
128:
129: try {
130: if (null == classLoader) {
131: englishBundle = ResourceBundle.getBundle(bundleName,
132: Locale.US);
133: } else {
134: englishBundle = ResourceBundle.getBundle(bundleName,
135: Locale.US, classLoader);
136: }
137: } catch (java.util.MissingResourceException mrEx) {
138: mLog.warning(MessageFormat.format(
139: LOG_UNABLE_TO_LOAD_BUNDLE, new Object[] {
140: bundleName, Locale.US, mrEx }));
141: }
142:
143: // If the default locale is English, set it as the primary bundle.
144: // If the default locale is not English, attempt to load the bundle.
145: // If it is found, save it as the primary and set the fallback to
146: // English. If it is not found, set the primary to English.
147: if (mDefaultLocale.equals(Locale.US)) {
148: mResourceBundle = englishBundle;
149: } else {
150: try {
151: if (null == classLoader) {
152: mResourceBundle = ResourceBundle
153: .getBundle(bundleName);
154: mFallbackBundle = englishBundle;
155: } else {
156: mResourceBundle = ResourceBundle.getBundle(
157: bundleName, mDefaultLocale, classLoader);
158: mFallbackBundle = englishBundle;
159: }
160: } catch (java.util.MissingResourceException mrEx) {
161: mLog.warning(MessageFormat.format(
162: LOG_UNABLE_TO_LOAD_BUNDLE, new Object[] {
163: bundleName, mDefaultLocale, mrEx }));
164: mLog.warning(MessageFormat.format(LOG_USING_BUNDLE,
165: new Object[] { Locale.US }));
166: mResourceBundle = englishBundle;
167: }
168: }
169: }
170:
171: /**
172: * Get a localized string using the specified resource key.
173: *
174: * @param key - the key to the localized string in the resource bundle.
175: *
176: * @return the localized string.
177: */
178: public String getString(String key) {
179: Object[] inserts = new Object[0];
180:
181: return getString(key, inserts);
182: }
183:
184: /**
185: * Get a localized string using the specified resource key. Handle one message
186: * insert.
187: *
188: * @param key - the key to the localized string in the resource bundle.
189: * @param insert1 - the message insert.
190: *
191: * @return the localized string formatted with the message insert.
192: */
193: public String getString(String key, Object insert1) {
194: Object[] inserts = { insert1 };
195:
196: return getString(key, inserts);
197: }
198:
199: /**
200: * Get a localized string using the specified resource key. Handle two message
201: * inserts.
202: *
203: * @param key - the key to the localized string in the resource bundle.
204: * @param insert1 - the first message insert.
205: * @param insert2 - the second message insert.
206: *
207: * @return the localized string formatted with the message inserts.
208: */
209: public String getString(String key, Object insert1, Object insert2) {
210: Object[] inserts = { insert1, insert2 };
211:
212: return getString(key, inserts);
213: }
214:
215: /**
216: * Get a localized string using the specified resource key. Handle three message
217: * inserts.
218: *
219: * @param key - the key to the localized string in the resource bundle.
220: * @param insert1 - the first message insert.
221: * @param insert2 - the second message insert.
222: * @param insert3 - the third message insert.
223: *
224: * @return the localized string formatted with the message inserts.
225: */
226: public String getString(String key, Object insert1, Object insert2,
227: Object insert3) {
228: Object[] inserts = { insert1, insert2, insert3 };
229:
230: return getString(key, inserts);
231: }
232:
233: /**
234: * Get a localized string using the specified resource key. Handle four message
235: * inserts.
236: *
237: * @param key - the key to the localized string in the resource bundle.
238: * @param insert1 - the first message insert.
239: * @param insert2 - the second message insert.
240: * @param insert3 - the third message insert.
241: * @param insert4 - the fourth message insert.
242: *
243: * @return the localized string formatted with the message inserts.
244: */
245: public String getString(String key, Object insert1, Object insert2,
246: Object insert3, Object insert4) {
247: Object[] inserts = { insert1, insert2, insert3, insert4 };
248:
249: return getString(key, inserts);
250: }
251:
252: /**
253: * Get a localized string using the specified resource key. Handle any number of
254: * message inserts. This method is called by all the other getString() methods in
255: * the class. The procedure for string lookup is to first look in the primary
256: * resource bundle, then in the fallback resource bundle. If the string is found in
257: * the primary, return the translated string quietly. If the string is not found in
258: * the primary but in the fallback, log a warning and return the translated string.
259: * If the string is not found in either bundle, log an error and return a message
260: * formatted with the key and insert values provided by the caller. If there is no
261: * resource bundle available, just return a message formatted with the key and
262: * insert values provided by the caller.
263: *
264: * @param key - the key to the localized string in the resource bundle.
265: * @param inserts - the array of message inserts.
266: *
267: * @return the localized string formatted with the message inserts.
268: */
269: public String getString(String key, Object[] inserts) {
270: String translated = null;
271:
272: if (null != mResourceBundle) {
273: try {
274: translated = mResourceBundle.getString(key);
275: translated = MessageFormat.format(translated, inserts);
276: } catch (java.util.MissingResourceException mrEx) {
277: if (null != mFallbackBundle) {
278: try {
279: translated = mFallbackBundle.getString(key);
280: translated = MessageFormat.format(translated,
281: inserts);
282: mLog.fine(MessageFormat.format(
283: LOG_TRANSLATION_USING_FALLBACK,
284: new Object[] { key, mDefaultLocale,
285: Locale.US }));
286: } catch (java.util.MissingResourceException mreEx) {
287: String fi = formatInserts(inserts);
288: translated = MessageFormat.format(
289: MSG_NO_TRANSLATION, new Object[] { key,
290: fi });
291: mLog.warning(MessageFormat.format(
292: LOG_NO_TRANSLATION_FOR_KEY,
293: new Object[] { key, fi }));
294: }
295: } else {
296: String fi = formatInserts(inserts);
297: translated = MessageFormat.format(
298: MSG_NO_TRANSLATION,
299: new Object[] { key, fi });
300: mLog.warning(MessageFormat.format(
301: LOG_NO_TRANSLATION_FOR_KEY_IN_BUNDLE,
302: new Object[] { key, mDefaultLocale, fi }));
303: }
304: }
305: } else {
306: translated = MessageFormat.format(MSG_NO_TRANSLATION,
307: new Object[] { key, formatInserts(inserts) });
308: }
309:
310: return translated;
311: }
312:
313: /**
314: * Format an array of message inserts into a string. The ouptut string is in the
315: * format "insert1,insert2,....,insertn".
316: *
317: * @param inserts - the array of message inserts.
318: *
319: * @return the string formatted with the message inserts.
320: */
321: private String formatInserts(Object[] inserts) {
322: StringBuffer formatted = new StringBuffer("");
323:
324: for (int i = 0; i < inserts.length; i++) {
325: if (i > 0) {
326: formatted.append(",");
327: }
328:
329: formatted.append(inserts[i].toString());
330: }
331:
332: return formatted.toString();
333: }
334: }
|