Statistics
| Revision:

root / branches / v10 / extensions / extI18n / src / org / gvsig / i18n / impl / I18nManagerImpl.java @ 26324

History | View | Annotate | Download (21.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.jar.*;
34
import java.util.zip.ZipEntry;
35

    
36
import org.gvsig.i18n.*;
37

    
38
import sun.security.action.GetPropertyAction;
39

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

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

    
54
    private static final String MF_LOCALE_VARIANT = "locale-variant";
55

    
56
    private static final String MF_LOCALE_COUNTRY = "locale-country";
57

    
58
    private static final String MF_LOCALE_LANGUAGE = "locale-language";
59

    
60
    private static final String MF_REFLOCALE_VARIANT = "reference-locale-variant";
61

    
62
    private static final String MF_REFLOCALE_COUNTRY = "reference-locale-country";
63

    
64
    private static final String MF_REFLOCALE_LANGUAGE = "reference-locale-language";
65

    
66
    private static final String I18N_EXTENSION = "org.gvsig.i18n";
67

    
68
    private static final String VARIANT = "variant";
69

    
70
    private static final String COUNTRY = "country";
71

    
72
    private static final String LANGUAGE = "language";
73

    
74
    private static final String REGISTERED_LOCALES_PERSISTENCE = "RegisteredLocales";
75

    
76
    private static final I18nManager DEFAULT = new I18nManagerImpl();
77

    
78
    private Set registeredLocales;
79

    
80
    /**
81
     * The list of default reference locales. The last one will be used to get
82
     * all the keys when translating to a new locale.
83
     */
84
    private Locale[] referenceLocales = new Locale[] { ENGLISH, SPANISH };
85

    
86
    private Locale[] defaultLocales = new Locale[] {
87
    // Default supported locales
88
            new Locale("ca"), // Catalan
89
            new Locale("cs"), // Czech
90
            new Locale("de"), // German
91
            ENGLISH, // English
92
            SPANISH, // Spanish
93
            new Locale("eu"), // Basque
94
            new Locale("fr"), // French
95
            new Locale("gl"), // Galician
96
            new Locale("it"), // Italian
97
            new Locale("pl"), // Polish
98
            new Locale("pt"), // Portuguese
99
            new Locale("ro"), // Romanian
100
            new Locale("zh"), // Chinese
101
    };
102

    
103
    /**
104
     * Returns the unique instance of the I18nManager.
105
     * 
106
     * @return the unique instance
107
     */
108
    public static I18nManager getInstance() {
109
        return DEFAULT;
110
    }
111

    
112
    public static String capitalize(String text) {
113
        // Convert the first letter to uppercase
114
        String capitalLetter = new String(new char[] { Character
115
                .toUpperCase(text.charAt(0)) });
116
        return capitalLetter.concat(text.substring(1));
117
    }
118

    
119
    /**
120
     * Empty constructor.
121
     */
122
    I18nManagerImpl() {
123
    }
124

    
125
    public Locale[] getInstalledLocales() {
126
        if (registeredLocales == null) {
127

    
128
            XMLEntity child = getRegisteredLocalesPersistence();
129

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

    
156
        return (Locale[]) registeredLocales
157
                .toArray(new Locale[registeredLocales.size()]);
158
    }
159

    
160
    public void uninstallLocale(Locale locale) throws I18nException {
161
        if (getCurrentLocale().equals(locale) || isReferenceLocale(locale)) {
162
            throw new UninstallLocaleException(locale);
163
        }
164

    
165
        if (registeredLocales.remove(locale)) {
166
            // Remove from the configured locale list
167
            storeInstalledLocales();
168

    
169
            // Remove the resource bundle file
170
            File bundleFile = new File(getResourcesFolder(),
171
                    getResourceFileName(locale));
172

    
173
            if (bundleFile.exists()) {
174
                bundleFile.delete();
175
            }
176
        }
177
    }
178

    
179
    public String getDisplayName(Locale locale) {
180
        return getDisplayName(locale, locale);
181
    }
182

    
183
    public String getDisplayName(Locale locale, Locale displayLocale) {
184
        StringBuffer name = new StringBuffer(getLanguageDisplayName(locale,
185
                displayLocale));
186

    
187
        boolean close = false;
188

    
189
        if (!isEmpty(locale.getCountry())) {
190
            name.append(" (");
191
            name.append(locale.getDisplayCountry(displayLocale));
192
            close = true;
193
        }
194

    
195
        if (!isEmpty(locale.getVariant())) {
196
            if (close) {
197
                name.append(" - ");
198
            }
199
            else {
200
                name.append(" (");
201
                close = true;
202
            }
203
            name.append(locale.getDisplayVariant(displayLocale));
204
        }
205

    
206
        if (close) {
207
            name.append(')');
208
        }
209

    
210
        return name.toString();
211
    }
212

    
213
    private boolean isEmpty(String text) {
214
        return text == null || text.trim().length() == 0;
215
    }
216

    
217
    public String getLanguageDisplayName(Locale locale) {
218
        return getLanguageDisplayName(locale, locale);
219
    }
220

    
221
    public String getLanguageDisplayName(Locale locale, Locale displayLocale) {
222

    
223
        String displayName;
224

    
225
        // Correction for the Basque language display name,
226
        // show it in Basque, not in Spanish
227
        if ("eu".equals(locale.getLanguage())
228
                && "vascuence".equals(locale.getDisplayLanguage())) {
229
            displayName = "Euskera";
230
        }
231
        // Patch for Valencian/Catalan
232
        else if ("ca".equals(locale.getLanguage())) {
233
            displayName = Messages.getText("__catalan");
234
        }
235
        else {
236
            displayName = locale.getDisplayLanguage(displayLocale);
237
        }
238

    
239
        return capitalize(displayName);
240
    }
241

    
242
    public Locale getCurrentLocale() {
243
        return Locale.getDefault();
244
    }
245
    
246
    public Locale getDefaultSystemLocale() {
247
        String language, region, country, variant;
248
        language = (String) AccessController
249
                .doPrivileged(new GetPropertyAction("user.language", "en"));
250
        // for compatibility, check for old user.region property
251
        region = (String) AccessController.doPrivileged(new GetPropertyAction(
252
                "user.region"));
253
        if (region != null) {
254
            // region can be of form country, country_variant, or _variant
255
            int i = region.indexOf('_');
256
            if (i >= 0) {
257
                country = region.substring(0, i);
258
                variant = region.substring(i + 1);
259
            }
260
            else {
261
                country = region;
262
                variant = "";
263
            }
264
        }
265
        else {
266
            country = (String) AccessController
267
                    .doPrivileged(new GetPropertyAction("user.country", ""));
268
            variant = (String) AccessController
269
                    .doPrivileged(new GetPropertyAction("user.variant", ""));
270
        }
271
        return new Locale(language, country, variant);
272
    }
273

    
274
    public void setCurrentLocale(Locale locale) {
275
        AndamiConfig config = Launcher.getAndamiConfig();
276
        config.setLocaleLanguage(locale.getLanguage());
277
        config.setLocaleCountry(locale.getCountry());
278
        config.setLocaleVariant(locale.getVariant());
279
    }
280

    
281
    public Locale[] installLocales(File importFile) throws I18nException {
282
        List importLocales = new ArrayList();
283

    
284
        try {
285
            FileInputStream fis = new FileInputStream(importFile);
286
            JarInputStream jaris = new JarInputStream(fis);
287

    
288
            JarEntry entry;
289
            while ((entry = jaris.getNextJarEntry()) != null) {
290

    
291
                Attributes attributes = entry.getAttributes();
292

    
293
                if (attributes != null) {
294
                    // Extract the language only if it is not a reference
295
                    // language
296
                    String language = attributes.getValue(MF_LOCALE_LANGUAGE);
297
                    if (language != null) {
298
                        String country = attributes.getValue(MF_LOCALE_COUNTRY);
299
                        country = country == null ? "" : country;
300
                        String variant = attributes.getValue(MF_LOCALE_VARIANT);
301
                        variant = variant == null ? "" : variant;
302
                        Locale locale = new Locale(language, country, variant);
303
                        importLocales.add(locale);
304

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

    
312
                        // Replace the old bundle with the new one
313
                        File bundleFile = getResourceFile(locale);
314
                        FileOutputStream fos = new FileOutputStream(bundleFile);
315
                        BufferedOutputStream bos = new BufferedOutputStream(fos);
316
                        int len = 0;
317
                        byte[] buffer = new byte[2048];
318
                        while ((len = jaris.read(buffer)) > 0) {
319
                            bos.write(buffer, 0, len);
320
                        }
321
                        bos.flush();
322
                        bos.close();
323
                        fos.close();
324
                    }
325
                }
326
            }
327

    
328
            jaris.close();
329
            fis.close();
330
        } catch (Exception ex) {
331
            throw new InstallLocalesException(importFile, ex);
332
        }
333

    
334
        return (Locale[]) importLocales
335
                .toArray(new Locale[importLocales.size()]);
336
    }
337

    
338
    public void exportLocaleForUpdate(Locale locale, Locale referenceLocale,
339
            File exportFile) throws I18nException {
340
        Manifest manifest = new Manifest();
341

    
342
        // First, add an entry for the locale to update
343
        addLocaleToManifest(locale, manifest, false);
344
        // Next, another entry for the reference locale, if not a default one
345
        if (!isReferenceLocale(referenceLocale)) {
346
            addLocaleToManifest(referenceLocale, manifest, true);
347
        }
348
        // Finally, an entry per default reference locale, if not the locale to
349
        // update
350
        for (int i = 0; i < referenceLocales.length; i++) {
351
            if (!locale.equals(referenceLocales[i])) {
352
                addLocaleToManifest(referenceLocales[i], manifest, true);
353
            }
354
        }
355

    
356
        try {
357
            FileOutputStream fos = new FileOutputStream(exportFile);
358
            JarOutputStream jaros = new JarOutputStream(fos, manifest);
359

    
360
            // BufferedOutputStream bos = new BufferedOutputStream(jaros);
361
            // PrintStream ps = new PrintStream(bos);
362
            PrintStream ps = new PrintStream(jaros);
363
            Map texts = null;
364

    
365
            // First, export the locale to update
366
            texts = getAllTexts(locale);
367
            putResourceInJar(jaros, ps, texts, getResourceFileName(locale));
368
            // Next, export the locale selected as reference (if not in the
369
            // default reference locales list)
370
            if (!isReferenceLocale(referenceLocale)) {
371
                texts = getAllTexts(referenceLocale);
372
                putResourceInJar(jaros, ps, texts,
373
                        getResourceFileName(referenceLocale));
374
            }
375
            // Finally, export the default reference locales
376
            for (int i = 0; i < referenceLocales.length; i++) {
377
                if (!locale.equals(referenceLocales[i])) {
378
                    texts = getAllTexts(referenceLocales[i]);
379
                    putResourceInJar(jaros, ps, texts,
380
                            getResourceFileName(referenceLocales[i]));
381
                }
382
            }
383

    
384
            ps.flush();
385
            ps.close();
386
            jaros.close();
387
            fos.close();
388
        } catch (IOException ex) {
389
            throw new ExportLocaleException(locale, ex);
390
        }
391
    }
392

    
393
    public void exportLocaleForTranslation(Locale locale,
394
            Locale referenceLocale, File exportFile) throws I18nException {
395
        Manifest manifest = new Manifest();
396

    
397
        // First, add an entry for the locale to update
398
        addLocaleToManifest(locale, manifest, false);
399
        // Next, another entry for the reference locale, if not a default one
400
        if (!isReferenceLocale(referenceLocale)) {
401
            addLocaleToManifest(referenceLocale, manifest, true);
402
        }
403
        // Finally, an entry per default reference locale
404
        for (int i = 0; i < referenceLocales.length; i++) {
405
            addLocaleToManifest(referenceLocales[i], manifest, true);
406
        }
407

    
408
        try {
409
            FileOutputStream fos = new FileOutputStream(exportFile);
410
            JarOutputStream jaros = new JarOutputStream(fos, manifest);
411

    
412
            // BufferedOutputStream bos = new BufferedOutputStream(jaros);
413
            // PrintStream ps = new PrintStream(bos);
414
            PrintStream ps = new PrintStream(jaros);
415
            Map texts = null;
416

    
417
            // First, export the reference locale translations
418
            for (int i = 0; i < referenceLocales.length; i++) {
419
                texts = getAllTexts(referenceLocales[i]);
420
                putResourceInJar(jaros, ps, texts,
421
                        getResourceFileName(referenceLocales[i]));
422
            }
423
            // Next, export the locale selected as reference (if not in the
424
            // default reference locales list)
425
            if (!isReferenceLocale(referenceLocale)) {
426
                texts = getAllTexts(referenceLocale);
427
                putResourceInJar(jaros, ps, texts,
428
                        getResourceFileName(referenceLocale));
429
            }
430

    
431
            // Finally, the new locale translations, taking the keys from
432
            // the reference locale, but without values
433
            // We will use the keys of the last reference locale
434
            putResourceInJar(jaros, ps, texts, getResourceFileName(locale),
435
                    false);
436

    
437
            ps.close();
438
            // bos.close();
439
            jaros.close();
440
            fos.close();
441
        } catch (IOException ex) {
442
            throw new ExportLocaleException(locale, ex);
443
        }
444
    }
445

    
446
    public Locale[] getReferenceLocales() {
447
        return referenceLocales;
448
    }
449

    
450
    public void setReferenceLocales(Locale[] referenceLocales) {
451
        this.referenceLocales = referenceLocales;
452
    }
453

    
454
    public void setDefaultLocales(Locale[] defaultLocales) {
455
        this.defaultLocales = defaultLocales;
456
    }
457

    
458
    /**
459
     * Returns all the localized texts and its keys for a locale.
460
     */
461
    private Map getAllTexts(Locale locale) {
462
        return Messages.getAllTexts(locale);
463
    }
464

    
465
    // private Map getZipFileLocales(ZipFile zipFile) throws IOException {
466
    // ZipEntry zipEntry = zipFile.getEntry("locales.csv");
467
    //
468
    // if (zipEntry == null) {
469
    // return null;
470
    // }
471
    //
472
    // InputStream is = zipFile.getInputStream(zipEntry);
473
    // BufferedReader reader = new BufferedReader(new InputStreamReader(is));
474
    //
475
    // Map locales = new HashMap(4);
476
    // String line;
477
    // while ((line = reader.readLine()) != null) {
478
    // StringTokenizer st = new StringTokenizer(line, ",");
479
    // String language = st.nextToken();
480
    // String country = st.nextToken();
481
    // country = country == null ? "" : country;
482
    // String variant = st.nextToken();
483
    // variant = variant == null ? "" : variant;
484
    // String ref = st.nextToken();
485
    //
486
    // Locale locale = new Locale(language, country, variant);
487
    //            
488
    // }
489
    // }
490

    
491
    /**
492
     * Returns if a locale is one of the default reference ones.
493
     */
494
    private boolean isReferenceLocale(Locale locale) {
495
        for (int i = 0; i < referenceLocales.length; i++) {
496
            if (referenceLocales[i].equals(locale)) {
497
                return true;
498
            }
499
        }
500
        return false;
501
    }
502

    
503
    /**
504
     * Puts a new resource file into a Jar file.
505
     */
506
    private void putResourceInJar(JarOutputStream jaros, PrintStream ps,
507
            Map texts, String resourceFileName) throws IOException {
508

    
509
        putResourceInJar(jaros, ps, texts, resourceFileName, true);
510
    }
511

    
512
    /**
513
     * Puts a new resource file into a Jar file.
514
     */
515
    private void putResourceInJar(JarOutputStream jaros, PrintStream ps,
516
            Map texts, String resourceFileName, boolean withValue)
517
            throws IOException {
518
        // Add ZIP entry for the resource bundle file
519
        jaros.putNextEntry(new ZipEntry(resourceFileName));
520

    
521
        for (Iterator iterator = texts.entrySet().iterator(); iterator
522
                .hasNext();) {
523
            Entry entry = (Entry) iterator.next();
524
            String keyEncoded = escape((String) entry.getKey(), true);
525
            ps.print(keyEncoded);
526
            ps.print("=");
527
            if (withValue) {
528
                String valueEncoded = escape((String) entry.getValue(), false);
529
                ps.println(valueEncoded);
530
            }
531
            else {
532
                ps.println();
533
            }
534
        }
535

    
536
        ps.flush();
537

    
538
        // Close the ZIP entry, the file is complete
539
        jaros.closeEntry();
540
    }
541

    
542
    /**
543
     * Adds an entry to a MANIFEST.MF file with the name of a locale resource
544
     * bundle properties file, adding labels with the id of the locale, and if
545
     * it is a reference or the locale to translate or update.
546
     */
547
    private String addLocaleToManifest(Locale locale, Manifest manifest,
548
            boolean isReference) {
549
        final String languageKey = isReference ? MF_REFLOCALE_LANGUAGE
550
                : MF_LOCALE_LANGUAGE;
551
        final String countryKey = isReference ? MF_REFLOCALE_COUNTRY
552
                : MF_LOCALE_COUNTRY;
553
        final String variantKey = isReference ? MF_REFLOCALE_VARIANT
554
                : MF_LOCALE_VARIANT;
555

    
556
        String resourceFileName = getResourceFileName(locale);
557

    
558
        Attributes localeAttributes = new Attributes(4);
559
        localeAttributes.putValue(languageKey, locale.getLanguage());
560
        String country = locale.getCountry();
561
        if (country != null && country.length() > 0) {
562
            localeAttributes.putValue(countryKey, country);
563
        }
564
        String variant = locale.getVariant();
565
        if (variant != null && variant.length() > 0) {
566
            localeAttributes.putValue(variantKey, variant);
567
        }
568
        manifest.getEntries().put(resourceFileName, localeAttributes);
569

    
570
        return resourceFileName;
571
    }
572

    
573
    /**
574
     * Returns the file which contains the translations for a locale.
575
     */
576
    private File getResourceFile(Locale locale) {
577
        return new File(getResourcesFolder(), getResourceFileName(locale));
578
    }
579

    
580
    /**
581
     * Returns the name of the file which contains the translations for a
582
     * locale.
583
     */
584
    private String getResourceFileName(Locale locale) {
585
        StringBuffer fileName = new StringBuffer("text");
586

    
587
        // Spanish without country is the default locale
588
        if (!(isEmpty(locale.getCountry()) && "es".equals(locale.getLanguage()))) {
589
            fileName.append('_').append(locale.getLanguage());
590
        }
591

    
592
        // Add the locale country
593
        if (!isEmpty(locale.getCountry())) {
594
            fileName.append('_').append(locale.getCountry());
595
        }
596

    
597
        // Add the locale variant
598
        if (!isEmpty(locale.getVariant())) {
599
            fileName.append('_').append(locale.getVariant());
600
        }
601

    
602
        fileName.append(".properties");
603
        return fileName.toString();
604
    }
605

    
606
    /**
607
     * Returns the folder where to store the resource bundle files.
608
     */
609
    private File getResourcesFolder() {
610
        return PluginServices.getPluginServices("com.iver.cit.gvsig")
611
                .getPluginDirectory();
612
    }
613

    
614
    /**
615
     * Returns the child XMLEntity with the RegisteredLocales.
616
     */
617
    private XMLEntity getRegisteredLocalesPersistence() {
618
        XMLEntity entity = getI18nPersistence();
619
        XMLEntity child = null;
620
        for (int i = entity.getChildrenCount() - 1; i >= 0; i--) {
621
            XMLEntity tmpchild = entity.getChild(i);
622
            if (tmpchild.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
623
                child = tmpchild;
624
                break;
625
            }
626
        }
627
        return child;
628
    }
629

    
630
    /**
631
     * Returns the I18n Plugin persistence.
632
     */
633
    private XMLEntity getI18nPersistence() {
634
        XMLEntity entity = PluginServices.getPluginServices(I18N_EXTENSION)
635
                .getPersistentXML();
636
        return entity;
637
    }
638

    
639
    /**
640
     * Returns the list of default locales bundled with gvSIG.
641
     */
642
    private Locale[] getDefaultLocales() {
643
        return defaultLocales;
644
    }
645

    
646
    /**
647
     * Stores the list of installed locales into the plugin persistence.
648
     */
649
    private void storeInstalledLocales() {
650
        XMLEntity localesEntity = getRegisteredLocalesPersistence();
651

    
652
        // Remove the previous list of registered languages
653
        if (localesEntity != null) {
654
            XMLEntity i18nPersistence = getI18nPersistence();
655
            for (int i = i18nPersistence.getChildrenCount() - 1; i >= 0; i--) {
656
                XMLEntity child = i18nPersistence.getChild(i);
657
                if (child.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
658
                    i18nPersistence.removeChild(i);
659
                    break;
660
                }
661
            }
662
        }
663

    
664
        // Create the new persistence for the registered languages
665
        localesEntity = new XMLEntity();
666

    
667
        localesEntity.setName(REGISTERED_LOCALES_PERSISTENCE);
668

    
669
        for (Iterator iterator = registeredLocales.iterator(); iterator
670
                .hasNext();) {
671
            Locale locale = (Locale) iterator.next();
672
            XMLEntity localeEntity = new XMLEntity();
673
            localeEntity.setName(locale.getDisplayName());
674
            localeEntity.putProperty(LANGUAGE, locale.getLanguage());
675
            localeEntity.putProperty(COUNTRY, locale.getCountry());
676
            localeEntity.putProperty(VARIANT, locale.getVariant());
677

    
678
            localesEntity.addChild(localeEntity);
679
        }
680

    
681
        getI18nPersistence().addChild(localesEntity);
682
    }
683

    
684
    private String escape(String value, boolean replaceBlanks) {
685
        // First replace non printable characters
686
        if (replaceBlanks) {
687
            value = StringUtilities.replace(value, " ", "\\ ");
688
        }
689
        value = StringUtilities.replace(value, ":", "\\:");
690
        value = StringUtilities.replace(value, "\n", "\\n");
691
        value = StringUtilities.replace(value, "\t", "\\t");
692
        value = StringUtilities.replace(value, "\b", "\\b");
693
        value = StringUtilities.replace(value, "\f", "\\f");
694
        value = StringUtilities.replace(value, "\r", "\\r");
695
        // value = StringUtilities.replace(value, "\\", "\\\\");
696
        // value = StringUtilities.replace(value, "\'", "\\\'");
697
        // value = StringUtilities.replace(value, "\"", "\\\"");
698

    
699
        // Next, encode in raw-unicode-escape
700
        return toRawUnicodeEncoded(value);
701
    }
702

    
703
    private String toRawUnicodeEncoded(String value) {
704
        StringBuffer sb = new StringBuffer();
705
        for (int i = 0; i < value.length(); i++) {
706
            char c = value.charAt(i);
707
            if (c <= 0x80) {
708
                sb.append(c);
709
            }
710
            else {
711
                sb.append("\\u");
712
                String hexValue = Integer.toHexString((int) c);
713
                // Append 0 if the hex value has less than 4 digits
714
                for (int j = hexValue.length(); j < 4; j++) {
715
                    sb.append('0');
716
                }
717
                sb.append(hexValue);
718
            }
719
        }
720
        return sb.toString();
721
    }
722
}