Revision 13649 trunk/libraries/libInternationalization/src/org/gvsig/i18n/Messages.java
Messages.java | ||
---|---|---|
1 | 1 |
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana |
2 | 2 |
* |
3 |
* Copyright (C) 2006 IVER T.I. and Generalitat Valenciana. |
|
3 |
* Copyright (C) 2006-2007 IVER T.I. and Generalitat Valenciana.
|
|
4 | 4 |
* |
5 | 5 |
* This program is free software; you can redistribute it and/or |
6 | 6 |
* modify it under the terms of the GNU General Public License |
... | ... | |
42 | 42 |
package org.gvsig.i18n; |
43 | 43 |
|
44 | 44 |
import java.io.File; |
45 |
import java.io.IOException; |
|
46 |
import java.io.InputStream; |
|
45 | 47 |
import java.net.MalformedURLException; |
46 | 48 |
import java.net.URL; |
49 |
import java.text.MessageFormat; |
|
47 | 50 |
import java.util.ArrayList; |
48 | 51 |
import java.util.Enumeration; |
49 |
import java.util.HashMap;
|
|
52 |
import java.util.IllegalFormatException;
|
|
50 | 53 |
import java.util.Iterator; |
51 | 54 |
import java.util.Locale; |
52 |
import java.util.MissingResourceException;
|
|
53 |
import java.util.ResourceBundle;
|
|
55 |
import java.util.Properties;
|
|
56 |
import java.util.Set;
|
|
54 | 57 |
|
55 | 58 |
import org.apache.log4j.Logger; |
56 | 59 |
|
... | ... | |
83 | 86 |
public class Messages { |
84 | 87 |
private static Logger logger = Logger.getLogger("Messages"); |
85 | 88 |
private static String _CLASSNAME = "org.gvsig.i18n.Messages"; |
86 |
private static int _INITIALSIZE = 3700; // I try to set an initial capacity similar to the amount of strings in gvSIG |
|
87 | 89 |
|
88 | 90 |
/* Each entry will contain a hashmap with translations. Each hasmap |
89 | 91 |
* contains the translations for one language, indexed by the |
... | ... | |
92 | 94 |
private static ArrayList localeResources = new ArrayList(); |
93 | 95 |
private static ArrayList preferredLocales = new ArrayList(); // contains the ordered list of prefered languages/locales (class Locale) |
94 | 96 |
|
97 |
/* |
|
98 |
* The language considered the origin of translations, which will |
|
99 |
* (possibly) be stored in a property file without language suffix |
|
100 |
* (ie: text.properties instead of text_es.properties). |
|
101 |
*/ |
|
102 |
private static String baseLanguage = "es"; |
|
103 |
|
|
95 | 104 |
/** |
96 | 105 |
* <p>Gets the localized message associated with the provided key. |
97 | 106 |
* If the key is not in the dictionary, return the key and register |
... | ... | |
114 | 123 |
if (key==null) return null; |
115 | 124 |
for (int numLocale=0; numLocale<localeResources.size(); numLocale++) { |
116 | 125 |
// try to get the translation for any of the languagues in the preferred languages list |
117 |
String translation = (String) ((HashMap)localeResources.get(numLocale)).get(key);
|
|
126 |
String translation = ((Properties)localeResources.get(numLocale)).getProperty(key);
|
|
118 | 127 |
if (translation!=null && !translation.equals("")) |
119 | 128 |
return translation; |
120 | 129 |
} |
121 |
logger.warn(callerName+ " -- " +Messages.getText("No_se_encontro_la_traduccion_para", _CLASSNAME ,false)+" "+key);
|
|
130 |
logger.warn(callerName+ " -- Cannot find translation for "+key);
|
|
122 | 131 |
return key; |
123 | 132 |
} |
124 | 133 |
|
134 |
public static String getText(String key, String[] arguments, String callerName) { |
|
135 |
String translation = getText(key, callerName); |
|
136 |
if (translation!=null) { |
|
137 |
try { |
|
138 |
translation = MessageFormat.format(translation, arguments); |
|
139 |
} |
|
140 |
catch (IllegalFormatException ex) { |
|
141 |
logger.error(callerName+" -- Error formating key: "+key+" -- "+translation); |
|
142 |
} |
|
143 |
} |
|
144 |
return translation; |
|
145 |
} |
|
146 |
|
|
125 | 147 |
/** |
126 | 148 |
* <p>Gets the localized message associated with the provided key. |
127 | 149 |
* If the key is not in the dictionary or the translation is empty, |
... | ... | |
136 | 158 |
return getText(key, _CLASSNAME); |
137 | 159 |
} |
138 | 160 |
|
161 |
public static String getText(String key, String[] arguments) { |
|
162 |
return getText(key, arguments, _CLASSNAME); |
|
163 |
} |
|
164 |
|
|
139 | 165 |
/** |
140 | 166 |
* <p>Gets the localized message associated with the provided key. |
141 | 167 |
* If the key is not in the dictionary or the translation is empty, |
... | ... | |
153 | 179 |
return getText(key, _CLASSNAME, log); |
154 | 180 |
} |
155 | 181 |
|
182 |
public static String getText(String key, String[] arguments, boolean log) { |
|
183 |
String translation = getText(key, _CLASSNAME, log); |
|
184 |
if (translation!=null) { |
|
185 |
try { |
|
186 |
translation = MessageFormat.format(translation, arguments); |
|
187 |
} |
|
188 |
catch (IllegalFormatException ex) { |
|
189 |
if (log) { |
|
190 |
logger.error(_CLASSNAME+" -- Error formating key: "+key+" -- "+translation); |
|
191 |
} |
|
192 |
} |
|
193 |
} |
|
194 |
return translation; |
|
195 |
} |
|
196 |
|
|
156 | 197 |
/** |
157 | 198 |
* <p>Gets the localized message associated with the provided key. |
158 | 199 |
* If the key is not in the dictionary, it returns null and the failure |
... | ... | |
169 | 210 |
if (key==null) return null; |
170 | 211 |
for (int numLocale=0; numLocale<localeResources.size(); numLocale++) { |
171 | 212 |
// try to get the translation for any of the languagues in the preferred languages list |
172 |
String translation = (String) ((HashMap)localeResources.get(numLocale)).get(key);
|
|
213 |
String translation = ((Properties)localeResources.get(numLocale)).getProperty(key);
|
|
173 | 214 |
if (translation!=null && !translation.equals("")) |
174 | 215 |
return translation; |
175 | 216 |
} |
176 | 217 |
if (log) { |
177 |
logger.warn(callerName+" -- "+Messages.getText("No_se_encontro_la_traduccion_para", _CLASSNAME ,false)+" "+key);
|
|
218 |
logger.warn(callerName+" -- Cannot find translation for "+key);
|
|
178 | 219 |
} |
179 | 220 |
return null; |
180 | 221 |
} |
222 |
|
|
223 |
public static String getText(String key, String[] arguments, String callerName, boolean log) { |
|
224 |
String translation = getText(key, callerName, log); |
|
225 |
if (translation!=null) { |
|
226 |
try { |
|
227 |
translation = MessageFormat.format(translation, arguments); |
|
228 |
} |
|
229 |
catch (IllegalFormatException ex) { |
|
230 |
if (log) { |
|
231 |
logger.error(callerName+" -- Error formating key: "+key+" -- "+translation); |
|
232 |
} |
|
233 |
} |
|
234 |
} |
|
235 |
return translation; |
|
236 |
} |
|
181 | 237 |
|
182 | 238 |
/** |
183 | 239 |
* <p>Adds an additional family of resource files containing some translations. |
... | ... | |
298 | 354 |
*/ |
299 | 355 |
public static void addResourceFamily(String family, ClassLoader loader, String callerName) { |
300 | 356 |
String currentKey; |
301 |
Enumeration properties; |
|
302 |
Locale defaultLocale = Locale.getDefault(); |
|
357 |
Enumeration keys; |
|
358 |
String lang; |
|
359 |
Properties properties, translations; |
|
303 | 360 |
int totalLocales = preferredLocales.size(); |
304 | 361 |
|
305 | 362 |
if (totalLocales == 0) { |
306 | 363 |
// if it's empty, warn about that |
307 |
logger.warn(Messages.getText("No_hay_lista_de_idiomas_preferidos_quiza_olvido_inicializar_clase", _CLASSNAME, false));
|
|
364 |
logger.warn("There is not preferred languages list. Maybe the Messages class was not initialized");
|
|
308 | 365 |
} |
309 |
Locale lang; |
|
310 |
ResourceBundle bundle = null; |
|
311 |
|
|
366 |
|
|
367 |
|
|
312 | 368 |
for (int numLocale=0; numLocale<totalLocales; numLocale++) { // for each language |
313 |
lang = (Locale) preferredLocales.get(numLocale); |
|
314 |
try { |
|
315 |
/** |
|
316 |
* Here we are doing a pervert use of getBundle method. Normally, it is call it in in this way: |
|
317 |
* getBundle("text", "en", loader), in order to get the file 'text_en.properties'. However, in |
|
318 |
* this way the default file ('text.properties') is also loaded, and we want to avoid this |
|
319 |
* (because 'text.properties contains the Spanish translation). |
|
320 |
* So we use the method in this non-standard way: |
|
321 |
* getBundle("text_en", "en", loader), ensuring that we are just loading the file 'text_en.properties' |
|
322 |
**/ |
|
323 |
if (!lang.getLanguage().equals("es")) |
|
324 |
bundle = ResourceBundle.getBundle(family+"_"+lang.getLanguage(), lang, loader); |
|
325 |
else { // we allow 'text.properties' to be loaded for Spanish |
|
326 |
if (Locale.getDefault().equals(lang)) { |
|
327 |
bundle = ResourceBundle.getBundle(family, lang, loader); |
|
328 |
} |
|
329 |
else { |
|
330 |
// we need to temporarily change the default locale to properly load spanish in corner cases |
|
331 |
Locale.setDefault(lang); |
|
332 |
bundle = ResourceBundle.getBundle(family, lang, loader); |
|
333 |
Locale.setDefault(defaultLocale); |
|
334 |
} |
|
369 |
properties = new Properties(); |
|
370 |
lang = ((Locale) preferredLocales.get(numLocale)).getLanguage(); |
|
371 |
InputStream is = loader.getResourceAsStream(family+"_"+lang+".properties"); |
|
372 |
if (is != null) { |
|
373 |
try { |
|
374 |
properties.load(is); |
|
375 |
} catch (IOException e) { |
|
335 | 376 |
} |
336 |
|
|
337 |
properties = bundle.getKeys(); |
|
338 |
while (properties.hasMoreElements()) { |
|
339 |
currentKey = (String) properties.nextElement(); |
|
340 |
if (! ((HashMap)localeResources.get(numLocale)).containsKey(currentKey)) { |
|
341 |
((HashMap)localeResources.get(numLocale)).put(currentKey, bundle.getString(currentKey)); |
|
377 |
} |
|
378 |
else if (lang.equals(baseLanguage)) { |
|
379 |
// try also "text.properties" for the base language |
|
380 |
is = loader.getResourceAsStream(family+".properties"); |
|
381 |
if (is!=null) { |
|
382 |
try { |
|
383 |
properties.load(is); |
|
384 |
} catch (IOException e) { |
|
342 | 385 |
} |
343 | 386 |
} |
344 | 387 |
} |
345 |
catch (MissingResourceException ex) { |
|
346 |
Locale.setDefault(defaultLocale); |
|
347 |
logger.warn(Messages.getText("Las_traducciones_no_pudieron_ser_cargadas", false)+" -- "+callerName+" -- "+lang.getLanguage()); |
|
388 |
|
|
389 |
translations = (Properties)localeResources.get(numLocale); |
|
390 |
keys = properties.keys(); |
|
391 |
while (keys.hasMoreElements()) { |
|
392 |
currentKey = (String) keys.nextElement(); |
|
393 |
if (! translations.containsKey(currentKey)) { |
|
394 |
translations.put(currentKey, properties.getProperty(currentKey)); |
|
395 |
} |
|
348 | 396 |
} |
349 | 397 |
} |
350 | 398 |
} |
... | ... | |
368 | 416 |
* @see <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a> |
369 | 417 |
*/ |
370 | 418 |
public static void addResourceFamily(String family, String callerName) { |
371 |
String currentKey; |
|
372 |
Enumeration properties; |
|
373 |
Locale defaultLocale = Locale.getDefault(); |
|
374 |
int totalLocales = preferredLocales.size(); |
|
375 |
|
|
376 |
if (totalLocales == 0) { |
|
377 |
// if it's empty, warn about that |
|
378 |
logger.warn(Messages.getText("No_hay_lista_de_idiomas_preferidos_quiza_olvido_inicializar_clase", _CLASSNAME, false)); |
|
379 |
} |
|
380 |
Locale lang; |
|
381 |
ResourceBundle bundle = null; |
|
382 |
|
|
383 |
for (int numLocale=0; numLocale<totalLocales; numLocale++) { // for each language |
|
384 |
try { |
|
385 |
lang = (Locale) preferredLocales.get(numLocale); |
|
386 |
if (!lang.getLanguage().equals("es")) // ensure we don't get a fallback |
|
387 |
bundle = ResourceBundle.getBundle(family+"_"+lang.getLanguage(), lang); |
|
388 |
else { // we allow 'text.properties' to be loaded for Spanish |
|
389 |
if (Locale.getDefault().equals(lang)) { |
|
390 |
bundle = ResourceBundle.getBundle(family, lang); |
|
391 |
} |
|
392 |
else { |
|
393 |
// we need to temporarily change the default locale to properly load spanish in corner cases |
|
394 |
Locale.setDefault(lang); |
|
395 |
bundle = ResourceBundle.getBundle(family, lang); |
|
396 |
Locale.setDefault(defaultLocale); |
|
397 |
} |
|
398 |
} |
|
399 |
|
|
400 |
properties = bundle.getKeys(); |
|
401 |
while (properties.hasMoreElements()) { |
|
402 |
currentKey = (String) properties.nextElement(); |
|
403 |
if (! ((HashMap)localeResources.get(numLocale)).containsKey(currentKey)) { |
|
404 |
((HashMap)localeResources.get(numLocale)).put(currentKey, bundle.getString(currentKey)); |
|
405 |
} |
|
406 |
} |
|
407 |
} |
|
408 |
catch (MissingResourceException ex) { |
|
409 |
Locale.setDefault(defaultLocale); |
|
410 |
logger.warn(callerName+" " + ex.getLocalizedMessage()); |
|
411 |
} |
|
412 |
} |
|
419 |
addResourceFamily(family, Messages.class.getClassLoader(), callerName); |
|
413 | 420 |
} |
414 |
|
|
415 |
private static void addResourceFamily(String family, Locale lang, HashMap dict) { |
|
416 |
String currentKey; |
|
417 |
Enumeration properties; |
|
418 | 421 |
|
419 |
ResourceBundle bundle = null; |
|
420 |
Locale defaultLocale = Locale.getDefault(); |
|
421 |
|
|
422 |
try { |
|
423 |
if (!lang.getLanguage().equals("es")) // ensure we don't get a fallback |
|
424 |
bundle = ResourceBundle.getBundle(family+"_"+lang.getLanguage(), lang); |
|
425 |
else { // we allow 'text.properties' to be loaded for Spanish |
|
426 |
if (Locale.getDefault().equals(lang)) { |
|
427 |
bundle = ResourceBundle.getBundle(family, lang); |
|
428 |
} |
|
429 |
else { |
|
430 |
// we need to temporarily change the default locale to properly load spanish in corner cases |
|
431 |
Locale.setDefault(lang); |
|
432 |
bundle = ResourceBundle.getBundle(family, lang); |
|
433 |
Locale.setDefault(defaultLocale); |
|
434 |
} |
|
435 |
} |
|
436 |
properties = bundle.getKeys(); |
|
437 |
while (properties.hasMoreElements()) { |
|
438 |
currentKey = (String) properties.nextElement(); |
|
439 |
if (! dict.containsKey(currentKey)) { |
|
440 |
dict.put(currentKey, bundle.getString(currentKey)); |
|
441 |
} |
|
442 |
} |
|
443 |
} |
|
444 |
catch (MissingResourceException ex) { |
|
445 |
Locale.setDefault(defaultLocale); |
|
446 |
logger.warn(Messages.class.getName()+" " + ex.getLocalizedMessage()); |
|
447 |
} |
|
448 |
} |
|
449 |
|
|
450 | 422 |
|
451 | 423 |
/** |
452 | 424 |
* Returns an ArrayList containing the ordered list of prefered Locales |
... | ... | |
500 | 472 |
public static void addLocale(Locale lang) { |
501 | 473 |
if (!preferredLocales.contains(lang)) { // avoid duplicates |
502 | 474 |
preferredLocales.add(lang); // add the lang to the ordered list of preferred locales |
503 |
HashMap dict = new HashMap(_INITIALSIZE);
|
|
475 |
Properties dict = new Properties();
|
|
504 | 476 |
localeResources.add(dict); // add a hashmap which will contain the translation for this language |
505 |
addResourceFamily("org.gvsig.i18n.resources.translations.text", lang, dict); |
|
506 | 477 |
} |
507 | 478 |
} |
508 | 479 |
|
... | ... | |
533 | 504 |
*/ |
534 | 505 |
public static void removeResources() { |
535 | 506 |
for (int numLocale=0; numLocale<localeResources.size(); numLocale++) { |
536 |
((HashMap)localeResources.get(numLocale)).clear();
|
|
507 |
((Properties)localeResources.get(numLocale)).clear();
|
|
537 | 508 |
} |
538 | 509 |
} |
539 | 510 |
|
... | ... | |
547 | 518 |
protected static int size(Locale lang) { |
548 | 519 |
int numLocale = preferredLocales.indexOf(lang); |
549 | 520 |
if (numLocale!=-1) { |
550 |
return ((HashMap)localeResources.get(numLocale)).size();
|
|
521 |
return ((Properties)localeResources.get(numLocale)).size();
|
|
551 | 522 |
}; |
552 | 523 |
return 0; |
553 | 524 |
} |
554 | 525 |
|
526 |
protected static Set keySet(Locale lang) { |
|
527 |
int numLocale = preferredLocales.indexOf(lang); |
|
528 |
if (numLocale!=-1) { |
|
529 |
return ((Properties)localeResources.get(numLocale)).keySet(); |
|
530 |
} |
|
531 |
else |
|
532 |
return null; |
|
533 |
} |
|
534 |
|
|
555 | 535 |
/** |
556 | 536 |
* Checks if some locale has been added to the preferred locales |
557 | 537 |
* list, which is necessary before loading any translation because |
... | ... | |
564 | 544 |
} |
565 | 545 |
|
566 | 546 |
/** |
547 |
* Gets the base language, the language considered the origin of |
|
548 |
* translations, which will be (possibly) stored in a property |
|
549 |
* file without language suffix |
|
550 |
* (ie: text.properties instead of text_es.properties). |
|
551 |
*/ |
|
552 |
public static String getBaseLanguage() { |
|
553 |
return baseLanguage; |
|
554 |
} |
|
555 |
|
|
556 |
/** |
|
557 |
* Sets the base language, the language considered the origin of |
|
558 |
* translations, which will be (possibly) |
|
559 |
* stored in a property file without language suffix |
|
560 |
* (ie: text.properties instead of text_es.properties). |
|
561 |
* |
|
562 |
* @param lang The base language to be set |
|
563 |
*/ |
|
564 |
public static void setBaseLanguage(String lang) { |
|
565 |
baseLanguage = lang; |
|
566 |
} |
|
567 |
|
|
568 |
/* |
|
567 | 569 |
* Searches the subdirectories of the provided directory, finding |
568 | 570 |
* all the translation files, and constructing a list of available translations. |
569 | 571 |
* It reports different country codes or variants, if available. |
Also available in: Unified diff