diff --git a/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java b/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java new file mode 100644 index 000000000..da15b8297 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java @@ -0,0 +1,30 @@ +package com.gmail.nossr50.commands.admin; + +import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.util.Permissions; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +/** + * @author Mark Vainomaa + */ +public final class McmmoReloadLocaleCommand implements CommandExecutor { + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + switch (args.length) { + case 0: + if (!Permissions.reloadlocale(sender)) { + sender.sendMessage(command.getPermissionMessage()); + return true; + } + + LocaleLoader.reloadLocale(); + sender.sendMessage(LocaleLoader.getString("Locale.Reloaded")); + + return true; + default: + return false; + } + } +} diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index 7454e3520..04b9ef54b 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -3,14 +3,25 @@ package com.gmail.nossr50.locale; import com.gmail.nossr50.mcMMO; import org.bukkit.ChatColor; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.text.MessageFormat; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; import java.util.ResourceBundle; +import java.util.logging.Level; public final class LocaleLoader { private static final String BUNDLE_ROOT = "com.gmail.nossr50.locale.locale"; + private static Map bundleCache = new HashMap<>(); private static ResourceBundle bundle = null; + private static ResourceBundle filesystemBundle = null; private static ResourceBundle enBundle = null; private LocaleLoader() { @@ -32,23 +43,44 @@ public final class LocaleLoader { initialize(); } - try { - return getString(key, bundle, messageArguments); - } catch (MissingResourceException ex) { - try { - return getString(key, enBundle, messageArguments); - } catch (MissingResourceException ex2) { - if (!key.contains("Guides")) { - mcMMO.p.getLogger().warning("Could not find locale string: " + key); - } - - return '!' + key + '!'; - } - } + String rawMessage = bundleCache.computeIfAbsent(key, LocaleLoader::getRawString); + return formatString(rawMessage, messageArguments); } - private static String getString(String key, ResourceBundle bundle, Object... messageArguments) throws MissingResourceException { - return formatString(bundle.getString(key), messageArguments); + /** + * Reloads locale + */ + public static void reloadLocale() { + bundle = null; + filesystemBundle = null; + enBundle = null; + bundleCache = new HashMap<>(); // Cheaper to replace than clear() + initialize(); + } + + private static String getRawString(String key) { + if (filesystemBundle != null) { + try { + return filesystemBundle.getString(key); + } + catch (MissingResourceException ignored) {} + } + + try { + return bundle.getString(key); + } + catch (MissingResourceException ignored) {} + + try { + return enBundle.getString(key); + } + catch (MissingResourceException ignored) { + if (!key.contains("Guides")) { + mcMMO.p.getLogger().warning("Could not find locale string: " + key); + } + + return '!' + key + '!'; + } } public static String formatString(String string, Object... messageArguments) { @@ -82,6 +114,19 @@ public final class LocaleLoader { locale = new Locale(myLocale[0], myLocale[1]); } + if (locale == null) { + throw new IllegalStateException("Failed to parse locale string '" + mcMMO.getConfigManager().getConfigLanguage().getTargetLanguage() + "'"); + } + + Path localePath = Paths.get(mcMMO.getLocalesDirectory() + "locale_" + locale.toString() + ".properties"); + if (Files.exists(localePath) && Files.isRegularFile(localePath)) { + try (Reader localeReader = Files.newBufferedReader(localePath)) { + mcMMO.p.getLogger().log(Level.INFO, "Loading locale from {0}", localePath); + filesystemBundle = new PropertyResourceBundle(localeReader); + } catch (IOException e) { + mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + localePath, e); + } + } bundle = ResourceBundle.getBundle(BUNDLE_ROOT, locale); enBundle = ResourceBundle.getBundle(BUNDLE_ROOT, Locale.US); } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index eb0758da5..e808f7171 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -90,6 +90,7 @@ public class mcMMO extends JavaPlugin { private static MaterialMapStore materialMapStore; /* File Paths */ private static String mainDirectory; + private static String localesDirectory; private static String flatFileDirectory; private static String usersFile; private static String modDirectory; @@ -421,13 +422,16 @@ public class mcMMO extends JavaPlugin { } databaseManager.onDisable(); - //Unload configs last configManager.unloadAllConfigsAndRegisters(); debug("Was disabled."); // How informative! } + public static String getLocalesDirectory() { + return localesDirectory; + } + public boolean isXPEventEnabled() { return xpEventEnabled; } @@ -458,6 +462,7 @@ public class mcMMO extends JavaPlugin { private void setupFilePaths() { mcmmo = getFile(); mainDirectory = getDataFolder().getPath() + File.separator; + localesDirectory = mainDirectory + "locales" + File.separator; flatFileDirectory = mainDirectory + "flatfile" + File.separator; usersFile = flatFileDirectory + "mcmmo.users"; modDirectory = mainDirectory + "mods" + File.separator; @@ -511,6 +516,8 @@ public class mcMMO extends JavaPlugin { File currentFlatfilePath = new File(flatFileDirectory); currentFlatfilePath.mkdirs(); + File localesDirectoryPath = new File(localesDirectory); + localesDirectoryPath.mkdirs(); } private void loadConfigFiles() { diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 01b747f33..cfa2f3909 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -233,6 +233,8 @@ public final class Permissions { return permissible.hasPermission("mcmmo.commands.mmoupdate"); } + public static boolean reloadlocale(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.reloadlocale"); } + /* * PERKS */ diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 1235231e2..356e63abe 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.util.commands; import com.gmail.nossr50.commands.*; +import com.gmail.nossr50.commands.admin.McmmoReloadLocaleCommand; import com.gmail.nossr50.commands.chat.AdminChatCommand; import com.gmail.nossr50.commands.chat.McChatSpy; import com.gmail.nossr50.commands.chat.PartyChatCommand; @@ -408,6 +409,15 @@ public final class CommandRegistrationManager { command.setExecutor(new McImportCommand()); } + private static void registerReloadLocaleCommand() { + PluginCommand command = mcMMO.p.getCommand("mcmmoreloadlocale"); + command.setDescription("Reloads locale"); // TODO: Localize + command.setPermission("mcmmo.commands.reloadlocale"); + command.setPermissionMessage(permissionsMessage); + command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcmmoreloadlocale")); + command.setExecutor(new McmmoReloadLocaleCommand()); + } + public static void registerCommands() { // Generic Commands registerMmoInfoCommand(); @@ -458,5 +468,7 @@ public final class CommandRegistrationManager { //Config Commands registerMcmmoReloadCommand(); + // Admin commands + registerReloadLocaleCommand(); } } diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 0d692bf93..976ac9751 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -1085,4 +1085,5 @@ Holiday.Anniversary=[[BLUE]]Happy {0} Year Anniversary!\n[[BLUE]]In honor of all Reminder.Squelched=[[GRAY]]Reminder: You are currently not receiving notifications from mcMMO, to enable notifications please run the /mcnotify command again. This is an automated hourly reminder. #Misc Commands.Reload.Start=mcMMO is reloading... this may take a moment -Commands.Reload.Finished=mcMMO has finished reloading! \ No newline at end of file +Commands.Reload.Finished=mcMMO has finished reloading! +Locale.Reloaded=[[GREEN]]Locale reloaded! diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index fb874b34e..893539ed7 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -163,6 +163,10 @@ commands: aliases: [macho, jumping, throwing, wrecking, crafting, walking, swimming, falling, climbing, flying, diving, piggy] description: Deploy jokes permission: mcmmo.commands.mcfools + mcmmoreloadlocale: + aliases: [mcreloadlocale] + description: Reloads locale + permission: mcmmo.commands.reloadlocale permissions: mcmmo.*: default: false @@ -800,6 +804,7 @@ permissions: mcmmo.commands.mmoedit.others: true mcmmo.commands.mmoshowdb: true mcmmo.commands.ptp.world.all: true + mcmmo.commands.reloadlocale: true mcmmo.commands.skillreset.all: true mcmmo.commands.xprate.all: true mcmmo.commands.acrobatics: