Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extI18n / src / org / gvsig / i18n / impl / I18nManagerImpl.java @ 28781

History | View | Annotate | Download (22.7 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.*;
30
import java.security.AccessController;
31
import java.util.*;
32
import java.util.Map.Entry;
33
import java.util.zip.*;
34

    
35
import org.gvsig.i18n.*;
36

    
37
import sun.security.action.GetPropertyAction;
38

    
39
import com.iver.andami.Launcher;
40
import com.iver.andami.PluginServices;
41
import com.iver.andami.config.generate.AndamiConfig;
42
import com.iver.utiles.StringUtilities;
43
import com.iver.utiles.XMLEntity;
44

    
45
/**
46
 * Implementation of the I18nManager interface.
47
 * 
48
 * @author <a href="mailto:dcervera@disid.com">David Cervera</a>
49
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
50
 */
51
public class I18nManagerImpl implements I18nManager {
52

    
53
    private static final String LOCALES_FILE_NAME = "locales.csv";
54

    
55
    private static final String CSV_SEPARATOR = ",";
56

    
57
    private static final String I18N_EXTENSION = "org.gvsig.i18n";
58

    
59
    private static final String VARIANT = "variant";
60

    
61
    private static final String COUNTRY = "country";
62

    
63
    private static final String LANGUAGE = "language";
64

    
65
    private static final String REGISTERED_LOCALES_PERSISTENCE = "RegisteredLocales";
66

    
67
    private static final I18nManager DEFAULT = new I18nManagerImpl();
68

    
69
    private Set registeredLocales;
70

    
71
    /**
72
     * The list of default reference locales. The last one will be used to get
73
     * all the keys when translating to a new locale.
74
     */
75
    private Locale[] referenceLocales = new Locale[] { ENGLISH, SPANISH };
76

    
77
    private Locale[] defaultLocales = new Locale[] {
78
    // Default supported locales
79
            new Locale("ca"), // Catalan
80
            new Locale("cs"), // Czech
81
            new Locale("de"), // German
82
            ENGLISH, // English
83
            SPANISH, // Spanish
84
            new Locale("eu"), // Basque
85
            new Locale("fr"), // French
86
            new Locale("gl"), // Galician
87
            new Locale("it"), // Italian
88
            new Locale("pl"), // Polish
89
            new Locale("pt"), // Portuguese
90
            new Locale("ro"), // Romanian
91
            new Locale("zh"), // Chinese
92
            new Locale("ru"), // Russian
93
            new Locale("el"), // Greek
94
            new Locale("ro"), // Romanian
95
            new Locale("pl"), // Polish
96
    };
97

    
98
    /**
99
     * Returns the unique instance of the I18nManager.
100
     * 
101
     * @return the unique instance
102
     */
103
    public static I18nManager getInstance() {
104
        return DEFAULT;
105
    }
106

    
107
    public static String capitalize(String text) {
108
        // Convert the first letter to uppercase
109
        String capitalLetter = new String(new char[] { Character
110
                .toUpperCase(text.charAt(0)) });
111
        return capitalLetter.concat(text.substring(1));
112
    }
113

    
114
    /**
115
     * Empty constructor.
116
     */
117
    I18nManagerImpl() {
118
    }
119

    
120
    public Locale[] getInstalledLocales() {
121
        if (registeredLocales == null) {
122

    
123
            XMLEntity child = getRegisteredLocalesPersistence();
124

    
125
            // If the list of registered locales is not already persisted,
126
            // this should be the first time gvSIG is run with the I18nPlugin
127
            // so we will take the list of default locales
128
            if (child == null) {
129
                Locale[] defaultLocales = getDefaultLocales();
130
                registeredLocales = new HashSet(defaultLocales.length);
131
                for (int i = 0; i < defaultLocales.length; i++) {
132
                    registeredLocales.add(defaultLocales[i]);
133
                }
134
                storeInstalledLocales();
135
            } else {
136
                XMLEntity localesEntity = getRegisteredLocalesPersistence();
137
                registeredLocales = new HashSet(localesEntity
138
                        .getChildrenCount());
139
                for (int i = 0; i < localesEntity.getChildrenCount(); i++) {
140
                    XMLEntity localeEntity = localesEntity.getChild(i);
141
                    String language = localeEntity.getStringProperty(LANGUAGE);
142
                    String country = localeEntity.getStringProperty(COUNTRY);
143
                    String variant = localeEntity.getStringProperty(VARIANT);
144
                    Locale locale = new Locale(language, country, variant);
145
                    registeredLocales.add(locale);
146
                }
147
            }
148
        }
149

    
150
        return (Locale[]) registeredLocales
151
                .toArray(new Locale[registeredLocales.size()]);
152
    }
153

    
154
    public void uninstallLocale(Locale locale) throws I18nException {
155
        if (getCurrentLocale().equals(locale) || isReferenceLocale(locale)) {
156
            throw new UninstallLocaleException(locale);
157
        }
158

    
159
        if (registeredLocales.remove(locale)) {
160
            // Remove from the configured locale list
161
            storeInstalledLocales();
162

    
163
            // Remove the resource bundle file
164
            File bundleFile = new File(getResourcesFolder(),
165
                    getResourceFileName(locale));
166

    
167
            if (bundleFile.exists()) {
168
                bundleFile.delete();
169
            }
170
        }
171
    }
172

    
173
    public String getDisplayName(Locale locale) {
174
        return getDisplayName(locale, locale);
175
    }
176

    
177
    public String getDisplayName(Locale locale, Locale displayLocale) {
178
        StringBuffer name = new StringBuffer(getLanguageDisplayName(locale,
179
                displayLocale));
180

    
181
        if (!isEmpty(locale.getCountry())) {
182
            name.append(" - ");
183
            name.append(locale.getDisplayCountry(displayLocale));
184
        }
185

    
186
        if (!isEmpty(locale.getVariant())) {
187
            name.append(" - ");
188
            name.append(locale.getDisplayVariant(displayLocale));
189
        }
190

    
191
        name.append(" (").append(locale.toString()).append(")");
192

    
193
        return name.toString();
194
    }
195

    
196
    private boolean isEmpty(String text) {
197
        return text == null || text.trim().length() == 0;
198
    }
199

    
200
    public String getLanguageDisplayName(Locale locale) {
201
        return getLanguageDisplayName(locale, locale);
202
    }
203

    
204
    public String getLanguageDisplayName(Locale locale, Locale displayLocale) {
205

    
206
        String displayName;
207

    
208
        // Correction for the Basque language display name,
209
        // show it in Basque, not in Spanish
210
        if ("eu".equals(locale.getLanguage())
211
                && "vascuence".equals(locale.getDisplayLanguage())) {
212
            displayName = "Euskera";
213
        }
214
        // Patch for Valencian/Catalan
215
        else if ("ca".equals(locale.getLanguage())) {
216
            // displayName = Messages.getText("__valenciano");
217
            // if ("__valenciano".equals(displayName)) {
218
            // displayName = Messages.getText("__catalan");
219
            // }
220
            displayName = "Valenci?";
221
        } else {
222
            displayName = locale.getDisplayLanguage(displayLocale);
223
        }
224

    
225
        return capitalize(displayName);
226
    }
227

    
228
    public Locale getCurrentLocale() {
229
        return Locale.getDefault();
230
    }
231

    
232
    public Locale getDefaultSystemLocale() {
233
        String language, region, country, variant;
234
        language = (String) AccessController
235
                .doPrivileged(new GetPropertyAction("user.language", "en"));
236
        // for compatibility, check for old user.region property
237
        region = (String) AccessController.doPrivileged(new GetPropertyAction(
238
                "user.region"));
239
        if (region != null) {
240
            // region can be of form country, country_variant, or _variant
241
            int i = region.indexOf('_');
242
            if (i >= 0) {
243
                country = region.substring(0, i);
244
                variant = region.substring(i + 1);
245
            } else {
246
                country = region;
247
                variant = "";
248
            }
249
        } else {
250
            country = (String) AccessController
251
                    .doPrivileged(new GetPropertyAction("user.country", ""));
252
            variant = (String) AccessController
253
                    .doPrivileged(new GetPropertyAction("user.variant", ""));
254
        }
255
        return new Locale(language, country, variant);
256
    }
257

    
258
    public void setCurrentLocale(Locale locale) {
259
        AndamiConfig config = Launcher.getAndamiConfig();
260
        config.setLocaleLanguage(locale.getLanguage());
261
        config.setLocaleCountry(locale.getCountry());
262
        config.setLocaleVariant(locale.getVariant());
263
    }
264

    
265
    public Locale[] installLocales(File importFile) throws I18nException {
266
        List importLocales = new ArrayList();
267

    
268
        try {
269
            ZipFile zipFile = new ZipFile(importFile);
270

    
271
            Map locales = getZipFileNonReferenceLocales(zipFile);
272

    
273
            if (locales == null || locales.size() == 0) {
274
                return null;
275
            }
276

    
277
            for (Iterator iterator = locales.entrySet().iterator(); iterator
278
                    .hasNext();) {
279
                Entry entry = (Entry) iterator.next();
280

    
281
                String fileName = (String) entry.getKey();
282
                Locale locale = (Locale) entry.getValue();
283
                importLocales.add(locale);
284

    
285
                // Add the locale to the list of installed ones, if it
286
                // is new, otherwise, update the texts.
287
                if (!registeredLocales.contains(locale)) {
288
                    registeredLocales.add(locale);
289
                    storeInstalledLocales();
290
                }
291

    
292
                // Replace the old bundle with the new one
293
                ZipEntry zipEntry = zipFile.getEntry(fileName);
294
                InputStream is = zipFile.getInputStream(zipEntry);
295
                BufferedReader reader = new BufferedReader(
296
                        new InputStreamReader(is));
297

    
298
                File bundleFile = getResourceFile(locale);
299
                FileWriter fileWriter = new FileWriter(bundleFile);
300
                BufferedWriter writer = new BufferedWriter(fileWriter);
301

    
302
                String line;
303
                while ((line = reader.readLine()) != null) {
304
                    writer.write(line);
305
                    writer.write('\n');
306
                }
307
                writer.flush();
308
                writer.close();
309
                fileWriter.close();
310
                reader.close();
311
                is.close();
312
            }
313

    
314
        } catch (Exception ex) {
315
            throw new InstallLocalesException(importFile, ex);
316
        }
317

    
318
        return (Locale[]) importLocales
319
                .toArray(new Locale[importLocales.size()]);
320
    }
321

    
322
    public void exportLocaleForUpdate(Locale locale, Locale referenceLocale,
323
            File exportFile) throws I18nException {
324

    
325
        exportLocalesForUpdate(new Locale[] { locale }, referenceLocale,
326
                exportFile);
327
    }
328

    
329
    public void exportLocalesForUpdate(Locale[] locales,
330
            Locale referenceLocale, File exportFile) throws I18nException {
331

    
332
        exportLocale(locales, new Locale[] { referenceLocale }, exportFile,
333
                true);
334
    }
335
    
336
    public void exportLocaleForTranslation(Locale locale,
337
            Locale referenceLocale, File exportFile) throws I18nException {
338
        
339
        exportLocaleForTranslation(locale, new Locale[] { referenceLocale },
340
                exportFile);
341
    }
342

    
343
    public void exportLocaleForTranslation(Locale locale,
344
            Locale[] referenceLocales, File exportFile) throws I18nException {
345

    
346
        exportLocale(new Locale[] { locale }, referenceLocales, exportFile,
347
                false);
348
    }
349

    
350
    public Locale[] getReferenceLocales() {
351
        return referenceLocales;
352
    }
353

    
354
    public void setReferenceLocales(Locale[] referenceLocales) {
355
        this.referenceLocales = referenceLocales;
356
    }
357

    
358
    public void setDefaultLocales(Locale[] defaultLocales) {
359
        this.defaultLocales = defaultLocales;
360
    }
361

    
362
    private void exportLocale(Locale[] locales, Locale[] referenceLocales,
363
            File exportFile, boolean update) throws I18nException {
364

    
365
        Locale[] refArray = getReferenceLocalesToExport(locales,
366
                referenceLocales);
367

    
368
        try {
369
            FileOutputStream fos = new FileOutputStream(exportFile);
370
            ZipOutputStream zipos = new ZipOutputStream(fos);
371

    
372
            // Create the index file
373
            writeZipFileLocales(zipos, locales, refArray);
374

    
375
            PrintStream ps = new PrintStream(zipos);
376
            Map texts = null;
377

    
378
            if (update) {
379
                // First, export the locales to update
380
                if (locales != null) {
381
                    for (int i = 0; i < locales.length; i++) {
382
                        texts = getAllTexts(locales[i]);
383
                        putResourceInZip(zipos, ps, texts,
384
                                getResourceFileName(locales[i]));
385
                    }
386
                }
387
            } else { // translate
388
                // First, export the locales to translate, taking the keys from
389
                // the reference locales, but without values
390
                // We will use the keys of the reference locales
391
                texts = getAllTexts(referenceLocales[0]);
392
                if (locales != null) {
393
                    for (int i = 0; i < locales.length; i++) {
394
                        putResourceInZip(zipos, ps, texts,
395
                                getResourceFileName(locales[i]), false);
396
                    }
397
                }
398
            }
399

    
400
            // Next, export the reference locales
401
            if (refArray != null) {
402
                for (int i = 0; i < refArray.length; i++) {
403
                    texts = getAllTexts(refArray[i]);
404
                    putResourceInZip(zipos, ps, texts,
405
                            getResourceFileName(refArray[i]));
406
                }
407
            }
408

    
409
            ps.flush();
410
            ps.close();
411
            zipos.close();
412
            fos.close();
413
        } catch (IOException ex) {
414
            throw new ExportLocaleException(locales, ex);
415
        }
416
    }
417

    
418
    /**
419
     * Returns the list of reference locales to export, as the union of the
420
     * default reference locales list and the one selected as reference. The
421
     * locales to translate or update are extracted from the list.
422
     */
423
    private Locale[] getReferenceLocalesToExport(Locale[] locales,
424
            Locale[] referenceLocalesSelected) {
425
        // The reference locales to export are the default ones plus the
426
        // selected by the user.
427
        Set exportRefLocales = new HashSet(referenceLocales.length);
428
        for (int i = 0; i < referenceLocales.length; i++) {
429
            exportRefLocales.add(referenceLocales[i]);
430
        }
431
        if (referenceLocalesSelected != null) {
432
            for (int i = 0; i < referenceLocalesSelected.length; i++) {
433
                exportRefLocales.add(referenceLocalesSelected[i]);
434
            }
435
        }
436
        if (locales != null) {
437
            for (int i = 0; i < locales.length; i++) {
438
                exportRefLocales.remove(locales[i]);
439
            }
440
        }
441
        Locale[] refArray = (Locale[]) exportRefLocales
442
                .toArray(new Locale[exportRefLocales.size()]);
443
        return refArray;
444
    }
445

    
446
    /**
447
     * Returns all the localized texts and its keys for a locale.
448
     */
449
    private Map getAllTexts(Locale locale) {
450
        return Messages.getAllTexts(locale);
451
    }
452

    
453
    private Map getZipFileNonReferenceLocales(ZipFile zipFile)
454
            throws I18nException {
455
        ZipEntry zipEntry = zipFile.getEntry(LOCALES_FILE_NAME);
456

    
457
        if (zipEntry == null) {
458
            return null;
459
        }
460

    
461
        Map locales;
462
        try {
463
            InputStream is = zipFile.getInputStream(zipEntry);
464
            BufferedReader reader = new BufferedReader(
465
                    new InputStreamReader(is));
466

    
467
            locales = new HashMap(2);
468
            String line;
469
            while ((line = reader.readLine()) != null) {
470
                // The excepted format is:
471
                // FILENAME,LANGUAGE,COUNTRY,VARIANT,IS_REFERENCE
472
                StringTokenizer st = new StringTokenizer(line, CSV_SEPARATOR,
473
                        true);
474
                // First: locale file name (required)
475
                String fileName = st.nextToken();
476
                if (CSV_SEPARATOR.equals(fileName)) {
477
                    throw new LocaleFileNameRequiredException(line);
478
                } else {
479
                    // Read the next separator
480
                    st.nextToken();
481
                }
482
                // Second: the locale language (required)
483
                String language = st.nextToken();
484
                if (CSV_SEPARATOR.equals(language)) {
485
                    throw new LocaleLanguageRequiredException(line);
486
                } else {
487
                    // Read the next separator
488
                    st.nextToken();
489
                }
490
                // Third: the country
491
                String country = st.nextToken();
492
                if (CSV_SEPARATOR.equals(country)) {
493
                    country = null;
494
                } else {
495
                    // Read the next separator
496
                    st.nextToken();
497
                }
498
                // Fourth: the variant
499
                String variant = st.nextToken();
500
                if (CSV_SEPARATOR.equals(variant)) {
501
                    variant = null;
502
                } else {
503
                    // Read the next separator
504
                    st.nextToken();
505
                }
506
                // Fifth: is a reference locale?
507
                String refStr = st.nextToken();
508
                if (CSV_SEPARATOR.equals(refStr)) {
509
                    refStr = null;
510
                }
511

    
512
                // Only add non reference locales
513
                if (refStr != null && !"true".equals(refStr.toLowerCase())) {
514
                    // Variant only accepted if country defined
515
                    if (country == null) {
516
                        variant = null;
517
                    }
518
                    country = country == null ? "" : country;
519
                    variant = variant == null ? "" : variant;
520
                    Locale locale = new Locale(language, country, variant);
521

    
522
                    locales.put(fileName, locale);
523
                }
524
            }
525

    
526
            reader.close();
527
            is.close();
528
        } catch (IOException ex) {
529
            throw new ReadCSVLocalesFileException(ex);
530
        }
531

    
532
        return locales;
533
    }
534

    
535
    private void writeZipFileLocales(ZipOutputStream zos, Locale[] locales,
536
            Locale[] referenceLocales) throws IOException {
537
        ZipEntry zipEntry = new ZipEntry(LOCALES_FILE_NAME);
538

    
539
        zos.putNextEntry(zipEntry);
540
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos));
541

    
542
        if (locales != null) {
543
            for (int i = 0; i < locales.length; i++) {
544
                writeLocaleEntry(locales[i], writer, false);
545
            }
546
        }
547
        if (referenceLocales != null) {
548
            for (int i = 0; i < referenceLocales.length; i++) {
549
                writeLocaleEntry(referenceLocales[i], writer, true);
550
            }
551
        }
552

    
553
        writer.flush();
554
        zos.closeEntry();
555
    }
556

    
557
    /**
558
     * Writes the locale entry into a writer.
559
     * 
560
     * @param locale
561
     *            the locale to create the entry for
562
     * @param writer
563
     *            to write to
564
     * @param reference
565
     *            is it is a reference locale or not
566
     * @throws IOException
567
     *             if there is an error creating the locale entry
568
     */
569
    private void writeLocaleEntry(Locale locale, BufferedWriter writer,
570
            boolean reference) throws IOException {
571
        String language = locale.getLanguage();
572
        String country = locale.getCountry();
573
        country = country == null ? "" : country;
574
        String variant = locale.getVariant();
575
        variant = variant == null ? "" : variant;
576

    
577
        writer.write(getResourceFileName(locale));
578
        writer.write(',');
579
        writer.write(language);
580
        writer.write(',');
581
        writer.write(country);
582
        writer.write(',');
583
        writer.write(variant);
584
        writer.write(',');
585
        writer.write(Boolean.toString(reference));
586
        writer.write('\n');
587
    }
588

    
589
    /**
590
     * Returns if a locale is one of the default reference ones.
591
     */
592
    private boolean isReferenceLocale(Locale locale) {
593
        for (int i = 0; i < referenceLocales.length; i++) {
594
            if (referenceLocales[i].equals(locale)) {
595
                return true;
596
            }
597
        }
598
        return false;
599
    }
600

    
601
    /**
602
     * Puts a new resource file into a Jar file.
603
     */
604
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
605
            Map texts, String resourceFileName) throws IOException {
606

    
607
        putResourceInZip(zipos, ps, texts, resourceFileName, true);
608
    }
609

    
610
    /**
611
     * Puts a new resource file into a Jar file.
612
     */
613
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
614
            Map texts, String resourceFileName, boolean withValue)
615
            throws IOException {
616
        // Add ZIP entry for the resource bundle file
617
        zipos.putNextEntry(new ZipEntry(resourceFileName));
618

    
619
        for (Iterator iterator = texts.entrySet().iterator(); iterator
620
                .hasNext();) {
621
            Entry entry = (Entry) iterator.next();
622
            String keyEncoded = escape((String) entry.getKey(), true);
623
            ps.print(keyEncoded);
624
            ps.print("=");
625
            if (withValue) {
626
                String valueEncoded = escape((String) entry.getValue(), false);
627
                ps.println(valueEncoded);
628
            } else {
629
                ps.println();
630
            }
631
        }
632

    
633
        ps.flush();
634

    
635
        // Close the ZIP entry, the file is complete
636
        zipos.closeEntry();
637
    }
638

    
639
    /**
640
     * Returns the file which contains the translations for a locale.
641
     */
642
    private File getResourceFile(Locale locale) {
643
        return new File(getResourcesFolder(), getResourceFileName(locale));
644
    }
645

    
646
    /**
647
     * Returns the name of the file which contains the translations for a
648
     * locale.
649
     */
650
    private String getResourceFileName(Locale locale) {
651
        StringBuffer fileName = new StringBuffer("text");
652

    
653
        // Spanish without country is the default locale
654
        if (!(isEmpty(locale.getCountry()) && "es".equals(locale.getLanguage()))) {
655
            fileName.append('_').append(locale.getLanguage());
656
        }
657

    
658
        // Add the locale country
659
        if (!isEmpty(locale.getCountry())) {
660
            fileName.append('_').append(locale.getCountry());
661
        }
662

    
663
        // Add the locale variant
664
        if (!isEmpty(locale.getVariant())) {
665
            fileName.append('_').append(locale.getVariant());
666
        }
667

    
668
        fileName.append(".properties");
669
        return fileName.toString();
670
    }
671

    
672
    /**
673
     * Returns the folder where to store the resource bundle files.
674
     */
675
    private File getResourcesFolder() {
676
        return PluginServices.getPluginServices("com.iver.cit.gvsig")
677
                .getPluginDirectory();
678
    }
679

    
680
    /**
681
     * Returns the child XMLEntity with the RegisteredLocales.
682
     */
683
    private XMLEntity getRegisteredLocalesPersistence() {
684
        XMLEntity entity = getI18nPersistence();
685
        XMLEntity child = null;
686
        for (int i = entity.getChildrenCount() - 1; i >= 0; i--) {
687
            XMLEntity tmpchild = entity.getChild(i);
688
            if (tmpchild.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
689
                child = tmpchild;
690
                break;
691
            }
692
        }
693
        return child;
694
    }
695

    
696
    /**
697
     * Returns the I18n Plugin persistence.
698
     */
699
    private XMLEntity getI18nPersistence() {
700
        XMLEntity entity = PluginServices.getPluginServices(I18N_EXTENSION)
701
                .getPersistentXML();
702
        return entity;
703
    }
704

    
705
    /**
706
     * Returns the list of default locales bundled with gvSIG.
707
     */
708
    private Locale[] getDefaultLocales() {
709
        return defaultLocales;
710
    }
711

    
712
    /**
713
     * Stores the list of installed locales into the plugin persistence.
714
     */
715
    private void storeInstalledLocales() {
716
        XMLEntity localesEntity = getRegisteredLocalesPersistence();
717

    
718
        // Remove the previous list of registered languages
719
        if (localesEntity != null) {
720
            XMLEntity i18nPersistence = getI18nPersistence();
721
            for (int i = i18nPersistence.getChildrenCount() - 1; i >= 0; i--) {
722
                XMLEntity child = i18nPersistence.getChild(i);
723
                if (child.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
724
                    i18nPersistence.removeChild(i);
725
                    break;
726
                }
727
            }
728
        }
729

    
730
        // Create the new persistence for the registered languages
731
        localesEntity = new XMLEntity();
732

    
733
        localesEntity.setName(REGISTERED_LOCALES_PERSISTENCE);
734

    
735
        for (Iterator iterator = registeredLocales.iterator(); iterator
736
                .hasNext();) {
737
            Locale locale = (Locale) iterator.next();
738
            XMLEntity localeEntity = new XMLEntity();
739
            localeEntity.setName(locale.getDisplayName());
740
            localeEntity.putProperty(LANGUAGE, locale.getLanguage());
741
            localeEntity.putProperty(COUNTRY, locale.getCountry());
742
            localeEntity.putProperty(VARIANT, locale.getVariant());
743

    
744
            localesEntity.addChild(localeEntity);
745
        }
746

    
747
        getI18nPersistence().addChild(localesEntity);
748
    }
749

    
750
    private String escape(String value, boolean replaceBlanks) {
751
        // First replace non printable characters
752
        if (replaceBlanks) {
753
            value = StringUtilities.replace(value, " ", "\\ ");
754
        }
755
        value = StringUtilities.replace(value, ":", "\\:");
756
        value = StringUtilities.replace(value, "\n", "\\n");
757
        value = StringUtilities.replace(value, "\t", "\\t");
758
        value = StringUtilities.replace(value, "\b", "\\b");
759
        value = StringUtilities.replace(value, "\f", "\\f");
760
        value = StringUtilities.replace(value, "\r", "\\r");
761
        // value = StringUtilities.replace(value, "\\", "\\\\");
762
        // value = StringUtilities.replace(value, "\'", "\\\'");
763
        // value = StringUtilities.replace(value, "\"", "\\\"");
764

    
765
        // Next, encode in raw-unicode-escape
766
        return toRawUnicodeEncoded(value);
767
    }
768

    
769
    private String toRawUnicodeEncoded(String value) {
770
        StringBuffer sb = new StringBuffer();
771
        for (int i = 0; i < value.length(); i++) {
772
            char c = value.charAt(i);
773
            if (c <= 0x80) {
774
                sb.append(c);
775
            } else {
776
                sb.append("\\u");
777
                String hexValue = Integer.toHexString((int) c);
778
                // Append 0 if the hex value has less than 4 digits
779
                for (int j = hexValue.length(); j < 4; j++) {
780
                    sb.append('0');
781
                }
782
                sb.append(hexValue);
783
            }
784
        }
785
        return sb.toString();
786
    }
787
}