/* * $Id$ * * Copyright (c) 2007 by Rodney Kinney, Brent Easton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License (LGPL) as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, copies are available * at http://www.opensource.org. */ package VASSAL.i18n; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Locale; import java.util.Properties; import VASSAL.build.AbstractConfigurable; import VASSAL.build.AutoConfigurable; import VASSAL.build.Buildable; import VASSAL.build.GameModule; import VASSAL.build.module.documentation.HelpFile; import VASSAL.configure.Configurer; import VASSAL.configure.ConfigurerFactory; import VASSAL.tools.ArchiveWriter; import VASSAL.tools.ReadErrorDialog; import VASSAL.tools.io.IOUtils; public class Translation extends AbstractConfigurable implements Comparable<Translation> { public static final String LOCALE = "locale"; //$NON-NLS-1$ protected Locale locale; protected boolean dirty = false; protected Properties localProperties; public Translation() { locale = new Locale(Locale.getDefault().getLanguage()); } public String[] getAttributeDescriptions() { return new String[]{"Locale: "}; } public Class<?>[] getAttributeTypes() { return new Class<?>[]{ LocalePrompt.class }; } public static class LocalePrompt implements ConfigurerFactory { public Configurer getConfigurer(AutoConfigurable c, String key, String name) { return new LocaleConfigurer(key, name, ""); } } public String[] getAttributeNames() { return new String[]{LOCALE}; } public String getAttributeValueString(String key) { if (LOCALE.equals(key)) { return LocaleConfigurer.localeToString(locale); } else return null; } public void setAttribute(String key, Object value) { if (LOCALE.equals(key)) { locale = LocaleConfigurer.stringToLocale((String) value); setConfigureName(locale.getDisplayName()); } } protected String getDescription() { return locale.getDisplayName(Locale.getDefault()); } public String getLanguageCode() { return locale.getLanguage(); } public String getConfigureName() { return getDescription(); } public Class<?>[] getAllowableConfigureComponents() { return new Class<?>[0]; } public HelpFile getHelpFile() { return null; } public void removeFrom(Buildable parent) { Localization.getInstance().removeTranslation(this); } public void addTo(Buildable parent) { Localization.getInstance().addTranslation(this); if (!GameModule.getGameModule().isLocalizationEnabled()) { try { loadProperties(); } // FIXME: review error message // FIXME: should we catch a FileNotFoundException here instead? catch (IOException e) { // Fail quietly: This error will occur when adding a new translation. } } } /** * Set a property into our property map. i.e. an attribute has been translated * * @param key * property key * @param value * property value */ public void setProperty(String key, String value) { if (value == null || value.length() == 0) { getProperties().remove(key); } else { getProperties().setProperty(key, value); } dirty = true; } /** * Return true if this translation has unsaved modifications * * @return true if undaved changes */ public boolean isDirty() { return dirty; } /** * Return the translation for the supplied key * * @param s * @return */ public String translate(String key) { return getProperties().getProperty(key); } /** * Load properties from the bundle file in the module/extension * @throws IOException * */ protected void loadProperties() throws IOException { if (localProperties == null) { localProperties = new Properties(); } if (GameModule.getGameModule() != null) { BufferedInputStream in = null; try { try { in = new BufferedInputStream( GameModule.getGameModule() .getDataArchive() .getInputStream(getBundleFileName()) ); } catch (FileNotFoundException e) { // ignore, properties have not been saved yet dirty = false; return; } localProperties.load(in); in.close(); } finally { IOUtils.closeQuietly(in); } } dirty = false; } protected VassalResourceBundle getBundle() throws IOException { BufferedInputStream in = null; try { in = new BufferedInputStream( GameModule.getGameModule() .getDataArchive() .getInputStream(getBundleFileName()) ); final VassalResourceBundle b = new VassalResourceBundle(in); in.close(); return b; } finally { IOUtils.closeQuietly(in); } } /** * Reload the properties from the module/extension * @throws IOException * */ public void reloadProperties() throws IOException { localProperties = new Properties(); loadProperties(); } /** * Save the properties back to the module/extension * @throws IOException * */ protected void saveProperties() throws IOException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); getProperties().store(out, "Module translation"); final ArchiveWriter writer = GameModule.getGameModule().getArchiveWriter(); if (writer != null) { writer.addFile(getBundleFileName(), out.toByteArray()); dirty = false; } } /** * Return the properties map for this translation. Create and load from * the module if necessary. * * @return properties */ public Properties getProperties() { if (localProperties == null) { try { loadProperties(); } catch (IOException e) { ReadErrorDialog.error(e, getBundleFileName()); localProperties = new Properties(); } } return localProperties; } /** * Build the bundle name * * @return bundle name */ public String getBundleName() { return Resources.MODULE_BUNDLE + "_" + locale.getLanguage() //$NON-NLS-1$ + (locale.getCountry().length() > 0 ? ("_" + locale.getCountry()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Build the bundle file name * * @return bundle file name */ public String getBundleFileName() { return getBundleName() + ".properties"; //$NON-NLS-1$ } public int compareTo(Translation o) { return getDescription().compareTo(o.getDescription()); } public Locale getLocale() { return locale; } }