Revision 13649 trunk/libraries/libInternationalization/src/org/gvsig/i18n/Messages.java

View differences:

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