Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1011 / libraries / libInternationalization / src / org / gvsig / i18n / Messages.java @ 12904

History | View | Annotate | Download (24.1 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
*
3
* Copyright (C) 2006 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.net.MalformedURLException;
46
import java.net.URL;
47
import java.net.URLClassLoader;
48
import java.util.ArrayList;
49
import java.util.Enumeration;
50
import java.util.HashMap;
51
import java.util.Iterator;
52
import java.util.List;
53
import java.util.Locale;
54
import java.util.MissingResourceException;
55
import java.util.ResourceBundle;
56
import java.util.StringTokenizer;
57

    
58
import org.apache.log4j.Logger;
59

    
60
/**
61
 * <p>This class offers some methods to provide internationalization services
62
 * to other projects. All the methods are static.</p>
63
 * 
64
 * <p>The most useful method is {@link #getText(String) getText(key)} (and family),
65
 * which returns the translation associated
66
 * with the provided key. The class must be initialized before getText can be
67
 * used.</p>
68
 * 
69
 * <p>The typical usage sequence would be:</p>
70
 * <ul>
71
 * <li>Add some locale to the prefered locales list: <code>Messages.addLocale(new Locale("es"))</code></li>
72
 * <li>Add some resource file containing translations: <code>Messages.addResourceFamily("text", new File("."))</code></li>
73
 * <li>And finaly getText can be used: <code>Messages.getText("aceptar")</code></li>
74
 * </ul>
75
 * 
76
 * <p>The resource files are Java properties files, which contain <code>key=translation</code>
77
 * pairs, one
78
 * pair per line. These files must be encoded using iso-8859-1 encoding, and unicode escaped
79
 * sequences must be used to include characters outside the former encoding.
80
 * There are several ways to specify the property file to load, see the different
81
 * addResourceFamily methods for details.</p> 
82
 * 
83
 * @author Cesar Martinez Izquierdo (cesar.martinez@iver.es)
84
 *
85
 */
86
public class Messages {
87
    private static Logger logger = Logger.getLogger("Messages");
88
    private static String _CLASSNAME = "org.gvsig.i18n.Messages";
89
    private static int _INITIALSIZE = 3700; // I try to set an initial capacity similar to the amount of strings in gvSIG
90
    
91
    /* Each entry will contain a hashmap with translations. Each hasmap
92
     * contains the translations for one language, indexed by the
93
     * translation key. The translations for language (i) in the preferred locales
94
     * list are contained in the position (i) of the localeResources list */
95
    private static ArrayList localeResources = new ArrayList(); 
96
        private static ArrayList preferredLocales = new ArrayList(); // contains the ordered list of prefered languages/locales (class Locale)
97
        
98
        /**
99
         * <p>Gets the localized message associated with the provided key.
100
         * If the key is not in the dictionary, return the key and register
101
         * the failure in the log.</p>
102
         * 
103
         * <p>The <code>callerName</code> parameter is only
104
         * used as a label when logging, so any String can be used. However, a
105
         * meaningful String should be used, such as the name of the class requiring
106
         * the translation services, in order to identify the source of the failure
107
         * in the log.</p>    
108
         * 
109
         * @param key         An String which identifies the translation that we want to get. 
110
         * @param callerName  A symbolic name given to the caller of this method, to
111
         *                    show it in the log if the key was not found
112
         * @return            an String with the message associated with the provided key.
113
         *                    If the key is not in the dictionary, return the key. If the key
114
         *                    is null, return null.
115
         */
116
        public static String getText(String key, String callerName) {
117
                if (key==null) return null;
118
                for (int numLocale=0; numLocale<localeResources.size(); numLocale++) {
119
                        // try to get the translation for any of the languagues in the preferred languages list
120
                        String translation = (String) ((HashMap)localeResources.get(numLocale)).get(key);
121
                        if (translation!=null && !translation.equals(""))
122
                                return translation;
123
                }
124
                logger.warn(callerName+ " -- " +Messages.getText("No_se_encontro_la_traduccion_para", _CLASSNAME ,false)+" "+key);
125
                return key;
126
        }
127
        
128
        /**
129
         * <p>Gets the localized message associated with the provided key.
130
         * If the key is not in the dictionary or the translation is empty,
131
         * return the key and register the failure in the log.</p>
132
         * 
133
         * @param key     An String which identifies the translation that we want to get.
134
         * @return        an String with the message associated with the provided key.
135
         *                If the key is not in the dictionary or the translation is empty,
136
         *                return the key. If the key is null, return null.
137
         */
138
        public static String getText(String key) {
139
                return getText(key, _CLASSNAME);
140
        }
141
        
142
        /**
143
         * <p>Gets the localized message associated with the provided key.
144
         * If the key is not in the dictionary or the translation is empty,
145
         * it returns null and the failure is only registered in the log if
146
         * the param log is true.</p>
147
         * 
148
         * @param key        An String which identifies the translation that we want
149
         *                                 to get.
150
         * @param log        Determines whether log a key failure or not
151
         * @return                an String with the message associated with the provided key,
152
         *                                 or null if the key is not in the dictionary or the
153
         *                                 translation is empty.
154
         */
155
        public static String getText(String key, boolean log) {
156
                return getText(key, _CLASSNAME, log);
157
        }
158
        
159
        /**
160
         * <p>Gets the localized message associated with the provided key.
161
         * If the key is not in the dictionary, it returns null and the failure
162
         * is only registered in the log if the param log is true.</p>
163
         * 
164
         * @param key         An String which identifies the translation that we want to get.
165
         * @param callerName  A symbolic name given to the caller of this method, to
166
         *                    show it in the log if the key was not found
167
         * @param log         Determines whether log a key failure or not
168
         * @return            an String with the message associated with the provided key,
169
         *                    or null if the key is not in the dictionary.
170
         */
171
        public static String getText(String key, String callerName, boolean log) {
172
                if (key==null) return null;
173
                for (int numLocale=0; numLocale<localeResources.size(); numLocale++) {
174
                        // try to get the translation for any of the languagues in the preferred languages list
175
                        String translation = (String) ((HashMap)localeResources.get(numLocale)).get(key);
176
                        if (translation!=null && !translation.equals(""))
177
                                return translation;
178
                }
179
                if (log) {
180
                        logger.warn(callerName+" -- "+Messages.getText("No_se_encontro_la_traduccion_para", _CLASSNAME ,false)+" "+key);
181
                }
182
                return null;
183
        }
184

    
185
        /**
186
         * <p>Adds an additional family of resource files containing some translations.
187
         * A family is a group of files with a common baseName.
188
         * The file must be an iso-8859-1 encoded file, which can contain any unicode
189
         * character using unicode escaped sequences, and following the syntax:
190
         * <code>key1=value1
191
         * key2=value2</code>
192
         * where 'key1' is the key used to identify the string and must not
193
         * contain the '=' symbol, and 'value1' is the associated translation.</p>
194
         * <p<For example:</p>
195
         * <code>cancel=Cancelar
196
         * accept=Aceptar</code>
197
         * <p>Only one pair key-value is allowed per line.</p>
198
         * 
199
         * <p>The actual name of the resource file to load is determined using the rules
200
         * explained in the class java.util.ResourceBundle. Summarizing, for each language
201
         * in the specified preferred locales list it will try to load a file with
202
         *  the following structure: <code>family_locale.properties</code></p>
203
         *
204
         * <p>For example, if the preferred locales list contains {"fr", "es", "en"}, and
205
         * the family name is "text", it will try to load the files "text_fr.properties",
206
         * "text_es.properties" and finally "text_en.properties".</p>
207
         * 
208
         * <p>Locales might be more specific, such us "es_AR"  (meaning Spanish from Argentina)
209
         * or "es_AR_linux" (meaning Linux system preferring Spanish from Argentina). In the
210
         * later case, it will try to load "text_es_AR_linux.properties", then
211
         * "text_es_AR.properties" if the former fails, and finally "text_es.properties".</p>
212
         * 
213
         * <p>The directory used to locate the resource file is determining by using the
214
         * getResource method from the provided ClassLoader.</p>
215
         *  
216
         * @param family    The family name (or base name) which is used to search
217
         *                  actual properties files.
218
         * @param loader    A ClassLoader which is able to find a property file matching
219
         *                                         the specified family name and the preferred locales
220
         * @see             <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
221
         */
222
        public static void addResourceFamily(String family, ClassLoader loader) {
223
                addResourceFamily(family, loader, "");
224
        }
225
        
226
        /**
227
         * <p>Adds an additional family of resource files containing some translations.
228
         * The search path to locate the files is provided by the dirList parameter.</p>
229
         * 
230
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
231
         * format of the property files and the way to determine the candidat files
232
         * to load. Note that those methods are different in the way to locate the 
233
         * candidat files. This method searches in the provided paths (<code>dirList</code>
234
         * parameter), while the referred method searches using the getResource method
235
         * of the provided ClassLoader.</p>
236
         *  
237
         * @param family    The family name (or base name) which is used to search
238
         *                  actual properties files.
239
         * @param dirList   A list of search paths to locate the property files
240
         * @throws MalformedURLException
241
         * @see             <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
242
         */
243
        public static void addResourceFamily(String family, File[] dirList) throws MalformedURLException{
244
                // use our own classloader
245
                URL[] urls = new URL[dirList.length];                
246
        
247
                        int i;
248
                        for (i=0; i<urls.length; i++) {
249
                                urls[i] = dirList[i].toURL();
250
                        }
251
        
252
                ClassLoader loader = new MessagesClassLoader(urls);
253
                addResourceFamily(family, loader, "");
254
        }
255

    
256
        /**
257
         * <p>Adds an additional family of resource files containing some translations.
258
         * The search path to locate the files is provided by the dir parameter.</p>
259
         * 
260
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
261
         * format of the property files and the way to determine the candidat files
262
         * to load. Note that those methods are different in the way to locate the 
263
         * candidat files. This method searches in the provided path (<code>dir</code>
264
         * parameter), while the referred method searches using the getResource method
265
         * of the provided ClassLoader.</p>
266
         *  
267
         * @param family    The family name (or base name) which is used to search
268
         *                  actual properties files.
269
         * @param dir       The search path to locate the property files
270
         * @throws MalformedURLException
271
         * @see             <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
272
         */
273
        public static void addResourceFamily(String family, File dir) throws MalformedURLException{
274
                // use our own classloader
275
                URL[] urls = new URL[1];                
276
                urls[0] = dir.toURL();
277
                ClassLoader loader = new MessagesClassLoader(urls);
278
                addResourceFamily(family, loader, "");
279
        }
280

    
281

    
282
        /**
283
         * <p>Adds an additional family of resource files containing some translations.
284
         * The search path is determined by the getResource method from the
285
         * provided ClassLoader.</p>
286
         * 
287
         * <p>This method is identical to {@link addResourceFamily(String, ClassLoader)},
288
         * except that it adds a <pode>callerName</code> parameter to show in the log.</p>
289
         * 
290
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
291
         * format of the property files andthe way to determine the candidat files
292
         * to load.</p>
293
         *  
294
         * @param family      The family name (or base name) which is used to search
295
         *                    actual properties files.
296
         * @param loader      A ClassLoader which is able to find a property file matching
297
         *                                           the specified family name and the preferred locales
298
         * @param callerName  A symbolic name given to the caller of this method, to
299
         *                    show it in the log if there is an error
300
         * @see               <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
301
         */
302
        public static void addResourceFamily(String family, ClassLoader loader, String callerName) {
303
                String currentKey;
304
                Enumeration properties;
305
                Locale defaultLocale = Locale.getDefault();
306
                int totalLocales = preferredLocales.size();
307

    
308
                if (totalLocales == 0) {
309
                        // if it's empty, warn about that
310
                        logger.warn(Messages.getText("No_hay_lista_de_idiomas_preferidos_quiza_olvido_inicializar_clase", _CLASSNAME, false));
311
                }
312
                Locale lang;                
313
                ResourceBundle bundle = null;
314
                
315
                for (int numLocale=0; numLocale<totalLocales; numLocale++) { // for each language
316
                        lang = (Locale) preferredLocales.get(numLocale);
317
                        try {
318
                                /**
319
                                 * Here we are doing a pervert use of getBundle method. Normally, it is call it in in this way:
320
                                 * getBundle("text", "en", loader), in order to get the file 'text_en.properties'. However, in
321
                                 * this way the default file ('text.properties') is also loaded, and we want to avoid this
322
                                 * (because 'text.properties contains the Spanish translation).
323
                                 * So we use the method in this non-standard way:
324
                                 * getBundle("text_en", "en", loader), ensuring that we are just loading the file 'text_en.properties'
325
                                 **/
326
                                if (!lang.getLanguage().equals("es"))
327
                                        bundle = ResourceBundle.getBundle(family+"_"+lang.getLanguage(), lang, loader);
328
                                else { // we allow 'text.properties' to be loaded for Spanish
329
                                         if (Locale.getDefault().equals(lang)) {
330
                                                 bundle = ResourceBundle.getBundle(family, lang, loader);                                                 
331
                                         }
332
                                         else {
333
                                                // we need to temporarily change the default locale to properly load spanish in corner cases
334
                                                 Locale.setDefault(lang);
335
                                                 bundle = ResourceBundle.getBundle(family, lang, loader);
336
                                                 Locale.setDefault(defaultLocale);
337
                                         }                                        
338
                                }
339

    
340
                                properties = bundle.getKeys();
341
                                while (properties.hasMoreElements()) {
342
                                        currentKey = (String) properties.nextElement();
343
                                        if (! ((HashMap)localeResources.get(numLocale)).containsKey(currentKey)) {
344
                                                ((HashMap)localeResources.get(numLocale)).put(currentKey, bundle.getString(currentKey));
345
                                        }
346
                                }
347
                        }
348
                        catch (MissingResourceException ex) {
349
                                Locale.setDefault(defaultLocale);
350
                                logger.warn(Messages.getText("Las_traducciones_no_pudieron_ser_cargadas", false)+" -- "+callerName+" -- "+lang.getLanguage());
351
                        }
352
                }
353
        }
354
        
355
        /**
356
         * <p>Adds an additional family of resource files containing some translations.</p>
357
         * 
358
         * <p>This method is identical to {@link addResourceFamily(String, ClassLoader, String)},
359
         * except that it uses the caller's class loader.</p>
360
         * 
361
         * <p>See {@link addResourceFamily(String, ClassLoader)} for a discussion about the
362
         * format of the property files and the way to determine the candidat files
363
         * to load.</p>
364
         *  
365
         * @param family      The family name (or base name) which is used to search
366
         *                    actual properties files.
367
         * @param callerName  A symbolic name given to the caller of this method, to
368
         *                    show it in the log if there is an error. This is only used
369
         *                    to show
370
         *                    something meaningful in the log, so you can use any string
371
         * @see               <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
372
         */
373
        public static void addResourceFamily(String family, String callerName) {
374
                String currentKey;
375
                Enumeration properties;
376
                Locale defaultLocale = Locale.getDefault();
377
                int totalLocales = preferredLocales.size();
378

    
379
                if (totalLocales == 0) {
380
                        // if it's empty, warn about that
381
                        logger.warn(Messages.getText("No_hay_lista_de_idiomas_preferidos_quiza_olvido_inicializar_clase", _CLASSNAME, false));
382
                }
383
                Locale lang;                
384
                ResourceBundle bundle = null;
385
                
386
                for (int numLocale=0; numLocale<totalLocales; numLocale++) { // for each language
387
                        try {
388
                                lang = (Locale) preferredLocales.get(numLocale);
389
                                if (!lang.getLanguage().equals("es"))         // ensure we don't get a fallback
390
                                        bundle = ResourceBundle.getBundle(family+"_"+lang.getLanguage(), lang);
391
                                else { // we allow 'text.properties' to be loaded for Spanish
392
                                         if (Locale.getDefault().equals(lang)) {
393
                                                 bundle = ResourceBundle.getBundle(family, lang);                                                 
394
                                         }
395
                                         else {
396
                                                // we need to temporarily change the default locale to properly load spanish in corner cases
397
                                                 Locale.setDefault(lang);
398
                                                 bundle = ResourceBundle.getBundle(family, lang);
399
                                                 Locale.setDefault(defaultLocale);
400
                                         }                                        
401
                                }
402
        
403
                                properties = bundle.getKeys();
404
                                while (properties.hasMoreElements()) {
405
                                        currentKey = (String) properties.nextElement();
406
                                        if (! ((HashMap)localeResources.get(numLocale)).containsKey(currentKey)) {
407
                                                ((HashMap)localeResources.get(numLocale)).put(currentKey, bundle.getString(currentKey));
408
                                        }
409
                                }
410
                        }
411
                        catch (MissingResourceException ex) {
412
                                Locale.setDefault(defaultLocale);
413
                                logger.warn(callerName+" " + ex.getLocalizedMessage());
414
                        }
415
                }
416
        }
417
        
418
        private static void addResourceFamily(String family, Locale lang, HashMap dict) {
419
                String currentKey;
420
                Enumeration properties;
421

    
422
                ResourceBundle bundle = null;
423
                Locale defaultLocale = Locale.getDefault();
424

    
425
                try {
426
                        if (!lang.getLanguage().equals("es")) // ensure we don't get a fallback
427
                                bundle = ResourceBundle.getBundle(family+"_"+lang.getLanguage(), lang);
428
                        else { // we allow 'text.properties' to be loaded for Spanish
429
                                 if (Locale.getDefault().equals(lang)) {
430
                                         bundle = ResourceBundle.getBundle(family, lang);                                                 
431
                                 }
432
                                 else {
433
                                        // we need to temporarily change the default locale to properly load spanish in corner cases
434
                                         Locale.setDefault(lang);
435
                                         bundle = ResourceBundle.getBundle(family, lang);
436
                                         Locale.setDefault(defaultLocale);
437
                                 }                                        
438
                        }
439
                        properties = bundle.getKeys();
440
                        while (properties.hasMoreElements()) {
441
                                currentKey = (String) properties.nextElement();
442
                                if (! dict.containsKey(currentKey)) {
443
                                        dict.put(currentKey, bundle.getString(currentKey));
444
                                }
445
                        }
446
                }
447
                catch (MissingResourceException ex) {
448
                        Locale.setDefault(defaultLocale);
449
                        logger.warn(Messages.class.getName()+" " + ex.getLocalizedMessage());
450
                }
451
        }
452

    
453
        
454
        /**
455
         * Returns an ArrayList containing the ordered list of prefered Locales
456
         * Each element of the ArrayList is a Locale object.
457
         * 
458
         * @return an ArrayList containing the ordered list of prefered Locales
459
         * Each element of the ArrayList is a Locale object.
460
         */
461
        public static ArrayList getPreferredLocales() {
462
                return preferredLocales;
463
        }
464
        
465
        /**
466
         * <p>Sets the ordered list of preferred locales.
467
         * Each element of the ArrayList is a Locale object.</p>
468
         * 
469
         * <p>Note that calling this method does not load any translation, it just
470
         * adds the language to the preferred locales list, so this method must
471
         * be always called before the translations are loaded using
472
         * the addResourceFamily() methods.</p>
473
         * 
474
         * <p>It there was any language in the preferred locale list, the language
475
         * and its associated translations are deleted.</p>
476
         * 
477
         * 
478
         * @param preferredLocales an ArrayList containing Locale objects.
479
         * The ArrayList represents an ordered list of preferred locales
480
         */
481
        public static void setPreferredLocales(ArrayList preferredLocalesList) {
482
                // delete all existing locales
483
                Iterator oldLocales = preferredLocales.iterator();
484
                while (oldLocales.hasNext()) {
485
                        removeLocale((Locale) oldLocales.next());
486
                }
487
                
488
                // add the new locales now
489
                for (int numLocale=0; numLocale < preferredLocalesList.size(); numLocale++) {
490
                        addLocale((Locale) preferredLocalesList.get(numLocale));
491
                }
492
        }
493

    
494
        /**
495
         * Adds a Locale at the end of the ordered list of preferred locales.
496
         * Note that calling this method does not load any translation, it just
497
         * adds the language to the preferred locales list, so this method must
498
         * be always called before the translations are loaded using
499
         * the addResourceFamily() methods.
500
         * 
501
         * @param lang   A Locale object specifying the locale to add
502
         */
503
        public static void addLocale(Locale lang) {
504
                if (!preferredLocales.contains(lang)) { // avoid duplicates
505
                                preferredLocales.add(lang); // add the lang to the ordered list of preferred locales
506
                                HashMap dict = new HashMap(_INITIALSIZE);
507
                                localeResources.add(dict); // add a hashmap which will contain the translation for this language
508
                                addResourceFamily("org.gvsig.i18n.resources.translations.text", lang, dict);
509
                }
510
        }
511

    
512
        /**
513
         * Removes the specified Locale from the list of preferred locales and the
514
         * translations associated with this locale.
515
         * 
516
         * @param lang   A Locale object specifying the locale to remove
517
         * @return       True if the locale was in the preferred locales list, false otherwise
518
         */
519
        public static boolean removeLocale(Locale lang) {
520
                int numLocale = preferredLocales.indexOf(lang);
521
                if (numLocale!=-1) { // we found the locale in the list
522
                        try {
523
                                preferredLocales.remove(numLocale);
524
                                localeResources.remove(numLocale);
525
                        }
526
                        catch (IndexOutOfBoundsException ex) {
527
                                logger.warn(_CLASSNAME + "." + "removeLocale: " + ex.getLocalizedMessage());
528
                        }
529
                        return true;
530
                }
531
                return false;
532
        }
533

    
534
        /**
535
         * Cleans the translation tables (removes all the translations from memory).
536
         */
537
        public static void removeResources() {
538
                for (int numLocale=0; numLocale<localeResources.size(); numLocale++) {
539
                        ((HashMap)localeResources.get(numLocale)).clear();
540
                }
541
        }
542

    
543
        /**
544
         * The number of translation keys which have been loaded till now  
545
         * (In other words: the number of available translation strings).
546
         * 
547
         * @param lang The language for which we want to know the number of translation keys
548
         * return The number of translation keys for the provided language.
549
         */
550
        protected static int size(Locale lang) {
551
                int numLocale = preferredLocales.indexOf(lang);
552
                if (numLocale!=-1) {
553
                        return ((HashMap)localeResources.get(numLocale)).size();
554
                };
555
                return 0;
556
        }
557
        
558
        /**
559
         * Checks if some locale has been added to the preferred locales
560
         * list, which is necessary before loading any translation because
561
         * only the translations for the preferred locales are loaded.
562
         * 
563
         * @return
564
         */
565
        public static boolean hasLocales() {
566
                return preferredLocales.size()>0;
567
        }
568
        
569
        /**
570
         * Searches the subdirectories of the provided directory, finding
571
         * all the translation files, and constructing a list of available translations.
572
         * It reports different country codes or variants, if available.
573
         * For example, if there is an en_US translation and an en_GB translation, both
574
         * locales will be present in the Vector.
575
         * 
576
         * @return
577
         */
578
        
579
        /**
580
         * 
581
         * @return A Vector containing the available locales. Each element is a Locale object
582
         */
583
        /*public static Vector getAvailableLocales() {
584
                return _availableLocales;
585
        }*/
586
        
587
        /**
588
         * 
589
         * @return A Vector containing the available languages. Each element is an String object
590
         */
591
        /*public static Vector getAvailableLanguages() {
592
                Vector availableLanguages = new Vector();
593
                Locale lang;
594
                Enumeration locales = _availableLocales.elements();
595
                while (locales.hasMoreElements()) {
596
                        lang = (Locale) locales.nextElement();
597
                        availableLanguages.add(lang.getLanguage());
598
                }
599
                return availableLanguages;
600
        }*/
601
}