Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2057 / libraries / libInternationalization / src / org / gvsig / i18n / Messages.java @ 39173

History | View | Annotate | Download (24.5 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
*
3
* Copyright (C) 2006-2007 IVER T.I. and Generalitat Valenciana.
4
*
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
*
19
* For more information, contact:
20
*
21
*  Generalitat Valenciana
22
*   Conselleria d'Infraestructures i Transport
23
*   Av. Blasco Ib??ez, 50
24
*   46010 VALENCIA
25
*   SPAIN
26
*
27
*      +34 963862235
28
*   gvsig@gva.es
29
*      www.gvsig.gva.es
30
*
31
*    or
32
*
33
*   IVER T.I. S.A
34
*   Salamanca 50
35
*   46005 Valencia
36
*   Spain
37
*
38
*   +34 963163400
39
*   dac@iver.es
40
*/
41

    
42
package org.gvsig.i18n;
43

    
44
import java.io.File;
45
import java.io.IOException;
46
import java.io.InputStream;
47
import java.net.MalformedURLException;
48
import java.net.URL;
49
import java.text.MessageFormat;
50
import java.util.ArrayList;
51
import java.util.Enumeration;
52
import java.util.HashSet;
53
import java.util.IllegalFormatException;
54
import java.util.Iterator;
55
import java.util.Locale;
56
import java.util.Properties;
57
import java.util.Set;
58

    
59
import org.slf4j.Logger;
60
import org.slf4j.LoggerFactory;
61

    
62
/**
63
 * <p>This class offers some methods to provide internationalization services
64
 * to other projects. All the methods are static.</p>
65
 *
66
 * <p>The most useful method is {@link #getText(String) getText(key)} (and family),
67
 * which returns the translation associated
68
 * with the provided key. The class must be initialized before getText can be
69
 * used.</p>
70
 *
71
 * <p>The typical usage sequence would be:</p>
72
 * <ul>
73
 * <li>Add some locale to the prefered locales list: <code>Messages.addLocale(new Locale("es"))</code></li>
74
 * <li>Add some resource file containing translations: <code>Messages.addResourceFamily("text", new File("."))</code></li>
75
 * <li>And finaly getText can be used: <code>Messages.getText("aceptar")</code></li>
76
 * </ul>
77
 *
78
 * <p>The resource files are Java properties files, which contain <code>key=translation</code>
79
 * pairs, one
80
 * pair per line. These files must be encoded using iso-8859-1 encoding, and unicode escaped
81
 * sequences must be used to include characters outside the former encoding.
82
 * There are several ways to specify the property file to load, see the different
83
 * addResourceFamily methods for details.</p>
84
 *
85
 * @author Cesar Martinez Izquierdo (cesar.martinez@iver.es)
86
 *
87
 */
88
public class Messages {
89
    private static Logger logger = LoggerFactory.getLogger("Messages");
90
    private static String _CLASSNAME = "org.gvsig.i18n.Messages";
91

    
92
    /* Each entry will contain a hashmap with translations. Each hasmap
93
     * contains the translations for one language, indexed by the
94
     * translation key. The translations for language (i) in the preferred locales
95
     * list are contained in the position (i) of the localeResources list */
96
    private static ArrayList localeResources = new ArrayList();
97
        private static ArrayList preferredLocales = new ArrayList(); // contains the ordered list of prefered languages/locales (class Locale)
98

    
99

    
100
        /* Set of resource families and classloaders used to load i18n resources. */
101
        private static Set resourceFamilies = new HashSet();
102
        private static Set classLoaders = new HashSet();
103

    
104
        /*
105
         * The language considered the origin of translations, which will
106
         * (possibly) be stored in a property file without language suffix
107
         * (ie: text.properties instead of text_es.properties).
108
         */
109
        private static String baseLanguage = "es";
110
        private static Locale baseLocale = new Locale(baseLanguage);
111

    
112
        /**
113
         * <p>Gets the localized message associated with the provided key.
114
         * If the key is not in the dictionary, return the key and register
115
         * the failure in the log.</p>
116
         *
117
         * <p>The <code>callerName</code> parameter is only
118
         * used as a label when logging, so any String can be used. However, a
119
         * meaningful String should be used, such as the name of the class requiring
120
         * the translation services, in order to identify the source of the failure
121
         * in the log.</p>
122
         *
123
         * @param key         An String which identifies the translation that we want to get.
124
         * @param callerName  A symbolic name given to the caller of this method, to
125
         *                    show it in the log if the key was not found
126
         * @return            an String with the message associated with the provided key.
127
         *                    If the key is not in the dictionary, return the key. If the key
128
         *                    is null, return null.
129
         */
130
        public static String getText(String key, String callerName) {
131
                if (key==null) {
132
                        return null;
133
                }
134
                for (int numLocale=0; numLocale<localeResources.size(); numLocale++) {
135
                        // try to get the translation for any of the languagues in the preferred languages list
136
                        String translation = ((Properties)localeResources.get(numLocale)).getProperty(key);
137
                        if (translation!=null && !translation.equals("")) {
138
                                return translation;
139
                        }
140
                }
141
                logger.warn(callerName+ " -- Cannot find translation for "+key);
142
                return key;
143
        }
144

    
145
        public static String getText(String key,  String[] arguments, String callerName) {
146
                String translation = getText(key, callerName);
147
                if (translation!=null && arguments!=null ) {
148
                        try {
149
                                translation = MessageFormat.format(translation, arguments);
150
                        }
151
                        catch (IllegalFormatException ex) {
152
                                logger.error(callerName+" -- Error formating key: "+key+" -- "+translation);
153
                        }
154
                }
155
                return translation;
156
        }
157
        
158
        public static String translate(String message, String[] args) {
159
                String msg = message;
160
                if (msg == null) {
161
                        return "";
162
                }
163
                msg = getText(msg, args);
164
                if (msg == null) {
165
                        msg = "_" + message.replace("_", " ");
166
                }
167
                return msg;
168
        }
169

    
170
        public static String translate(String message) {
171
                String msg = message;
172
                if (msg == null) {
173
                        return "";
174
                }
175
                msg = getText(msg, (String[]) null);
176
                if (msg == null) {
177
                        msg = "_" + message.replace("_", " ");
178
                }
179
                return msg;
180
        }
181

    
182
        /**
183
         * <p>Gets the localized message associated with the provided key.
184
         * If the key is not in the dictionary or the translation is empty,
185
         * return the key and register the failure in the log.</p>
186
         *
187
         * @param key     An String which identifies the translation that we want to get.
188
         * @return        an String with the message associated with the provided key.
189
         *                If the key is not in the dictionary or the translation is empty,
190
         *                return the key. If the key is null, return null.
191
         */
192
        public static String getText(String key) {
193
                return getText(key, _CLASSNAME);
194
        }
195

    
196
        public static String getText(String key, String[] arguments) {
197
                return getText(key, arguments, _CLASSNAME);
198
        }
199

    
200
        
201
        /**
202
         * <p>Gets the localized message associated with the provided key.
203
         * If the key is not in the dictionary or the translation is empty,
204
         * it returns null and the failure is only registered in the log if
205
         * the param log is true.</p>
206
         *
207
         * @param key        An String which identifies the translation that we want
208
         *                                 to get.
209
         * @param log        Determines whether log a key failure or not
210
         * @return                an String with the message associated with the provided key,
211
         *                                 or null if the key is not in the dictionary or the
212
         *                                 translation is empty.
213
         */
214
        public static String getText(String key, boolean log) {
215
                return getText(key, _CLASSNAME, log);
216
        }
217

    
218
        public static String getText(String key, String[] arguments, boolean log) {
219
                String translation = getText(key, _CLASSNAME, log);
220
                if (translation!=null && arguments!=null ) {
221
                        try {
222
                                translation = MessageFormat.format(translation, arguments);
223
                        } catch (IllegalFormatException ex) {
224
                                if (log) {
225
                                        logger.error(_CLASSNAME+" -- Error formating key: "+key+" -- "+translation);
226
                                }
227
                        }
228
                }
229
                return translation;
230
        }
231

    
232
        /**
233
         * <p>Gets the localized message associated with the provided key.
234
         * If the key is not in the dictionary, it returns null and the failure
235
         * is only registered in the log if the param log is true.</p>
236
         *
237
         * @param key         An String which identifies the translation that we want to get.
238
         * @param callerName  A symbolic name given to the caller of this method, to
239
         *                    show it in the log if the key was not found
240
         * @param log         Determines whether log a key failure or not
241
         * @return            an String with the message associated with the provided key,
242
         *                    or null if the key is not in the dictionary.
243
         */
244
        public static String getText(String key, String callerName, boolean log) {
245
                if (key==null) {
246
                        return null;
247
                }
248
                for (int numLocale=0; numLocale<localeResources.size(); numLocale++) {
249
                        // try to get the translation for any of the languagues in the preferred languages list
250
                        String translation = ((Properties)localeResources.get(numLocale)).getProperty(key);
251
                        if (translation!=null && !translation.equals("")) {
252
                                return translation;
253
                        }
254
                }
255
                if (log) {
256
                        logger.warn(callerName+" -- Cannot find translation for "+key);
257
                }
258
                return null;
259
        }
260

    
261
        public static String getText(String key, String[] arguments, String callerName, boolean log) {
262
                String translation = getText(key, callerName, log);
263
                if (translation!=null) {
264
                        try {
265
                                translation = MessageFormat.format(translation, arguments);
266
                        }
267
                        catch (IllegalFormatException ex) {
268
                                if (log) {
269
                                        logger.error(callerName+" -- Error formating key: "+key+" -- "+translation);
270
                                }
271
                        }
272
                }
273
                return translation;
274
        }
275

    
276
        /**
277
         * <p>Adds an additional family of resource files containing some translations.
278
         * A family is a group of files with a common baseName.
279
         * The file must be an iso-8859-1 encoded file, which can contain any unicode
280
         * character using unicode escaped sequences, and following the syntax:
281
         * <code>key1=value1
282
         * key2=value2</code>
283
         * where 'key1' is the key used to identify the string and must not
284
         * contain the '=' symbol, and 'value1' is the associated translation.</p>
285
         * <p<For example:</p>
286
         * <code>cancel=Cancelar
287
         * accept=Aceptar</code>
288
         * <p>Only one pair key-value is allowed per line.</p>
289
         *
290
         * <p>The actual name of the resource file to load is determined using the rules
291
         * explained in the class java.util.ResourceBundle. Summarizing, for each language
292
         * in the specified preferred locales list it will try to load a file with
293
         *  the following structure: <code>family_locale.properties</code></p>
294
         *
295
         * <p>For example, if the preferred locales list contains {"fr", "es", "en"}, and
296
         * the family name is "text", it will try to load the files "text_fr.properties",
297
         * "text_es.properties" and finally "text_en.properties".</p>
298
         *
299
         * <p>Locales might be more specific, such us "es_AR"  (meaning Spanish from Argentina)
300
         * or "es_AR_linux" (meaning Linux system preferring Spanish from Argentina). In the
301
         * later case, it will try to load "text_es_AR_linux.properties", then
302
         * "text_es_AR.properties" if the former fails, and finally "text_es.properties".</p>
303
         *
304
         * <p>The directory used to locate the resource file is determining by using the
305
         * getResource method from the provided ClassLoader.</p>
306
         *
307
         * @param family    The family name (or base name) which is used to search
308
         *                  actual properties files.
309
         * @param loader    A ClassLoader which is able to find a property file matching
310
         *                                         the specified family name and the preferred locales
311
         * @see             <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
312
         */
313
        public static void addResourceFamily(String family, ClassLoader loader) {
314
                addResourceFamily(family, loader, "");
315
        }
316

    
317
        /**
318
         * <p>Adds an additional family of resource files containing some translations.
319
         * The search path to locate the files is provided by the dirList parameter.</p>
320
         *
321
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
322
         * format of the property files and the way to determine the candidat files
323
         * to load. Note that those methods are different in the way to locate the
324
         * candidat files. This method searches in the provided paths (<code>dirList</code>
325
         * parameter), while the referred method searches using the getResource method
326
         * of the provided ClassLoader.</p>
327
         *
328
         * @param family    The family name (or base name) which is used to search
329
         *                  actual properties files.
330
         * @param dirList   A list of search paths to locate the property files
331
         * @throws MalformedURLException
332
         * @see             <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
333
         */
334
        public static void addResourceFamily(String family, File[] dirList) throws MalformedURLException{
335
                // use our own classloader
336
                URL[] urls = new URL[dirList.length];
337

    
338
                        int i;
339
                        for (i=0; i<urls.length; i++) {
340
                                urls[i] = dirList[i].toURL();
341
                        }
342

    
343
                ClassLoader loader = new MessagesClassLoader(urls);
344
                addResourceFamily(family, loader, "");
345
        }
346

    
347
        /**
348
         * <p>Adds an additional family of resource files containing some translations.
349
         * The search path to locate the files is provided by the dir parameter.</p>
350
         *
351
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
352
         * format of the property files and the way to determine the candidat files
353
         * to load. Note that those methods are different in the way to locate the
354
         * candidat files. This method searches in the provided path (<code>dir</code>
355
         * parameter), while the referred method searches using the getResource method
356
         * of the provided ClassLoader.</p>
357
         *
358
         * @param family    The family name (or base name) which is used to search
359
         *                  actual properties files.
360
         * @param dir       The search path to locate the property files
361
         * @throws MalformedURLException
362
         * @see             <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
363
         */
364
        public static void addResourceFamily(String family, File dir) throws MalformedURLException{
365
                // use our own classloader
366
                URL[] urls = new URL[1];
367
                urls[0] = dir.toURL();
368
                ClassLoader loader = new MessagesClassLoader(urls);
369
                addResourceFamily(family, loader, "");
370
        }
371

    
372

    
373
        /**
374
         * <p>Adds an additional family of resource files containing some translations.
375
         * The search path is determined by the getResource method from the
376
         * provided ClassLoader.</p>
377
         *
378
         * <p>This method is identical to {@link addResourceFamily(String, ClassLoader)},
379
         * except that it adds a <pode>callerName</code> parameter to show in the log.</p>
380
         *
381
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
382
         * format of the property files andthe way to determine the candidat files
383
         * to load.</p>
384
         *
385
         * @param family      The family name (or base name) which is used to search
386
         *                    actual properties files.
387
         * @param loader      A ClassLoader which is able to find a property file matching
388
         *                                           the specified family name and the preferred locales
389
         * @param callerName  A symbolic name given to the caller of this method, to
390
         *                    show it in the log if there is an error
391
         * @see               <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
392
         */
393
        public static void addResourceFamily(String family, ClassLoader loader, String callerName) {
394
                String currentKey;
395
                Enumeration keys;
396
                Locale lang;
397
                Properties properties, translations;
398
                int totalLocales = preferredLocales.size();
399

    
400
                if (totalLocales == 0) {
401
                        // if it's empty, warn about that
402
                        logger.warn("There is not preferred languages list. Maybe the Messages class was not initialized");
403
                }
404

    
405
                resourceFamilies.add(family);
406
                classLoaders.add(loader);
407

    
408
                for (int numLocale=0; numLocale<totalLocales; numLocale++) { // for each language
409
                        properties =  new Properties();
410

    
411
                        lang = (Locale) preferredLocales.get(numLocale);
412
                        translations = (Properties) localeResources.get(numLocale);
413

    
414
                        addResourceFamily(lang, translations, family, loader, callerName);
415
                }
416
        }
417

    
418
        private static void addResourceFamily(Locale lang, Properties translations,
419
                        String family, ClassLoader loader, String callerName) {
420
                Properties properties = new Properties();
421
                String resource = family.replace('.', '/') + "_" + lang.toString()
422
                                + ".properties";
423
                InputStream is = loader.getResourceAsStream(resource);
424
                if (is != null) {
425
                        try {
426
                                properties.load(is);
427
                        } catch (IOException e) {
428
                        }
429
                } else if (lang.equals(baseLocale)) {
430
                        // try also "text.properties" for the base language
431
                        is = loader.getResourceAsStream(family.replace('.', '/')
432
                                        + ".properties");
433

    
434

    
435
                        if (is != null) {
436
                                try {
437
                                        properties.load(is);
438
                                } catch (IOException e) {
439
                                }
440
                        }
441

    
442
                }
443
                Enumeration keys = properties.keys();
444
                while (keys.hasMoreElements()) {
445
                        String currentKey = (String) keys.nextElement();
446
                        if (!translations.containsKey(currentKey)) {
447
                                translations
448
                                                .put(currentKey, properties.getProperty(currentKey));
449
                        }
450
                }
451

    
452
        }
453

    
454
        /**
455
         * <p>Adds an additional family of resource files containing some translations.</p>
456
         *
457
         * <p>This method is identical to {@link addResourceFamily(String, ClassLoader, String)},
458
         * except that it uses the caller's class loader.</p>
459
         *
460
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
461
         * format of the property files and the way to determine the candidat files
462
         * to load.</p>
463
         *
464
         * @param family      The family name (or base name) which is used to search
465
         *                    actual properties files.
466
         * @param callerName  A symbolic name given to the caller of this method, to
467
         *                    show it in the log if there is an error. This is only used
468
         *                    to show
469
         *                    something meaningful in the log, so you can use any string
470
         * @see               <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
471
         */
472
        public static void addResourceFamily(String family, String callerName) {
473
                addResourceFamily(family, Messages.class.getClassLoader(), callerName);
474
        }
475

    
476

    
477
        /**
478
         * Returns an ArrayList containing the ordered list of prefered Locales
479
         * Each element of the ArrayList is a Locale object.
480
         *
481
         * @return an ArrayList containing the ordered list of prefered Locales
482
         * Each element of the ArrayList is a Locale object.
483
         */
484
        public static ArrayList getPreferredLocales() {
485
                return preferredLocales;
486
        }
487

    
488
        /**
489
         * <p>Sets the ordered list of preferred locales.
490
         * Each element of the ArrayList is a Locale object.</p>
491
         *
492
         * <p>Note that calling this method does not load any translation, it just
493
         * adds the language to the preferred locales list, so this method must
494
         * be always called before the translations are loaded using
495
         * the addResourceFamily() methods.</p>
496
         *
497
         * <p>It there was any language in the preferred locale list, the language
498
         * and its associated translations are deleted.</p>
499
         *
500
         *
501
         * @param preferredLocales an ArrayList containing Locale objects.
502
         * The ArrayList represents an ordered list of preferred locales
503
         */
504
        public static void setPreferredLocales(ArrayList preferredLocalesList) {
505
                // delete all existing locales
506
                Iterator oldLocales = preferredLocales.iterator();
507
                while (oldLocales.hasNext()) {
508
                        removeLocale((Locale) oldLocales.next());
509
                }
510

    
511
                // add the new locales now
512
                for (int numLocale=0; numLocale < preferredLocalesList.size(); numLocale++) {
513
                        addLocale((Locale) preferredLocalesList.get(numLocale));
514
                }
515
        }
516

    
517
        /**
518
         * Adds a Locale at the end of the ordered list of preferred locales.
519
         * Note that calling this method does not load any translation, it just
520
         * adds the language to the preferred locales list, so this method must
521
         * be always called before the translations are loaded using
522
         * the addResourceFamily() methods.
523
         *
524
         * @param lang   A Locale object specifying the locale to add
525
         */
526
        public static void addLocale(Locale lang) {
527
                if (!preferredLocales.contains(lang)) { // avoid duplicates
528
                                preferredLocales.add(lang); // add the lang to the ordered list of preferred locales
529
                                Properties dict = new Properties();
530
                                localeResources.add(dict); // add a hashmap which will contain the translation for this language
531
                }
532
        }
533

    
534
        /**
535
         * Removes the specified Locale from the list of preferred locales and the
536
         * translations associated with this locale.
537
         *
538
         * @param lang   A Locale object specifying the locale to remove
539
         * @return       True if the locale was in the preferred locales list, false otherwise
540
         */
541
        public static boolean removeLocale(Locale lang) {
542
                int numLocale = preferredLocales.indexOf(lang);
543
                if (numLocale!=-1) { // we found the locale in the list
544
                        try {
545
                                preferredLocales.remove(numLocale);
546
                                localeResources.remove(numLocale);
547
                        }
548
                        catch (IndexOutOfBoundsException ex) {
549
                                logger.warn(_CLASSNAME + "." + "removeLocale: " + ex.getLocalizedMessage());
550
                        }
551
                        return true;
552
                }
553
                return false;
554
        }
555

    
556
        /**
557
         * Cleans the translation tables (removes all the translations from memory).
558
         */
559
        public static void removeResources() {
560
                for (int numLocale=0; numLocale<localeResources.size(); numLocale++) {
561
                        ((Properties)localeResources.get(numLocale)).clear();
562
                }
563
        }
564

    
565
        /**
566
         * The number of translation keys which have been loaded till now
567
         * (In other words: the number of available translation strings).
568
         *
569
         * @param lang The language for which we want to know the number of translation keys
570
         * return The number of translation keys for the provided language.
571
         */
572
        protected static int size(Locale lang) {
573
                int numLocale = preferredLocales.indexOf(lang);
574
                if (numLocale!=-1) {
575
                        return ((Properties)localeResources.get(numLocale)).size();
576
                };
577
                return 0;
578
        }
579

    
580
        protected static Set keySet(Locale lang) {
581
                int numLocale = preferredLocales.indexOf(lang);
582
                if (numLocale!=-1) {
583
                        return ((Properties)localeResources.get(numLocale)).keySet();
584
                } else {
585
                        return null;
586
                }
587
        }
588

    
589
        /**
590
         * Checks if some locale has been added to the preferred locales
591
         * list, which is necessary before loading any translation because
592
         * only the translations for the preferred locales are loaded.
593
         *
594
         * @return
595
         */
596
        public static boolean hasLocales() {
597
                return preferredLocales.size()>0;
598
        }
599

    
600
        /**
601
         * Gets the base language, the language considered the origin of
602
         * translations, which will be (possibly) stored in a property
603
         * file without language suffix
604
         * (ie: text.properties instead of text_es.properties).
605
         */
606
        public static String getBaseLanguage() {
607
                return baseLanguage;
608
        }
609

    
610
        /**
611
         * Sets the base language, the language considered the origin of
612
         * translations, which will be (possibly)
613
         * stored in a property file without language suffix
614
         * (ie: text.properties instead of text_es.properties).
615
         *
616
         * @param lang The base language to be set
617
         */
618
        public static void setBaseLanguage(String lang) {
619
                baseLanguage = lang;
620
                baseLocale = new Locale(baseLanguage);
621
        }
622

    
623
        /*
624
         * Searches the subdirectories of the provided directory, finding
625
         * all the translation files, and constructing a list of available translations.
626
         * It reports different country codes or variants, if available.
627
         * For example, if there is an en_US translation and an en_GB translation, both
628
         * locales will be present in the Vector.
629
         *
630
         * @return
631
         */
632

    
633
        /**
634
         *
635
         * @return A Vector containing the available locales. Each element is a Locale object
636
         */
637
        /*public static Vector getAvailableLocales() {
638
                return _availableLocales;
639
        }*/
640

    
641
        /**
642
         *
643
         * @return A Vector containing the available languages. Each element is an String object
644
         */
645
        /*public static Vector getAvailableLanguages() {
646
                Vector availableLanguages = new Vector();
647
                Locale lang;
648
                Enumeration locales = _availableLocales.elements();
649
                while (locales.hasMoreElements()) {
650
                        lang = (Locale) locales.nextElement();
651
                        availableLanguages.add(lang.getLanguage());
652
                }
653
                return availableLanguages;
654
        }*/
655

    
656
        public static Properties getAllTexts(Locale lang) {
657
                Properties texts = new Properties();
658
                getAllTexts(lang, null, texts);
659
                for (Iterator iterator = classLoaders.iterator(); iterator.hasNext();) {
660
                        getAllTexts(lang, (ClassLoader) iterator.next(), texts);
661
                }
662
                return texts;
663
        }
664

    
665
        private static void getAllTexts(Locale lang, ClassLoader classLoader,
666
                        Properties texts) {
667
                ClassLoader loader = classLoader == null ? Messages.class
668
                                .getClassLoader() : classLoader;
669

    
670
                for (Iterator iterator = resourceFamilies.iterator(); iterator
671
                                .hasNext();) {
672
                        String family = (String) iterator.next();
673
                        addResourceFamily(lang, texts, family, loader,
674
                                        "Messages.getAllTexts");
675
                }
676
        }
677

    
678
}