Statistics
| Revision:

root / branches / v2_0_0_prep / extensions / extI18n / src / org / gvsig / i18n / impl / I18nManagerImpl.java @ 28767

History | View | Annotate | Download (22.6 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
        } else {
221
            displayName = locale.getDisplayLanguage(displayLocale);
222
        }
223

    
224
        return capitalize(displayName);
225
    }
226

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

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

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

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

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

    
270
            Map locales = getZipFileNonReferenceLocales(zipFile);
271

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
531
        return locales;
532
    }
533

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

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

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

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

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

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

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

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

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

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

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

    
632
        ps.flush();
633

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
732
        localesEntity.setName(REGISTERED_LOCALES_PERSISTENCE);
733

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

    
743
            localesEntity.addChild(localeEntity);
744
        }
745

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

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

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

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