Statistics
| Revision:

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

History | View | Annotate | Download (21.3 KB)

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

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

    
29
import java.io.*;
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 CSV_SEPARATOR = ",";
54

    
55
    private static final String I18N_EXTENSION = "org.gvsig.i18n";
56

    
57
    private static final String VARIANT = "variant";
58

    
59
    private static final String COUNTRY = "country";
60

    
61
    private static final String LANGUAGE = "language";
62

    
63
    private static final String REGISTERED_LOCALES_PERSISTENCE = "RegisteredLocales";
64

    
65
    private static final I18nManager DEFAULT = new I18nManagerImpl();
66

    
67
    private Set registeredLocales;
68

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

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

    
92
    /**
93
     * Returns the unique instance of the I18nManager.
94
     * 
95
     * @return the unique instance
96
     */
97
    public static I18nManager getInstance() {
98
        return DEFAULT;
99
    }
100

    
101
    public static String capitalize(String text) {
102
        // Convert the first letter to uppercase
103
        String capitalLetter = new String(new char[] { Character
104
                .toUpperCase(text.charAt(0)) });
105
        return capitalLetter.concat(text.substring(1));
106
    }
107

    
108
    /**
109
     * Empty constructor.
110
     */
111
    I18nManagerImpl() {
112
    }
113

    
114
    public Locale[] getInstalledLocales() {
115
        if (registeredLocales == null) {
116

    
117
            XMLEntity child = getRegisteredLocalesPersistence();
118

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

    
145
        return (Locale[]) registeredLocales
146
                .toArray(new Locale[registeredLocales.size()]);
147
    }
148

    
149
    public void uninstallLocale(Locale locale) throws I18nException {
150
        if (getCurrentLocale().equals(locale) || isReferenceLocale(locale)) {
151
            throw new UninstallLocaleException(locale);
152
        }
153

    
154
        if (registeredLocales.remove(locale)) {
155
            // Remove from the configured locale list
156
            storeInstalledLocales();
157

    
158
            // Remove the resource bundle file
159
            File bundleFile = new File(getResourcesFolder(),
160
                    getResourceFileName(locale));
161

    
162
            if (bundleFile.exists()) {
163
                bundleFile.delete();
164
            }
165
        }
166
    }
167

    
168
    public String getDisplayName(Locale locale) {
169
        return getDisplayName(locale, locale);
170
    }
171

    
172
    public String getDisplayName(Locale locale, Locale displayLocale) {
173
        StringBuffer name = new StringBuffer(getLanguageDisplayName(locale,
174
                displayLocale));
175

    
176
        boolean close = false;
177

    
178
        if (!isEmpty(locale.getCountry())) {
179
            name.append(" (");
180
            name.append(locale.getDisplayCountry(displayLocale));
181
            close = true;
182
        }
183

    
184
        if (!isEmpty(locale.getVariant())) {
185
            if (close) {
186
                name.append(" - ");
187
            }
188
            else {
189
                name.append(" (");
190
                close = true;
191
            }
192
            name.append(locale.getDisplayVariant(displayLocale));
193
        }
194

    
195
        if (close) {
196
            name.append(')');
197
        }
198

    
199
        return name.toString();
200
    }
201

    
202
    private boolean isEmpty(String text) {
203
        return text == null || text.trim().length() == 0;
204
    }
205

    
206
    public String getLanguageDisplayName(Locale locale) {
207
        return getLanguageDisplayName(locale, locale);
208
    }
209

    
210
    public String getLanguageDisplayName(Locale locale, Locale displayLocale) {
211

    
212
        String displayName;
213

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

    
228
        return capitalize(displayName);
229
    }
230

    
231
    public Locale getCurrentLocale() {
232
        return Locale.getDefault();
233
    }
234

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

    
263
    public void setCurrentLocale(Locale locale) {
264
        AndamiConfig config = Launcher.getAndamiConfig();
265
        config.setLocaleLanguage(locale.getLanguage());
266
        config.setLocaleCountry(locale.getCountry());
267
        config.setLocaleVariant(locale.getVariant());
268
    }
269

    
270
    public Locale[] installLocales(File importFile) throws I18nException {
271
        List importLocales = new ArrayList();
272

    
273
        try {
274
            ZipFile zipFile = new ZipFile(importFile);
275

    
276
            Map locales = getZipFileNonReferenceLocales(zipFile);
277

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

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

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

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

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

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

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

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

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

    
326
        exportLocale(locale, referenceLocale, exportFile, true);
327
    }
328

    
329
    public void exportLocaleForTranslation(Locale locale,
330
            Locale referenceLocale, File exportFile) throws I18nException {
331

    
332
        exportLocale(locale, referenceLocale, exportFile, false);
333
    }
334

    
335
    public Locale[] getReferenceLocales() {
336
        return referenceLocales;
337
    }
338

    
339
    public void setReferenceLocales(Locale[] referenceLocales) {
340
        this.referenceLocales = referenceLocales;
341
    }
342

    
343
    public void setDefaultLocales(Locale[] defaultLocales) {
344
        this.defaultLocales = defaultLocales;
345
    }
346

    
347
    private void exportLocale(Locale locale, Locale referenceLocale,
348
            File exportFile, boolean update) throws I18nException {
349

    
350
        Locale[] refArray = getReferenceLocalesToExport(locale, referenceLocale);
351

    
352
        try {
353
            FileOutputStream fos = new FileOutputStream(exportFile);
354
            ZipOutputStream zipos = new ZipOutputStream(fos);
355

    
356
            // Create the index file
357
            writeZipFileLocales(zipos, locale, refArray);
358

    
359
            PrintStream ps = new PrintStream(zipos);
360
            Map texts = null;
361

    
362
            if (update) {
363
                // First, export the locale to update
364
                texts = getAllTexts(locale);
365
                putResourceInZip(zipos, ps, texts, getResourceFileName(locale));
366
            }
367
            else { // translate
368
                // First, export the locale to translate, taking the keys from
369
                // the reference locale, but without values
370
                // We will use the keys of the reference locale
371
                texts = getAllTexts(referenceLocale);
372
                putResourceInZip(zipos, ps, texts, getResourceFileName(locale),
373
                        false);
374

    
375
            }
376

    
377
            // Next, export the reference locales
378
            for (int i = 0; i < refArray.length; i++) {
379
                texts = getAllTexts(refArray[i]);
380
                putResourceInZip(zipos, ps, texts,
381
                        getResourceFileName(refArray[i]));
382
            }
383

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

    
393
    /**
394
     * Returns the list of reference locales to export, as the union of the
395
     * default reference locales list and the one selected as reference. The
396
     * locale to translate or update is extracted from the list.
397
     */
398
    private Locale[] getReferenceLocalesToExport(Locale locale,
399
            Locale referenceLocale) {
400
        // The reference locales to export are the default ones plus the
401
        // selected by the user.
402
        Set exportRefLocales = new HashSet(referenceLocales.length);
403
        for (int i = 0; i < referenceLocales.length; i++) {
404
            exportRefLocales.add(referenceLocales[i]);
405
        }
406
        exportRefLocales.add(referenceLocale);
407
        exportRefLocales.remove(locale);
408
        Locale[] refArray = (Locale[]) exportRefLocales
409
                .toArray(new Locale[exportRefLocales.size()]);
410
        return refArray;
411
    }
412

    
413
    /**
414
     * Returns all the localized texts and its keys for a locale.
415
     */
416
    private Map getAllTexts(Locale locale) {
417
        return Messages.getAllTexts(locale);
418
    }
419

    
420
    private Map getZipFileNonReferenceLocales(ZipFile zipFile)
421
            throws I18nException {
422
        ZipEntry zipEntry = zipFile.getEntry("locales.csv");
423

    
424
        if (zipEntry == null) {
425
            return null;
426
        }
427

    
428
        Map locales;
429
        try {
430
            InputStream is = zipFile.getInputStream(zipEntry);
431
            BufferedReader reader = new BufferedReader(
432
                    new InputStreamReader(is));
433

    
434
            locales = new HashMap(2);
435
            String line;
436
            while ((line = reader.readLine()) != null) {
437
                // The excepted format is:
438
                // FILENAME,LANGUAGE,COUNTRY,VARIANT,IS_REFERENCE
439
                StringTokenizer st = new StringTokenizer(line, CSV_SEPARATOR,
440
                        true);
441
                // First: locale file name (required)
442
                String fileName = st.nextToken();
443
                if (CSV_SEPARATOR.equals(fileName)) {
444
                    throw new LocaleFileNameRequiredException(line);
445
                }
446
                else {
447
                    // Read the next separator
448
                    st.nextToken();
449
                }
450
                // Second: the locale language (required)
451
                String language = st.nextToken();
452
                if (CSV_SEPARATOR.equals(language)) {
453
                    throw new LocaleLanguageRequiredException(line);
454
                }
455
                else {
456
                    // Read the next separator
457
                    st.nextToken();
458
                }
459
                // Third: the country
460
                String country = st.nextToken();
461
                if (CSV_SEPARATOR.equals(country)) {
462
                    country = null;
463
                }
464
                else {
465
                    // Read the next separator
466
                    st.nextToken();
467
                }
468
                // Fourth: the variant
469
                String variant = st.nextToken();
470
                if (CSV_SEPARATOR.equals(variant)) {
471
                    variant = null;
472
                }
473
                else {
474
                    // Read the next separator
475
                    st.nextToken();
476
                }
477
                // Fifth: is a reference locale?
478
                String refStr = st.nextToken();
479
                if (CSV_SEPARATOR.equals(refStr)) {
480
                    refStr = null;
481
                }
482

    
483
                // Only add non reference locales
484
                if (refStr != null && !"true".equals(refStr.toLowerCase())) {
485
                    // Variant only accepted if country defined
486
                    if (country == null) {
487
                        variant = null;
488
                    }
489
                    country = country == null ? "" : country;
490
                    variant = variant == null ? "" : variant;
491
                    Locale locale = new Locale(language, country, variant);
492

    
493
                    locales.put(fileName, locale);
494
                }
495
            }
496

    
497
            reader.close();
498
            is.close();
499
        } catch (IOException ex) {
500
            throw new ReadCSVLocalesFileException(ex);
501
        }
502

    
503
        return locales;
504
    }
505

    
506
    private void writeZipFileLocales(ZipOutputStream zos, Locale locale,
507
            Locale[] referenceLocales) throws IOException {
508
        ZipEntry zipEntry = new ZipEntry("locales.csv");
509

    
510
        zos.putNextEntry(zipEntry);
511
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos));
512

    
513
        writeLocaleEntry(locale, writer, false);
514
        for (int i = 0; i < referenceLocales.length; i++) {
515
            writeLocaleEntry(referenceLocales[i], writer, true);
516
        }
517

    
518
        writer.flush();
519
        zos.closeEntry();
520
    }
521

    
522
    /**
523
     * Writes the locale entry into a writer.
524
     * 
525
     * @param locale
526
     *            the locale to create the entry for
527
     * @param writer
528
     *            to write to
529
     * @param reference
530
     *            is it is a reference locale or not
531
     * @throws IOException
532
     *             if there is an error creating the locale entry
533
     */
534
    private void writeLocaleEntry(Locale locale, BufferedWriter writer,
535
            boolean reference) throws IOException {
536
        String language = locale.getLanguage();
537
        String country = locale.getCountry();
538
        country = country == null ? "" : country;
539
        String variant = locale.getVariant();
540
        variant = variant == null ? "" : variant;
541

    
542
        writer.write(getResourceFileName(locale));
543
        writer.write(',');
544
        writer.write(language);
545
        writer.write(',');
546
        writer.write(country);
547
        writer.write(',');
548
        writer.write(variant);
549
        writer.write(',');
550
        writer.write(Boolean.toString(reference));
551
        writer.write('\n');
552
    }
553

    
554
    /**
555
     * Returns if a locale is one of the default reference ones.
556
     */
557
    private boolean isReferenceLocale(Locale locale) {
558
        for (int i = 0; i < referenceLocales.length; i++) {
559
            if (referenceLocales[i].equals(locale)) {
560
                return true;
561
            }
562
        }
563
        return false;
564
    }
565

    
566
    /**
567
     * Puts a new resource file into a Jar file.
568
     */
569
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
570
            Map texts, String resourceFileName) throws IOException {
571

    
572
        putResourceInZip(zipos, ps, texts, resourceFileName, true);
573
    }
574

    
575
    /**
576
     * Puts a new resource file into a Jar file.
577
     */
578
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
579
            Map texts, String resourceFileName, boolean withValue)
580
            throws IOException {
581
        // Add ZIP entry for the resource bundle file
582
        zipos.putNextEntry(new ZipEntry(resourceFileName));
583

    
584
        for (Iterator iterator = texts.entrySet().iterator(); iterator
585
                .hasNext();) {
586
            Entry entry = (Entry) iterator.next();
587
            String keyEncoded = escape((String) entry.getKey(), true);
588
            ps.print(keyEncoded);
589
            ps.print("=");
590
            if (withValue) {
591
                String valueEncoded = escape((String) entry.getValue(), false);
592
                ps.println(valueEncoded);
593
            }
594
            else {
595
                ps.println();
596
            }
597
        }
598

    
599
        ps.flush();
600

    
601
        // Close the ZIP entry, the file is complete
602
        zipos.closeEntry();
603
    }
604

    
605
    /**
606
     * Returns the file which contains the translations for a locale.
607
     */
608
    private File getResourceFile(Locale locale) {
609
        return new File(getResourcesFolder(), getResourceFileName(locale));
610
    }
611

    
612
    /**
613
     * Returns the name of the file which contains the translations for a
614
     * locale.
615
     */
616
    private String getResourceFileName(Locale locale) {
617
        StringBuffer fileName = new StringBuffer("text");
618

    
619
        // Spanish without country is the default locale
620
        if (!(isEmpty(locale.getCountry()) && "es".equals(locale.getLanguage()))) {
621
            fileName.append('_').append(locale.getLanguage());
622
        }
623

    
624
        // Add the locale country
625
        if (!isEmpty(locale.getCountry())) {
626
            fileName.append('_').append(locale.getCountry());
627
        }
628

    
629
        // Add the locale variant
630
        if (!isEmpty(locale.getVariant())) {
631
            fileName.append('_').append(locale.getVariant());
632
        }
633

    
634
        fileName.append(".properties");
635
        return fileName.toString();
636
    }
637

    
638
    /**
639
     * Returns the folder where to store the resource bundle files.
640
     */
641
    private File getResourcesFolder() {
642
        return PluginServices.getPluginServices("com.iver.cit.gvsig")
643
                .getPluginDirectory();
644
    }
645

    
646
    /**
647
     * Returns the child XMLEntity with the RegisteredLocales.
648
     */
649
    private XMLEntity getRegisteredLocalesPersistence() {
650
        XMLEntity entity = getI18nPersistence();
651
        XMLEntity child = null;
652
        for (int i = entity.getChildrenCount() - 1; i >= 0; i--) {
653
            XMLEntity tmpchild = entity.getChild(i);
654
            if (tmpchild.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
655
                child = tmpchild;
656
                break;
657
            }
658
        }
659
        return child;
660
    }
661

    
662
    /**
663
     * Returns the I18n Plugin persistence.
664
     */
665
    private XMLEntity getI18nPersistence() {
666
        XMLEntity entity = PluginServices.getPluginServices(I18N_EXTENSION)
667
                .getPersistentXML();
668
        return entity;
669
    }
670

    
671
    /**
672
     * Returns the list of default locales bundled with gvSIG.
673
     */
674
    private Locale[] getDefaultLocales() {
675
        return defaultLocales;
676
    }
677

    
678
    /**
679
     * Stores the list of installed locales into the plugin persistence.
680
     */
681
    private void storeInstalledLocales() {
682
        XMLEntity localesEntity = getRegisteredLocalesPersistence();
683

    
684
        // Remove the previous list of registered languages
685
        if (localesEntity != null) {
686
            XMLEntity i18nPersistence = getI18nPersistence();
687
            for (int i = i18nPersistence.getChildrenCount() - 1; i >= 0; i--) {
688
                XMLEntity child = i18nPersistence.getChild(i);
689
                if (child.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
690
                    i18nPersistence.removeChild(i);
691
                    break;
692
                }
693
            }
694
        }
695

    
696
        // Create the new persistence for the registered languages
697
        localesEntity = new XMLEntity();
698

    
699
        localesEntity.setName(REGISTERED_LOCALES_PERSISTENCE);
700

    
701
        for (Iterator iterator = registeredLocales.iterator(); iterator
702
                .hasNext();) {
703
            Locale locale = (Locale) iterator.next();
704
            XMLEntity localeEntity = new XMLEntity();
705
            localeEntity.setName(locale.getDisplayName());
706
            localeEntity.putProperty(LANGUAGE, locale.getLanguage());
707
            localeEntity.putProperty(COUNTRY, locale.getCountry());
708
            localeEntity.putProperty(VARIANT, locale.getVariant());
709

    
710
            localesEntity.addChild(localeEntity);
711
        }
712

    
713
        getI18nPersistence().addChild(localesEntity);
714
    }
715

    
716
    private String escape(String value, boolean replaceBlanks) {
717
        // First replace non printable characters
718
        if (replaceBlanks) {
719
            value = StringUtilities.replace(value, " ", "\\ ");
720
        }
721
        value = StringUtilities.replace(value, ":", "\\:");
722
        value = StringUtilities.replace(value, "\n", "\\n");
723
        value = StringUtilities.replace(value, "\t", "\\t");
724
        value = StringUtilities.replace(value, "\b", "\\b");
725
        value = StringUtilities.replace(value, "\f", "\\f");
726
        value = StringUtilities.replace(value, "\r", "\\r");
727
        // value = StringUtilities.replace(value, "\\", "\\\\");
728
        // value = StringUtilities.replace(value, "\'", "\\\'");
729
        // value = StringUtilities.replace(value, "\"", "\\\"");
730

    
731
        // Next, encode in raw-unicode-escape
732
        return toRawUnicodeEncoded(value);
733
    }
734

    
735
    private String toRawUnicodeEncoded(String value) {
736
        StringBuffer sb = new StringBuffer();
737
        for (int i = 0; i < value.length(); i++) {
738
            char c = value.charAt(i);
739
            if (c <= 0x80) {
740
                sb.append(c);
741
            }
742
            else {
743
                sb.append("\\u");
744
                String hexValue = Integer.toHexString((int) c);
745
                // Append 0 if the hex value has less than 4 digits
746
                for (int j = hexValue.length(); j < 4; j++) {
747
                    sb.append('0');
748
                }
749
                sb.append(hexValue);
750
            }
751
        }
752
        return sb.toString();
753
    }
754
}