Statistics
| Revision:

root / trunk / extensions / extI18n / src / org / gvsig / i18n / impl / I18nManagerImpl.java @ 28781

History | View | Annotate | Download (22.7 KB)

1 25963 cordinyana
/* 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 26324 cordinyana
import java.security.AccessController;
31 25963 cordinyana
import java.util.*;
32
import java.util.Map.Entry;
33 26430 cordinyana
import java.util.zip.*;
34 25963 cordinyana
35 26048 cordinyana
import org.gvsig.i18n.*;
36 25963 cordinyana
37 26324 cordinyana
import sun.security.action.GetPropertyAction;
38
39 25963 cordinyana
import com.iver.andami.Launcher;
40
import com.iver.andami.PluginServices;
41
import com.iver.andami.config.generate.AndamiConfig;
42 26048 cordinyana
import com.iver.utiles.StringUtilities;
43 25963 cordinyana
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 26431 cordinyana
    private static final String LOCALES_FILE_NAME = "locales.csv";
54
55 26430 cordinyana
    private static final String CSV_SEPARATOR = ",";
56 25963 cordinyana
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 28781 cordinyana
            new Locale("ru"), // Russian
93
            new Locale("el"), // Greek
94
            new Locale("ro"), // Romanian
95
            new Locale("pl"), // Polish
96 25963 cordinyana
    };
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 28461 cordinyana
            } else {
136 25963 cordinyana
                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 26048 cordinyana
    public void uninstallLocale(Locale locale) throws I18nException {
155 25963 cordinyana
        if (getCurrentLocale().equals(locale) || isReferenceLocale(locale)) {
156 26048 cordinyana
            throw new UninstallLocaleException(locale);
157 25963 cordinyana
        }
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 28180 cordinyana
            name.append(" - ");
183 25963 cordinyana
            name.append(locale.getDisplayCountry(displayLocale));
184
        }
185
186
        if (!isEmpty(locale.getVariant())) {
187 28180 cordinyana
            name.append(" - ");
188 25963 cordinyana
            name.append(locale.getDisplayVariant(displayLocale));
189
        }
190
191 28461 cordinyana
        name.append(" (").append(locale.toString()).append(")");
192
193 25963 cordinyana
        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 28781 cordinyana
            // displayName = Messages.getText("__valenciano");
217
            // if ("__valenciano".equals(displayName)) {
218
            // displayName = Messages.getText("__catalan");
219
            // }
220
            displayName = "Valenci?";
221 28461 cordinyana
        } else {
222 25963 cordinyana
            displayName = locale.getDisplayLanguage(displayLocale);
223
        }
224
225
        return capitalize(displayName);
226
    }
227
228
    public Locale getCurrentLocale() {
229
        return Locale.getDefault();
230
    }
231 26430 cordinyana
232 26324 cordinyana
    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 28461 cordinyana
            } else {
246 26324 cordinyana
                country = region;
247
                variant = "";
248
            }
249 28461 cordinyana
        } else {
250 26324 cordinyana
            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 25963 cordinyana
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 26048 cordinyana
    public Locale[] installLocales(File importFile) throws I18nException {
266 25963 cordinyana
        List importLocales = new ArrayList();
267
268
        try {
269 26430 cordinyana
            ZipFile zipFile = new ZipFile(importFile);
270 25963 cordinyana
271 26430 cordinyana
            Map locales = getZipFileNonReferenceLocales(zipFile);
272 28461 cordinyana
273 26710 cordinyana
            if (locales == null || locales.size() == 0) {
274
                return null;
275
            }
276 25963 cordinyana
277 26430 cordinyana
            for (Iterator iterator = locales.entrySet().iterator(); iterator
278
                    .hasNext();) {
279
                Entry entry = (Entry) iterator.next();
280 25963 cordinyana
281 26430 cordinyana
                String fileName = (String) entry.getKey();
282
                Locale locale = (Locale) entry.getValue();
283
                importLocales.add(locale);
284 25963 cordinyana
285 26430 cordinyana
                // 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 25963 cordinyana
292 26430 cordinyana
                // 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 25963 cordinyana
                }
307 26430 cordinyana
                writer.flush();
308
                writer.close();
309
                fileWriter.close();
310
                reader.close();
311
                is.close();
312 25963 cordinyana
            }
313
314 26048 cordinyana
        } catch (Exception ex) {
315
            throw new InstallLocalesException(importFile, ex);
316 25963 cordinyana
        }
317
318
        return (Locale[]) importLocales
319
                .toArray(new Locale[importLocales.size()]);
320
    }
321
322
    public void exportLocaleForUpdate(Locale locale, Locale referenceLocale,
323 26048 cordinyana
            File exportFile) throws I18nException {
324 25963 cordinyana
325 28461 cordinyana
        exportLocalesForUpdate(new Locale[] { locale }, referenceLocale,
326
                exportFile);
327 26430 cordinyana
    }
328 25963 cordinyana
329 28461 cordinyana
    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 26430 cordinyana
    public void exportLocaleForTranslation(Locale locale,
337
            Locale referenceLocale, File exportFile) throws I18nException {
338 28461 cordinyana
339
        exportLocaleForTranslation(locale, new Locale[] { referenceLocale },
340
                exportFile);
341
    }
342 26430 cordinyana
343 28461 cordinyana
    public void exportLocaleForTranslation(Locale locale,
344
            Locale[] referenceLocales, File exportFile) throws I18nException {
345
346
        exportLocale(new Locale[] { locale }, referenceLocales, exportFile,
347
                false);
348 26430 cordinyana
    }
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 28461 cordinyana
    private void exportLocale(Locale[] locales, Locale[] referenceLocales,
363 26430 cordinyana
            File exportFile, boolean update) throws I18nException {
364
365 28461 cordinyana
        Locale[] refArray = getReferenceLocalesToExport(locales,
366
                referenceLocales);
367 26430 cordinyana
368 25963 cordinyana
        try {
369
            FileOutputStream fos = new FileOutputStream(exportFile);
370 26430 cordinyana
            ZipOutputStream zipos = new ZipOutputStream(fos);
371 25963 cordinyana
372 26430 cordinyana
            // Create the index file
373 28461 cordinyana
            writeZipFileLocales(zipos, locales, refArray);
374 26430 cordinyana
375
            PrintStream ps = new PrintStream(zipos);
376 25963 cordinyana
            Map texts = null;
377
378 26430 cordinyana
            if (update) {
379 28461 cordinyana
                // 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 26430 cordinyana
            }
399
400
            // Next, export the reference locales
401 28461 cordinyana
            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 25963 cordinyana
            }
408
409
            ps.flush();
410
            ps.close();
411 26430 cordinyana
            zipos.close();
412 25963 cordinyana
            fos.close();
413 26048 cordinyana
        } catch (IOException ex) {
414 28461 cordinyana
            throw new ExportLocaleException(locales, ex);
415 25963 cordinyana
        }
416
    }
417
418 26430 cordinyana
    /**
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 28461 cordinyana
     * locales to translate or update are extracted from the list.
422 26430 cordinyana
     */
423 28461 cordinyana
    private Locale[] getReferenceLocalesToExport(Locale[] locales,
424
            Locale[] referenceLocalesSelected) {
425 26430 cordinyana
        // The reference locales to export are the default ones plus the
426
        // selected by the user.
427
        Set exportRefLocales = new HashSet(referenceLocales.length);
428 25963 cordinyana
        for (int i = 0; i < referenceLocales.length; i++) {
429 26430 cordinyana
            exportRefLocales.add(referenceLocales[i]);
430 25963 cordinyana
        }
431 28461 cordinyana
        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 26430 cordinyana
        Locale[] refArray = (Locale[]) exportRefLocales
442
                .toArray(new Locale[exportRefLocales.size()]);
443
        return refArray;
444
    }
445 25963 cordinyana
446 26430 cordinyana
    /**
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 26431 cordinyana
        ZipEntry zipEntry = zipFile.getEntry(LOCALES_FILE_NAME);
456 26430 cordinyana
457
        if (zipEntry == null) {
458
            return null;
459
        }
460
461
        Map locales;
462 25963 cordinyana
        try {
463 26430 cordinyana
            InputStream is = zipFile.getInputStream(zipEntry);
464
            BufferedReader reader = new BufferedReader(
465
                    new InputStreamReader(is));
466 25963 cordinyana
467 26430 cordinyana
            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 28461 cordinyana
                } else {
479 26430 cordinyana
                    // 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 28461 cordinyana
                } else {
487 26430 cordinyana
                    // 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 28461 cordinyana
                } else {
495 26430 cordinyana
                    // 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 28461 cordinyana
                } else {
503 26430 cordinyana
                    // 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 25963 cordinyana
512 26430 cordinyana
                // 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 25963 cordinyana
            }
525
526 26430 cordinyana
            reader.close();
527
            is.close();
528 26048 cordinyana
        } catch (IOException ex) {
529 26430 cordinyana
            throw new ReadCSVLocalesFileException(ex);
530 25963 cordinyana
        }
531
532 26430 cordinyana
        return locales;
533 25963 cordinyana
    }
534
535 28461 cordinyana
    private void writeZipFileLocales(ZipOutputStream zos, Locale[] locales,
536 26430 cordinyana
            Locale[] referenceLocales) throws IOException {
537 26431 cordinyana
        ZipEntry zipEntry = new ZipEntry(LOCALES_FILE_NAME);
538 25963 cordinyana
539 26430 cordinyana
        zos.putNextEntry(zipEntry);
540
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos));
541
542 28461 cordinyana
        if (locales != null) {
543
            for (int i = 0; i < locales.length; i++) {
544
                writeLocaleEntry(locales[i], writer, false);
545
            }
546 26430 cordinyana
        }
547 28461 cordinyana
        if (referenceLocales != null) {
548
            for (int i = 0; i < referenceLocales.length; i++) {
549
                writeLocaleEntry(referenceLocales[i], writer, true);
550
            }
551
        }
552 26430 cordinyana
553
        writer.flush();
554
        zos.closeEntry();
555 25963 cordinyana
    }
556
557
    /**
558 26430 cordinyana
     * 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 25963 cordinyana
     */
569 26430 cordinyana
    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 25963 cordinyana
    }
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 26430 cordinyana
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
605 25963 cordinyana
            Map texts, String resourceFileName) throws IOException {
606
607 26430 cordinyana
        putResourceInZip(zipos, ps, texts, resourceFileName, true);
608 25963 cordinyana
    }
609
610
    /**
611
     * Puts a new resource file into a Jar file.
612
     */
613 26430 cordinyana
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
614 25963 cordinyana
            Map texts, String resourceFileName, boolean withValue)
615
            throws IOException {
616
        // Add ZIP entry for the resource bundle file
617 26430 cordinyana
        zipos.putNextEntry(new ZipEntry(resourceFileName));
618 25963 cordinyana
619
        for (Iterator iterator = texts.entrySet().iterator(); iterator
620
                .hasNext();) {
621
            Entry entry = (Entry) iterator.next();
622 26048 cordinyana
            String keyEncoded = escape((String) entry.getKey(), true);
623
            ps.print(keyEncoded);
624 25963 cordinyana
            ps.print("=");
625
            if (withValue) {
626 26048 cordinyana
                String valueEncoded = escape((String) entry.getValue(), false);
627
                ps.println(valueEncoded);
628 28461 cordinyana
            } else {
629 25963 cordinyana
                ps.println();
630
            }
631
        }
632
633
        ps.flush();
634
635
        // Close the ZIP entry, the file is complete
636 26430 cordinyana
        zipos.closeEntry();
637 25963 cordinyana
    }
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 26048 cordinyana
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 26065 cordinyana
        // value = StringUtilities.replace(value, "\'", "\\\'");
763
        // value = StringUtilities.replace(value, "\"", "\\\"");
764 26048 cordinyana
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 28461 cordinyana
            } else {
776 26048 cordinyana
                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 25963 cordinyana
}