package org.limewire.ui.swing.util;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.limewire.core.settings.ApplicationSettings;
import org.limewire.io.IOUtils;
import org.limewire.util.FileUtils;
import org.limewire.util.OSUtils;
/**
* This class provides utility methods retrieving supported languages and
* changing language settings.
*/
public class LanguageUtils {
private static Log LOG = LogFactory.getLog(LanguageUtils.class);
private static final String BUNDLE_PREFIX = "org/limewire/i18n/Messages_";
private static final String BUNDLE_POSTFIX = ".class";
private static final String BUNDLE_MARKER = "org/limewire/i18n/Messages.class";
/**
* Applies this language code to be the new language of the program.
*/
public static void setLocale(Locale locale) {
ApplicationSettings.LANGUAGE.set(locale.getLanguage());
ApplicationSettings.COUNTRY.set(locale.getCountry());
ApplicationSettings.LOCALE_VARIANT.set(locale.getVariant());
LocaleUtils.setLocaleFromPreferences();
}
/**
* Returns a Locale of the current language that is being used.
*/
public static Locale getCurrentLocale() {
return LocaleUtils.getCurrentLocale();
}
/**
* Returns an array of supported language as a LanguageInfo[], always having
* the English language as the first element.
* <p>
* This will only include languages that can be displayed using the given
* font. If the font is null, all languages are returned.
*/
public static Locale[] getLocales(Font font) {
final List<Locale> locales = new LinkedList<Locale>();
File jar = FileUtils.getJarFromClasspath(LanguageUtils.class.getClassLoader(), BUNDLE_MARKER);
if (jar != null) {
addLocalesFromJar(locales, jar);
} else {
LOG.warn("Could not find bundle jar to determine locales");
}
// TODO: fix for build
/* if (LimeWireUtils.isTestingVersion()) {
addLocalesFromJar(locales, new File(CVS_BUNDLE_FILE));
} */
Collections.sort(locales, new Comparator<Locale>() {
public int compare(Locale o1, Locale o2) {
return o1.getDisplayName(o1).compareToIgnoreCase(
o2.getDisplayName(o2));
}
});
locales.remove(Locale.ENGLISH);
locales.add(0, Locale.ENGLISH);
// remove languages that cannot be displayed using this font
if (font != null && !OSUtils.isMacOSX()) {
for (Iterator<Locale> it = locales.iterator(); it.hasNext();) {
Locale locale = it.next();
if (!GuiUtils.canDisplay(font, locale.getDisplayName(locale))) {
it.remove();
}
}
}
return locales.toArray(new Locale[0]);
}
/**
* Returns the languages as found from the classpath in messages.jar.
*/
static void addLocalesFromJar(List<Locale> locales, File jar) {
ZipFile zip = null;
try {
zip = new ZipFile(jar);
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (!name.startsWith(BUNDLE_PREFIX) || !name.endsWith(BUNDLE_POSTFIX)
|| name.indexOf("$") != -1) {
continue;
}
String iso = name.substring(BUNDLE_PREFIX.length(), name.length()
- BUNDLE_POSTFIX.length());
List<String> tokens = new ArrayList<String>(Arrays.asList(iso.split("_", 3)));
if (tokens.size() < 1) {
continue;
}
while (tokens.size() < 3) {
tokens.add("");
}
Locale locale = new Locale(tokens.get(0), tokens.get(1), tokens.get(2));
locales.add(locale);
}
} catch (IOException e) {
LOG.warn("Could not determine locales", e);
} finally {
if (zip != null) {
try {
zip.close();
} catch (IOException ioe) {
}
}
}
}
/**
* Returns true if the language of <code>locale</code> is English.
*/
public static boolean isEnglishLocale(Locale locale) {
return Locale.ENGLISH.getLanguage().equals(locale.getLanguage());
}
/**
* Returns a score between -1 and 3 how well <code>specificLocale</code>
* matches <code>genericLocale</code>.
*
* @return -1, if locales do not match, 3 if locales are equal
*/
public static int getMatchScore(Locale specificLocale, Locale genericLocale) {
int i = 0;
if (specificLocale.getLanguage().equals(genericLocale.getLanguage())) {
i += 1;
} else if (genericLocale.getLanguage().length() > 0) {
return -1;
}
if (specificLocale.getCountry().equals(genericLocale.getCountry())) {
i += 1;
} else if (genericLocale.getCountry().length() > 0) {
return -1;
}
if (specificLocale.getVariant().equals(genericLocale.getVariant())) {
i += 1;
} else if (genericLocale.getVariant().length() > 0) {
return -1;
}
return i;
}
/**
* Uses the guess mechanism to attempt to guess the current locale. The guess
* is then compared to the given list of available languages and the closest
* match is returned. If no match is found English is defaulted since
* English will always be available.
*/
public static Locale guessBestAvailableLocale(Locale... locales) {
Locale guessLocale = guessLocale();
Locale bestLocale = Locale.ENGLISH;
int bestScore = Integer.MIN_VALUE;
for ( Locale item : locales ) {
int checkScore = getMatchScore(guessLocale, item);
if (checkScore >= 0 && checkScore > bestScore) {
bestLocale = item;
bestScore = checkScore;
}
}
return bestLocale;
}
public static Locale guessLocale() {
String[] language = guessLanguage();
return new Locale(language[0], language[1], language[2]);
}
public static String[] guessLanguage() {
String ln = ApplicationSettings.LANGUAGE.get();
String cn = ApplicationSettings.COUNTRY.get();
String vn = ApplicationSettings.LOCALE_VARIANT.get();
File file = new File("language.prop");
if(!file.exists())
return new String[] { ln, cn, vn };
InputStream in = null;
BufferedReader reader = null;
String code = "";
try {
in = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(in));
code = reader.readLine();
} catch(IOException ignored) {
} finally {
IOUtils.close(in);
IOUtils.close(reader);
}
String[] mapped = getLCID(code);
if(mapped != null)
return mapped;
else
return new String[] { ln, cn, vn };
}
/**
* Returns the String[] { languageCode, countryCode, variantCode }
* for the Windows LCID.
*/
public static String[] getLCID(String code) {
Map<String, String[]> map = new HashMap<String, String[]>();
map.put("1078", new String[] { "af", "", "" } );
map.put("1052", new String[] { "sq", "", "" } );
map.put("5121", new String[] { "ar", "", "" } );
map.put("15361", new String[] { "ar", "", "" } );
map.put("3073", new String[] { "ar", "", "" } );
map.put("2049", new String[] { "ar", "", "" } );
map.put("11265", new String[] { "ar", "", "" } );
map.put("13313", new String[] { "ar", "", "" } );
map.put("12289", new String[] { "ar", "", "" } );
map.put("4097", new String[] { "ar", "", "" } );
map.put("6145", new String[] { "ar", "", "" } );
map.put("8193", new String[] { "ar", "", "" } );
map.put("16385", new String[] { "ar", "", "" } );
map.put("1025", new String[] { "ar", "", "" } );
map.put("10241", new String[] { "ar", "", "" } );
map.put("7169", new String[] { "ar", "", "" } );
map.put("14337", new String[] { "ar", "", "" } );
map.put("9217", new String[] { "ar", "", "" } );
map.put("1069", new String[] { "eu", "", "" } );
map.put("1059", new String[] { "be", "", "" } );
map.put("1093", new String[] { "bn", "", "" } );
map.put("1027", new String[] { "ca", "", "" } );
map.put("3076", new String[] { "zh", "", "" } );
map.put("5124", new String[] { "zh", "", "" } );
map.put("2052", new String[] { "zh", "", "" } );
map.put("4100", new String[] { "zh", "", "" } );
map.put("1028", new String[] { "zh", "TW", "" } );
map.put("1050", new String[] { "hr", "", "" } );
map.put("1029", new String[] { "cs", "", "" } );
map.put("1030", new String[] { "da", "", "" } );
map.put("2067", new String[] { "nl", "", "" } );
map.put("1043", new String[] { "nl", "", "" } );
map.put("3081", new String[] { "en", "", "" } );
map.put("10249", new String[] { "en", "", "" } );
map.put("4105", new String[] { "en", "", "" } );
map.put("9225", new String[] { "en", "", "" } );
map.put("6153", new String[] { "en", "", "" } );
map.put("8201", new String[] { "en", "", "" } );
map.put("5129", new String[] { "en", "", "" } );
map.put("13321", new String[] { "en", "", "" } );
map.put("7177", new String[] { "en", "", "" } );
map.put("11273", new String[] { "en", "", "" } );
map.put("2057", new String[] { "en", "", "" } );
map.put("1033", new String[] { "en", "", "" } );
map.put("12297", new String[] { "en", "", "" } );
map.put("1061", new String[] { "et", "", "" } );
map.put("1035", new String[] { "fi", "", "" } );
map.put("2060", new String[] { "fr", "", "" } );
map.put("11276", new String[] { "fr", "", "" } );
map.put("3084", new String[] { "fr", "", "" } );
map.put("9228", new String[] { "fr", "", "" } );
map.put("12300", new String[] { "fr", "", "" } );
map.put("1036", new String[] { "fr", "", "" } );
map.put("5132", new String[] { "fr", "", "" } );
map.put("13324", new String[] { "fr", "", "" } );
map.put("6156", new String[] { "fr", "", "" } );
map.put("10252", new String[] { "fr", "", "" } );
map.put("4108", new String[] { "fr", "", "" } );
map.put("7180", new String[] { "fr", "", "" } );
map.put("3079", new String[] { "de", "", "" } );
map.put("1031", new String[] { "de", "", "" } );
map.put("5127", new String[] { "de", "", "" } );
map.put("4103", new String[] { "de", "", "" } );
map.put("2055", new String[] { "de", "", "" } );
map.put("1032", new String[] { "el", "", "" } );
map.put("1037", new String[] { "iw", "", "" } );
map.put("1081", new String[] { "hi", "", "" } );
map.put("1038", new String[] { "hu", "", "" } );
map.put("1039", new String[] { "is", "", "" } );
map.put("1057", new String[] { "id", "", "" } );
map.put("1040", new String[] { "it", "", "" } );
map.put("2064", new String[] { "it", "", "" } );
map.put("1041", new String[] { "ja", "", "" } );
map.put("1042", new String[] { "ko", "", "" } );
map.put("1062", new String[] { "lv", "", "" } );
map.put("2110", new String[] { "ms", "", "" } );
map.put("1086", new String[] { "ms", "", "" } );
map.put("1082", new String[] { "mt", "", "" } );
map.put("1044", new String[] { "no", "", "" } );
map.put("2068", new String[] { "nn", "", "" } );
map.put("1045", new String[] { "pl", "", "" } );
map.put("1046", new String[] { "pt", "BR", "" } );
map.put("2070", new String[] { "pt", "", "" } );
map.put("1048", new String[] { "ro", "", "" } );
map.put("2072", new String[] { "ro", "", "" } );
map.put("1049", new String[] { "ru", "", "" } );
map.put("2073", new String[] { "ru", "", "" } );
map.put("3098", new String[] { "sr", "", "" } );
map.put("2074", new String[] { "sr", "", "" } );
map.put("1051", new String[] { "sk", "", "" } );
map.put("1060", new String[] { "sl", "", "" } );
map.put("11274", new String[] { "es", "", "" } );
map.put("16394", new String[] { "es", "", "" } );
map.put("13322", new String[] { "es", "", "" } );
map.put("9226", new String[] { "es", "", "" } );
map.put("5130", new String[] { "es", "", "" } );
map.put("7178", new String[] { "es", "", "" } );
map.put("12298", new String[] { "es", "", "" } );
map.put("17418", new String[] { "es", "", "" } );
map.put("4106", new String[] { "es", "", "" } );
map.put("18442", new String[] { "es", "", "" } );
map.put("3082", new String[] { "es", "", "" } );
map.put("2058", new String[] { "es", "", "" } );
map.put("19466", new String[] { "es", "", "" } );
map.put("6154", new String[] { "es", "", "" } );
map.put("15370", new String[] { "es", "", "" } );
map.put("10250", new String[] { "es", "", "" } );
map.put("20490", new String[] { "es", "", "" } );
map.put("1034", new String[] { "es", "", "" } );
map.put("14346", new String[] { "es", "", "" } );
map.put("8202", new String[] { "es", "", "" } );
map.put("1053", new String[] { "sv", "", "" } );
map.put("2077", new String[] { "sv", "", "" } );
map.put("1097", new String[] { "ta", "", "" } );
map.put("1054", new String[] { "th", "", "" } );
map.put("1055", new String[] { "tr", "", "" } );
map.put("1058", new String[] { "uk", "", "" } );
map.put("1056", new String[] { "ur", "", "" } );
map.put("2115", new String[] { "uz", "", "" } );
map.put("1091", new String[] { "uz", "", "" } );
map.put("1066", new String[] { "vi", "", "" } );
return map.get(code);
}
}