Statistics
| Revision:

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

History | View | Annotate | Download (24.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 29906 vcaballero
 *
6 25963 cordinyana
 * 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 29906 vcaballero
 *
11 25963 cordinyana
 * 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 29906 vcaballero
 *
16 25963 cordinyana
 * 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 29906 vcaballero
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 25963 cordinyana
 * MA  02110-1301, USA.
20 29906 vcaballero
 *
21 25963 cordinyana
 */
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 38062 fpuga
import java.io.BufferedReader;
30
import java.io.BufferedWriter;
31
import java.io.File;
32
import java.io.FileOutputStream;
33
import java.io.FileWriter;
34
import java.io.IOException;
35
import java.io.InputStream;
36
import java.io.InputStreamReader;
37
import java.io.OutputStreamWriter;
38
import java.io.PrintStream;
39 26324 cordinyana
import java.security.AccessController;
40 38062 fpuga
import java.util.ArrayList;
41
import java.util.HashMap;
42
import java.util.HashSet;
43
import java.util.Iterator;
44
import java.util.LinkedHashSet;
45
import java.util.List;
46
import java.util.Locale;
47
import java.util.Map;
48 25963 cordinyana
import java.util.Map.Entry;
49 38062 fpuga
import java.util.Set;
50
import java.util.StringTokenizer;
51
import java.util.zip.ZipEntry;
52
import java.util.zip.ZipFile;
53
import java.util.zip.ZipOutputStream;
54 25963 cordinyana
55 38062 fpuga
import org.gvsig.i18n.I18nException;
56
import org.gvsig.i18n.I18nManager;
57
import org.gvsig.i18n.Messages;
58 25963 cordinyana
59 26324 cordinyana
import sun.security.action.GetPropertyAction;
60
61 25963 cordinyana
import com.iver.andami.Launcher;
62
import com.iver.andami.PluginServices;
63
import com.iver.andami.config.generate.AndamiConfig;
64 26048 cordinyana
import com.iver.utiles.StringUtilities;
65 25963 cordinyana
import com.iver.utiles.XMLEntity;
66
67
/**
68
 * Implementation of the I18nManager interface.
69 29906 vcaballero
 *
70 25963 cordinyana
 * @author <a href="mailto:dcervera@disid.com">David Cervera</a>
71
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
72
 */
73
public class I18nManagerImpl implements I18nManager {
74
75 26431 cordinyana
    private static final String LOCALES_FILE_NAME = "locales.csv";
76
77 26430 cordinyana
    private static final String CSV_SEPARATOR = ",";
78 25963 cordinyana
79
    private static final String I18N_EXTENSION = "org.gvsig.i18n";
80
81
    private static final String VARIANT = "variant";
82
83
    private static final String COUNTRY = "country";
84
85
    private static final String LANGUAGE = "language";
86
87
    private static final String REGISTERED_LOCALES_PERSISTENCE = "RegisteredLocales";
88
89
    private static final I18nManager DEFAULT = new I18nManagerImpl();
90
91
    private Set registeredLocales;
92
93
    /**
94
     * The list of default reference locales. The last one will be used to get
95
     * all the keys when translating to a new locale.
96
     */
97
    private Locale[] referenceLocales = new Locale[] { ENGLISH, SPANISH };
98
99
    private Locale[] defaultLocales = new Locale[] {
100
    // Default supported locales
101 29208 cordinyana
            SPANISH, // Spanish
102
            ENGLISH, // English
103 29906 vcaballero
            new Locale("en","US"), // English US
104 25963 cordinyana
            new Locale("ca"), // Catalan
105 29208 cordinyana
            new Locale("gl"), // Galician
106
            new Locale("eu"), // Basque
107
            new Locale("de"), // German
108 25963 cordinyana
            new Locale("cs"), // Czech
109
            new Locale("fr"), // French
110
            new Locale("it"), // Italian
111
            new Locale("pl"), // Polish
112
            new Locale("pt"), // Portuguese
113 29208 cordinyana
            new Locale("pt", "BR"), // Portuguese Brazil
114 25963 cordinyana
            new Locale("ro"), // Romanian
115
            new Locale("zh"), // Chinese
116 28781 cordinyana
            new Locale("ru"), // Russian
117
            new Locale("el"), // Greek
118
            new Locale("pl"), // Polish
119 30488 vcaballero
            new Locale("tr"), // Turkish
120
            new Locale("sr"), // Serbio
121 38062 fpuga
            new Locale("sw"), // Swahili
122
            new Locale("km") // Khmer
123 29906 vcaballero
        };
124 25963 cordinyana
125
    /**
126
     * Returns the unique instance of the I18nManager.
127 29906 vcaballero
     *
128 25963 cordinyana
     * @return the unique instance
129
     */
130
    public static I18nManager getInstance() {
131
        return DEFAULT;
132
    }
133
134
    public static String capitalize(String text) {
135
        // Convert the first letter to uppercase
136
        String capitalLetter = new String(new char[] { Character
137
                .toUpperCase(text.charAt(0)) });
138
        return capitalLetter.concat(text.substring(1));
139
    }
140
141
    /**
142
     * Empty constructor.
143
     */
144
    I18nManagerImpl() {
145
    }
146
147
    public Locale[] getInstalledLocales() {
148
        if (registeredLocales == null) {
149
150
            XMLEntity child = getRegisteredLocalesPersistence();
151
152
            // If the list of registered locales is not already persisted,
153
            // this should be the first time gvSIG is run with the I18nPlugin
154
            // so we will take the list of default locales
155
            if (child == null) {
156
                Locale[] defaultLocales = getDefaultLocales();
157 29208 cordinyana
                registeredLocales = new LinkedHashSet(defaultLocales.length);
158 25963 cordinyana
                for (int i = 0; i < defaultLocales.length; i++) {
159
                    registeredLocales.add(defaultLocales[i]);
160
                }
161
                storeInstalledLocales();
162 28461 cordinyana
            } else {
163 25963 cordinyana
                XMLEntity localesEntity = getRegisteredLocalesPersistence();
164 29208 cordinyana
                registeredLocales = new LinkedHashSet(localesEntity
165 25963 cordinyana
                        .getChildrenCount());
166
                for (int i = 0; i < localesEntity.getChildrenCount(); i++) {
167
                    XMLEntity localeEntity = localesEntity.getChild(i);
168
                    String language = localeEntity.getStringProperty(LANGUAGE);
169
                    String country = localeEntity.getStringProperty(COUNTRY);
170
                    String variant = localeEntity.getStringProperty(VARIANT);
171
                    Locale locale = new Locale(language, country, variant);
172
                    registeredLocales.add(locale);
173
                }
174
            }
175
        }
176
177
        return (Locale[]) registeredLocales
178
                .toArray(new Locale[registeredLocales.size()]);
179
    }
180
181 26048 cordinyana
    public void uninstallLocale(Locale locale) throws I18nException {
182 25963 cordinyana
        if (getCurrentLocale().equals(locale) || isReferenceLocale(locale)) {
183 26048 cordinyana
            throw new UninstallLocaleException(locale);
184 25963 cordinyana
        }
185
186
        if (registeredLocales.remove(locale)) {
187
            // Remove from the configured locale list
188
            storeInstalledLocales();
189
190
            // Remove the resource bundle file
191
            File bundleFile = new File(getResourcesFolder(),
192
                    getResourceFileName(locale));
193
194
            if (bundleFile.exists()) {
195
                bundleFile.delete();
196
            }
197
        }
198
    }
199
200
    public String getDisplayName(Locale locale) {
201
        return getDisplayName(locale, locale);
202
    }
203
204
    public String getDisplayName(Locale locale, Locale displayLocale) {
205
        StringBuffer name = new StringBuffer(getLanguageDisplayName(locale,
206
                displayLocale));
207
208
        if (!isEmpty(locale.getCountry())) {
209 28180 cordinyana
            name.append(" - ");
210 25963 cordinyana
            name.append(locale.getDisplayCountry(displayLocale));
211
        }
212
213
        if (!isEmpty(locale.getVariant())) {
214 28180 cordinyana
            name.append(" - ");
215 25963 cordinyana
            name.append(locale.getDisplayVariant(displayLocale));
216
        }
217
218 28461 cordinyana
        name.append(" (").append(locale.toString()).append(")");
219
220 25963 cordinyana
        return name.toString();
221
    }
222
223
    private boolean isEmpty(String text) {
224
        return text == null || text.trim().length() == 0;
225
    }
226
227
    public String getLanguageDisplayName(Locale locale) {
228
        return getLanguageDisplayName(locale, locale);
229
    }
230
231
    public String getLanguageDisplayName(Locale locale, Locale displayLocale) {
232
233
        String displayName;
234
235
        // Correction for the Basque language display name,
236
        // show it in Basque, not in Spanish
237
        if ("eu".equals(locale.getLanguage())
238
                && "vascuence".equals(locale.getDisplayLanguage())) {
239
            displayName = "Euskera";
240
        }
241
        // Patch for Valencian/Catalan
242
        else if ("ca".equals(locale.getLanguage())) {
243 28781 cordinyana
            // displayName = Messages.getText("__valenciano");
244
            // if ("__valenciano".equals(displayName)) {
245
            // displayName = Messages.getText("__catalan");
246
            // }
247
            displayName = "Valenci?";
248 38062 fpuga
        }
249
        // Correction for the Galician language display name.
250
        else if ("gl".equals(locale.getLanguage())
251 35483 jestevez
                && "gallegan".equalsIgnoreCase(locale
252
                        .getDisplayLanguage(displayLocale))) {
253
            displayName = "Galego";
254 28461 cordinyana
        } else {
255 25963 cordinyana
            displayName = locale.getDisplayLanguage(displayLocale);
256
        }
257
258
        return capitalize(displayName);
259
    }
260
261
    public Locale getCurrentLocale() {
262
        return Locale.getDefault();
263
    }
264 26430 cordinyana
265 26324 cordinyana
    public Locale getDefaultSystemLocale() {
266
        String language, region, country, variant;
267
        language = (String) AccessController
268
                .doPrivileged(new GetPropertyAction("user.language", "en"));
269
        // for compatibility, check for old user.region property
270
        region = (String) AccessController.doPrivileged(new GetPropertyAction(
271
                "user.region"));
272
        if (region != null) {
273
            // region can be of form country, country_variant, or _variant
274
            int i = region.indexOf('_');
275
            if (i >= 0) {
276
                country = region.substring(0, i);
277
                variant = region.substring(i + 1);
278 28461 cordinyana
            } else {
279 26324 cordinyana
                country = region;
280
                variant = "";
281
            }
282 28461 cordinyana
        } else {
283 26324 cordinyana
            country = (String) AccessController
284
                    .doPrivileged(new GetPropertyAction("user.country", ""));
285
            variant = (String) AccessController
286
                    .doPrivileged(new GetPropertyAction("user.variant", ""));
287
        }
288
        return new Locale(language, country, variant);
289
    }
290 25963 cordinyana
291
    public void setCurrentLocale(Locale locale) {
292
        AndamiConfig config = Launcher.getAndamiConfig();
293
        config.setLocaleLanguage(locale.getLanguage());
294
        config.setLocaleCountry(locale.getCountry());
295
        config.setLocaleVariant(locale.getVariant());
296
    }
297
298 26048 cordinyana
    public Locale[] installLocales(File importFile) throws I18nException {
299 25963 cordinyana
        List importLocales = new ArrayList();
300
301
        try {
302 26430 cordinyana
            ZipFile zipFile = new ZipFile(importFile);
303 25963 cordinyana
304 26430 cordinyana
            Map locales = getZipFileNonReferenceLocales(zipFile);
305 28461 cordinyana
306 26710 cordinyana
            if (locales == null || locales.size() == 0) {
307
                return null;
308
            }
309 25963 cordinyana
310 26430 cordinyana
            for (Iterator iterator = locales.entrySet().iterator(); iterator
311
                    .hasNext();) {
312
                Entry entry = (Entry) iterator.next();
313 25963 cordinyana
314 26430 cordinyana
                String fileName = (String) entry.getKey();
315
                Locale locale = (Locale) entry.getValue();
316
                importLocales.add(locale);
317 25963 cordinyana
318 26430 cordinyana
                // Add the locale to the list of installed ones, if it
319
                // is new, otherwise, update the texts.
320
                if (!registeredLocales.contains(locale)) {
321
                    registeredLocales.add(locale);
322
                    storeInstalledLocales();
323
                }
324 25963 cordinyana
325 26430 cordinyana
                // Replace the old bundle with the new one
326
                ZipEntry zipEntry = zipFile.getEntry(fileName);
327
                InputStream is = zipFile.getInputStream(zipEntry);
328
                BufferedReader reader = new BufferedReader(
329
                        new InputStreamReader(is));
330
331
                File bundleFile = getResourceFile(locale);
332
                FileWriter fileWriter = new FileWriter(bundleFile);
333
                BufferedWriter writer = new BufferedWriter(fileWriter);
334
335
                String line;
336
                while ((line = reader.readLine()) != null) {
337
                    writer.write(line);
338
                    writer.write('\n');
339 25963 cordinyana
                }
340 26430 cordinyana
                writer.flush();
341
                writer.close();
342
                fileWriter.close();
343
                reader.close();
344
                is.close();
345 25963 cordinyana
            }
346
347 26048 cordinyana
        } catch (Exception ex) {
348
            throw new InstallLocalesException(importFile, ex);
349 25963 cordinyana
        }
350
351
        return (Locale[]) importLocales
352
                .toArray(new Locale[importLocales.size()]);
353
    }
354
355
    public void exportLocaleForUpdate(Locale locale, Locale referenceLocale,
356 26048 cordinyana
            File exportFile) throws I18nException {
357 25963 cordinyana
358 28461 cordinyana
        exportLocalesForUpdate(new Locale[] { locale }, referenceLocale,
359
                exportFile);
360 26430 cordinyana
    }
361 25963 cordinyana
362 28461 cordinyana
    public void exportLocalesForUpdate(Locale[] locales,
363
            Locale referenceLocale, File exportFile) throws I18nException {
364
365
        exportLocale(locales, new Locale[] { referenceLocale }, exportFile,
366
                true);
367
    }
368 29906 vcaballero
369 26430 cordinyana
    public void exportLocaleForTranslation(Locale locale,
370
            Locale referenceLocale, File exportFile) throws I18nException {
371 29906 vcaballero
372 28461 cordinyana
        exportLocaleForTranslation(locale, new Locale[] { referenceLocale },
373
                exportFile);
374
    }
375 26430 cordinyana
376 28461 cordinyana
    public void exportLocaleForTranslation(Locale locale,
377
            Locale[] referenceLocales, File exportFile) throws I18nException {
378
379
        exportLocale(new Locale[] { locale }, referenceLocales, exportFile,
380
                false);
381 26430 cordinyana
    }
382
383
    public Locale[] getReferenceLocales() {
384
        return referenceLocales;
385
    }
386
387
    public void setReferenceLocales(Locale[] referenceLocales) {
388
        this.referenceLocales = referenceLocales;
389
    }
390
391
    public void setDefaultLocales(Locale[] defaultLocales) {
392
        this.defaultLocales = defaultLocales;
393
    }
394
395 28461 cordinyana
    private void exportLocale(Locale[] locales, Locale[] referenceLocales,
396 26430 cordinyana
            File exportFile, boolean update) throws I18nException {
397
398 28461 cordinyana
        Locale[] refArray = getReferenceLocalesToExport(locales,
399
                referenceLocales);
400 26430 cordinyana
401 32338 cordinyana
        Set allReferenceKeys = new HashSet();
402
        Map referenceTexts = new HashMap(refArray.length);
403
        for (int i = 0; i < refArray.length; i++) {
404
            Map texts = getAllTexts(refArray[i]);
405
            referenceTexts.put(refArray[i], texts);
406
            allReferenceKeys.addAll(texts.keySet());
407
        }
408
409 25963 cordinyana
        try {
410
            FileOutputStream fos = new FileOutputStream(exportFile);
411 26430 cordinyana
            ZipOutputStream zipos = new ZipOutputStream(fos);
412 25963 cordinyana
413 32338 cordinyana
                // Create the index file
414 28461 cordinyana
            writeZipFileLocales(zipos, locales, refArray);
415 26430 cordinyana
416 32338 cordinyana
                PrintStream ps = new PrintStream(zipos);
417 25963 cordinyana
            Map texts = null;
418
419 32338 cordinyana
                if (update) {
420 28461 cordinyana
                // First, export the locales to update
421
                if (locales != null) {
422
                    for (int i = 0; i < locales.length; i++) {
423
                        texts = getAllTexts(locales[i]);
424 32338 cordinyana
                        addPendingKeys(texts, allReferenceKeys);
425 28461 cordinyana
                        putResourceInZip(zipos, ps, texts,
426
                                getResourceFileName(locales[i]));
427
                    }
428
                }
429
            } else { // translate
430
                // First, export the locales to translate, taking the keys from
431
                // the reference locales, but without values
432
                if (locales != null) {
433
                    for (int i = 0; i < locales.length; i++) {
434 32338 cordinyana
                        putResourceInZip(zipos, ps, allReferenceKeys,
435
                                getResourceFileName(locales[i]));
436 28461 cordinyana
                    }
437
                }
438 32338 cordinyana
                }
439 26430 cordinyana
440
            // Next, export the reference locales
441 28461 cordinyana
            if (refArray != null) {
442
                for (int i = 0; i < refArray.length; i++) {
443
                    texts = getAllTexts(refArray[i]);
444
                    putResourceInZip(zipos, ps, texts,
445
                            getResourceFileName(refArray[i]));
446
                }
447 32338 cordinyana
                }
448 25963 cordinyana
449
            ps.flush();
450
            ps.close();
451 26430 cordinyana
            zipos.close();
452 25963 cordinyana
            fos.close();
453 26048 cordinyana
        } catch (IOException ex) {
454 28461 cordinyana
            throw new ExportLocaleException(locales, ex);
455 25963 cordinyana
        }
456
    }
457
458 26430 cordinyana
    /**
459 32338 cordinyana
     * Adds the keys of the set to the map that aren't still contained in it
460
     * with a related empty String.
461 38062 fpuga
     *
462 32338 cordinyana
     * @param texts
463
     *            the map to complete with the keys
464
     * @param allReferenceKeys
465
     *            the complete key set
466
     */
467
    private void addPendingKeys(Map texts, Set allReferenceKeys) {
468
        for (Iterator iterator = allReferenceKeys.iterator(); iterator
469
                .hasNext();) {
470
            Object key = (Object) iterator.next();
471
            if (!texts.containsKey(key)) {
472
                texts.put(key, "");
473
            }
474
        }
475
    }
476
477
    /**
478 26430 cordinyana
     * Returns the list of reference locales to export, as the union of the
479
     * default reference locales list and the one selected as reference. The
480 28461 cordinyana
     * locales to translate or update are extracted from the list.
481 26430 cordinyana
     */
482 28461 cordinyana
    private Locale[] getReferenceLocalesToExport(Locale[] locales,
483
            Locale[] referenceLocalesSelected) {
484 26430 cordinyana
        // The reference locales to export are the default ones plus the
485
        // selected by the user.
486
        Set exportRefLocales = new HashSet(referenceLocales.length);
487 25963 cordinyana
        for (int i = 0; i < referenceLocales.length; i++) {
488 26430 cordinyana
            exportRefLocales.add(referenceLocales[i]);
489 25963 cordinyana
        }
490 28461 cordinyana
        if (referenceLocalesSelected != null) {
491
            for (int i = 0; i < referenceLocalesSelected.length; i++) {
492
                exportRefLocales.add(referenceLocalesSelected[i]);
493
            }
494
        }
495
        if (locales != null) {
496
            for (int i = 0; i < locales.length; i++) {
497
                exportRefLocales.remove(locales[i]);
498
            }
499
        }
500 26430 cordinyana
        Locale[] refArray = (Locale[]) exportRefLocales
501
                .toArray(new Locale[exportRefLocales.size()]);
502
        return refArray;
503
    }
504 25963 cordinyana
505 26430 cordinyana
    /**
506
     * Returns all the localized texts and its keys for a locale.
507
     */
508
    private Map getAllTexts(Locale locale) {
509
        return Messages.getAllTexts(locale);
510
    }
511
512
    private Map getZipFileNonReferenceLocales(ZipFile zipFile)
513
            throws I18nException {
514 26431 cordinyana
        ZipEntry zipEntry = zipFile.getEntry(LOCALES_FILE_NAME);
515 26430 cordinyana
516
        if (zipEntry == null) {
517
            return null;
518
        }
519
520
        Map locales;
521 25963 cordinyana
        try {
522 26430 cordinyana
            InputStream is = zipFile.getInputStream(zipEntry);
523
            BufferedReader reader = new BufferedReader(
524
                    new InputStreamReader(is));
525 25963 cordinyana
526 26430 cordinyana
            locales = new HashMap(2);
527
            String line;
528
            while ((line = reader.readLine()) != null) {
529
                // The excepted format is:
530
                // FILENAME,LANGUAGE,COUNTRY,VARIANT,IS_REFERENCE
531
                StringTokenizer st = new StringTokenizer(line, CSV_SEPARATOR,
532
                        true);
533
                // First: locale file name (required)
534
                String fileName = st.nextToken();
535
                if (CSV_SEPARATOR.equals(fileName)) {
536
                    throw new LocaleFileNameRequiredException(line);
537 28461 cordinyana
                } else {
538 26430 cordinyana
                    // Read the next separator
539
                    st.nextToken();
540
                }
541
                // Second: the locale language (required)
542
                String language = st.nextToken();
543
                if (CSV_SEPARATOR.equals(language)) {
544
                    throw new LocaleLanguageRequiredException(line);
545 28461 cordinyana
                } else {
546 26430 cordinyana
                    // Read the next separator
547
                    st.nextToken();
548
                }
549
                // Third: the country
550
                String country = st.nextToken();
551
                if (CSV_SEPARATOR.equals(country)) {
552
                    country = null;
553 28461 cordinyana
                } else {
554 26430 cordinyana
                    // Read the next separator
555
                    st.nextToken();
556
                }
557
                // Fourth: the variant
558
                String variant = st.nextToken();
559
                if (CSV_SEPARATOR.equals(variant)) {
560
                    variant = null;
561 28461 cordinyana
                } else {
562 26430 cordinyana
                    // Read the next separator
563
                    st.nextToken();
564
                }
565
                // Fifth: is a reference locale?
566
                String refStr = st.nextToken();
567
                if (CSV_SEPARATOR.equals(refStr)) {
568
                    refStr = null;
569
                }
570 25963 cordinyana
571 26430 cordinyana
                // Only add non reference locales
572
                if (refStr != null && !"true".equals(refStr.toLowerCase())) {
573
                    // Variant only accepted if country defined
574
                    if (country == null) {
575
                        variant = null;
576
                    }
577
                    country = country == null ? "" : country;
578
                    variant = variant == null ? "" : variant;
579
                    Locale locale = new Locale(language, country, variant);
580
581
                    locales.put(fileName, locale);
582
                }
583 25963 cordinyana
            }
584
585 26430 cordinyana
            reader.close();
586
            is.close();
587 26048 cordinyana
        } catch (IOException ex) {
588 26430 cordinyana
            throw new ReadCSVLocalesFileException(ex);
589 25963 cordinyana
        }
590
591 26430 cordinyana
        return locales;
592 25963 cordinyana
    }
593
594 28461 cordinyana
    private void writeZipFileLocales(ZipOutputStream zos, Locale[] locales,
595 26430 cordinyana
            Locale[] referenceLocales) throws IOException {
596 26431 cordinyana
        ZipEntry zipEntry = new ZipEntry(LOCALES_FILE_NAME);
597 25963 cordinyana
598 26430 cordinyana
        zos.putNextEntry(zipEntry);
599
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos));
600
601 28461 cordinyana
        if (locales != null) {
602
            for (int i = 0; i < locales.length; i++) {
603
                writeLocaleEntry(locales[i], writer, false);
604
            }
605 26430 cordinyana
        }
606 28461 cordinyana
        if (referenceLocales != null) {
607
            for (int i = 0; i < referenceLocales.length; i++) {
608
                writeLocaleEntry(referenceLocales[i], writer, true);
609
            }
610
        }
611 26430 cordinyana
612
        writer.flush();
613
        zos.closeEntry();
614 25963 cordinyana
    }
615
616
    /**
617 26430 cordinyana
     * Writes the locale entry into a writer.
618 29906 vcaballero
     *
619 26430 cordinyana
     * @param locale
620
     *            the locale to create the entry for
621
     * @param writer
622
     *            to write to
623
     * @param reference
624
     *            is it is a reference locale or not
625
     * @throws IOException
626
     *             if there is an error creating the locale entry
627 25963 cordinyana
     */
628 26430 cordinyana
    private void writeLocaleEntry(Locale locale, BufferedWriter writer,
629
            boolean reference) throws IOException {
630
        String language = locale.getLanguage();
631
        String country = locale.getCountry();
632
        country = country == null ? "" : country;
633
        String variant = locale.getVariant();
634
        variant = variant == null ? "" : variant;
635
636
        writer.write(getResourceFileName(locale));
637
        writer.write(',');
638
        writer.write(language);
639
        writer.write(',');
640
        writer.write(country);
641
        writer.write(',');
642
        writer.write(variant);
643
        writer.write(',');
644
        writer.write(Boolean.toString(reference));
645
        writer.write('\n');
646 25963 cordinyana
    }
647
648
    /**
649
     * Returns if a locale is one of the default reference ones.
650
     */
651
    private boolean isReferenceLocale(Locale locale) {
652
        for (int i = 0; i < referenceLocales.length; i++) {
653
            if (referenceLocales[i].equals(locale)) {
654
                return true;
655
            }
656
        }
657
        return false;
658
    }
659
660
    /**
661
     * Puts a new resource file into a Jar file.
662
     */
663 26430 cordinyana
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
664 25963 cordinyana
            Map texts, String resourceFileName) throws IOException {
665 32338 cordinyana
        // Add ZIP entry for the resource bundle file
666
        zipos.putNextEntry(new ZipEntry(resourceFileName));
667 25963 cordinyana
668 32338 cordinyana
        for (Iterator iterator = texts.entrySet().iterator(); iterator
669
                .hasNext();) {
670
            Entry entry = (Entry) iterator.next();
671
            String keyEncoded = escape((String) entry.getKey(), true);
672
            ps.print(keyEncoded);
673
            ps.print("=");
674
            String valueEncoded = escape((String) entry.getValue(), false);
675
            ps.println(valueEncoded);
676
        }
677
678
        ps.flush();
679
680
        // Close the ZIP entry, the file is complete
681
        zipos.closeEntry();
682 25963 cordinyana
    }
683
684
    /**
685
     * Puts a new resource file into a Jar file.
686
     */
687 26430 cordinyana
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
688 32338 cordinyana
            Set keys, String resourceFileName) throws IOException {
689 25963 cordinyana
        // Add ZIP entry for the resource bundle file
690 26430 cordinyana
        zipos.putNextEntry(new ZipEntry(resourceFileName));
691 25963 cordinyana
692 32338 cordinyana
        for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
693
            String value = (String) iterator.next();
694
            String keyEncoded = escape(value, true);
695 26048 cordinyana
            ps.print(keyEncoded);
696 25963 cordinyana
            ps.print("=");
697 32338 cordinyana
            ps.println();
698 25963 cordinyana
        }
699
700
        ps.flush();
701
702
        // Close the ZIP entry, the file is complete
703 26430 cordinyana
        zipos.closeEntry();
704 25963 cordinyana
    }
705
706
    /**
707
     * Returns the file which contains the translations for a locale.
708
     */
709
    private File getResourceFile(Locale locale) {
710
        return new File(getResourcesFolder(), getResourceFileName(locale));
711
    }
712
713
    /**
714
     * Returns the name of the file which contains the translations for a
715
     * locale.
716
     */
717
    private String getResourceFileName(Locale locale) {
718
        StringBuffer fileName = new StringBuffer("text");
719
720
        // Spanish without country is the default locale
721
        if (!(isEmpty(locale.getCountry()) && "es".equals(locale.getLanguage()))) {
722
            fileName.append('_').append(locale.getLanguage());
723
        }
724
725
        // Add the locale country
726
        if (!isEmpty(locale.getCountry())) {
727
            fileName.append('_').append(locale.getCountry());
728
        }
729
730
        // Add the locale variant
731
        if (!isEmpty(locale.getVariant())) {
732
            fileName.append('_').append(locale.getVariant());
733
        }
734
735
        fileName.append(".properties");
736
        return fileName.toString();
737
    }
738
739
    /**
740
     * Returns the folder where to store the resource bundle files.
741
     */
742
    private File getResourcesFolder() {
743
        return PluginServices.getPluginServices("com.iver.cit.gvsig")
744
                .getPluginDirectory();
745
    }
746
747
    /**
748
     * Returns the child XMLEntity with the RegisteredLocales.
749
     */
750
    private XMLEntity getRegisteredLocalesPersistence() {
751
        XMLEntity entity = getI18nPersistence();
752
        XMLEntity child = null;
753
        for (int i = entity.getChildrenCount() - 1; i >= 0; i--) {
754
            XMLEntity tmpchild = entity.getChild(i);
755
            if (tmpchild.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
756
                child = tmpchild;
757
                break;
758
            }
759
        }
760
        return child;
761
    }
762
763
    /**
764
     * Returns the I18n Plugin persistence.
765
     */
766
    private XMLEntity getI18nPersistence() {
767
        XMLEntity entity = PluginServices.getPluginServices(I18N_EXTENSION)
768
                .getPersistentXML();
769
        return entity;
770
    }
771
772
    /**
773
     * Returns the list of default locales bundled with gvSIG.
774
     */
775
    private Locale[] getDefaultLocales() {
776
        return defaultLocales;
777
    }
778
779
    /**
780
     * Stores the list of installed locales into the plugin persistence.
781
     */
782
    private void storeInstalledLocales() {
783
        XMLEntity localesEntity = getRegisteredLocalesPersistence();
784
785
        // Remove the previous list of registered languages
786
        if (localesEntity != null) {
787
            XMLEntity i18nPersistence = getI18nPersistence();
788
            for (int i = i18nPersistence.getChildrenCount() - 1; i >= 0; i--) {
789
                XMLEntity child = i18nPersistence.getChild(i);
790
                if (child.getName().equals(REGISTERED_LOCALES_PERSISTENCE)) {
791
                    i18nPersistence.removeChild(i);
792
                    break;
793
                }
794
            }
795
        }
796
797
        // Create the new persistence for the registered languages
798
        localesEntity = new XMLEntity();
799
800
        localesEntity.setName(REGISTERED_LOCALES_PERSISTENCE);
801
802
        for (Iterator iterator = registeredLocales.iterator(); iterator
803
                .hasNext();) {
804
            Locale locale = (Locale) iterator.next();
805
            XMLEntity localeEntity = new XMLEntity();
806
            localeEntity.setName(locale.getDisplayName());
807
            localeEntity.putProperty(LANGUAGE, locale.getLanguage());
808
            localeEntity.putProperty(COUNTRY, locale.getCountry());
809
            localeEntity.putProperty(VARIANT, locale.getVariant());
810
811
            localesEntity.addChild(localeEntity);
812
        }
813
814
        getI18nPersistence().addChild(localesEntity);
815
    }
816 26048 cordinyana
817
    private String escape(String value, boolean replaceBlanks) {
818
        // First replace non printable characters
819
        if (replaceBlanks) {
820
            value = StringUtilities.replace(value, " ", "\\ ");
821
        }
822
        value = StringUtilities.replace(value, ":", "\\:");
823
        value = StringUtilities.replace(value, "\n", "\\n");
824
        value = StringUtilities.replace(value, "\t", "\\t");
825
        value = StringUtilities.replace(value, "\b", "\\b");
826
        value = StringUtilities.replace(value, "\f", "\\f");
827
        value = StringUtilities.replace(value, "\r", "\\r");
828
        // value = StringUtilities.replace(value, "\\", "\\\\");
829 26065 cordinyana
        // value = StringUtilities.replace(value, "\'", "\\\'");
830
        // value = StringUtilities.replace(value, "\"", "\\\"");
831 26048 cordinyana
832
        // Next, encode in raw-unicode-escape
833
        return toRawUnicodeEncoded(value);
834
    }
835
836
    private String toRawUnicodeEncoded(String value) {
837
        StringBuffer sb = new StringBuffer();
838
        for (int i = 0; i < value.length(); i++) {
839
            char c = value.charAt(i);
840
            if (c <= 0x80) {
841
                sb.append(c);
842 28461 cordinyana
            } else {
843 26048 cordinyana
                sb.append("\\u");
844
                String hexValue = Integer.toHexString((int) c);
845
                // Append 0 if the hex value has less than 4 digits
846
                for (int j = hexValue.length(); j < 4; j++) {
847
                    sb.append('0');
848
                }
849
                sb.append(hexValue);
850
            }
851
        }
852
        return sb.toString();
853
    }
854 25963 cordinyana
}