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

View differences:

I18nManagerImpl.java
30 30
import java.security.AccessController;
31 31
import java.util.*;
32 32
import java.util.Map.Entry;
33
import java.util.jar.*;
34
import java.util.zip.ZipEntry;
33
import java.util.zip.*;
35 34

  
36 35
import org.gvsig.i18n.*;
37 36

  
......
51 50
 */
52 51
public class I18nManagerImpl implements I18nManager {
53 52

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

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

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

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

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

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

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

  
68 57
    private static final String VARIANT = "variant";
......
242 231
    public Locale getCurrentLocale() {
243 232
	return Locale.getDefault();
244 233
    }
245
    
234

  
246 235
    public Locale getDefaultSystemLocale() {
247 236
	String language, region, country, variant;
248 237
	language = (String) AccessController
......
282 271
	List importLocales = new ArrayList();
283 272

  
284 273
	try {
285
	    FileInputStream fis = new FileInputStream(importFile);
286
	    JarInputStream jaris = new JarInputStream(fis);
274
	    ZipFile zipFile = new ZipFile(importFile);
287 275

  
288
	    JarEntry entry;
289
	    while ((entry = jaris.getNextJarEntry()) != null) {
276
	    Map locales = getZipFileNonReferenceLocales(zipFile);
290 277

  
291
		Attributes attributes = entry.getAttributes();
278
	    for (Iterator iterator = locales.entrySet().iterator(); iterator
279
		    .hasNext();) {
280
		Entry entry = (Entry) iterator.next();
292 281

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

  
305
			// Add the locale to the list of installed ones, if it
306
			// is new, otherwise, update the texts.
307
			if (!registeredLocales.contains(locale)) {
308
			    registeredLocales.add(locale);
309
			    storeInstalledLocales();
310
			}
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
		}
311 292

  
312
			// Replace the old bundle with the new one
313
			File bundleFile = getResourceFile(locale);
314
			FileOutputStream fos = new FileOutputStream(bundleFile);
315
			BufferedOutputStream bos = new BufferedOutputStream(fos);
316
			int len = 0;
317
			byte[] buffer = new byte[2048];
318
			while ((len = jaris.read(buffer)) > 0) {
319
			    bos.write(buffer, 0, len);
320
			}
321
			bos.flush();
322
			bos.close();
323
			fos.close();
324
		    }
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');
325 307
		}
308
		writer.flush();
309
		writer.close();
310
		fileWriter.close();
311
		reader.close();
312
		is.close();
326 313
	    }
327 314

  
328
	    jaris.close();
329
	    fis.close();
330 315
	} catch (Exception ex) {
331 316
	    throw new InstallLocalesException(importFile, ex);
332 317
	}
......
337 322

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

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

  
356 352
	try {
357 353
	    FileOutputStream fos = new FileOutputStream(exportFile);
358
	    JarOutputStream jaros = new JarOutputStream(fos, manifest);
354
	    ZipOutputStream zipos = new ZipOutputStream(fos);
359 355

  
360
	    // BufferedOutputStream bos = new BufferedOutputStream(jaros);
361
	    // PrintStream ps = new PrintStream(bos);
362
	    PrintStream ps = new PrintStream(jaros);
356
	    // Create the index file
357
	    writeZipFileLocales(zipos, locale, refArray);
358

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

  
365
	    // First, export the locale to update
366
	    texts = getAllTexts(locale);
367
	    putResourceInJar(jaros, ps, texts, getResourceFileName(locale));
368
	    // Next, export the locale selected as reference (if not in the
369
	    // default reference locales list)
370
	    if (!isReferenceLocale(referenceLocale)) {
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 371
		texts = getAllTexts(referenceLocale);
372
		putResourceInJar(jaros, ps, texts,
373
			getResourceFileName(referenceLocale));
372
		putResourceInZip(zipos, ps, texts, getResourceFileName(locale),
373
			false);
374

  
374 375
	    }
375
	    // Finally, export the default reference locales
376
	    for (int i = 0; i < referenceLocales.length; i++) {
377
		if (!locale.equals(referenceLocales[i])) {
378
		    texts = getAllTexts(referenceLocales[i]);
379
		    putResourceInJar(jaros, ps, texts,
380
			    getResourceFileName(referenceLocales[i]));
381
		}
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 382
	    }
383 383

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

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

  
397
	// First, add an entry for the locale to update
398
	addLocaleToManifest(locale, manifest, false);
399
	// Next, another entry for the reference locale, if not a default one
400
	if (!isReferenceLocale(referenceLocale)) {
401
	    addLocaleToManifest(referenceLocale, manifest, true);
402
	}
403
	// Finally, an entry per default reference locale
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);
404 403
	for (int i = 0; i < referenceLocales.length; i++) {
405
	    addLocaleToManifest(referenceLocales[i], manifest, true);
404
	    exportRefLocales.add(referenceLocales[i]);
406 405
	}
406
	exportRefLocales.add(referenceLocale);
407
	exportRefLocales.remove(locale);
408
	Locale[] refArray = (Locale[]) exportRefLocales
409
		.toArray(new Locale[exportRefLocales.size()]);
410
	return refArray;
411
    }
407 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;
408 429
	try {
409
	    FileOutputStream fos = new FileOutputStream(exportFile);
410
	    JarOutputStream jaros = new JarOutputStream(fos, manifest);
430
	    InputStream is = zipFile.getInputStream(zipEntry);
431
	    BufferedReader reader = new BufferedReader(
432
		    new InputStreamReader(is));
411 433

  
412
	    // BufferedOutputStream bos = new BufferedOutputStream(jaros);
413
	    // PrintStream ps = new PrintStream(bos);
414
	    PrintStream ps = new PrintStream(jaros);
415
	    Map texts = null;
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
		}
416 482

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

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

  
437
	    ps.close();
438
	    // bos.close();
439
	    jaros.close();
440
	    fos.close();
497
	    reader.close();
498
	    is.close();
441 499
	} catch (IOException ex) {
442
	    throw new ExportLocaleException(locale, ex);
500
	    throw new ReadCSVLocalesFileException(ex);
443 501
	}
444
    }
445 502

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

  
450
    public void setReferenceLocales(Locale[] referenceLocales) {
451
	this.referenceLocales = referenceLocales;
452
    }
506
    private void writeZipFileLocales(ZipOutputStream zos, Locale locale,
507
	    Locale[] referenceLocales) throws IOException {
508
	ZipEntry zipEntry = new ZipEntry("locales.csv");
453 509

  
454
    public void setDefaultLocales(Locale[] defaultLocales) {
455
	this.defaultLocales = defaultLocales;
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();
456 520
    }
457 521

  
458 522
    /**
459
     * Returns all the localized texts and its keys for a locale.
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
460 533
     */
461
    private Map getAllTexts(Locale locale) {
462
	return Messages.getAllTexts(locale);
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');
463 552
    }
464 553

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

  
491 554
    /**
492 555
     * Returns if a locale is one of the default reference ones.
493 556
     */
......
503 566
    /**
504 567
     * Puts a new resource file into a Jar file.
505 568
     */
506
    private void putResourceInJar(JarOutputStream jaros, PrintStream ps,
569
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
507 570
	    Map texts, String resourceFileName) throws IOException {
508 571

  
509
	putResourceInJar(jaros, ps, texts, resourceFileName, true);
572
	putResourceInZip(zipos, ps, texts, resourceFileName, true);
510 573
    }
511 574

  
512 575
    /**
513 576
     * Puts a new resource file into a Jar file.
514 577
     */
515
    private void putResourceInJar(JarOutputStream jaros, PrintStream ps,
578
    private void putResourceInZip(ZipOutputStream zipos, PrintStream ps,
516 579
	    Map texts, String resourceFileName, boolean withValue)
517 580
	    throws IOException {
518 581
	// Add ZIP entry for the resource bundle file
519
	jaros.putNextEntry(new ZipEntry(resourceFileName));
582
	zipos.putNextEntry(new ZipEntry(resourceFileName));
520 583

  
521 584
	for (Iterator iterator = texts.entrySet().iterator(); iterator
522 585
		.hasNext();) {
......
536 599
	ps.flush();
537 600

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

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

  
556
	String resourceFileName = getResourceFileName(locale);
557

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

  
570
	return resourceFileName;
571
    }
572

  
573
    /**
574 606
     * Returns the file which contains the translations for a locale.
575 607
     */
576 608
    private File getResourceFile(Locale locale) {

Also available in: Unified diff