Backport Messages from BigDoors v2
- Backported the Messages system from BigDoors v2. This new system does not overwrite the default language file anymore (nor does it make it read-only). Instead, it reads as many translations from whatever file is selected and takes any missing translations from the translation file inside the jar (and lets the admin know that a translation is missing in the console). This makes the plugin a bit friendlier to use for people that cannot be bothered to read the disclaimer at the top of the file.
This commit is contained in:
parent
e093b18124
commit
7f09a34fdb
@ -9,8 +9,9 @@ import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor;
|
|||||||
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
||||||
import nl.pim16aap2.armoredElytra.util.ArmorTierName;
|
import nl.pim16aap2.armoredElytra.util.ArmorTierName;
|
||||||
import nl.pim16aap2.armoredElytra.util.ConfigLoader;
|
import nl.pim16aap2.armoredElytra.util.ConfigLoader;
|
||||||
import nl.pim16aap2.armoredElytra.util.Messages;
|
|
||||||
import nl.pim16aap2.armoredElytra.util.UpdateManager;
|
import nl.pim16aap2.armoredElytra.util.UpdateManager;
|
||||||
|
import nl.pim16aap2.armoredElytra.util.messages.Message;
|
||||||
|
import nl.pim16aap2.armoredElytra.util.messages.Messages;
|
||||||
import org.bstats.bukkit.Metrics;
|
import org.bstats.bukkit.Metrics;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -21,9 +22,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
|
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
// TODO: Figure out if the config really does read the list of enchantments accurately. A bug report with a customized config seemed to load the default settings...
|
// TODO: Figure out if the config really does read the list of enchantments accurately. A bug report with a customized config seemed to load the default settings...
|
||||||
// TODO: Verify enchantments on startup. Remove them from the list if they're invalid.
|
// TODO: Verify enchantments on startup. Remove them from the list if they're invalid.
|
||||||
@ -37,9 +36,6 @@ public class ArmoredElytra extends JavaPlugin implements Listener
|
|||||||
private ConfigLoader config;
|
private ConfigLoader config;
|
||||||
|
|
||||||
private final Map<ArmorTier, ArmorTierName> armorTierNames = new EnumMap<>(ArmorTier.class);
|
private final Map<ArmorTier, ArmorTierName> armorTierNames = new EnumMap<>(ArmorTier.class);
|
||||||
private String elytraReceivedMessage;
|
|
||||||
private String usageDeniedMessage;
|
|
||||||
private String elytraLore;
|
|
||||||
private boolean upToDate;
|
private boolean upToDate;
|
||||||
private boolean is1_9;
|
private boolean is1_9;
|
||||||
private UpdateManager updateManager;
|
private UpdateManager updateManager;
|
||||||
@ -112,35 +108,19 @@ public class ArmoredElytra extends JavaPlugin implements Listener
|
|||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String getColorCodedStringFromConfig(final String configEntry)
|
|
||||||
{
|
|
||||||
return getMyMessages().getString(configEntry).replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readMessages()
|
private void readMessages()
|
||||||
{
|
{
|
||||||
// Replace color codes by the corresponding colors.
|
|
||||||
usageDeniedMessage = getColorCodedStringFromConfig("MESSAGES.UsageDenied");
|
|
||||||
elytraReceivedMessage = getColorCodedStringFromConfig("MESSAGES.ElytraReceived");
|
|
||||||
elytraLore = getColorCodedStringFromConfig("MESSAGES.Lore");
|
|
||||||
|
|
||||||
armorTierNames.put(ArmorTier.NONE, new ArmorTierName("NONE", "NONE")); // Shouldn't be used.
|
armorTierNames.put(ArmorTier.NONE, new ArmorTierName("NONE", "NONE")); // Shouldn't be used.
|
||||||
armorTierNames.put(ArmorTier.LEATHER, new ArmorTierName(getColorCodedStringFromConfig("TIER.Leather"),
|
armorTierNames.put(ArmorTier.LEATHER, new ArmorTierName(messages.getString(Message.TIER_LEATHER),
|
||||||
getColorCodedStringFromConfig("TIER.SHORT.Leather")));
|
messages.getString(Message.TIER_SHORT_LEATHER)));
|
||||||
armorTierNames.put(ArmorTier.GOLD, new ArmorTierName(getColorCodedStringFromConfig("TIER.Gold"),
|
armorTierNames.put(ArmorTier.GOLD, new ArmorTierName(messages.getString(Message.TIER_GOLD),
|
||||||
getColorCodedStringFromConfig("TIER.SHORT.Gold")));
|
messages.getString(Message.TIER_SHORT_GOLD)));
|
||||||
armorTierNames.put(ArmorTier.CHAIN, new ArmorTierName(getColorCodedStringFromConfig("TIER.Chain"),
|
armorTierNames.put(ArmorTier.CHAIN, new ArmorTierName(messages.getString(Message.TIER_CHAIN),
|
||||||
getColorCodedStringFromConfig("TIER.SHORT.Chain")));
|
messages.getString(Message.TIER_SHORT_CHAIN)));
|
||||||
armorTierNames.put(ArmorTier.IRON, new ArmorTierName(getColorCodedStringFromConfig("TIER.Iron"),
|
armorTierNames.put(ArmorTier.IRON, new ArmorTierName(messages.getString(Message.TIER_IRON),
|
||||||
getColorCodedStringFromConfig("TIER.SHORT.Iron")));
|
messages.getString(Message.TIER_SHORT_IRON)));
|
||||||
armorTierNames.put(ArmorTier.DIAMOND, new ArmorTierName(getColorCodedStringFromConfig("TIER.Diamond"),
|
armorTierNames.put(ArmorTier.DIAMOND, new ArmorTierName(messages.getString(Message.TIER_DIAMOND),
|
||||||
getColorCodedStringFromConfig("TIER.SHORT.Diamond")));
|
messages.getString(Message.TIER_SHORT_DIAMOND)));
|
||||||
|
|
||||||
// Change the string to null if it says "NONE".
|
|
||||||
usageDeniedMessage = (Objects.equals(usageDeniedMessage, new String("NONE")) ? null : usageDeniedMessage);
|
|
||||||
elytraReceivedMessage = (Objects.equals(elytraReceivedMessage, new String("NONE")) ? null :
|
|
||||||
elytraReceivedMessage);
|
|
||||||
elytraLore = (Objects.equals(elytraLore, new String("NONE")) ? null : elytraLore);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean playerHasCraftPerm(Player player, ArmorTier armorTier)
|
public boolean playerHasCraftPerm(Player player, ArmorTier armorTier)
|
||||||
@ -185,41 +165,41 @@ public class ArmoredElytra extends JavaPlugin implements Listener
|
|||||||
messagePlayer(player, ChatColor.WHITE, str);
|
messagePlayer(player, ChatColor.WHITE, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getMessageWithTierNames(final Message message, final ArmorTier armorTier)
|
||||||
|
{
|
||||||
|
ArmorTierName tierName = armorTierNames.get(armorTier);
|
||||||
|
return getMyMessages().getString(message,
|
||||||
|
tierName.getLongName(),
|
||||||
|
tierName.getShortName());
|
||||||
|
}
|
||||||
|
|
||||||
// Send the usageDeniedMessage message to the player.
|
// Send the usageDeniedMessage message to the player.
|
||||||
public void usageDeniedMessage(Player player, ArmorTier armorTier)
|
public void usageDeniedMessage(Player player, ArmorTier armorTier)
|
||||||
{
|
{
|
||||||
if (usageDeniedMessage != null)
|
final String message = getMessageWithTierNames(Message.MESSAGES_USAGEDENIED, armorTier);
|
||||||
{
|
if (!message.equals("NONE"))
|
||||||
final String message = fillInArmorTierInStringNoColor(usageDeniedMessage, armorTier);
|
|
||||||
messagePlayer(player, ChatColor.RED, message);
|
messagePlayer(player, ChatColor.RED, message);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the elytraReceivedMessage message to the player.
|
// Send the elytraReceivedMessage message to the player.
|
||||||
public void elytraReceivedMessage(Player player, ArmorTier armorTier)
|
public void elytraReceivedMessage(Player player, ArmorTier armorTier)
|
||||||
{
|
{
|
||||||
if (elytraReceivedMessage != null)
|
final String message = getMessageWithTierNames(Message.MESSAGES_ELYTRARECEIVED, armorTier);
|
||||||
{
|
if (!message.equals("NONE"))
|
||||||
final String message = fillInArmorTierInStringNoColor(elytraReceivedMessage, armorTier);
|
|
||||||
messagePlayer(player, ChatColor.GREEN, message);
|
messagePlayer(player, ChatColor.GREEN, message);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern ARMOR_TIER = Pattern.compile("%ARMOR_TIER%");
|
public void sendNoGivePermissionMessage(Player player, ArmorTier armorTier)
|
||||||
private static final Pattern ARMOR_TIER_SHORT = Pattern.compile("%ARMOR_TIER_SHORT%");
|
|
||||||
|
|
||||||
// Replace %ARMOR_TIER% by the name of that armor tier in a string, but strip %ARMOR_TIER% of its color.
|
|
||||||
public String fillInArmorTierInStringNoColor(String string, ArmorTier armorTier)
|
|
||||||
{
|
{
|
||||||
if (armorTier == null)
|
final String message = getMessageWithTierNames(Message.MESSAGES_NOGIVEPERMISSION, armorTier);
|
||||||
{
|
messagePlayer(player, ChatColor.RED, message);
|
||||||
getLogger().log(Level.INFO, "ArmorTier was null! Failed to obtain proper string!");
|
}
|
||||||
return string;
|
|
||||||
}
|
public String getElytraLore(ArmorTier armorTier)
|
||||||
final ArmorTierName tierName = armorTierNames.get(armorTier);
|
{
|
||||||
return ARMOR_TIER_SHORT
|
final String message = getMessageWithTierNames(Message.MESSAGES_LORE, armorTier);
|
||||||
.matcher(ARMOR_TIER.matcher(string).replaceAll(ChatColor.stripColor(tierName.getLongName())))
|
Bukkit.broadcastMessage(message);
|
||||||
.replaceAll(ChatColor.stripColor(tierName.getShortName()));
|
return message.equals("NONE") ? null : message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print a string to the log.
|
// Print a string to the log.
|
||||||
@ -258,11 +238,6 @@ public class ArmoredElytra extends JavaPlugin implements Listener
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getElytraLore()
|
|
||||||
{
|
|
||||||
return elytraLore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArmoredElytraName(ArmorTier tier)
|
public String getArmoredElytraName(ArmorTier tier)
|
||||||
{
|
{
|
||||||
if (tier == null)
|
if (tier == null)
|
||||||
|
@ -3,6 +3,7 @@ package nl.pim16aap2.armoredElytra.handlers;
|
|||||||
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
||||||
import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor;
|
import nl.pim16aap2.armoredElytra.nbtEditor.NBTEditor;
|
||||||
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
||||||
|
import nl.pim16aap2.armoredElytra.util.messages.Message;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@ -34,7 +35,7 @@ public class CommandHandler implements CommandExecutor
|
|||||||
|
|
||||||
if (plugin.getConfigLoader().uninstallMode())
|
if (plugin.getConfigLoader().uninstallMode())
|
||||||
{
|
{
|
||||||
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.UninstallMode"));
|
plugin.messagePlayer(player, plugin.getMyMessages().getString(Message.MESSAGES_UNINSTALLMODE));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +68,8 @@ public class CommandHandler implements CommandExecutor
|
|||||||
allowed = player.hasPermission("armoredelytra.give." + ArmorTier.getName(armorTier));
|
allowed = player.hasPermission("armoredelytra.give." + ArmorTier.getName(armorTier));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
plugin.messagePlayer(player, plugin.getMyMessages().getString("MESSAGES.UnsupportedTier"));
|
plugin.messagePlayer(player, plugin.getMyMessages()
|
||||||
|
.getString(Message.MESSAGES_UNSUPPORTEDTIER));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,8 +81,7 @@ public class CommandHandler implements CommandExecutor
|
|||||||
plugin.giveArmoredElytraToPlayer(receiver, newElytra);
|
plugin.giveArmoredElytraToPlayer(receiver, newElytra);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
plugin.messagePlayer(player, plugin.fillInArmorTierInStringNoColor(
|
plugin.sendNoGivePermissionMessage(player, armorTier);
|
||||||
plugin.getMyMessages().getString("MESSAGES.NoGivePermission"), armorTier));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +95,7 @@ public class CommandHandler implements CommandExecutor
|
|||||||
|
|
||||||
if (args.length == 2)
|
if (args.length == 2)
|
||||||
{
|
{
|
||||||
ItemStack newElytra = null;
|
ItemStack newElytra;
|
||||||
final String tier = args[1];
|
final String tier = args[1];
|
||||||
if (Bukkit.getPlayer(args[0]) != null)
|
if (Bukkit.getPlayer(args[0]) != null)
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,7 @@ import nl.pim16aap2.armoredElytra.util.AllowedToWearEnum;
|
|||||||
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
||||||
import nl.pim16aap2.armoredElytra.util.Util;
|
import nl.pim16aap2.armoredElytra.util.Util;
|
||||||
import nl.pim16aap2.armoredElytra.util.XMaterial;
|
import nl.pim16aap2.armoredElytra.util.XMaterial;
|
||||||
|
import nl.pim16aap2.armoredElytra.util.messages.Message;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
@ -525,7 +526,7 @@ public class EventHandlers implements Listener
|
|||||||
case ALLOWED:
|
case ALLOWED:
|
||||||
break;
|
break;
|
||||||
case BROKEN:
|
case BROKEN:
|
||||||
plugin.messagePlayer(e.getPlayer(), plugin.getMyMessages().getString("MESSAGES.RepairNeeded"));
|
plugin.messagePlayer(e.getPlayer(), plugin.getMyMessages().getString(Message.MESSAGES_REPAIRNEEDED));
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
break;
|
break;
|
||||||
case NOPERMISSION:
|
case NOPERMISSION:
|
||||||
|
@ -3,6 +3,7 @@ package nl.pim16aap2.armoredElytra.nbtEditor;
|
|||||||
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
||||||
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
import nl.pim16aap2.armoredElytra.util.ArmorTier;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
@ -145,10 +146,9 @@ public class NBTEditor
|
|||||||
int armorToughness = ArmorTier.getToughness(armorTier);
|
int armorToughness = ArmorTier.getToughness(armorTier);
|
||||||
|
|
||||||
itemmeta.setDisplayName(ArmoredElytra.getInstance().getArmoredElytraName(armorTier));
|
itemmeta.setDisplayName(ArmoredElytra.getInstance().getArmoredElytraName(armorTier));
|
||||||
if (ArmoredElytra.getInstance().getElytraLore() != null)
|
final String message = ChatColor.stripColor(ArmoredElytra.getInstance().getElytraLore(armorTier));
|
||||||
itemmeta
|
if (message != null)
|
||||||
.setLore(Arrays.asList(ArmoredElytra.getInstance().fillInArmorTierInStringNoColor(
|
itemmeta.setLore(Arrays.asList(message));
|
||||||
ArmoredElytra.getInstance().getElytraLore(), armorTier)));
|
|
||||||
|
|
||||||
item.setItemMeta(itemmeta);
|
item.setItemMeta(itemmeta);
|
||||||
|
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
package nl.pim16aap2.armoredElytra.util;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
|
||||||
|
|
||||||
public class Messages
|
|
||||||
{
|
|
||||||
private Map<String, String> messageMap = new HashMap<>();
|
|
||||||
private ArmoredElytra plugin;
|
|
||||||
private File textFile;
|
|
||||||
|
|
||||||
public Messages(ArmoredElytra plugin)
|
|
||||||
{
|
|
||||||
this.plugin = plugin;
|
|
||||||
textFile = new File(plugin.getDataFolder(), plugin.getConfigLoader().languageFile() + ".txt");
|
|
||||||
if (!textFile.exists())
|
|
||||||
{
|
|
||||||
plugin.myLogger(Level.WARNING, "Failed to load language file: \"" + textFile + "\": File not found! Using default file instead!");
|
|
||||||
textFile = new File(plugin.getDataFolder(), "en_US.txt");
|
|
||||||
}
|
|
||||||
readFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeDefaultFile()
|
|
||||||
{
|
|
||||||
File defaultFile = new File(plugin.getDataFolder(), "en_US.txt");
|
|
||||||
if (!defaultFile.setWritable(true))
|
|
||||||
plugin.myLogger(Level.SEVERE, "Failed to make file \"" + defaultFile + "\" writable!");
|
|
||||||
|
|
||||||
// Load the default en_US from the resources.
|
|
||||||
plugin.saveResource("en_US.txt", true);
|
|
||||||
if (!defaultFile.setWritable(false))
|
|
||||||
{
|
|
||||||
plugin.myLogger(Level.WARNING, "Could not set default language file to read-only!");
|
|
||||||
plugin.myLogger(Level.WARNING, "This is not a big problem. Just remember not to edit the file!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read locale file.
|
|
||||||
private void readFile()
|
|
||||||
{
|
|
||||||
writeDefaultFile();
|
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new FileReader(textFile)))
|
|
||||||
{
|
|
||||||
String sCurrentLine;
|
|
||||||
|
|
||||||
while ((sCurrentLine = br.readLine()) != null)
|
|
||||||
{
|
|
||||||
// Ignore comments.
|
|
||||||
if (sCurrentLine.startsWith("#") || sCurrentLine.isEmpty())
|
|
||||||
continue;
|
|
||||||
String key, value;
|
|
||||||
String[] parts = sCurrentLine.split("=", 2);
|
|
||||||
key = parts[0];
|
|
||||||
value = parts[1].replaceAll("&((?i)[0-9a-fk-or])", "\u00A7$1");
|
|
||||||
String[] newLineSplitter = value.split("\\\\n");
|
|
||||||
|
|
||||||
String values = newLineSplitter[0];
|
|
||||||
|
|
||||||
for (int idx = 1; idx < newLineSplitter.length; ++idx)
|
|
||||||
values += "\n" + newLineSplitter[idx];
|
|
||||||
|
|
||||||
messageMap.put(key, values);
|
|
||||||
}
|
|
||||||
br.close();
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException e)
|
|
||||||
{
|
|
||||||
plugin.myLogger(Level.SEVERE, "Locale file \"" + textFile + "\" does not exist!");
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
plugin.myLogger(Level.SEVERE, "Could not read locale file: \"" + textFile + "\"");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a string from a key. Returns "null" if null.
|
|
||||||
public String getString(String key)
|
|
||||||
{
|
|
||||||
String value = messageMap.get(key);
|
|
||||||
if (value != null)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
plugin.myLogger(Level.WARNING, "Failed to get the translation for key " + key);
|
|
||||||
return "Translation for key \"" + key + "\" not found! Contact server admin!";
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package nl.pim16aap2.armoredElytra.util.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents supported variables in localizable messages.
|
||||||
|
*
|
||||||
|
* @author Pim
|
||||||
|
*/
|
||||||
|
public interface IMessageVariable
|
||||||
|
{
|
||||||
|
String VAR_TIER_NAME = "%ARMOR_TIER%";
|
||||||
|
String VAR_TIER_NAME_SHORT = "%ARMOR_TIER_SHORT%";
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package nl.pim16aap2.armoredElytra.util.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a localizable message.
|
||||||
|
*
|
||||||
|
* @author Pim
|
||||||
|
*/
|
||||||
|
public enum Message implements IMessageVariable
|
||||||
|
{
|
||||||
|
EMPTY(),
|
||||||
|
|
||||||
|
TIER_LEATHER(),
|
||||||
|
TIER_GOLD(),
|
||||||
|
TIER_CHAIN(),
|
||||||
|
TIER_IRON(),
|
||||||
|
TIER_DIAMOND(),
|
||||||
|
|
||||||
|
TIER_SHORT_LEATHER(),
|
||||||
|
TIER_SHORT_GOLD(),
|
||||||
|
TIER_SHORT_CHAIN(),
|
||||||
|
TIER_SHORT_IRON(),
|
||||||
|
TIER_SHORT_DIAMOND(),
|
||||||
|
|
||||||
|
MESSAGES_UNINSTALLMODE(),
|
||||||
|
MESSAGES_UNSUPPORTEDTIER(),
|
||||||
|
|
||||||
|
MESSAGES_REPAIRNEEDED(),
|
||||||
|
MESSAGES_LORE(VAR_TIER_NAME, VAR_TIER_NAME_SHORT),
|
||||||
|
MESSAGES_NOGIVEPERMISSION(VAR_TIER_NAME, VAR_TIER_NAME_SHORT),
|
||||||
|
MESSAGES_USAGEDENIED(VAR_TIER_NAME, VAR_TIER_NAME_SHORT),
|
||||||
|
MESSAGES_ELYTRARECEIVED(VAR_TIER_NAME, VAR_TIER_NAME_SHORT),
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of names that can be used as variables in this message.
|
||||||
|
* <p>
|
||||||
|
* For example: "This door will move %BLOCKSTOMOVE% blocks." Would contain at least "%BLOCKSTOMOVE%".
|
||||||
|
*/
|
||||||
|
private final String[] variableNames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message.
|
||||||
|
*
|
||||||
|
* @param variableNames The names of the variables in the value that can be replaced.
|
||||||
|
*/
|
||||||
|
Message(final String... variableNames)
|
||||||
|
{
|
||||||
|
this.variableNames = variableNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the variable at the given position for the given message.
|
||||||
|
*
|
||||||
|
* @param msg The message for which to retrieve the variable name.
|
||||||
|
* @param idx The index of the variable name.
|
||||||
|
* @return The name of the variable at the given position of this message.
|
||||||
|
*/
|
||||||
|
public static String getVariableName(final Message msg, final int idx)
|
||||||
|
{
|
||||||
|
return msg.variableNames[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the names of the variables for the given message..
|
||||||
|
*
|
||||||
|
* @param msg The message for which to retrieve the variable names.
|
||||||
|
* @return The names of the variables of this message.
|
||||||
|
*/
|
||||||
|
public static String[] getVariableNames(final Message msg)
|
||||||
|
{
|
||||||
|
return msg.variableNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of variables in this message that can be substituted.
|
||||||
|
*
|
||||||
|
* @param msg The message to retrieve the variable count for.
|
||||||
|
* @return The number of variables in this message that can be substituted.
|
||||||
|
*/
|
||||||
|
public static int getVariableCount(final Message msg)
|
||||||
|
{
|
||||||
|
return msg.variableNames.length;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,250 @@
|
|||||||
|
package nl.pim16aap2.armoredElytra.util.messages;
|
||||||
|
|
||||||
|
import nl.pim16aap2.armoredElytra.ArmoredElytra;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Messages
|
||||||
|
{
|
||||||
|
private static final String DEFAULTFILENAME = "en_US.txt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of all messages.
|
||||||
|
* <p>
|
||||||
|
* Key: The {@link Message} enum entry.
|
||||||
|
* <p>
|
||||||
|
* Value: The translated message.
|
||||||
|
*/
|
||||||
|
private Map<Message, String> messageMap = new EnumMap<>(Message.class);
|
||||||
|
|
||||||
|
private final ArmoredElytra plugin;
|
||||||
|
private File textFile;
|
||||||
|
|
||||||
|
private static final Pattern matchDots = Pattern.compile("\\.");
|
||||||
|
private static final Pattern matchNewLines = Pattern.compile("\\\\n");
|
||||||
|
private static final Pattern matchColorCodes = Pattern.compile("&((?i)[0-9a-fk-or])");
|
||||||
|
|
||||||
|
public Messages(final ArmoredElytra plugin)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
textFile = new File(plugin.getDataFolder(), plugin.getConfigLoader().languageFile() + ".txt");
|
||||||
|
if (!textFile.exists())
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.WARNING, "Failed to load language file: \"" + textFile +
|
||||||
|
"\": File not found! Using default file instead!");
|
||||||
|
textFile = new File(plugin.getDataFolder(), DEFAULTFILENAME);
|
||||||
|
}
|
||||||
|
populateMessageMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDefaultFile()
|
||||||
|
{
|
||||||
|
File defaultFile = new File(plugin.getDataFolder(), DEFAULTFILENAME);
|
||||||
|
|
||||||
|
InputStream in = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL url = getClass().getClassLoader().getResource(DEFAULTFILENAME);
|
||||||
|
if (url == null)
|
||||||
|
plugin.myLogger(Level.SEVERE, "Failed to read resources file from the jar! " +
|
||||||
|
"The default translation file cannot be generated! Please contact pim16aap2");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
in = connection.getInputStream();
|
||||||
|
java.nio.file.Files.copy(in, defaultFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.SEVERE, "Failed to write default file to \"" + textFile + "\".");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (in != null)
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the contents of a file. Each valid line will be split up in the message key and the message value. It
|
||||||
|
* then
|
||||||
|
*
|
||||||
|
* @param br The {@link BufferedReader} that supplies the text.
|
||||||
|
* @param action The action to take for every message and value combination that is encountered.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void processFile(final BufferedReader br, final BiConsumer<Message, String> action)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
String sCurrentLine;
|
||||||
|
|
||||||
|
while ((sCurrentLine = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
// Ignore comments.
|
||||||
|
if (sCurrentLine.startsWith("#") || sCurrentLine.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String[] parts = sCurrentLine.split("=", 2);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final Message msg = Message.valueOf(matchDots.matcher(parts[0]).replaceAll("_").toUpperCase());
|
||||||
|
final String value = matchNewLines.matcher(matchColorCodes.matcher(parts[1]).replaceAll("\u00A7$1"))
|
||||||
|
.replaceAll("\n");
|
||||||
|
action.accept(msg, value);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.WARNING, "Failed to identify Message corresponding to key: \"" + parts[0] +
|
||||||
|
"\". Its value will be ignored!");
|
||||||
|
|
||||||
|
System.out.println(
|
||||||
|
"Trying to find enum value of: " + matchDots.matcher(parts[0]).replaceAll("_").toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a message to the {@link #messageMap}.
|
||||||
|
*
|
||||||
|
* @param message The {@link Message}.
|
||||||
|
* @param value The value of the message.
|
||||||
|
*/
|
||||||
|
private void addMessage(final Message message, final String value)
|
||||||
|
{
|
||||||
|
messageMap.put(message, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a message to the {@link #messageMap} if it isn't on the map already.
|
||||||
|
*
|
||||||
|
* @param message The {@link Message}.
|
||||||
|
* @param value The value of the message.
|
||||||
|
*/
|
||||||
|
private void addBackupMessage(final Message message, final String value)
|
||||||
|
{
|
||||||
|
if (messageMap.containsKey(message))
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugin.myLogger(Level.WARNING,
|
||||||
|
"Could not find translation of key: \"" + message.name() + "\". Using default value instead!");
|
||||||
|
addMessage(message, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the translations from the provided translations file.
|
||||||
|
* <p>
|
||||||
|
* Missing translations will use their default value.
|
||||||
|
*/
|
||||||
|
private void populateMessageMap()
|
||||||
|
{
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(textFile)))
|
||||||
|
{
|
||||||
|
processFile(br, this::addMessage);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.SEVERE, "Locale file \"" + textFile + "\" does not exist!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.SEVERE, "Could not read locale file! \"" + textFile + "\"");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try (BufferedReader br = new BufferedReader(
|
||||||
|
new InputStreamReader(
|
||||||
|
Objects.requireNonNull(getClass().getClassLoader().getResource(DEFAULTFILENAME)).openStream())))
|
||||||
|
{
|
||||||
|
processFile(br, this::addBackupMessage);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.SEVERE, "Failed to load internal locale file!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.SEVERE, "Could not read internal locale file!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Message msg : Message.values())
|
||||||
|
if (!msg.equals(Message.EMPTY) && !messageMap.containsKey(msg))
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.WARNING, "Could not find translation of key: " + msg.name());
|
||||||
|
messageMap.put(msg, getFailureString(msg.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default String to return in case a value could not be found for a given String.
|
||||||
|
*
|
||||||
|
* @param key The key that could not be resolved.
|
||||||
|
* @return The default String to return in case a value could not be found for a given String.
|
||||||
|
*/
|
||||||
|
private String getFailureString(final String key)
|
||||||
|
{
|
||||||
|
return "Translation for key \"" + key + "\" not found! Contact server admin!";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the translated message of the provided {@link Message} and substitutes its variables for the provided
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @param msg The {@link Message} to translate.
|
||||||
|
* @param values The values to substitute for the variables in the message.
|
||||||
|
* @return The translated message of the provided {@link Message} and substitutes its variables for the provided
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
public String getString(final Message msg, final String... values)
|
||||||
|
{
|
||||||
|
if (msg.equals(Message.EMPTY))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (values.length != Message.getVariableCount(msg))
|
||||||
|
{
|
||||||
|
plugin.myLogger(Level.SEVERE,
|
||||||
|
"Expected " + Message.getVariableCount(msg) + " variables for key " + msg.name() +
|
||||||
|
" but only got " + values.length + ". This is a bug. Please contact pim16aap2!");
|
||||||
|
return getFailureString(msg.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = messageMap.get(msg);
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
for (int idx = 0; idx != values.length; ++idx)
|
||||||
|
value = value.replaceAll(Message.getVariableName(msg, idx), values[idx]);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.myLogger(Level.WARNING, "Failed to get the translation for key " + msg.name());
|
||||||
|
return getFailureString(msg.name());
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
# This file contains all the (partial) sentences used in this plugin.
|
# This file contains all the (partial) sentences used in this plugin.
|
||||||
# If you want to modify anything, make sure to do so in a copy, as this file will be regenerated on startup!
|
|
||||||
# You can change which file will be used in the config.yml.
|
# You can change which file will be used in the config.yml.
|
||||||
# The format is "key=value" (without quotation marks). You can modify the values, but not the keys.
|
# The format is "key=value" (without quotation marks). You can modify the values, but not the keys.
|
||||||
# Order doesn't matter and you can use comments if you so desire.
|
# Order doesn't matter and you can use comments if you so desire.
|
||||||
@ -25,4 +24,4 @@ MESSAGES.RepairNeeded=&cYou cannot equip this elytra! Please repair it in an anv
|
|||||||
MESSAGES.Lore=Elytra with %ARMOR_TIER_SHORT% level protection.
|
MESSAGES.Lore=Elytra with %ARMOR_TIER_SHORT% level protection.
|
||||||
MESSAGES.NoGivePermission=&cYou do not have the required permission node to give a(n) %ARMOR_TIER%s.
|
MESSAGES.NoGivePermission=&cYou do not have the required permission node to give a(n) %ARMOR_TIER%s.
|
||||||
MESSAGES.UsageDenied=You do not have the required permissions to wear a(n) %ARMOR_TIER%!
|
MESSAGES.UsageDenied=You do not have the required permissions to wear a(n) %ARMOR_TIER%!
|
||||||
MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you!
|
MESSAGES.ElytraReceived=&2A(n) %ARMOR_TIER% has been bestowed upon you!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user