Essentials/Essentials/src/main/java/com/earth2me/essentials/I18n.java

211 lines
7.7 KiB
Java
Raw Normal View History

2011-11-18 15:03:14 +01:00
package com.earth2me.essentials;
2015-04-15 06:06:16 +02:00
import net.ess3.api.IEssentials;
2020-10-03 19:46:05 +02:00
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
2011-11-18 15:03:14 +01:00
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
2011-11-18 15:03:14 +01:00
import java.text.MessageFormat;
2020-10-03 19:46:05 +02:00
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
2011-11-18 15:03:14 +01:00
import java.util.logging.Level;
2011-11-21 03:05:18 +01:00
import java.util.logging.Logger;
import java.util.regex.Pattern;
2015-04-15 06:06:16 +02:00
public class I18n implements net.ess3.api.II18n {
private static final String MESSAGES = "messages";
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
public Enumeration<String> getKeys() {
return null;
}
2020-10-03 19:46:05 +02:00
protected Object handleGetObject(final String key) {
2015-04-15 06:06:16 +02:00
return null;
}
};
2020-10-03 19:46:05 +02:00
private static I18n instance;
private final transient Locale defaultLocale = Locale.getDefault();
private final transient ResourceBundle defaultBundle;
private final transient IEssentials ess;
private transient Locale currentLocale = defaultLocale;
private transient ResourceBundle customBundle;
private transient ResourceBundle localeBundle;
private transient Map<String, MessageFormat> messageFormatCache = new HashMap<>();
2015-04-15 06:06:16 +02:00
public I18n(final IEssentials ess) {
this.ess = ess;
defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH, new UTF8PropertiesControl());
2015-04-15 06:06:16 +02:00
localeBundle = defaultBundle;
customBundle = NULL_BUNDLE;
}
2020-10-03 19:46:05 +02:00
public static String tl(final String string, final Object... objects) {
if (instance == null) {
return "";
}
if (objects.length == 0) {
return NODOUBLEMARK.matcher(instance.translate(string)).replaceAll("'");
} else {
return instance.format(string, objects);
}
}
public static String capitalCase(final String input) {
return input == null || input.length() == 0 ? input : input.toUpperCase(Locale.ENGLISH).charAt(0) + input.toLowerCase(Locale.ENGLISH).substring(1);
}
2015-04-15 06:06:16 +02:00
public void onEnable() {
instance = this;
}
public void onDisable() {
instance = null;
}
@Override
public Locale getCurrentLocale() {
return currentLocale;
}
private String translate(final String string) {
try {
try {
return customBundle.getString(string);
2020-10-03 19:46:05 +02:00
} catch (final MissingResourceException ex) {
2015-04-15 06:06:16 +02:00
return localeBundle.getString(string);
}
2020-10-03 19:46:05 +02:00
} catch (final MissingResourceException ex) {
2015-04-15 06:06:16 +02:00
Logger.getLogger("Essentials").log(Level.WARNING, String.format("Missing translation key \"%s\" in translation file %s", ex.getKey(), localeBundle.getLocale().toString()), ex);
return defaultBundle.getString(string);
}
}
public String format(final String string, final Object... objects) {
String format = translate(string);
MessageFormat messageFormat = messageFormatCache.get(format);
if (messageFormat == null) {
try {
messageFormat = new MessageFormat(format);
2020-10-03 19:46:05 +02:00
} catch (final IllegalArgumentException e) {
2015-04-15 06:06:16 +02:00
ess.getLogger().log(Level.SEVERE, "Invalid Translation key for '" + string + "': " + e.getMessage());
format = format.replaceAll("\\{(\\D*?)\\}", "\\[$1\\]");
messageFormat = new MessageFormat(format);
}
messageFormatCache.put(format, messageFormat);
}
return messageFormat.format(objects).replace(' ', ' '); // replace nbsp with a space
2015-04-15 06:06:16 +02:00
}
public void updateLocale(final String loc) {
if (loc != null && !loc.isEmpty()) {
final String[] parts = loc.split("[_\\.]");
if (parts.length == 1) {
currentLocale = new Locale(parts[0]);
}
if (parts.length == 2) {
currentLocale = new Locale(parts[0], parts[1]);
}
if (parts.length == 3) {
currentLocale = new Locale(parts[0], parts[1], parts[2]);
}
}
ResourceBundle.clearCache();
messageFormatCache = new HashMap<>();
2015-04-15 06:06:16 +02:00
Logger.getLogger("Essentials").log(Level.INFO, String.format("Using locale %s", currentLocale.toString()));
try {
localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new UTF8PropertiesControl());
2020-10-03 19:46:05 +02:00
} catch (final MissingResourceException ex) {
2015-04-15 06:06:16 +02:00
localeBundle = NULL_BUNDLE;
}
try {
customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess), new UTF8PropertiesControl());
2020-10-03 19:46:05 +02:00
} catch (final MissingResourceException ex) {
2015-04-15 06:06:16 +02:00
customBundle = NULL_BUNDLE;
}
}
/**
* Attempts to load properties files from the plugin directory before falling back to the jar.
*/
2015-04-15 06:06:16 +02:00
private static class FileResClassLoader extends ClassLoader {
private final transient File dataFolder;
FileResClassLoader(final ClassLoader classLoader, final IEssentials ess) {
super(classLoader);
this.dataFolder = ess.getDataFolder();
}
@Override
public URL getResource(final String string) {
final File file = new File(dataFolder, string);
if (file.exists()) {
try {
return file.toURI().toURL();
2020-10-03 19:46:05 +02:00
} catch (final MalformedURLException ignored) {
}
2015-04-15 06:06:16 +02:00
}
return null;
}
@Override
public InputStream getResourceAsStream(final String string) {
final File file = new File(dataFolder, string);
if (file.exists()) {
try {
return new FileInputStream(file);
2020-10-03 19:46:05 +02:00
} catch (final FileNotFoundException ignored) {
}
2015-04-15 06:06:16 +02:00
}
return null;
}
}
/**
* Reads .properties files as UTF-8 instead of ISO-8859-1, which is the default on Java 8/below.
* Java 9 fixes this by defaulting to UTF-8 for .properties files.
*/
private static class UTF8PropertiesControl extends ResourceBundle.Control {
2020-10-03 19:46:05 +02:00
public ResourceBundle newBundle(final String baseName, final Locale locale, final String format, final ClassLoader loader, final boolean reload) throws IOException {
final String resourceName = toResourceName(toBundleName(baseName, locale), "properties");
ResourceBundle bundle = null;
InputStream stream = null;
if (reload) {
2020-10-03 19:46:05 +02:00
final URL url = loader.getResource(resourceName);
if (url != null) {
2020-10-03 19:46:05 +02:00
final URLConnection connection = url.openConnection();
if (connection != null) {
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
} else {
stream = loader.getResourceAsStream(resourceName);
}
if (stream != null) {
try {
// use UTF-8 here, this is the important bit
bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8));
} finally {
stream.close();
}
}
return bundle;
}
}
2011-11-18 15:03:14 +01:00
}