Adds some code required for custom formatting and translation
This commit is contained in:
parent
cfff5485b2
commit
5b02a094e8
@ -1,5 +1,6 @@
|
|||||||
package net.knarcraft.dynmapcitizens;
|
package net.knarcraft.dynmapcitizens;
|
||||||
|
|
||||||
|
import net.knarcraft.dynmapcitizens.formatting.Translator;
|
||||||
import net.knarcraft.dynmapcitizens.handler.VaultHandler;
|
import net.knarcraft.dynmapcitizens.handler.VaultHandler;
|
||||||
import net.knarcraft.dynmapcitizens.handler.trait.BlacksmithHandler;
|
import net.knarcraft.dynmapcitizens.handler.trait.BlacksmithHandler;
|
||||||
import net.knarcraft.dynmapcitizens.handler.trait.CitizensTraitHandler;
|
import net.knarcraft.dynmapcitizens.handler.trait.CitizensTraitHandler;
|
||||||
@ -49,6 +50,9 @@ public final class DynmapCitizens extends JavaPlugin {
|
|||||||
configuration = this.getConfig();
|
configuration = this.getConfig();
|
||||||
this.globalSettings.load(configuration);
|
this.globalSettings.load(configuration);
|
||||||
|
|
||||||
|
//Load all messages
|
||||||
|
Translator.loadLanguages("en");
|
||||||
|
|
||||||
//Initialize all enabled traits
|
//Initialize all enabled traits
|
||||||
initializeTraitHandlers(configuration);
|
initializeTraitHandlers(configuration);
|
||||||
|
|
||||||
|
@ -0,0 +1,114 @@
|
|||||||
|
package net.knarcraft.dynmapcitizens.formatting;
|
||||||
|
|
||||||
|
import net.knarcraft.dynmapcitizens.DynmapCitizens;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A formatter for formatting displayed messages
|
||||||
|
*/
|
||||||
|
public final class StringFormatter {
|
||||||
|
|
||||||
|
private final static String pluginName = DynmapCitizens.getInstance().getDescription().getName();
|
||||||
|
|
||||||
|
private StringFormatter() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a message signifying a successful action
|
||||||
|
*
|
||||||
|
* @param sender <p>The command sender to display the message to</p>
|
||||||
|
* @param message <p>The translatable message to display</p>
|
||||||
|
*/
|
||||||
|
public static void displaySuccessMessage(CommandSender sender, TranslatableMessage message) {
|
||||||
|
sender.sendMessage(ChatColor.GREEN + getFormattedMessage(Translator.getTranslatedMessage(message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a message signifying a successful action
|
||||||
|
*
|
||||||
|
* @param sender <p>The command sender to display the message to</p>
|
||||||
|
* @param message <p>The raw message to display</p>
|
||||||
|
*/
|
||||||
|
public static void displaySuccessMessage(CommandSender sender, String message) {
|
||||||
|
sender.sendMessage(ChatColor.GREEN + getFormattedMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a message signifying an unsuccessful action
|
||||||
|
*
|
||||||
|
* @param sender <p>The command sender to display the message to</p>
|
||||||
|
* @param message <p>The translatable message to display</p>
|
||||||
|
*/
|
||||||
|
public static void displayErrorMessage(CommandSender sender, TranslatableMessage message) {
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + getFormattedMessage(Translator.getTranslatedMessage(message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the formatted version of any chat message
|
||||||
|
*
|
||||||
|
* @param message <p>The message to format</p>
|
||||||
|
* @return <p>The formatted message</p>
|
||||||
|
*/
|
||||||
|
private static String getFormattedMessage(String message) {
|
||||||
|
return "[" + pluginName + "] " + ChatColor.RESET + translateColors(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates & color codes to proper colors
|
||||||
|
*
|
||||||
|
* @param input <p>The input string to translate colors for</p>
|
||||||
|
* @return <p>The input with color codes translated</p>
|
||||||
|
*/
|
||||||
|
private static String translateColors(String input) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces a placeholder in a string
|
||||||
|
*
|
||||||
|
* @param input <p>The input string to replace in</p>
|
||||||
|
* @param placeholder <p>The placeholder to replace</p>
|
||||||
|
* @param replacement <p>The replacement value</p>
|
||||||
|
* @return <p>The input string with the placeholder replaced</p>
|
||||||
|
*/
|
||||||
|
public static String replacePlaceholder(String input, String placeholder, String replacement) {
|
||||||
|
return input.replace(placeholder, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces placeholders in a string
|
||||||
|
*
|
||||||
|
* @param input <p>The input string to replace in</p>
|
||||||
|
* @param placeholders <p>The placeholders to replace</p>
|
||||||
|
* @param replacements <p>The replacement values</p>
|
||||||
|
* @return <p>The input string with placeholders replaced</p>
|
||||||
|
*/
|
||||||
|
public static String replacePlaceholders(String input, String[] placeholders, String[] replacements) {
|
||||||
|
for (int i = 0; i < Math.min(placeholders.length, replacements.length); i++) {
|
||||||
|
input = replacePlaceholder(input, placeholders[i], replacements[i]);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates all found color codes to formatting in a string
|
||||||
|
*
|
||||||
|
* @param message <p>The string to search for color codes</p>
|
||||||
|
* @return <p>The message with color codes translated</p>
|
||||||
|
*/
|
||||||
|
public static String translateAllColorCodes(String message) {
|
||||||
|
message = ChatColor.translateAlternateColorCodes('&', message);
|
||||||
|
Pattern pattern = Pattern.compile("(#[a-fA-F0-9]{6})");
|
||||||
|
Matcher matcher = pattern.matcher(message);
|
||||||
|
while (matcher.find()) {
|
||||||
|
message = message.replace(matcher.group(), "" + ChatColor.of(matcher.group()));
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package net.knarcraft.dynmapcitizens.formatting;
|
||||||
|
|
||||||
|
public enum TranslatableMessage {
|
||||||
|
|
||||||
|
SENTINEL_DETAILS
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package net.knarcraft.dynmapcitizens.formatting;
|
||||||
|
|
||||||
|
import net.knarcraft.dynmapcitizens.DynmapCitizens;
|
||||||
|
import net.knarcraft.dynmapcitizens.util.FileHelper;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tool to get strings translated to the correct language
|
||||||
|
*/
|
||||||
|
public final class Translator {
|
||||||
|
|
||||||
|
private static Map<TranslatableMessage, String> translatedMessages;
|
||||||
|
private static Map<TranslatableMessage, String> backupTranslatedMessages;
|
||||||
|
|
||||||
|
private Translator() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the languages used by this translator
|
||||||
|
*/
|
||||||
|
public static void loadLanguages(String selectedLanguage) {
|
||||||
|
backupTranslatedMessages = loadTranslatedMessages("en");
|
||||||
|
translatedMessages = loadCustomTranslatedMessages(selectedLanguage);
|
||||||
|
if (translatedMessages == null) {
|
||||||
|
translatedMessages = loadTranslatedMessages(selectedLanguage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a translated version of the given translatable message
|
||||||
|
*
|
||||||
|
* @param translatableMessage <p>The message to translate</p>
|
||||||
|
* @return <p>The translated message</p>
|
||||||
|
*/
|
||||||
|
public static String getTranslatedMessage(TranslatableMessage translatableMessage) {
|
||||||
|
if (translatedMessages == null) {
|
||||||
|
return "Translated strings not loaded";
|
||||||
|
}
|
||||||
|
String translatedMessage;
|
||||||
|
if (translatedMessages.containsKey(translatableMessage)) {
|
||||||
|
translatedMessage = translatedMessages.get(translatableMessage);
|
||||||
|
} else if (backupTranslatedMessages.containsKey(translatableMessage)) {
|
||||||
|
translatedMessage = backupTranslatedMessages.get(translatableMessage);
|
||||||
|
} else {
|
||||||
|
translatedMessage = translatableMessage.toString();
|
||||||
|
}
|
||||||
|
return StringFormatter.translateAllColorCodes(translatedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all translated messages for the given language
|
||||||
|
*
|
||||||
|
* @param language <p>The language chosen by the user</p>
|
||||||
|
* @return <p>A mapping of all strings for the given language</p>
|
||||||
|
*/
|
||||||
|
public static Map<TranslatableMessage, String> loadTranslatedMessages(String language) {
|
||||||
|
try {
|
||||||
|
BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/strings.yml");
|
||||||
|
return loadTranslatableMessages(language, reader);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
DynmapCitizens.getInstance().getLogger().log(Level.SEVERE, "Unable to load translated messages");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to load translated messages from a custom strings.yml file
|
||||||
|
*
|
||||||
|
* @param language <p>The selected language</p>
|
||||||
|
* @return <p>The loaded translated strings, or null if no custom language file exists</p>
|
||||||
|
*/
|
||||||
|
public static Map<TranslatableMessage, String> loadCustomTranslatedMessages(String language) {
|
||||||
|
DynmapCitizens instance = DynmapCitizens.getInstance();
|
||||||
|
|
||||||
|
File strings = new File(instance.getDataFolder(), "strings.yml");
|
||||||
|
if (!strings.exists()) {
|
||||||
|
instance.getLogger().log(Level.FINEST, "Strings file not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
instance.getLogger().log(Level.INFO, "Loading custom strings...");
|
||||||
|
return loadTranslatableMessages(language, new BufferedReader(new InputStreamReader(new FileInputStream(strings))));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
instance.getLogger().log(Level.WARNING, "Unable to load custom messages");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads translatable messages from the given reader
|
||||||
|
*
|
||||||
|
* @param language <p>The selected language</p>
|
||||||
|
* @param reader <p>The buffered reader to read from</p>
|
||||||
|
* @return <p>The loaded translated strings</p>
|
||||||
|
*/
|
||||||
|
private static Map<TranslatableMessage, String> loadTranslatableMessages(String language, BufferedReader reader) {
|
||||||
|
Map<TranslatableMessage, String> translatedMessages = new HashMap<>();
|
||||||
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(reader);
|
||||||
|
|
||||||
|
for (TranslatableMessage message : TranslatableMessage.values()) {
|
||||||
|
String translated = configuration.getString(language + "." + message.toString());
|
||||||
|
if (translated != null) {
|
||||||
|
translatedMessages.put(message, translated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return translatedMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -47,12 +47,14 @@ public class SentinelHandler extends AbstractTraitHandler {
|
|||||||
description += "<br><b>Squad:</b> " + trait.squad;
|
description += "<br><b>Squad:</b> " + trait.squad;
|
||||||
}
|
}
|
||||||
if (settings.displaySentinelStats()) {
|
if (settings.displaySentinelStats()) {
|
||||||
description += "<br><b>Invincible:</b> " + trait.invincible + "<br><b>Armor:</b> " +
|
description += "<br><b>Invincible:</b> " + trait.invincible + "<br><b>Armor:</b> " + trait.armor;
|
||||||
trait.armor + "<br><b>Health:</b> " + trait.health + "<br><b>Accuracy:</b> " + trait.accuracy +
|
description += "<br><b>Health:</b> " + trait.health + "<br><b>Accuracy:</b> " + trait.accuracy;
|
||||||
"<br><b>Damage:</b> " + trait.damage + "<br><b>Allow knockback:</b> " + trait.allowKnockback;
|
description += "<br><b>Damage:</b> " + trait.damage + "<br><b>Speed:</b> " + trait.speed;
|
||||||
|
description += "<br><b>Allow knockback:</b> " + trait.allowKnockback;
|
||||||
description += "<br><b>Range:</b> " + trait.range + "<br><b>Reach:</b> " + trait.reach;
|
description += "<br><b>Range:</b> " + trait.range + "<br><b>Reach:</b> " + trait.reach;
|
||||||
description += "<br><b>Targets:</b> " + trait.allTargets.toAllInOneString() + "<br><b>Avoids:</b> " +
|
description += "<br><b>Targets:</b> " + trait.allTargets.toAllInOneString();
|
||||||
trait.allAvoids.toAllInOneString() + "<br><b>Ignores:</b> " + trait.allIgnores.toAllInOneString();
|
description += "<br><b>Avoids:</b> " + trait.allAvoids.toAllInOneString();
|
||||||
|
description += "<br><b>Ignores:</b> " + trait.allIgnores.toAllInOneString();
|
||||||
}
|
}
|
||||||
addNPCMarker(npc.getUniqueId(), "Sentinel NPC: ", description,
|
addNPCMarker(npc.getUniqueId(), "Sentinel NPC: ", description,
|
||||||
DynmapCitizens.getInstance().getGlobalSettings().getMarkerIcons().get(Icon.SENTINEL), super.markerSet);
|
DynmapCitizens.getInstance().getGlobalSettings().getMarkerIcons().get(Icon.SENTINEL), super.markerSet);
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package net.knarcraft.dynmapcitizens.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for dealing with files
|
||||||
|
*/
|
||||||
|
public final class FileHelper {
|
||||||
|
|
||||||
|
private FileHelper() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a buffered reader for
|
||||||
|
*
|
||||||
|
* @return <p>A buffered read for reading the file</p>
|
||||||
|
* @throws FileNotFoundException <p>If unable to get an input stream for the given file</p>
|
||||||
|
*/
|
||||||
|
public static BufferedReader getBufferedReaderForInternalFile(String file) throws FileNotFoundException {
|
||||||
|
InputStream inputStream = FileHelper.class.getResourceAsStream(file);
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new FileNotFoundException("Unable to read the given file");
|
||||||
|
}
|
||||||
|
return new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,7 +9,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholder;
|
import static net.knarcraft.dynmapcitizens.formatting.StringFormatter.replacePlaceholder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for time formatting
|
* A helper class for time formatting
|
||||||
|
55
src/main/resources/strings.yml
Normal file
55
src/main/resources/strings.yml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
en:
|
||||||
|
SENTINEL_DESCRIPTION: |
|
||||||
|
<h2>name</h2>
|
||||||
|
<br><b>Squad:</b> {squad}
|
||||||
|
{sentinelDetails}
|
||||||
|
SENTINEL_DETAILS: |
|
||||||
|
<ul>
|
||||||
|
<li><b>Invincible:</b> {invincible}</li>
|
||||||
|
<li><b>Armor:</b> {armor}</li>
|
||||||
|
<li><b>Health:</b> {health}</li>
|
||||||
|
<li><b>Accuracy:</b> {accuracy}</li>
|
||||||
|
<li><b>Damage:</b> {damage}</li>
|
||||||
|
<li><b>Speed:</b> {speed}</li>
|
||||||
|
<li><b>Allow knockback:</b> {allowKnockback}</li>
|
||||||
|
<li><b>Range:</b> {range}</li>
|
||||||
|
<li><b>Reach:</b> {reach}</li>
|
||||||
|
<li><b>Targets:</b> {targets}</li>
|
||||||
|
<li><b>Avoids:</b> {avoids}</li>
|
||||||
|
<li><b>Ignores:</b> {ignores}</li>
|
||||||
|
</ul>
|
||||||
|
QUESTS_PLANNER_DESCRIPTION: |
|
||||||
|
<b>Planner:</b><ul>
|
||||||
|
{questCoolDown}
|
||||||
|
{questFrom}
|
||||||
|
{questUntil}
|
||||||
|
{questRepeat}
|
||||||
|
</ul>
|
||||||
|
QUESTS_PLANNER_COOL_DOWN: "<li>Quest repeatable after: {coolDown}</li>"
|
||||||
|
QUESTS_PLANNER_UNREPEATABLE: "<li>Quest cannot be repeated!</li>"
|
||||||
|
QUESTS_PLANNER_FROM: "<li>Quest available from {startDate}</li>"
|
||||||
|
QUESTS_PLANNER_UNTIL: "<li>Quest available until {endDate}</li>"
|
||||||
|
QUEST_PLANNER_REPEAT: "<li>Quest will become available again after {repeatDelay}</li>"
|
||||||
|
QUESTS_REQUIREMENTS_FORMAT: |
|
||||||
|
<b>Requirements: </b><ul>
|
||||||
|
{requirementQuestPoints}
|
||||||
|
{requirementExp}
|
||||||
|
{requirementBlockedByQuests}
|
||||||
|
{requirementRequiredQuests}
|
||||||
|
{requirementRequiredItems}
|
||||||
|
{requirementMCMMOSkills}
|
||||||
|
{requirementPermissions}
|
||||||
|
{requirementCustom}
|
||||||
|
</ul>
|
||||||
|
QUESTS_REQUIREMENTS_QUEST_POINTS: "<li>{questPoints} quest points</li>"
|
||||||
|
QUESTS_REQUIREMENTS_EXP: "<li>{exp} exp</li>"
|
||||||
|
QUESTS_REQUIREMENTS_BLOCKED_BY_QUEST_FORMAT: "<li>Blocked by quests:<ul>{blockingQuests}</ul></li>"
|
||||||
|
QUESTS_REQUIREMENTS_BLOCKED_BY_QUEST_ITEM: "<li>{questName}</li>"
|
||||||
|
QUESTS_REQUIREMENTS_REQUIRED_QUEST_FORMAT: "<li>Required quests:<ul>{requiredQuests}</ul></li>"
|
||||||
|
QUESTS_REQUIREMENTS_REQUIRED_QUEST_ITEM: "<li>{questName}</li>"
|
||||||
|
QUESTS_REQUIREMENTS_REQUIRED_ITEM_FORMAT: "<li>Required items:<ul>{requiredItems}</ul></li>"
|
||||||
|
QUESTS_REQUIREMENTS_REQUIRED_ITEM_ITEM: "<li>{itemName}</li>"
|
||||||
|
QUESTS_REQUIREMENTS_MCMMO_SKILL: "<li>Requires mcMMO skill {skill} at level {level}</li>"
|
||||||
|
QUESTS_REQUIREMENTS_REQUIRED_PERMISSION_FORMAT: "<li>Required permissions:<ul>{permissions}</ul></li>"
|
||||||
|
QUESTS_REQUIREMENTS_REQUIRED_PERMISSION_ITEM: "<li>{permission}</li>"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user