/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * FreeCol 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.common.option; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import org.freecolandroid.xml.stream.XMLStreamException; import org.freecolandroid.xml.stream.XMLStreamWriter; import net.sf.freecol.FreeCol; import net.sf.freecol.client.gui.i18n.Messages; import net.sf.freecol.common.model.Specification; /** * Option for selecting a language. The possible choices are determined * using the available language files in "data/strings". */ public class LanguageOption extends AbstractOption<LanguageOption.Language> { public static final String AUTO = "automatic"; private static final Logger logger = Logger.getLogger(LanguageOption.class.getName()); private static final Map<String, Language> languages = new HashMap<String, Language>(); private static final Map<String, String> languageNames = new HashMap<String, String>(); private Language DEFAULT = new Language(AUTO, getLocale(AUTO)); private Language value; static { // add non-standard language names here languageNames.put("arz", "\u0645\u0635\u0631\u064A"); languageNames.put("hsb", "Serb\u0161\u0107ina"); languageNames.put("nds", "Plattd\u00fc\u00fctsch"); languageNames.put("pms", "Piemont\u00e9s"); languageNames.put("be-tarask", "\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f " + "(\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430)"); findLanguages(); } private static Comparator<Language> languageComparator = new Comparator<Language>() { public int compare(Language l1, Language l2) { if (l1.getKey().equals(AUTO)) { if (l2.getKey().equals(AUTO)) { return 0; } else { return -1; } } else if (l2.getKey().equals(AUTO)) { return 1; } else { return l1.toString().compareTo(l2.toString()); } } }; /** * Creates a new <code>LanguageOption</code>. * * @param specification The specification this option belongs * to. May be null. */ public LanguageOption(Specification specification) { super(specification); languages.put(AUTO, DEFAULT); } public LanguageOption clone() throws CloneNotSupportedException { LanguageOption result = new LanguageOption(getSpecification()); result.setValues(this); return result; } /** * Get the <code>Value</code> value. * * @return a <code>String</code> value */ public final Language getValue() { return value; } /** * Set the <code>Value</code> value. * * @param newValue The new Value value. */ public final void setValue(final Language newValue) { final Language oldValue = this.value; this.value = newValue; if (!newValue.equals(oldValue)) { firePropertyChange(VALUE_TAG, oldValue, value); } } /** * Sets the value of this Option from the given string * representation. Both parameters must not be null at the same * time. * * @param valueString the string representation of the value of * this Option * @param defaultValueString the string representation of the * default value of this Option */ protected void setValue(String valueString, String defaultValueString) { setValue(languages.get((valueString != null) ? valueString : AUTO)); } /** * Returns a list of the available languages. * @return The available languages in a human readable format. */ public Language[] getOptions() { List<Language> names = new ArrayList<Language>(languages.values()); Collections.sort(names, languageComparator); return names.toArray(new Language[0]); } /** * Finds the languages available in the default directory. */ private static void findLanguages() { File i18nDirectory = new File(FreeCol.getDataDirectory(), Messages.STRINGS_DIRECTORY); File[] files = i18nDirectory.listFiles(); if (files == null) { throw new RuntimeException("No language files could be found in the <" + i18nDirectory + "> folder. Make sure you ran the ant correctly."); } String prefix = Messages.FILE_PREFIX + "_"; int prefixLength = prefix.length(); for (File file : files) { if (file.getName() == null) { continue; } if (file.getName().startsWith(prefix)) { try { final String languageID = file.getName().substring(prefixLength, file.getName().indexOf(".")); // qqq contains explanations only if (!"qqq".equals(languageID)) { languages.put(languageID, new Language(languageID, getLocale(languageID))); } } catch (Exception e) { logger.log(Level.WARNING, "Exception in findLanguages()", e); continue; } } } } /** * Returns the <code>Locale</code> decided by the given name. * * @param languageID A String using the same format as * {@link #getValue()}. * @return The Locale. */ public static Locale getLocale(String languageID) { if (languageID == null || AUTO.equals(languageID)) { return Locale.getDefault(); } try { String language, country = "", variant = ""; StringTokenizer st = new StringTokenizer(languageID, "_", true); language = st.nextToken(); if (st.hasMoreTokens()) { // Skip _ st.nextToken(); } if (st.hasMoreTokens()) { String token = st.nextToken(); if (!token.equals("_")) { country = token; } if (st.hasMoreTokens()) { token = st.nextToken(); if (token.equals("_") && st.hasMoreTokens()) { token = st.nextToken(); } if (!token.equals("_")) { variant = token; } } } return new Locale(language, country, variant); } catch (Exception e) { logger.log(Level.WARNING, "Cannot choose locale: " + languageID, e); return Locale.getDefault(); } } public static class Language { /** * Describe key here. */ private String key; /** * Describe locale here. */ private Locale locale; public Language(String key, Locale locale) { this.key = key; this.locale = locale; } /** * Get the <code>Key</code> value. * * @return a <code>String</code> value */ public final String getKey() { return key; } /** * Set the <code>Key</code> value. * * @param newKey The new Key value. */ public final void setKey(final String newKey) { this.key = newKey; } /** * Get the <code>Locale</code> value. * * @return a <code>Locale</code> value */ public final Locale getLocale() { return locale; } /** * Set the <code>Locale</code> value. * * @param newLocale The new Locale value. */ public final void setLocale(final Locale newLocale) { this.locale = newLocale; } public String toString() { if (getKey().equals(AUTO)) { return Messages.message("clientOptions.gui.languageOption.autoDetectLanguage"); } else { String name = locale.getDisplayName(locale); if (name.equals(key) && languageNames.containsKey(key)) { name = languageNames.get(key); } return name.substring(0, 1).toUpperCase(locale) + name.substring(1); } } public boolean equals(Object o) { if ((o instanceof Language) && ((Language) o).getKey().equals(key)) { return true; } else { return false; } } } /** * This method writes an XML-representation of this object to * the given stream. * * @param out The target stream. * @throws XMLStreamException if there are any problems writing * to the stream. */ protected void toXMLImpl(XMLStreamWriter out) throws XMLStreamException { super.toXML(out, getXMLElementTagName()); } /** * Write the attributes of this object to a stream. * * @param out The target stream. * @throws XMLStreamException if there are any problems writing to * the stream. */ @Override protected void writeAttributes(XMLStreamWriter out) throws XMLStreamException { super.writeAttributes(out); out.writeAttribute(VALUE_TAG, getValue().getKey()); } /** * Gets the tag name of the root element representing this object. * * @return "languageOption". */ public static String getXMLElementTagName() { return "languageOption"; } }