Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / extensions / extI18n / src / main / java / org / gvsig / i18n / impl / I18nManagerImpl.java @ 30489

History | View | Annotate | Download (23.3 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Gobernment (CIT)
5
 * 
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 * 
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
19
 * MA  02110-1301, USA.
20
 * 
21
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {DiSiD Technologies}  {New extension for installation and update of text translations}
26
 */
27
package org.gvsig.i18n.impl;
28

    
29
import java.io.BufferedReader;
30
import java.io.BufferedWriter;
31
import java.io.File;
32
import java.io.FileOutputStream;
33
import java.io.FileWriter;
34
import java.io.IOException;
35
import java.io.InputStream;
36
import java.io.InputStreamReader;
37
import java.io.OutputStreamWriter;
38
import java.io.PrintStream;
39
import java.security.AccessController;
40
import java.security.PrivilegedAction;
41
import java.util.ArrayList;
42
import java.util.HashMap;
43
import java.util.HashSet;
44
import java.util.Iterator;
45
import java.util.List;
46
import java.util.Locale;
47
import java.util.Map;
48
import java.util.Set;
49
import java.util.StringTokenizer;
50
import java.util.Map.Entry;
51
import java.util.zip.ZipEntry;
52
import java.util.zip.ZipFile;
53
import java.util.zip.ZipOutputStream;
54

    
55
import org.gvsig.andami.Launcher;
56
import org.gvsig.andami.PluginServices;
57
import org.gvsig.andami.config.generate.AndamiConfig;
58
import org.gvsig.i18n.I18nException;
59
import org.gvsig.i18n.I18nManager;
60
import org.gvsig.i18n.Messages;
61
import org.gvsig.utils.StringUtilities;
62
import org.gvsig.utils.XMLEntity;
63

    
64

    
65
/**
66
 * Implementation of the I18nManager interface.
67
 * 
68
 * @author <a href="mailto:dcervera@disid.com">David Cervera</a>
69
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
70
 */
71
public class I18nManagerImpl implements I18nManager {
72

    
73
        private static final String LOCALES_FILE_NAME = "locales.csv";
74

    
75
        private static final String CSV_SEPARATOR = ",";
76

    
77
        private static final String I18N_EXTENSION = "org.gvsig.i18n.extension";
78

    
79
        private static final String VARIANT = "variant";
80

    
81
        private static final String COUNTRY = "country";
82

    
83
        private static final String LANGUAGE = "language";
84

    
85
        private static final String REGISTERED_LOCALES_PERSISTENCE = "RegisteredLocales";
86

    
87
        private static final I18nManager DEFAULT = new I18nManagerImpl();
88

    
89
        private Set registeredLocales;
90

    
91
        /**
92
         * The list of default reference locales. The last one will be used to get
93
         * all the keys when translating to a new locale.
94
         */
95
        private Locale[] referenceLocales = new Locale[] { ENGLISH, SPANISH };
96

    
97
        private Locale[] defaultLocales = new Locale[] {
98
                        // Default supported locales
99
                        SPANISH, // Spanish
100
                        ENGLISH, // English
101
                        new Locale("en","US"), // English US
102
                        new Locale("ca"), // Catalan
103
                        new Locale("gl"), // Galician
104
                        new Locale("eu"), // Basque
105
                        new Locale("de"), // German
106
                        new Locale("cs"), // Czech
107
                        new Locale("fr"), // French
108
                        new Locale("it"), // Italian
109
                        new Locale("pl"), // Polish
110
                        new Locale("pt"), // Portuguese
111
                        new Locale("pt", "BR"), // Portuguese Brazil
112
                        new Locale("ro"), // Romanian
113
                        new Locale("zh"), // Chinese
114
                        new Locale("ru"), // Russian
115
                        new Locale("el"), // Greek
116
                        new Locale("ro"), // Romanian
117
                        new Locale("pl"), // Polish
118
                        new Locale("tr"), // Turkish
119
                        new Locale("sr"), // Serbio
120
                        new Locale("sw") // Swahili
121
        };
122

    
123

    
124
        /**
125
         * Returns the unique instance of the I18nManager.
126
         * 
127
         * @return the unique instance
128
         */
129
        public static I18nManager getInstance() {
130
                return DEFAULT;
131
        }
132

    
133
        public static String capitalize(String text) {
134
                // Convert the first letter to uppercase
135
                String capitalLetter = new String(new char[] { Character
136
                                .toUpperCase(text.charAt(0)) });
137
                return capitalLetter.concat(text.substring(1));
138
        }
139

    
140
        /**
141
         * Empty constructor.
142
         */
143
        I18nManagerImpl() {
144
        }
145

    
146
        public Locale[] getInstalledLocales() {
147
                if (registeredLocales == null) {
148

    
149
                        XMLEntity child = getRegisteredLocalesPersistence();
150

    
151
                        // If the list of registered locales is not already persisted,
152
                        // this should be the first time gvSIG is run with the I18nPlugin
153
                        // so we will take the list of default locales
154
                        if (child == null) {
155
                                Locale[] defaultLocales = getDefaultLocales();
156
                                registeredLocales = new HashSet(defaultLocales.length);
157
                                for (int i = 0; i < defaultLocales.length; i++) {
158
                                        registeredLocales.add(defaultLocales[i]);
159
                                }
160
                                storeInstalledLocales();
161
                        } else {
162
                                XMLEntity localesEntity = getRegisteredLocalesPersistence();
163
                                registeredLocales = new HashSet(localesEntity
164
                                                .getChildrenCount());
165
                                for (int i = 0; i < localesEntity.getChildrenCount(); i++) {
166
                                        XMLEntity localeEntity = localesEntity.getChild(i);
167
                                        String language = localeEntity.getStringProperty(LANGUAGE);
168
                                        String country = localeEntity.getStringProperty(COUNTRY);
169
                                        String variant = localeEntity.getStringProperty(VARIANT);
170
                                        Locale locale = new Locale(language, country, variant);
171
                                        registeredLocales.add(locale);
172
                                }
173
                        }
174
                }
175

    
176
                return (Locale[]) registeredLocales
177
                                .toArray(new Locale[registeredLocales.size()]);
178
        }
179

    
180
        public void uninstallLocale(Locale locale) throws I18nException {
181
                if (getCurrentLocale().equals(locale) || isReferenceLocale(locale)) {
182
                        throw new UninstallLocaleException(locale);
183
                }
184

    
185
                if (registeredLocales.remove(locale)) {
186
                        // Remove from the configured locale list
187
                        storeInstalledLocales();
188

    
189
                        // Remove the resource bundle file
190
                        File bundleFile = new File(getResourcesFolder(),
191
                                        getResourceFileName(locale));
192

    
193
                        if (bundleFile.exists()) {
194
                                bundleFile.delete();
195
                        }
196
                }
197
        }
198

    
199
        public String getDisplayName(Locale locale) {
200
                return getDisplayName(locale, locale);
201
        }
202

    
203
        public String getDisplayName(Locale locale, Locale displayLocale) {
204
                StringBuffer name = new StringBuffer(getLanguageDisplayName(locale,
205
                                displayLocale));
206

    
207
                if (!isEmpty(locale.getCountry())) {
208
                        name.append(" - ");
209
                        name.append(locale.getDisplayCountry(displayLocale));
210
                }
211

    
212
                if (!isEmpty(locale.getVariant())) {
213
                        name.append(" - ");
214
                        name.append(locale.getDisplayVariant(displayLocale));
215
                }
216

    
217
                name.append(" (").append(locale.toString()).append(")");
218

    
219
                return name.toString();
220
        }
221

    
222
        private boolean isEmpty(String text) {
223
                return text == null || text.trim().length() == 0;
224
        }
225

    
226
        public String getLanguageDisplayName(Locale locale) {
227
                return getLanguageDisplayName(locale, locale);
228
        }
229

    
230
        public String getLanguageDisplayName(Locale locale, Locale displayLocale) {
231

    
232
                String displayName;
233

    
234
                // Correction for the Basque language display name,
235
                // show it in Basque, not in Spanish
236
                if ("eu".equals(locale.getLanguage())
237
                                && "vascuence".equals(locale.getDisplayLanguage())) {
238
                        displayName = "Euskera";
239
                }
240
                // Patch for Valencian/Catalan
241
                else if ("ca".equals(locale.getLanguage())) {
242
                        // displayName = Messages.getText("__valenciano");
243
                        // if ("__valenciano".equals(displayName)) {
244
                        // displayName = Messages.getText("__catalan");
245
                        // }
246
                        displayName = "Valenci?";
247
                } else {
248
                        displayName = locale.getDisplayLanguage(displayLocale);
249
                }
250

    
251
                return capitalize(displayName);
252
        }
253

    
254
        public Locale getCurrentLocale() {
255
                return Locale.getDefault();
256
        }
257

    
258
        public Locale getDefaultSystemLocale() {
259
                String language, region, country, variant;
260
                language = getSystemProperty("user.language", "en");
261
                // for compatibility, check for old user.region property
262
                region = getSystemProperty("user.region", null);
263

    
264
                if (region != null) {
265
                        // region can be of form country, country_variant, or _variant
266
                        int i = region.indexOf('_');
267
                        if (i >= 0) {
268
                                country = region.substring(0, i);
269
                                variant = region.substring(i + 1);
270
                        } else {
271
                                country = region;
272
                                variant = "";
273
                        }
274
                } else {
275
                        country = getSystemProperty("user.country", "");
276
                        variant = getSystemProperty("user.variant", "");
277
                }
278
                return new Locale(language, country, variant);
279
        }
280

    
281
        public void setCurrentLocale(Locale locale) {
282
                AndamiConfig config = Launcher.getAndamiConfig();
283
                config.setLocaleLanguage(locale.getLanguage());
284
                config.setLocaleCountry(locale.getCountry());
285
                config.setLocaleVariant(locale.getVariant());
286
        }
287

    
288
        public Locale[] installLocales(File importFile) throws I18nException {
289
                List importLocales = new ArrayList();
290

    
291
                try {
292
                        ZipFile zipFile = new ZipFile(importFile);
293

    
294
                        Map locales = getZipFileNonReferenceLocales(zipFile);
295

    
296
                        if (locales == null || locales.size() == 0) {
297
                                return null;
298
                        }
299

    
300
                        for (Iterator iterator = locales.entrySet().iterator(); iterator
301
                                        .hasNext();) {
302
                                Entry entry = (Entry) iterator.next();
303

    
304
                                String fileName = (String) entry.getKey();
305
                                Locale locale = (Locale) entry.getValue();
306
                                importLocales.add(locale);
307

    
308
                                // Add the locale to the list of installed ones, if it
309
                                // is new, otherwise, update the texts.
310
                                if (!registeredLocales.contains(locale)) {
311
                                        registeredLocales.add(locale);
312
                                        storeInstalledLocales();
313
                                }
314

    
315
                                // Replace the old bundle with the new one
316
                                ZipEntry zipEntry = zipFile.getEntry(fileName);
317
                                InputStream is = zipFile.getInputStream(zipEntry);
318
                                BufferedReader reader = new BufferedReader(
319
                                                new InputStreamReader(is));
320

    
321
                                File bundleFile = getResourceFile(locale);
322
                                FileWriter fileWriter = new FileWriter(bundleFile);
323
                                BufferedWriter writer = new BufferedWriter(fileWriter);
324

    
325
                                String line;
326
                                while ((line = reader.readLine()) != null) {
327
                                        writer.write(line);
328
                                        writer.write('\n');
329
                                }
330
                                writer.flush();
331
                                writer.close();
332
                                fileWriter.close();
333
                                reader.close();
334
                                is.close();
335
                        }
336

    
337
                } catch (Exception ex) {
338
                        throw new InstallLocalesException(importFile, ex);
339
                }
340

    
341
                return (Locale[]) importLocales
342
                                .toArray(new Locale[importLocales.size()]);
343
        }
344

    
345
        public void exportLocaleForUpdate(Locale locale, Locale referenceLocale,
346
                        File exportFile) throws I18nException {
347

    
348
                exportLocalesForUpdate(new Locale[] { locale }, referenceLocale,
349
                                exportFile);
350
        }
351

    
352
        public void exportLocalesForUpdate(Locale[] locales,
353
                        Locale referenceLocale, File exportFile) throws I18nException {
354

    
355
                exportLocale(locales, new Locale[] { referenceLocale }, exportFile,
356
                                true);
357
        }
358

    
359
        public void exportLocaleForTranslation(Locale locale,
360
                        Locale referenceLocale, File exportFile) throws I18nException {
361

    
362
                exportLocaleForTranslation(locale, new Locale[] { referenceLocale },
363
                                exportFile);
364
        }
365

    
366
        public void exportLocaleForTranslation(Locale locale,
367
                        Locale[] referenceLocales, File exportFile) throws I18nException {
368

    
369
                exportLocale(new Locale[] { locale }, referenceLocales, exportFile,
370
                                false);
371
        }
372

    
373
        public Locale[] getReferenceLocales() {
374
                return referenceLocales;
375
        }
376

    
377
        public void setReferenceLocales(Locale[] referenceLocales) {
378
                this.referenceLocales = referenceLocales;
379
        }
380

    
381
        public void setDefaultLocales(Locale[] defaultLocales) {
382
                this.defaultLocales = defaultLocales;
383
        }
384

    
385
        private void exportLocale(Locale[] locales, Locale[] referenceLocales,
386
                        File exportFile, boolean update) throws I18nException {
387

    
388
                Locale[] refArray = getReferenceLocalesToExport(locales,
389
                                referenceLocales);
390

    
391
                try {
392
                        FileOutputStream fos = new FileOutputStream(exportFile);
393
                        ZipOutputStream zipos = new ZipOutputStream(fos);
394

    
395
                        // Create the index file
396
                        writeZipFileLocales(zipos, locales, refArray);
397

    
398
                        PrintStream ps = new PrintStream(zipos);
399
                        Map texts = null;
400

    
401
                        if (update) {
402
                                // First, export the locales to update
403
                                if (locales != null) {
404
                                        for (int i = 0; i < locales.length; i++) {
405
                                                texts = getAllTexts(locales[i]);
406
                                                putResourceInZip(zipos, ps, texts,
407
                                                                getResourceFileName(locales[i]));
408
                                        }
409
                                }
410
                        } else { // translate
411
                                // First, export the locales to translate, taking the keys from
412
                                // the reference locales, but without values
413
                                // We will use the keys of the reference locales
414
                                texts = getAllTexts(referenceLocales[0]);
415
                                if (locales != null) {
416
                                        for (int i = 0; i < locales.length; i++) {
417
                                                putResourceInZip(zipos, ps, texts,
418
                                                                getResourceFileName(locales[i]), false);
419
                                        }
420
                                }
421
                        }
422

    
423
                        // Next, export the reference locales
424
                        if (refArray != null) {
425
                                for (int i = 0; i < refArray.length; i++) {
426
                                        texts = getAllTexts(refArray[i]);
427
                                        putResourceInZip(zipos, ps, texts,
428
                                                        getResourceFileName(refArray[i]));
429
                                }
430
                        }
431

    
432
                        ps.flush();
433
                        ps.close();
434
                        zipos.close();
435
                        fos.close();
436
                } catch (IOException ex) {
437
                        throw new ExportLocaleException(locales, ex);
438
                }
439
        }
440

    
441
        /**
442
         * Returns the list of reference locales to export, as the union of the
443
         * default reference locales list and the one selected as reference. The
444
         * locales to translate or update are extracted from the list.
445
         */
446
        private Locale[] getReferenceLocalesToExport(Locale[] locales,
447
                        Locale[] referenceLocalesSelected) {
448
                // The reference locales to export are the default ones plus the
449
                // selected by the user.
450
                Set exportRefLocales = new HashSet(referenceLocales.length);
451
                for (int i = 0; i < referenceLocales.length; i++) {
452
                        exportRefLocales.add(referenceLocales[i]);
453
                }
454
                if (referenceLocalesSelected != null) {
455
                        for (int i = 0; i < referenceLocalesSelected.length; i++) {
456
                                exportRefLocales.add(referenceLocalesSelected[i]);
457
                        }
458
                }
459
                if (locales != null) {
460
                        for (int i = 0; i < locales.length; i++) {
461
                                exportRefLocales.remove(locales[i]);
462
                        }
463
                }
464
                Locale[] refArray = (Locale[]) exportRefLocales
465
                                .toArray(new Locale[exportRefLocales.size()]);
466
                return refArray;
467
        }
468

    
469
        /**
470
         * Returns all the localized texts and its keys for a locale.
471
         */
472
        private Map getAllTexts(Locale locale) {
473
                return Messages.getAllTexts(locale);
474
        }
475

    
476
        private Map getZipFileNonReferenceLocales(ZipFile zipFile)
477
                        throws I18nException {
478
                ZipEntry zipEntry = zipFile.getEntry(LOCALES_FILE_NAME);
479

    
480
                if (zipEntry == null) {
481
                        return null;
482
                }
483

    
484
                Map locales;
485
                try {
486
                        InputStream is = zipFile.getInputStream(zipEntry);
487
                        BufferedReader reader = new BufferedReader(
488
                                        new InputStreamReader(is));
489

    
490
                        locales = new HashMap(2);
491
                        String line;
492
                        while ((line = reader.readLine()) != null) {
493
                                // The excepted format is:
494
                                // FILENAME,LANGUAGE,COUNTRY,VARIANT,IS_REFERENCE
495
                                StringTokenizer st = new StringTokenizer(line, CSV_SEPARATOR,
496
                                                true);
497
                                // First: locale file name (required)
498
                                String fileName = st.nextToken();
499
                                if (CSV_SEPARATOR.equals(fileName)) {
500
                                        throw new LocaleFileNameRequiredException(line);
501
                                } else {
502
                                        // Read the next separator
503
                                        st.nextToken();
504
                                }
505
                                // Second: the locale language (required)
506
                                String language = st.nextToken();
507
                                if (CSV_SEPARATOR.equals(language)) {
508
                                        throw new LocaleLanguageRequiredException(line);
509
                                } else {
510
                                        // Read the next separator
511
                                        st.nextToken();
512
                                }
513
                                // Third: the country
514
                                String country = st.nextToken();
515
                                if (CSV_SEPARATOR.equals(country)) {
516
                                        country = null;
517
                                } else {
518
                                        // Read the next separator
519
                                        st.nextToken();
520
                                }
521
                                // Fourth: the variant
522
                                String variant = st.nextToken();
523
                                if (CSV_SEPARATOR.equals(variant)) {
524
                                        variant = null;
525
                                } else {
526
                                        // Read the next separator
527
                                        st.nextToken();
528
                                }
529
                                // Fifth: is a reference locale?
530
                                String refStr = st.nextToken();
531
                                if (CSV_SEPARATOR.equals(refStr)) {
532
                                        refStr = null;
533
                                }
534

    
535
                                // Only add non reference locales
536
                                if (refStr != null && !"true".equals(refStr.toLowerCase())) {
537
                                        // Variant only accepted if country defined
538
                                        if (country == null) {
539
                                                variant = null;
540
                                        }
541
                                        country = country == null ? "" : country;
542
                                        variant = variant == null ? "" : variant;
543
                                        Locale locale = new Locale(language, country, variant);
544

    
545
                                        locales.put(fileName, locale);
546
                                }
547
                        }
548

    
549
                        reader.close();
550
                        is.close();
551
                } catch (IOException ex) {
552
                        throw new ReadCSVLocalesFileException(ex);
553
                }
554

    
555
                return locales;
556
        }
557

    
558
        private void writeZipFileLocales(ZipOutputStream zos, Locale[] locales,
559
                        Locale[] referenceLocales) throws IOException {
560
                ZipEntry zipEntry = new ZipEntry(LOCALES_FILE_NAME);
561

    
562
                zos.putNextEntry(zipEntry);
563
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos));
564

    
565
                if (locales != null) {
566
                        for (int i = 0; i < locales.length; i++) {
567
                                writeLocaleEntry(locales[i], writer, false);
568
                        }
569
                }
570
                if (referenceLocales != null) {
571
                        for (int i = 0; i < referenceLocales.length; i++) {
572
                                writeLocaleEntry(referenceLocales[i], writer, true);
573
                        }
574
                }
575

    
576
                writer.flush();
577
                zos.closeEntry();
578
        }
579

    
580
        /**
581
         * Writes the locale entry into a writer.
582
         * 
583
         * @param locale
584
         *            the locale to create the entry for
585
         * @param writer
586
         *            to write to
587
         * @param reference
588
         *            is it is a reference locale or not
589
         * @throws IOException
590
         *             if there is an error creating the locale entry
591
         */
592
        private void writeLocaleEntry(Locale locale, BufferedWriter writer,
593
                        boolean reference) throws IOException {
594
                String language = locale.getLanguage();
595
                String country = locale.getCountry();
596
                country = country == null ? "" : country;
597
                String variant = locale.getVariant();
598
                variant = variant == null ? "" : variant;
599

    
600
                writer.write(getResourceFileName(locale));
601
                writer.write(',');
602
                writer.write(language);
603
                writer.write(',');
604
                writer.write(country);
605
                writer.write(',');
606
                writer.write(variant);
607
                writer.write(',');
608
                writer.write(Boolean.toString(reference));
609
                writer.write('\n');
610
        }
611

    
612
        /**
613
         * Returns if a locale is one of the default reference ones.
614
         */
615
        private boolean isReferenceLocale(Locale locale) {
616
                for (int i = 0; i < referenceLocales.length; i++) {
617
                        if (referenceLocales[i].equals(locale)) {
618
                                return true;
619
                        }
620
                }
621
                return false;
622
        }
623

    
624
        /**
625
         * Puts a new resource file into a Jar file.
626
         */
627
        private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
628
                        Map texts, String resourceFileName) throws IOException {
629

    
630
                putResourceInZip(zipos, ps, texts, resourceFileName, true);
631
        }
632

    
633
        /**
634
         * Puts a new resource file into a Jar file.
635
         */
636
        private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
637
                        Map texts, String resourceFileName, boolean withValue)
638
                        throws IOException {
639
                // Add ZIP entry for the resource bundle file
640
                zipos.putNextEntry(new ZipEntry(resourceFileName));
641

    
642
                for (Iterator iterator = texts.entrySet().iterator(); iterator
643
                                .hasNext();) {
644
                        Entry entry = (Entry) iterator.next();
645
                        String keyEncoded = escape((String) entry.getKey(), true);
646
                        ps.print(keyEncoded);
647
                        ps.print("=");
648
                        if (withValue) {
649
                                String valueEncoded = escape((String) entry.getValue(), false);
650
                                ps.println(valueEncoded);
651
                        } else {
652
                                ps.println();
653
                        }
654
                }
655

    
656
                ps.flush();
657

    
658
                // Close the ZIP entry, the file is complete
659
                zipos.closeEntry();
660
        }
661

    
662
        /**
663
         * Returns the file which contains the translations for a locale.
664
         */
665
        private File getResourceFile(Locale locale) {
666
                return new File(getResourcesFolder(), getResourceFileName(locale));
667
        }
668

    
669
        /**
670
         * Returns the name of the file which contains the translations for a
671
         * locale.
672
         */
673
        private String getResourceFileName(Locale locale) {
674
                StringBuffer fileName = new StringBuffer("text");
675

    
676
                // Spanish without country is the default locale
677
                if (!(isEmpty(locale.getCountry()) && "es".equals(locale.getLanguage()))) {
678
                        fileName.append('_').append(locale.getLanguage());
679
                }
680

    
681
                // Add the locale country
682
                if (!isEmpty(locale.getCountry())) {
683
                        fileName.append('_').append(locale.getCountry());
684
                }
685

    
686
                // Add the locale variant
687
                if (!isEmpty(locale.getVariant())) {
688
                        fileName.append('_').append(locale.getVariant());
689
                }
690

    
691
                fileName.append(".properties");
692
                return fileName.toString();
693
        }
694

    
695
        /**
696
         * Returns the folder where to store the resource bundle files.
697
         */
698
        private File getResourcesFolder() {
699
                return PluginServices.getPluginServices("com.iver.cit.gvsig")
700
                                .getPluginDirectory();
701
        }
702

    
703
        /**
704
         * Returns the child XMLEntity with the RegisteredLocales.
705
         */
706
        private XMLEntity getRegisteredLocalesPersistence() {
707
                XMLEntity entity = getI18nPersistence();
708
                XMLEntity child = null;
709
                for (int i = entity.getChildrenCount() - 1; i >= 0; i--) {
710
                        XMLEntity tmpchild = entity.getChild(i);
711
                        if (tmpchild.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
712
                                child = tmpchild;
713
                                break;
714
                        }
715
                }
716
                return child;
717
        }
718

    
719
        /**
720
         * Returns the I18n Plugin persistence.
721
         */
722
        private XMLEntity getI18nPersistence() {
723
                XMLEntity entity = PluginServices.getPluginServices(I18N_EXTENSION)
724
                                .getPersistentXML();
725
                return entity;
726
        }
727

    
728
        /**
729
         * Returns the list of default locales bundled with gvSIG.
730
         */
731
        private Locale[] getDefaultLocales() {
732
                return defaultLocales;
733
        }
734

    
735
        /**
736
         * Stores the list of installed locales into the plugin persistence.
737
         */
738
        private void storeInstalledLocales() {
739
                XMLEntity localesEntity = getRegisteredLocalesPersistence();
740

    
741
                // Remove the previous list of registered languages
742
                if (localesEntity != null) {
743
                        XMLEntity i18nPersistence = getI18nPersistence();
744
                        for (int i = i18nPersistence.getChildrenCount() - 1; i >= 0; i--) {
745
                                XMLEntity child = i18nPersistence.getChild(i);
746
                                if (child.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
747
                                        i18nPersistence.removeChild(i);
748
                                        break;
749
                                }
750
                        }
751
                }
752

    
753
                // Create the new persistence for the registered languages
754
                localesEntity = new XMLEntity();
755

    
756
                localesEntity.setName(REGISTERED_LOCALES_PERSISTENCE);
757

    
758
                for (Iterator iterator = registeredLocales.iterator(); iterator
759
                                .hasNext();) {
760
                        Locale locale = (Locale) iterator.next();
761
                        XMLEntity localeEntity = new XMLEntity();
762
                        localeEntity.setName(locale.getDisplayName());
763
                        localeEntity.putProperty(LANGUAGE, locale.getLanguage());
764
                        localeEntity.putProperty(COUNTRY, locale.getCountry());
765
                        localeEntity.putProperty(VARIANT, locale.getVariant());
766

    
767
                        localesEntity.addChild(localeEntity);
768
                }
769

    
770
                getI18nPersistence().addChild(localesEntity);
771
        }
772

    
773
        private String escape(String value, boolean replaceBlanks) {
774
                // First replace non printable characters
775
                if (replaceBlanks) {
776
                        value = StringUtilities.replace(value, " ", "\\ ");
777
                }
778
                value = StringUtilities.replace(value, ":", "\\:");
779
                value = StringUtilities.replace(value, "\n", "\\n");
780
                value = StringUtilities.replace(value, "\t", "\\t");
781
                value = StringUtilities.replace(value, "\b", "\\b");
782
                value = StringUtilities.replace(value, "\f", "\\f");
783
                value = StringUtilities.replace(value, "\r", "\\r");
784
                // value = StringUtilities.replace(value, "\\", "\\\\");
785
                // value = StringUtilities.replace(value, "\'", "\\\'");
786
                // value = StringUtilities.replace(value, "\"", "\\\"");
787

    
788
                // Next, encode in raw-unicode-escape
789
                return toRawUnicodeEncoded(value);
790
        }
791

    
792
        private String toRawUnicodeEncoded(String value) {
793
                StringBuffer sb = new StringBuffer();
794
                for (int i = 0; i < value.length(); i++) {
795
                        char c = value.charAt(i);
796
                        if (c <= 0x80) {
797
                                sb.append(c);
798
                        } else {
799
                                sb.append("\\u");
800
                                String hexValue = Integer.toHexString((int) c);
801
                                // Append 0 if the hex value has less than 4 digits
802
                                for (int j = hexValue.length(); j < 4; j++) {
803
                                        sb.append('0');
804
                                }
805
                                sb.append(hexValue);
806
                        }
807
                }
808
                return sb.toString();
809
        }
810
        
811
        @SuppressWarnings("unchecked")
812
        private String getSystemProperty(final String property, String defaultValue) {
813
                String value = (String) AccessController
814
                .doPrivileged(new PrivilegedAction() {
815
                        public Object run() {
816
                                return System.getProperty(property);
817
                        }
818
                });                
819
                return value == null ? defaultValue : value;
820
        }
821
}