KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > commons > cbutil > CBIntText


1 package com.ca.commons.cbutil;
2
3 import java.text.MessageFormat JavaDoc;
4 import java.util.*;
5 import java.util.logging.Level JavaDoc;
6 import java.util.logging.Logger JavaDoc;
7
8
9 /**
10  * This 'International Text' static class acts as a central source of all localised
11  * strings. If it cannot find a localised properties file, the
12  * default (english) file is used. If that file can not be found, the key used to
13  * look up the translation is returned unchanged - hence it is useful if the keys
14  * are meaningful in their own right (i.e. use 'File' rather than 'String 42' as
15  * a key).<p>
16  * <p/>
17  * Currently the class is static to provide easy access to i18n text by
18  * all classes and plugins, and because it is difficult to see how
19  * supporting multiple different-locale languages would be helpful (note
20  * that multiple languages can be supported simply by using unicode).
21  */

22
23 public class CBIntText
24 {
25     static Locale locale = null;
26
27     static MessageFormat JavaDoc messageFormatter = null;
28
29     static Hashtable translations;
30
31     private static boolean errorGiven = false; // This is a 'complain once' class - usually it's either working or it's not...
32

33     private static Logger JavaDoc log = Logger.getLogger(CBIntText.class.getName());
34     /*
35      * If the local language is english, don't print warning messages
36      * about missing translation files (it confuses soooo many people)
37      */

38      
39     private static boolean english = true;
40
41     /**
42      * This initialises the international text class.
43      *
44      * @param bundleLocation the name of the i18n bundle (e.g. "language/JX_ja.properties").
45      * @param customLoader a custom class loader (may be null). JX uses a custom loader
46      * that auto-detects unicode and utf-8 files for ease of configuration by
47      * non-expert users.
48      */

49
50     public static void init(String JavaDoc bundleLocation, ClassLoader JavaDoc customLoader)
51     {
52         locale = Locale.getDefault();
53
54         Locale def = Locale.getDefault();
55
56         log.info("Default Locale is: " + def.getDisplayName());
57
58         log.info("Using Locale: " + locale.getDisplayName() + " for " + locale.getDisplayCountry());
59         log.info("language, localized for default locale is: " + def.getDisplayLanguage(locale));
60         log.info("country name, localized for default locale: " + def.getDisplayCountry(locale));
61         log.info("Default language, localized for your locale is: " + locale.getDisplayLanguage(def));
62         log.info("Default country name, localized for your locale is: " + locale.getDisplayCountry(def));
63
64         translations = new Hashtable(500);
65
66         addBundle(bundleLocation, customLoader);
67
68         if (!def.getLanguage().equals("en"))
69             english = false;
70
71         messageFormatter = new MessageFormat JavaDoc("");
72         messageFormatter.setLocale(locale);
73     }
74
75     /**
76      * Once init() has been called, this method can be used to add
77      * multiple resource bundles to the universal 'CBIntText' list of
78      * translations. Note that clashes (i.e. translations of identical
79      * terms) are resolved with the earliest registered bundle having
80      * priority. (i.e. if both JX and a plugin have a translation for
81      * 'file', the JX one will be used). If this is a problem, remember
82      * that the translated string is arbitrary - e.g. a plugin could
83      * translate the string 'pluginFile' instead.
84      */

85
86     public static void addBundle(String JavaDoc bundleLocation, ClassLoader JavaDoc customLoader)
87     {
88
89         log.fine("adding resource bundle: " + bundleLocation + " using loader: " + customLoader.toString());
90
91         int startSize = translations.size();
92
93         if (locale == null)
94         {
95             log.warning(" ERROR: - CBIntText.addBundle() has been called before CBIntText was initialised! - ignoring call.");
96             return;
97         }
98
99         try
100         {
101 // CBResourceBundle bundle = new CBResourceBundle( bundleLocation, locale, customLoader);
102
CBResourceBundle bundle = new CBResourceBundle(bundleLocation, locale);
103
104             String JavaDoc name = bundle.getString("name");
105             log.info(" added language localizaton set: " + ((name == null) ? "(not named)" : name));
106             
107             // Copy the new resource set into the hashtable, unless
108
// a value already exists in the hashtable... (earlier values have precedence).
109

110             Enumeration keys = bundle.getKeys();
111             while (keys.hasMoreElements())
112             {
113                 Object JavaDoc key = keys.nextElement();
114                 if (translations.containsKey(key) == false)
115                 {
116                     log.fine("adding key: " + key + " trans: " + bundle.getString((String JavaDoc) key));
117
118                     translations.put(key, bundle.getString((String JavaDoc) key));
119                 }
120             }
121
122         }
123         catch (MissingResourceException e)
124         {
125             log.log(Level.WARNING, "unable to load resource bundle for " + locale.getDisplayLanguage(locale) + " in country " + locale.getDisplayCountry(locale), e);
126         }
127         finally
128         {
129             if (startSize < translations.size()) // i.e. we added stuff...
130
{
131                 log.info(" locale language is " + locale.getDisplayLanguage(locale) + " in country " + locale.getDisplayCountry(locale));
132             }
133             else
134             {
135                 log.info("Unable to load language resource bundle (couldn't even find default 'JX.properties' file)!");
136             }
137         }
138     }
139
140     /**
141      * This attempts to get the localised version of a string.
142      * If anything goes wrong, it attempts to return the key
143      * string it was given - hence using a meaningfull key is
144      * a good harm minimization strategy.
145      */

146
147     public static String JavaDoc get(String JavaDoc key)
148     {
149
150         if (key == null) // sanity check that a valid key has been passed.
151
{
152             return "null key";
153         }
154
155         if (translations == null || translations.size() == 0) // we never opened a bundle...
156
{
157             if (errorGiven == false) // only print error message once! (otherwise we'd print an
158
{ // error for every string in the program!)
159
if (!english) log.info("Unable to translate (" + key + ") - can't find language resource bundle.");
160                 errorGiven = true;
161             }
162             return key; // try to keep on trucking using the (english) key phrase
163
}
164
165         try
166         {
167             String JavaDoc val = (String JavaDoc) translations.get(key); // return the translated word!
168
if (val == null) // this shouldn't happen, but can occur with an out-of-date (=incomplete) translation file.
169
{
170                 if (!english) log.fine("Can't find translation for (" + key + ") - returning unchanged.");
171                 return key;
172             }
173             return val;
174         }
175         catch (MissingResourceException e)
176         {
177             return key; // couldn't find a translation, so return the keyword instead.
178
}
179     }
180
181     /**
182      * This attempts to get the localised version of a formatted string,
183      * inserting arguments as appropriate (see MessageFormat class
184      * for more details).
185      * If anything goes wrong, it attempts to return the key
186      * string it was given - hence using a meaningfull key is
187      * a good harm minimization strategy.
188      *
189      * @param key the format pattern; e.g. 'JXplorer has saved {0} ldif entries'.
190      * @param args the list of parameters to insert into the format pattern.
191      */

192
193     public static String JavaDoc get(String JavaDoc key, Object JavaDoc[] args)
194     {
195
196         if (key == null) // sanity check that a valid key has been passed.
197
{
198             return "null key";
199         }
200         String JavaDoc val = key;
201
202         if (translations == null || translations.size() == 0) // we never opened a bundle...
203
{
204             if (errorGiven == false) // only print error message once! (otherwise we'd print an
205
{ // error for every string in the program!)
206
if (!english) log.info("Unable to translate (" + key + ") - can't find language resource bundle.");
207                 errorGiven = true;
208             }
209         }
210         else
211         {
212             try
213             {
214                 val = (String JavaDoc) translations.get(key); // return the translated word!
215
if (val == null) // this shouldn't happen, but can occur with an out-of-date (=incomplete) translation file.
216
{
217                     if (!english) log.fine("Can't find translation for (" + key + ") - returning unchanged.");
218                     val = key; // revert to english
219
}
220             }
221             catch (MissingResourceException e)
222             {
223                 val = key; // couldn't find a translation, so return the keyword instead.
224
}
225         }
226
227         //XXX it may be better to reuse MessageFormat objects, but this will require some thought...
228

229         return MessageFormat.format(key, args); // try to keep on trucking using the (english) key phrase
230

231     }
232 }
Popular Tags