From 9f53ed0832dd60e64adc5cdfaf357c99a5c9bc0c Mon Sep 17 00:00:00 2001 From: Brianna Date: Sat, 20 Jul 2019 07:28:09 -0400 Subject: [PATCH] Locale QoL --- .../com/songoda/ultimaterepairing/Locale.java | 375 ------------------ .../songoda/ultimaterepairing/References.java | 14 - .../ultimaterepairing/UltimateRepairing.java | 15 +- .../command/CommandManager.java | 8 +- .../command/commands/CommandReload.java | 2 +- .../commands/CommandUltimateRepairing.java | 3 +- .../handlers/RepairHandler.java | 114 +++--- .../ultimaterepairing/hologram/Hologram.java | 8 +- .../listeners/InventoryListeners.java | 2 +- .../utils/locale/Locale.java | 302 ++++++++++++++ .../utils/locale/Message.java | 115 ++++++ .../utils/updateModules/LocaleModule.java | 2 +- 12 files changed, 497 insertions(+), 463 deletions(-) delete mode 100644 src/main/java/com/songoda/ultimaterepairing/Locale.java delete mode 100644 src/main/java/com/songoda/ultimaterepairing/References.java create mode 100644 src/main/java/com/songoda/ultimaterepairing/utils/locale/Locale.java create mode 100644 src/main/java/com/songoda/ultimaterepairing/utils/locale/Message.java diff --git a/src/main/java/com/songoda/ultimaterepairing/Locale.java b/src/main/java/com/songoda/ultimaterepairing/Locale.java deleted file mode 100644 index 6fbe570..0000000 --- a/src/main/java/com/songoda/ultimaterepairing/Locale.java +++ /dev/null @@ -1,375 +0,0 @@ -package com.songoda.ultimaterepairing; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import org.bukkit.ChatColor; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * Assists in the creation of multiple localizations and languages, - * as well as the generation of default .lang files - * - * @author Parker Hawke - 2008Choco - */ -public class Locale { - - private static final List LOCALES = Lists.newArrayList(); - private static final Pattern NODE_PATTERN = Pattern.compile("(\\w+(?:\\.{1}\\w+)*)\\s*=\\s*\"(.*)\""); - private static final String FILE_EXTENSION = ".lang"; - private static JavaPlugin plugin; - private static File localeFolder; - - private static String defaultLocale; - - private final Map nodes = new HashMap<>(); - - private final File file; - private final String name, region; - - private Locale(String name, String region) { - if (plugin == null) - throw new IllegalStateException("Cannot generate locales without first initializing the class (Locale#init(JavaPlugin))"); - - this.name = name.toLowerCase(); - this.region = region.toUpperCase(); - - String fileName = name + "_" + region + FILE_EXTENSION; - this.file = new File(localeFolder, fileName); - - if (this.reloadMessages()) return; - - plugin.getLogger().info("Loaded locale " + fileName); - } - - /** - * Initialize the locale class to generate information and search for localizations. - * This must be called before any other methods in the Locale class can be invoked. - * Note that this will also call {@link #searchForLocales()}, so there is no need to - * invoke it for yourself after the initialization - * - * @param plugin the plugin instance - */ - public static void init(JavaPlugin plugin) { - Locale.plugin = plugin; - - if (localeFolder == null) { - localeFolder = new File(plugin.getDataFolder(), "locales/"); - } - - localeFolder.mkdirs(); - Locale.searchForLocales(); - } - - /** - * Find all .lang file locales under the "locales" folder - */ - public static void searchForLocales() { - if (!localeFolder.exists()) localeFolder.mkdirs(); - - for (File file : localeFolder.listFiles()) { - String name = file.getName(); - if (!name.endsWith(".lang")) continue; - - String fileName = name.substring(0, name.lastIndexOf('.')); - String[] localeValues = fileName.split("_"); - - if (localeValues.length != 2) continue; - if (localeExists(localeValues[0] + "_" + localeValues[1])) continue; - - LOCALES.add(new Locale(localeValues[0], localeValues[1])); - plugin.getLogger().info("Found and loaded locale \"" + fileName + "\""); - } - } - - /** - * Get a locale by its entire proper name (i.e. "en_US") - * - * @param name the full name of the locale - * @return locale of the specified name - */ - public static Locale getLocale(String name) { - for (Locale locale : LOCALES) - if (locale.getLanguageTag().equalsIgnoreCase(name)) return locale; - return null; - } - - /** - * Get a locale from the cache by its name (i.e. "en" from "en_US") - * - * @param name the name of the language - * @return locale of the specified language. Null if not cached - */ - public static Locale getLocaleByName(String name) { - for (Locale locale : LOCALES) - if (locale.getName().equalsIgnoreCase(name)) return locale; - return null; - } - - /** - * Get a locale from the cache by its region (i.e. "US" from "en_US") - * - * @param region the name of the region - * @return locale of the specified region. Null if not cached - */ - public static Locale getLocaleByRegion(String region) { - for (Locale locale : LOCALES) - if (locale.getRegion().equalsIgnoreCase(region)) return locale; - return null; - } - - /** - * Check whether a locale exists and is registered or not - * - * @param name the whole language tag (i.e. "en_US") - * @return true if it exists - */ - public static boolean localeExists(String name) { - for (Locale locale : LOCALES) - if (locale.getLanguageTag().equals(name)) return true; - return false; - } - - /** - * Get an immutable list of all currently loaded locales - * - * @return list of all locales - */ - public static List getLocales() { - return ImmutableList.copyOf(LOCALES); - } - - /** - * Save a default locale file from the project source directory, to the locale folder - * - * @param in file to save - * @param fileName the name of the file to save - * @return true if the operation was successful, false otherwise - */ - public static boolean saveDefaultLocale(InputStream in, String fileName) { - if (!localeFolder.exists()) localeFolder.mkdirs(); - - if (!fileName.endsWith(FILE_EXTENSION)) - fileName = (fileName.lastIndexOf(".") == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.'))) + FILE_EXTENSION; - - File destinationFile = new File(localeFolder, fileName); - if (destinationFile.exists()) { - return compareFiles(plugin.getResource(fileName), destinationFile); - } - - try (OutputStream outputStream = new FileOutputStream(destinationFile)) { - copy(in == null ? plugin.getResource(fileName) : in, outputStream); - - fileName = fileName.substring(0, fileName.lastIndexOf('.')); - String[] localeValues = fileName.split("_"); - - if (localeValues.length != 2) return false; - - LOCALES.add(new Locale(localeValues[0], localeValues[1])); - if (defaultLocale == null) defaultLocale = fileName; - - return true; - } catch (IOException e) { - return false; - } - } - - /** - * Save a default locale file from the project source directory, to the locale folder - * - * @param fileName the name of the file to save - * @return true if the operation was successful, false otherwise - */ - public static boolean saveDefaultLocale(String fileName) { - return saveDefaultLocale(null, fileName); - } - - /** - * Clear all current locale data - */ - public static void clearLocaleData() { - for (Locale locale : LOCALES) - locale.nodes.clear(); - LOCALES.clear(); - } - - // Write new changes to existing files, if any at all - private static boolean compareFiles(InputStream defaultFile, File existingFile) { - // Look for default - if (defaultFile == null) { - defaultFile = plugin.getResource(defaultLocale != null ? defaultLocale : "en_US"); - if (defaultFile == null) return false; // No default at all - } - - boolean changed = false; - - List defaultLines, existingLines; - try (BufferedReader defaultReader = new BufferedReader(new InputStreamReader(defaultFile)); - BufferedReader existingReader = new BufferedReader(new FileReader(existingFile)); - BufferedWriter writer = new BufferedWriter(new FileWriter(existingFile, true))) { - defaultLines = defaultReader.lines().collect(Collectors.toList()); - existingLines = existingReader.lines().map(s -> s.split("\\s*=")[0]).collect(Collectors.toList()); - - for (String defaultValue : defaultLines) { - if (defaultValue.isEmpty() || defaultValue.startsWith("#")) continue; - - String key = defaultValue.split("\\s*=")[0]; - - if (!existingLines.contains(key)) { - if (!changed) { - writer.newLine(); - writer.newLine(); - writer.write("# New messages for " + plugin.getName() + " v" + plugin.getDescription().getVersion()); - } - - writer.newLine(); - writer.write(defaultValue); - - changed = true; - } - } - } catch (IOException e) { - return false; - } - - return changed; - } - - private static void copy(InputStream input, OutputStream output) { - int n; - byte[] buffer = new byte[1024 * 4]; - - try { - while ((n = input.read(buffer)) != -1) { - output.write(buffer, 0, n); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Get the name of the language that this locale is based on. - * (i.e. "en" for English, or "fr" for French) - * - * @return the name of the language - */ - public String getName() { - return name; - } - - /** - * Get the name of the region that this locale is from. - * (i.e. "US" for United States or "CA" for Canada) - * - * @return the name of the region - */ - public String getRegion() { - return region; - } - - /** - * Return the entire locale tag (i.e. "en_US") - * - * @return the language tag - */ - public String getLanguageTag() { - return name + "_" + region; - } - - /** - * Get the file that represents this locale - * - * @return the locale file (.lang) - */ - public File getFile() { - return file; - } - - /** - * Get a message set for a specific node - * - * @param node the node to get - * @return the message for the specified node - */ - public String getMessage(String node) { - return ChatColor.translateAlternateColorCodes('&', this.getMessageOrDefault(node, node)); - } - - /** - * Get a message set for a specific node and replace its params with a supplied arguments. - * - * @param node the node to get - * @param args the replacement arguments - * @return the message for the specified node - */ - public String getMessage(String node, Object... args) { - String message = getMessage(node); - for (Object arg : args) { - message = message.replaceFirst("\\%.*?\\%", arg.toString()); - } - return message; - } - - /** - * Get a message set for a specific node - * - * @param node the node to get - * @param defaultValue the default value given that a value for the node was not found - * @return the message for the specified node. Default if none found - */ - public String getMessageOrDefault(String node, String defaultValue) { - return this.nodes.getOrDefault(node, defaultValue); - } - - /** - * Get the key-value map of nodes to messages - * - * @return node-message map - */ - public Map getMessageNodeMap() { - return ImmutableMap.copyOf(nodes); - } - - /** - * Clear the previous message cache and load new messages directly from file - * - * @return reload messages from file - */ - public boolean reloadMessages() { - if (!this.file.exists()) { - plugin.getLogger().warning("Could not find file for locale " + this.name); - return false; - } - - this.nodes.clear(); // Clear previous data (if any) - - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - String line; - for (int lineNumber = 0; (line = reader.readLine()) != null; lineNumber++) { - if (line.isEmpty() || line.startsWith("#") /* Comment */) continue; - - Matcher matcher = NODE_PATTERN.matcher(line); - if (!matcher.find()) { - System.err.println("Invalid locale syntax at (line=" + lineNumber + ")"); - continue; - } - - nodes.put(matcher.group(1), matcher.group(2)); - } - } catch (IOException e) { - e.printStackTrace(); - return false; - } - return true; - } - -} \ No newline at end of file diff --git a/src/main/java/com/songoda/ultimaterepairing/References.java b/src/main/java/com/songoda/ultimaterepairing/References.java deleted file mode 100644 index c665db1..0000000 --- a/src/main/java/com/songoda/ultimaterepairing/References.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.songoda.ultimaterepairing; - -public class References { - - private String prefix; - - public References() { - prefix = UltimateRepairing.getInstance().getLocale().getMessage("general.nametag.prefix") + " "; - } - - public String getPrefix() { - return this.prefix; - } -} diff --git a/src/main/java/com/songoda/ultimaterepairing/UltimateRepairing.java b/src/main/java/com/songoda/ultimaterepairing/UltimateRepairing.java index cd99743..4e47d6a 100644 --- a/src/main/java/com/songoda/ultimaterepairing/UltimateRepairing.java +++ b/src/main/java/com/songoda/ultimaterepairing/UltimateRepairing.java @@ -13,6 +13,7 @@ import com.songoda.ultimaterepairing.handlers.RepairHandler; import com.songoda.ultimaterepairing.hologram.Hologram; import com.songoda.ultimaterepairing.hologram.HologramHolographicDisplays; import com.songoda.ultimaterepairing.utils.*; +import com.songoda.ultimaterepairing.utils.locale.Locale; import com.songoda.ultimaterepairing.utils.updateModules.LocaleModule; import com.songoda.update.Plugin; import com.songoda.update.SongodaUpdate; @@ -31,8 +32,6 @@ public final class UltimateRepairing extends JavaPlugin implements Listener { private ConfigWrapper dataFile = new ConfigWrapper(this, "", "data.yml"); - public References references = null; - private ServerVersion serverVersion = ServerVersion.fromPackageName(Bukkit.getServer().getClass().getPackage().getName()); private Locale locale; @@ -63,10 +62,8 @@ public final class UltimateRepairing extends JavaPlugin implements Listener { settingsManager.updateSettings(); setupConfig(); - String langMode = getConfig().getString("System.Language Mode"); - Locale.init(this); - Locale.saveDefaultLocale("en_US"); - this.locale = Locale.getLocale(getConfig().getString("System.Language Mode", langMode)); + new Locale(this, "en_US"); + this.locale = Locale.getLocale(getConfig().getString("System.Language Mode")); //Running Songoda Updater Plugin plugin = new Plugin(this, 20); @@ -76,8 +73,6 @@ public final class UltimateRepairing extends JavaPlugin implements Listener { this.editor = new Editor(this); this.anvilManager = new AnvilManager(); - references = new References(); - this.repairHandler = new RepairHandler(this); this.commandManager = new CommandManager(this); new ParticleHandler(this); @@ -180,8 +175,8 @@ public final class UltimateRepairing extends JavaPlugin implements Listener { public void reload() { try { - locale.reloadMessages(); - references = new References(); + this.locale = Locale.getLocale(getConfig().getString("System.Language Mode")); + this.locale.reloadMessages(); reloadConfig(); saveConfig(); } catch (Exception ex) { diff --git a/src/main/java/com/songoda/ultimaterepairing/command/CommandManager.java b/src/main/java/com/songoda/ultimaterepairing/command/CommandManager.java index c6d584a..e4d11a4 100644 --- a/src/main/java/com/songoda/ultimaterepairing/command/CommandManager.java +++ b/src/main/java/com/songoda/ultimaterepairing/command/CommandManager.java @@ -55,7 +55,7 @@ public class CommandManager implements CommandExecutor { } } } - commandSender.sendMessage(instance.references.getPrefix() + Methods.formatText("&7The command you entered does not exist or is spelt incorrectly.")); + instance.getLocale().newMessage("&7The command you entered does not exist or is spelt incorrectly.").sendPrefixedMessage(commandSender); return true; } @@ -67,12 +67,12 @@ public class CommandManager implements CommandExecutor { if (command.getPermissionNode() == null || sender.hasPermission(command.getPermissionNode())) { AbstractCommand.ReturnType returnType = command.runCommand(instance, sender, strings); if (returnType == AbstractCommand.ReturnType.SYNTAX_ERROR) { - sender.sendMessage(instance.references.getPrefix() + Methods.formatText("&cInvalid Syntax!")); - sender.sendMessage(instance.references.getPrefix() + Methods.formatText("&7The valid syntax is: &6" + command.getSyntax() + "&7.")); + instance.getLocale().newMessage("&cInvalid Syntax!").sendPrefixedMessage(sender); + instance.getLocale().newMessage("&7The valid syntax is: &6" + command.getSyntax() + "&7.").sendPrefixedMessage(sender); } return; } - sender.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.general.nopermission")); + instance.getLocale().newMessage("event.general.nopermission").sendPrefixedMessage(sender); } public List getCommands() { diff --git a/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandReload.java b/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandReload.java index dc1559f..46c2ce7 100644 --- a/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandReload.java +++ b/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandReload.java @@ -14,7 +14,7 @@ public class CommandReload extends AbstractCommand { @Override protected ReturnType runCommand(UltimateRepairing instance, CommandSender sender, String... args) { instance.reload(); - sender.sendMessage(Methods.formatText(instance.references.getPrefix() + "&7Configuration and Language files reloaded.")); + instance.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender); return ReturnType.SUCCESS; } diff --git a/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandUltimateRepairing.java b/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandUltimateRepairing.java index e7aa730..30c9722 100644 --- a/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandUltimateRepairing.java +++ b/src/main/java/com/songoda/ultimaterepairing/command/commands/CommandUltimateRepairing.java @@ -14,7 +14,8 @@ public class CommandUltimateRepairing extends AbstractCommand { @Override protected ReturnType runCommand(UltimateRepairing instance, CommandSender sender, String... args) { sender.sendMessage(""); - sender.sendMessage(Methods.formatText(instance.references.getPrefix() + "&7Version " + instance.getDescription().getVersion() + " Created with <3 by &5&l&oBrianna")); + instance.getLocale().newMessage("&7Version " + instance.getDescription().getVersion() + + " Created with <3 by &5&l&oSongoda").sendPrefixedMessage(sender); for (AbstractCommand command : instance.getCommandManager().getCommands()) { if (command.getPermissionNode() == null || sender.hasPermission(command.getPermissionNode())) { diff --git a/src/main/java/com/songoda/ultimaterepairing/handlers/RepairHandler.java b/src/main/java/com/songoda/ultimaterepairing/handlers/RepairHandler.java index 5b5dd97..830fb2e 100644 --- a/src/main/java/com/songoda/ultimaterepairing/handlers/RepairHandler.java +++ b/src/main/java/com/songoda/ultimaterepairing/handlers/RepairHandler.java @@ -41,7 +41,7 @@ public class RepairHandler { yesNo(p, getDataFor(p).getType(), getDataFor(p).getToBeRepaired()); return; } - Inventory i = Bukkit.createInventory(null, 27, Methods.formatText(instance.getLocale().getMessage("interface.repair.title"))); + Inventory i = Bukkit.createInventory(null, 27, Methods.formatText(instance.getLocale().getMessage("interface.repair.title").getMessage())); int nu = 0; while (nu != 27) { @@ -52,9 +52,9 @@ public class RepairHandler { ItemStack item = new ItemStack(Material.valueOf(instance.getConfig().getString("Interfaces.Economy Icon")), 1); ItemMeta itemmeta = item.getItemMeta(); ArrayList lore = new ArrayList<>(); - lore.add(instance.getLocale().getMessage("interface.repair.ecolore")); + lore.add(instance.getLocale().getMessage("interface.repair.ecolore").getMessage()); itemmeta.setLore(lore); - itemmeta.setDisplayName(instance.getLocale().getMessage("interface.repair.eco")); + itemmeta.setDisplayName(instance.getLocale().getMessage("interface.repair.eco").getMessage()); item.setItemMeta(itemmeta); Material mat = Methods.getType(p.getItemInHand()); @@ -63,17 +63,19 @@ public class RepairHandler { String name = (mat.name().substring(0, 1).toUpperCase() + mat.name().toLowerCase().substring(1)).replace("_", " "); ItemMeta itemmeta3 = item3.getItemMeta(); ArrayList lore3 = new ArrayList<>(); - lore3.add(instance.getLocale().getMessage("interface.repair.itemlore", name)); + lore3.add(instance.getLocale().getMessage("interface.repair.itemlore") + .processPlaceholder("item", name).getMessage()); itemmeta3.setLore(lore3); - itemmeta3.setDisplayName(instance.getLocale().getMessage("interface.repair.item", name)); + itemmeta3.setDisplayName(instance.getLocale().getMessage("interface.repair.item") + .processPlaceholder("ITEM", name).getMessage()); item3.setItemMeta(itemmeta3); ItemStack item2 = new ItemStack(Material.valueOf(instance.getConfig().getString("Interfaces.XP Icon")), 1); ItemMeta itemmeta2 = item2.getItemMeta(); ArrayList lore2 = new ArrayList<>(); - lore2.add(instance.getLocale().getMessage("interface.repair.xplore")); + lore2.add(instance.getLocale().getMessage("interface.repair.xplore").getMessage()); itemmeta2.setLore(lore2); - itemmeta2.setDisplayName(instance.getLocale().getMessage("interface.repair.xp")); + itemmeta2.setDisplayName(instance.getLocale().getMessage("interface.repair.xp").getMessage()); item2.setItemMeta(itemmeta2); if (p.hasPermission("ultimaterepairing.use.ECO")) @@ -107,37 +109,38 @@ public class RepairHandler { } - public void preRepair(Player p, RepairType type, Location loc) { + public void preRepair(Player player, RepairType type, Location loc) { try { - Item i = p.getWorld().dropItem(loc.add(0.5, 2, 0.5), p.getItemInHand()); + Item item = player.getWorld().dropItem(loc.add(0.5, 2, 0.5), player.getItemInHand()); // Support for EpicHoppers suction. - i.setMetadata("grabbed", new FixedMetadataValue(instance, "true")); + item.setMetadata("grabbed", new FixedMetadataValue(instance, "true")); - i.setMetadata("betterdrops_ignore", new FixedMetadataValue(instance, true)); - Vector vec = p.getEyeLocation().getDirection(); + item.setMetadata("betterdrops_ignore", new FixedMetadataValue(instance, true)); + Vector vec = player.getEyeLocation().getDirection(); vec.setX(0); vec.setY(0); vec.setZ(0); - i.setVelocity(vec); - i.setPickupDelay(3600); - i.setMetadata("UltimateRepairing", new FixedMetadataValue(instance, "")); + item.setVelocity(vec); + item.setPickupDelay(3600); + item.setMetadata("UltimateRepairing", new FixedMetadataValue(instance, "")); // Get from Map, put new instance in Map if it doesn't exist - PlayerAnvilData playerData = playerAnvilData.computeIfAbsent(p.getUniqueId(), uuid -> new PlayerAnvilData()); - playerData.setItem(i); - playerData.setToBeRepaired(p.getItemInHand()); + PlayerAnvilData playerData = playerAnvilData.computeIfAbsent(player.getUniqueId(), uuid -> new PlayerAnvilData()); + playerData.setItem(item); + playerData.setToBeRepaired(player.getItemInHand()); playerData.setLocations(loc.add(0, -2, 0)); - yesNo(p, type, p.getItemInHand()); + yesNo(player, type, player.getItemInHand()); - p.setItemInHand(null); + player.setItemInHand(null); Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> { - if (i.isValid() && !playerData.isBeingRepaired()) { - p.sendMessage(Methods.formatText(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.timeout"))); - removeItem(playerData, p); - p.closeInventory(); + if (item.isValid() && !playerData.isBeingRepaired()) { + + instance.getLocale().getMessage("event.repair.timeout").sendPrefixedMessage(player); + removeItem(playerData, player); + player.closeInventory(); } }, instance.getConfig().getLong("Main.Time Before Repair Auto Canceled")); @@ -146,38 +149,38 @@ public class RepairHandler { } } - public void initRepair(Player p, Location location) { + public void initRepair(Player player, Location location) { int num = 0; - if (p.hasPermission("ultimaterepairing.use.ECO")) + if (player.hasPermission("ultimaterepairing.use.ECO")) num++; - if (p.hasPermission("ultimaterepairing.use.XP")) + if (player.hasPermission("ultimaterepairing.use.XP")) num++; - if (p.hasPermission("ultimaterepairing.use.ITEM")) + if (player.hasPermission("ultimaterepairing.use.ITEM")) num++; if (location.add(0, 1, 0).getBlock().getType() != Material.AIR) { - p.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.needspace")); + instance.getLocale().getMessage("event.repair.needspace").sendPrefixedMessage(player); return; } - if (p.getItemInHand().getDurability() <= 0) { - p.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.notdamaged")); + if (player.getItemInHand().getDurability() <= 0) { + instance.getLocale().getMessage("event.repair.notdamaged").sendPrefixedMessage(player); return; } - if (p.getItemInHand().getMaxStackSize() != 1) { - p.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.cantrepair")); + if (player.getItemInHand().getMaxStackSize() != 1) { + instance.getLocale().getMessage("event.repair.cantrepair").sendPrefixedMessage(player); return; } - if (num >= 2 || p.hasPermission("ultimaterepairing.use.*")) { - repairType(p); - getDataFor(p).setLocation(location); - } else if (p.hasPermission("ultimaterepairing.use.eco")) - instance.getRepairHandler().preRepair(p, RepairType.ECONOMY, location); - else if (p.hasPermission("ultimaterepairing.use.XP")) - instance.getRepairHandler().preRepair(p, RepairType.XP, location); - else if (p.hasPermission("ultimaterepairing.use.ITEM")) - instance.getRepairHandler().preRepair(p, RepairType.ITEM, location); + if (num >= 2 || player.hasPermission("ultimaterepairing.use.*")) { + repairType(player); + getDataFor(player).setLocation(location); + } else if (player.hasPermission("ultimaterepairing.use.eco")) + instance.getRepairHandler().preRepair(player, RepairType.ECONOMY, location); + else if (player.hasPermission("ultimaterepairing.use.XP")) + instance.getRepairHandler().preRepair(player, RepairType.XP, location); + else if (player.hasPermission("ultimaterepairing.use.ITEM")) + instance.getRepairHandler().preRepair(player, RepairType.ITEM, location); } private void yesNo(Player p, RepairType type, ItemStack item) { @@ -193,7 +196,7 @@ public class RepairHandler { int price = Methods.getCost(type, item); String cost = "0"; - Material mat = new Methods().getType(item); + Material mat = Methods.getType(item); String name = Methods.formatText(mat.name(), true); if (type == RepairType.XP) @@ -203,7 +206,9 @@ public class RepairHandler { else if (type == RepairType.ITEM) cost = price + " " + name; - Inventory inventory = Bukkit.createInventory(null, 27, Methods.formatTitle(instance.getLocale().getMessage("interface.yesno.title", cost))); + Inventory inventory = Bukkit.createInventory(null, 27, + Methods.formatTitle(instance.getLocale().getMessage("interface.yesno.title") + .processPlaceholder("cost", cost).getMessage())); int nu = 0; while (nu != 27) { @@ -213,12 +218,12 @@ public class RepairHandler { ItemStack item2 = new ItemStack(Material.valueOf(instance.getConfig().getString("Interfaces.Buy Icon")), 1); ItemMeta itemmeta2 = item2.getItemMeta(); - itemmeta2.setDisplayName(instance.getLocale().getMessage("interface.yesno.yes")); + itemmeta2.setDisplayName(instance.getLocale().getMessage("interface.yesno.yes").getMessage()); item2.setItemMeta(itemmeta2); ItemStack item3 = new ItemStack(Material.valueOf(instance.getConfig().getString("Interfaces.Exit Icon")), 1); ItemMeta itemmeta3 = item3.getItemMeta(); - itemmeta3.setDisplayName(instance.getLocale().getMessage("interface.yesno.no")); + itemmeta3.setDisplayName(instance.getLocale().getMessage("interface.yesno.no").getMessage()); item3.setItemMeta(itemmeta3); inventory.setItem(4, item); @@ -258,7 +263,7 @@ public class RepairHandler { PlayerAnvilData playerData = playerAnvilData.computeIfAbsent(player.getUniqueId(), uuid -> new PlayerAnvilData()); if (!answer) { removeItem(playerData, player); - player.sendMessage(Methods.formatText(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.cancelled"))); + instance.getLocale().getMessage("event.repair.cancelled").sendPrefixedMessage(player); return; } RepairType type = playerData.getType(); @@ -330,14 +335,14 @@ public class RepairHandler { player.playSound(location, Sound.valueOf("BLOCK_ANVIL_LAND"), 1L, 1L); player.getWorld().playEffect(location, effect, blockTypeFinal); player.getWorld().playEffect(location, effect, Material.ANVIL); - player.sendMessage(Methods.formatText(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.success"))); + instance.getLocale().getMessage("event.repair.success").sendPrefixedMessage(player); playerData.getToBeRepaired().setDurability((short) 0); HashMap items = player.getInventory().addItem(playerData.getToBeRepaired()); for (ItemStack item : items.values()) { player.getWorld().dropItemNaturally(player.getLocation(), item); } - + playerData.getItem().remove(); if (player.getGameMode() != GameMode.CREATIVE && type == RepairType.XP) { @@ -353,11 +358,16 @@ public class RepairHandler { if (!economy) player.sendMessage("Vault is not installed."); else - player.sendMessage(Methods.formatText(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.notenough", instance.getLocale().getMessage("interface.repair.eco")))); + instance.getLocale().getMessage("event.repair.notenough") + .processPlaceholder("type", instance.getLocale().getMessage("interface.repair.eco").getMessage()) + .sendPrefixedMessage(player); } else if (type == RepairType.XP) - player.sendMessage(Methods.formatText(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.notenough", instance.getLocale().getMessage("interface.repair.xp")))); + instance.getLocale().getMessage("event.repair.notenough") + .processPlaceholder("type", instance.getLocale().getMessage("interface.repair.xp").getMessage()) + .sendPrefixedMessage(player); else - player.sendMessage(Methods.formatText(instance.references.getPrefix() + instance.getLocale().getMessage("event.repair.notenough", name))); + instance.getLocale().getMessage("event.repair.notenough") + .processPlaceholder("type", name).sendPrefixedMessage(player); } catch (Exception ex) { diff --git a/src/main/java/com/songoda/ultimaterepairing/hologram/Hologram.java b/src/main/java/com/songoda/ultimaterepairing/hologram/Hologram.java index 45d922d..5f3bdbc 100644 --- a/src/main/java/com/songoda/ultimaterepairing/hologram/Hologram.java +++ b/src/main/java/com/songoda/ultimaterepairing/hologram/Hologram.java @@ -55,13 +55,13 @@ public abstract class Hologram { ArrayList lines = new ArrayList<>(); if (!instance.getConfig().getBoolean("Main.Enable Default Anvil Function")) - lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.oneclick"))); + lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.oneclick").getMessage())); else if (instance.getConfig().getBoolean("Main.Swap Right And Left Click Options")) - lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.swapclick"))); + lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.swapclick").getMessage())); else - lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.click"))); + lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.click").getMessage())); - lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.torepair"))); + lines.add(Methods.formatText(instance.getLocale().getMessage("general.hologram.torepair").getMessage())); Location location = anvil.getLocation(); diff --git a/src/main/java/com/songoda/ultimaterepairing/listeners/InventoryListeners.java b/src/main/java/com/songoda/ultimaterepairing/listeners/InventoryListeners.java index 3300f89..3e8d14e 100644 --- a/src/main/java/com/songoda/ultimaterepairing/listeners/InventoryListeners.java +++ b/src/main/java/com/songoda/ultimaterepairing/listeners/InventoryListeners.java @@ -55,7 +55,7 @@ public class InventoryListeners implements Listener { instance.getRepairHandler().finish(false, p); p.closeInventory(); } - } else if (event.getView().getTitle().equals(Methods.formatTitle(instance.getLocale().getMessage("interface.repair.title")))) { + } else if (event.getView().getTitle().equals(Methods.formatTitle(instance.getLocale().getMessage("interface.repair.title").getMessage()))) { event.setCancelled(true); Location loc = instance.getRepairHandler().getDataFor(p).getLocation(); if (event.getSlot() == 11) { diff --git a/src/main/java/com/songoda/ultimaterepairing/utils/locale/Locale.java b/src/main/java/com/songoda/ultimaterepairing/utils/locale/Locale.java new file mode 100644 index 0000000..33c1172 --- /dev/null +++ b/src/main/java/com/songoda/ultimaterepairing/utils/locale/Locale.java @@ -0,0 +1,302 @@ +package com.songoda.ultimaterepairing.utils.locale; + +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Assists in the utilization of localization files. + * Created to be used by the Songoda Team. + * + * @author Brianna O'Keefe - Songoda + */ +public class Locale { + + private static final List LOCALES = new ArrayList<>(); + private static final Pattern NODE_PATTERN = Pattern.compile("(\\w+(?:\\.{1}\\w+)*)\\s*=\\s*\"(.*)\""); + private static final String FILE_EXTENSION = ".lang"; + private static JavaPlugin plugin; + private static File localeFolder; + + private final Map nodes = new HashMap<>(); + + private static String defaultLocale; + + private File file; + private String name; + + /** + * Instantiate the Locale class for future use + * + * @param name the name of the instantiated language + */ + private Locale(String name) { + if (plugin == null) + return; + + this.name = name; + + String fileName = name + FILE_EXTENSION; + this.file = new File(localeFolder, fileName); + + if (!this.reloadMessages()) return; + + plugin.getLogger().info("Loaded locale \"" + fileName + "\""); + } + + /** + * Initialize the class to load all existing language files and update them. + * This must be called before any other methods in this class as otherwise + * the methods will fail to invoke + * + * @param plugin the plugin instance + * @param defaultLocale the default language + */ + public Locale(JavaPlugin plugin, String defaultLocale) { + + Locale.plugin = plugin; + Locale.localeFolder = new File(plugin.getDataFolder(), "locales/"); + + if (!localeFolder.exists()) localeFolder.mkdirs(); + + //Save the default locale file. + Locale.defaultLocale = defaultLocale; + saveLocale(defaultLocale); + + for (File file : localeFolder.listFiles()) { + String fileName = file.getName(); + if (!fileName.endsWith(FILE_EXTENSION)) continue; + + String name = fileName.substring(0, fileName.lastIndexOf('.')); + + if (name.split("_").length != 2) continue; + if (localeLoaded(name)) continue; + + LOCALES.add(new Locale(name)); + } + } + + /** + * Save a locale file from the InputStream, to the locale folder + * + * @param fileName the name of the file to save + * @return true if the operation was successful, false otherwise + */ + public static boolean saveLocale(String fileName) { + return saveLocale(plugin.getResource(defaultLocale + FILE_EXTENSION), fileName); + } + + + /** + * Save a locale file from the InputStream, to the locale folder + * + * @param in file to save + * @param fileName the name of the file to save + * @return true if the operation was successful, false otherwise + */ + public static boolean saveLocale(InputStream in, String fileName) { + if (!localeFolder.exists()) localeFolder.mkdirs(); + + if (!fileName.endsWith(FILE_EXTENSION)) + fileName = (fileName.lastIndexOf(".") == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.'))) + FILE_EXTENSION; + + File destinationFile = new File(localeFolder, fileName); + if (destinationFile.exists()) + return compareFiles(in, destinationFile); + + try (OutputStream outputStream = new FileOutputStream(destinationFile)) { + copy(in, outputStream); + + fileName = fileName.substring(0, fileName.lastIndexOf('.')); + + if (fileName.split("_").length != 2) return false; + + LOCALES.add(new Locale(fileName)); + if (defaultLocale == null) defaultLocale = fileName; + return true; + } catch (IOException e) { + return false; + } + } + + // Write new changes to existing files, if any at all + private static boolean compareFiles(InputStream in, File existingFile) { + InputStream defaultFile = + in == null ? plugin.getResource((defaultLocale != null ? defaultLocale : "en_US") + FILE_EXTENSION) : in; + + boolean changed = false; + + List defaultLines, existingLines; + try (BufferedReader defaultReader = new BufferedReader(new InputStreamReader(defaultFile)); + BufferedReader existingReader = new BufferedReader(new FileReader(existingFile)); + BufferedWriter writer = new BufferedWriter(new FileWriter(existingFile, true))) { + defaultLines = defaultReader.lines().collect(Collectors.toList()); + existingLines = existingReader.lines().map(s -> s.split("\\s*=")[0]).collect(Collectors.toList()); + + for (String defaultValue : defaultLines) { + if (defaultValue.isEmpty() || defaultValue.startsWith("#")) continue; + + String key = defaultValue.split("\\s*=")[0]; + + if (!existingLines.contains(key)) { + if (!changed) { + writer.newLine(); + writer.newLine(); + // Leave a note alerting the user of the newly added messages. + writer.write("# New messages for " + plugin.getName() + " v" + plugin.getDescription().getVersion() + "."); + + // If changes were found outside of the default file leave a note explaining that. + if (in == null) { + writer.newLine(); + writer.write("# These translations were found untranslated, join"); + writer.newLine(); + writer.write("# our translation Discord https://discord.gg/f7fpZEf"); + writer.newLine(); + writer.write("# to request an official update!"); + } + } + + writer.newLine(); + writer.write(defaultValue); + + changed = true; + } + } + if (in != null && !changed) compareFiles(null, existingFile); + } catch (IOException e) { + return false; + } + + return changed; + } + + + /** + * Check whether a locale exists and is registered or not + * + * @param name the whole language tag (i.e. "en_US") + * @return true if it exists + */ + public static boolean localeLoaded(String name) { + for (Locale locale : LOCALES) + if (locale.getName().equals(name)) return true; + return false; + } + + + /** + * Get a locale by its entire proper name (i.e. "en_US") + * + * @param name the full name of the locale + * @return locale of the specified name + */ + public static Locale getLocale(String name) { + for (Locale locale : LOCALES) + if (locale.getName().equalsIgnoreCase(name)) return locale; + return null; + } + + /** + * Clear the previous message cache and load new messages directly from file + * + * @return reload messages from file + */ + public boolean reloadMessages() { + if (!this.file.exists()) { + plugin.getLogger().warning("Could not find file for locale \"" + this.name + "\""); + return false; + } + + this.nodes.clear(); // Clear previous data (if any) + + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + for (int lineNumber = 0; (line = reader.readLine()) != null; lineNumber++) { + if (line.trim().isEmpty() || line.startsWith("#") /* Comment */) continue; + + Matcher matcher = NODE_PATTERN.matcher(line); + if (!matcher.find()) { + System.err.println("Invalid locale syntax at (line=" + lineNumber + ")"); + continue; + } + + nodes.put(matcher.group(1), matcher.group(2)); + } + } catch (IOException e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Supply the Message object with the plugins prefix. + * + * @param message message to be applied + * @return applied message + */ + private Message supplyPrefix(Message message) { + return message.setPrefix(this.nodes.getOrDefault("general.nametag.prefix", "[Plugin]")); + } + + /** + * Create a new unsaved Message + * + * @param message the message to create + * @return the created message + */ + public Message newMessage(String message) { + return supplyPrefix(new Message(message)); + } + + /** + * Get a message set for a specific node. + * + * @param node the node to get + * @return the message for the specified node + */ + public Message getMessage(String node) { + return this.getMessageOrDefault(node, node); + } + + /** + * Get a message set for a specific node + * + * @param node the node to get + * @param defaultValue the default value given that a value for the node was not found + * @return the message for the specified node. Default if none found + */ + public Message getMessageOrDefault(String node, String defaultValue) { + return supplyPrefix(new Message(this.nodes.getOrDefault(node, defaultValue))); + } + + /** + * Return the locale name (i.e. "en_US") + * + * @return the locale name + */ + public String getName() { + return name; + } + + private static void copy(InputStream input, OutputStream output) { + int n; + byte[] buffer = new byte[1024 * 4]; + + try { + while ((n = input.read(buffer)) != -1) { + output.write(buffer, 0, n); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/songoda/ultimaterepairing/utils/locale/Message.java b/src/main/java/com/songoda/ultimaterepairing/utils/locale/Message.java new file mode 100644 index 0000000..a7ca868 --- /dev/null +++ b/src/main/java/com/songoda/ultimaterepairing/utils/locale/Message.java @@ -0,0 +1,115 @@ +package com.songoda.ultimaterepairing.utils.locale; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +/** + * The Message object. This holds the message to be sent + * as well as the plugins prefix so that they can both be + * easily manipulated then deployed + */ +public class Message { + + private String prefix = null; + private String message; + + /** + * create a new message + * + * @param message the message text + */ + public Message(String message) { + this.message = message; + } + + /** + * Format and send the held message to a player + * + * @param player player to send the message to + */ + public void sendMessage(Player player) { + player.sendMessage(this.getMessage()); + } + + /** + * Format and send the held message with the + * appended plugin prefix to a player + * + * @param player player to send the message to + */ + public void sendPrefixedMessage(Player player) { + player.sendMessage(this.getPrefixedMessage()); + } + + /** + * Format and send the held message to a player + * + * @param sender command sender to send the message to + */ + public void sendMessage(CommandSender sender) { + sender.sendMessage(this.getMessage()); + } + + /** + * Format and send the held message with the + * appended plugin prefix to a command sender + * + * @param sender command sender to send the message to + */ + public void sendPrefixedMessage(CommandSender sender) { + sender.sendMessage(this.getPrefixedMessage()); + } + + /** + * Format the held message and append the plugins + * prefix + * + * @return the prefixed message + */ + public String getPrefixedMessage() { + return ChatColor.translateAlternateColorCodes('&',(prefix == null ? "" : this.prefix) + + " " + this.message); + } + + /** + * Get and format the held message + * + * @return the message + */ + public String getMessage() { + return ChatColor.translateAlternateColorCodes('&', this.message); + } + + /** + * Get the held message + * + * @return the message + */ + public String getUnformattedMessage() { + return this.message; + } + + /** + * Replace the provided placeholder with the + * provided object + * + * @param placeholder the placeholder to replace + * @param replacement the replacement object + * @return the modified Message + */ + public Message processPlaceholder(String placeholder, Object replacement) { + this.message = message.replace("%" + placeholder + "%", replacement.toString()); + return this; + } + + Message setPrefix(String prefix) { + this.prefix = prefix; + return this; + } + + @Override + public String toString() { + return this.message; + } +} \ No newline at end of file diff --git a/src/main/java/com/songoda/ultimaterepairing/utils/updateModules/LocaleModule.java b/src/main/java/com/songoda/ultimaterepairing/utils/updateModules/LocaleModule.java index 96f2b80..bee2d23 100644 --- a/src/main/java/com/songoda/ultimaterepairing/utils/updateModules/LocaleModule.java +++ b/src/main/java/com/songoda/ultimaterepairing/utils/updateModules/LocaleModule.java @@ -22,7 +22,7 @@ public class LocaleModule implements Module { if (file.get("type").equals("locale")) { InputStream in = new URL((String) file.get("link")).openStream(); - UltimateRepairing.getInstance().getLocale().saveDefaultLocale(in, (String) file.get("name")); + UltimateRepairing.getInstance().getLocale().saveLocale(in, (String) file.get("name")); } } } catch (IOException e) {