Merge pull request #55 from itHotL/multiple-language-support

Multiple language support
This commit is contained in:
Elise 2022-06-22 11:40:24 +02:00 committed by GitHub
commit c70bbce0f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 317 additions and 39 deletions

View File

@ -32,6 +32,7 @@
<artifactSet>
<excludes>
<exclude>org.jetbrains:annotations</exclude>
<exclude>META-INF/versions/**</exclude>
</excludes>
</artifactSet>
</configuration>

View File

@ -95,6 +95,7 @@
<artifactSet>
<excludes>
<exclude>org.jetbrains:annotations</exclude>
<exclude>META-INF/versions/**</exclude>
</excludes>
</artifactSet>
</configuration>

View File

@ -5,6 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.commands.StatCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.TabCompleter;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.listeners.JoinListener;
import com.gmail.artemis.the.gr8.playerstats.msg.LanguageKeyHandler;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory;
import com.gmail.artemis.the.gr8.playerstats.msg.PrideMessageFactory;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
@ -33,21 +34,22 @@ public class Main extends JavaPlugin {
//initialize the Adventure library
adventure = BukkitAudiences.create(this);
//first get an instance of the ConfigHandler
//first get an instance of the ConfigHandler and LanguageKeyHandler
ConfigHandler config = new ConfigHandler(this);
LanguageKeyHandler language = new LanguageKeyHandler();
//then determine if we need a regular MessageFactory or a festive one
MessageFactory messageFactory;
if (config.useFestiveFormatting()) {
if (LocalDate.now().getMonth().equals(Month.JUNE)) {
messageFactory = new PrideMessageFactory(config);
messageFactory = new PrideMessageFactory(config, language);
}
else {
messageFactory = new MessageFactory(config);
messageFactory = new MessageFactory(config, language);
}
}
else {
messageFactory = new MessageFactory(config);
messageFactory = new MessageFactory(config, language);
}
//initialize the threadManager

View File

@ -2,12 +2,17 @@ package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.enums.Query;
import com.gmail.artemis.the.gr8.playerstats.msg.LanguageKeyHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Statistic;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@ -16,6 +21,9 @@ import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static net.kyori.adventure.text.Component.space;
import static net.kyori.adventure.text.Component.text;
public class StatCommand implements CommandExecutor {
@ -45,6 +53,11 @@ public class StatCommand implements CommandExecutor {
adventure.sender(sender).sendMessage(messageFactory.usageExamples(sender instanceof ConsoleCommandSender));
return true;
}
else if (args[0].equalsIgnoreCase("test")) {
String selection = (args.length > 1) ? args[1] : null;
printTranslatableNames(sender, selection);
return true;
}
else { //part 1: collecting all relevant information from the args
StatRequest request = generateRequest(sender, args);
@ -60,6 +73,72 @@ public class StatCommand implements CommandExecutor {
}
}
//test method
private void printTranslatableNames(CommandSender sender, String selection) {
LanguageKeyHandler lang = new LanguageKeyHandler();
if (selection == null) {
TextComponent msg = Component.text("Include 'block', 'item', 'entity' or 'stat'").color(TextColor.fromHexString("#FFB80E"));
adventure.sender(sender).sendMessage(msg);
}
else if (selection.equalsIgnoreCase("block")) {
for (String name : EnumHandler.getBlockNames()) {
String key = lang.getBlockKey(name);
if (key != null) {
TranslatableComponent msg = Component.translatable(key)
.color(TextColor.fromHexString("#FFB80E"))
.append(space())
.append(text("for blockName: ").color(NamedTextColor.WHITE))
.append(text(name).color(TextColor.fromHexString("#55AAFF")));
adventure.sender(sender).sendMessage(msg);
}
}
}
else if (selection.equalsIgnoreCase("entity")) {
for (String name : EnumHandler.getEntityNames()) {
String key = lang.getEntityKey(name);
if (key != null) {
TranslatableComponent msg = Component.translatable(key)
.color(TextColor.fromHexString("#FFB80E"))
.append(space())
.append(text("for entityName: ").color(NamedTextColor.WHITE))
.append(text(name).color(TextColor.fromHexString("#55AAFF")));
adventure.sender(sender).sendMessage(msg);
}
}
}
else if (selection.equalsIgnoreCase("item")) {
for (String name : EnumHandler.getItemNames()) {
String key = lang.getItemKey(name);
if (key != null) {
TranslatableComponent msg = Component.translatable(key)
.color(TextColor.fromHexString("#FFB80E"))
.append(space())
.append(text("for itemName: ").color(NamedTextColor.WHITE))
.append(text(name).color(TextColor.fromHexString("#55AAFF")));
adventure.sender(sender).sendMessage(msg);
}
}
}
else if (selection.equalsIgnoreCase("stat")) {
for (String name : EnumHandler.getStatNames()) {
String key = lang.getStatKey(name);
if (key != null) {
TranslatableComponent msg = Component.translatable(key)
.color(TextColor.fromHexString("#FFB80E"))
.append(space())
.append(text("for statName: ").color(NamedTextColor.WHITE))
.append(text(name).color(TextColor.fromHexString("#55AAFF")));
adventure.sender(sender).sendMessage(msg);
}
}
}
else {
TextComponent msg = Component.text("hi :)").color(TextColor.fromHexString("#FFB80E"));
adventure.sender(sender).sendMessage(msg);
}
}
//create a StatRequest Object with all the relevant information from the args
private StatRequest generateRequest(CommandSender sender, String[] args) {
StatRequest request = new StatRequest(sender);

View File

@ -0,0 +1,126 @@
package com.gmail.artemis.the.gr8.playerstats.msg;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashMap;
public class LanguageKeyHandler {
private final HashMap<Statistic, String> statNameKeys;
public LanguageKeyHandler() {
statNameKeys = new HashMap<>();
generateStatNameKeys();
}
public @Nullable String getStatKey(@NotNull String statName) {
try {
Statistic stat = EnumHandler.getStatEnum(statName);
if (stat.getType() == Statistic.Type.UNTYPED) {
return "stat.minecraft." + statNameKeys.get(stat);
}
else {
return "stat_type.minecraft." + statNameKeys.get(stat);
}
}
catch (IllegalArgumentException e) {
Bukkit.getLogger().info("PlayerStats, LanguageKeyHandler 33: " + e);
return null;
}
}
public @Nullable String getEntityKey(@NotNull String entityName) {
if (entityName.equalsIgnoreCase("UNKNOWN")) {
return null;
}
else {
try {
return "entity.minecraft." + EnumHandler.getEntityEnum(entityName).getKey().getKey();
}
catch (IllegalArgumentException e) {
Bukkit.getLogger().info("PlayerStats, LanguageKeyHandler 47: " + e);
return null;
}
}
}
public @Nullable String getItemKey(@NotNull String itemName) {
try {
Material item = EnumHandler.getItemEnum(itemName);
if (item.isBlock()) {
return "block.minecraft." + item.getKey().getKey();
}
else {
return "item.minecraft." + EnumHandler.getItemEnum(itemName).getKey().getKey();
}
}
catch (IllegalArgumentException e) {
Bukkit.getLogger().info("PlayerStats, LanguageKeyHandler 64: " + e);
return null;
}
}
public @Nullable String getBlockKey(@NotNull String materialName) {
String name = materialName;
if (materialName.toLowerCase().contains("wall_banner")) {
name = materialName.replace("wall_", "");
}
try {
return "block.minecraft." + EnumHandler.getBlockEnum(name).getKey().getKey();
}
catch (IllegalArgumentException e) {
Bukkit.getLogger().info("PlayerStats, LanguageKeyHandler 78: " + e);
return null;
}
}
private void generateDefaultKeys() {
Arrays.stream(Statistic.values()).forEach(statistic -> statNameKeys.put(statistic, statistic.toString().toLowerCase()));
}
private void generateStatNameKeys() {
//get the enum names for all statistics first
generateDefaultKeys();
//replace the ones for which the language key is different from the enum name
statNameKeys.put(Statistic.ARMOR_CLEANED, "clean_armor");
statNameKeys.put(Statistic.BANNER_CLEANED, "clean_banner");
statNameKeys.put(Statistic.DROP_COUNT, "drop");
statNameKeys.put(Statistic.CAKE_SLICES_EATEN, "eat_cake_slice");
statNameKeys.put(Statistic.ITEM_ENCHANTED, "enchant_item");
statNameKeys.put(Statistic.CAULDRON_FILLED, "fill_cauldron");
statNameKeys.put(Statistic.DISPENSER_INSPECTED, "inspect_dispenser");
statNameKeys.put(Statistic.DROPPER_INSPECTED, "inspect_dropper");
statNameKeys.put(Statistic.HOPPER_INSPECTED, "inspect_hopper");
statNameKeys.put(Statistic.BEACON_INTERACTION, "interact_with_beacon");
statNameKeys.put(Statistic.BREWINGSTAND_INTERACTION, "interact_with_brewingstand");
statNameKeys.put(Statistic.CRAFTING_TABLE_INTERACTION, "interact_with_crafting_table");
statNameKeys.put(Statistic.FURNACE_INTERACTION, "interact_with_furnace");
statNameKeys.put(Statistic.CHEST_OPENED, "open_chest");
statNameKeys.put(Statistic.ENDERCHEST_OPENED, "open_enderchest");
statNameKeys.put(Statistic.SHULKER_BOX_OPENED, "open_shulker_box");
statNameKeys.put(Statistic.NOTEBLOCK_PLAYED, "play_noteblock");
statNameKeys.put(Statistic.PLAY_ONE_MINUTE, "play_time");
statNameKeys.put(Statistic.RECORD_PLAYED, "play_record");
statNameKeys.put(Statistic.FLOWER_POTTED, "pot_flower");
statNameKeys.put(Statistic.TRAPPED_CHEST_TRIGGERED, "trigger_trapped_chest");
statNameKeys.put(Statistic.NOTEBLOCK_TUNED, "tune_noteblock");
statNameKeys.put(Statistic.CAULDRON_USED, "use_cauldron");
//do the same for the statistics that have a subtype
statNameKeys.put(Statistic.DROP, "dropped");
statNameKeys.put(Statistic.PICKUP, "picked_up");
statNameKeys.put(Statistic.MINE_BLOCK, "mined");
statNameKeys.put(Statistic.USE_ITEM, "used");
statNameKeys.put(Statistic.BREAK_ITEM, "broken");
statNameKeys.put(Statistic.CRAFT_ITEM, "crafted");
statNameKeys.put(Statistic.KILL_ENTITY, "killed");
statNameKeys.put(Statistic.ENTITY_KILLED_BY, "killed_by");
}
}

View File

@ -2,8 +2,10 @@ package com.gmail.artemis.the.gr8.playerstats.msg;
import com.gmail.artemis.the.gr8.playerstats.enums.Query;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
@ -22,14 +24,16 @@ import static net.kyori.adventure.text.Component.*;
public class MessageFactory {
private static ConfigHandler config;
private final LanguageKeyHandler language;
private final TextColor msgColor; //my favorite shade of light blue, somewhere between blue and aqua
private final TextColor hoverBaseColor; //light blue - one shade lighter than msgColor
private final TextColor accentColor1; //gold - one shade lighter than standard gold
private final TextColor accentColor2; //yellow - a few shades darker than standard yellow
public MessageFactory(ConfigHandler c) {
public MessageFactory(ConfigHandler c, LanguageKeyHandler l) {
config = c;
language = l;
msgColor = TextColor.fromHexString("#55AAFF");
hoverBaseColor = TextColor.fromHexString("#55C6FF");
@ -152,22 +156,19 @@ public class MessageFactory {
.append(newline());
}
public TextComponent formatPlayerStat(String playerName, String statName, String subStatEntryName, int stat) {
TextComponent.Builder singleStat = Component.text();
singleStat.append(playerNameComponent(Query.PLAYER, playerName + ": "))
public TextComponent formatPlayerStat(String playerName, String statName, String subStatEntry, int stat) {
return Component.text()
.append(playerNameComponent(Query.PLAYER, playerName + ": "))
.append(statNumberComponent(Query.PLAYER, stat))
.append(space())
.append(statNameComponent(Query.PLAYER, statName))
.append(statNameComponent(Query.PLAYER, statName, subStatEntry))
.append(space())
.append(subStatNameComponent(Query.PLAYER, subStatEntryName));
return singleStat.build();
.build();
}
public TextComponent formatTopStats(@NotNull LinkedHashMap<String, Integer> topStats, String statName, String subStatEntryName, boolean isConsoleSender) {
public TextComponent formatTopStats(@NotNull LinkedHashMap<String, Integer> topStats, String statName, String subStatEntry, boolean isConsoleSender) {
TextComponent.Builder topList = Component.text();
topList.append(getTopStatTitle(topStats.size(), statName, subStatEntryName, isConsoleSender));
topList.append(getTopStatTitle(topStats.size(), statName, subStatEntry, isConsoleSender));
boolean useDots = config.useDots();
Set<String> playerNames = topStats.keySet();
@ -204,18 +205,16 @@ public class MessageFactory {
}
public TextComponent formatServerStat(String statName, String subStatEntry, int stat) {
TextComponent.Builder serverStat = Component.text();
serverStat.append(titleComponent(Query.SERVER, config.getServerTitle()))
return Component.text()
.append(titleComponent(Query.SERVER, config.getServerTitle()))
.append(space())
.append(serverNameComponent())
.append(space())
.append(statNumberComponent(Query.SERVER, stat))
.append(space())
.append(statNameComponent(Query.SERVER, statName))
.append(statNameComponent(Query.SERVER, statName, subStatEntry))
.append(space())
.append(subStatNameComponent(Query.SERVER, subStatEntry));
return serverStat.build();
.build();
}
protected TextComponent getPrefixAsTitle(boolean isConsoleSender) {
@ -233,13 +232,17 @@ public class MessageFactory {
.append(text(underscores));
}
protected TextComponent getTopStatTitle(int topLength, String statName, String subStatEntryName, boolean isConsoleSender) {
return Component.newline()
protected TextComponent getTopStatTitle(int topLength, String statName, String subStatEntry, boolean isConsoleSender) {
return Component.text()
.append(newline())
.append(pluginPrefix(isConsoleSender))
.append(titleComponent(Query.TOP, config.getTopStatsTitle())).append(space())
.append(titleNumberComponent(topLength)).append(space())
.append(statNameComponent(Query.TOP, statName)).append(space())
.append(subStatNameComponent(Query.TOP, subStatEntryName));
.append(titleComponent(Query.TOP, config.getTopStatsTitle()))
.append(space())
.append(titleNumberComponent(topLength))
.append(space())
.append(statNameComponent(Query.TOP, statName, subStatEntry))
.append(space())
.build();
}
protected TextComponent playerNameComponent(Query selection, String playerName) {
@ -248,21 +251,86 @@ public class MessageFactory {
getStyleFromString(config.getPlayerNameFormatting(selection, true)));
}
protected TextComponent statNameComponent(Query selection, @NotNull String statName) {
return getComponent(statName.toLowerCase().replace("_", " "),
getColorFromString(config.getStatNameFormatting(selection, false)),
getStyleFromString(config.getStatNameFormatting(selection, true)));
protected TranslatableComponent statNameComponent(Query selection, @NotNull String statName, String subStatName) {
TextColor statNameColor = getColorFromString(config.getStatNameFormatting(selection, false));
TextDecoration statNameStyle = getStyleFromString(config.getStatNameFormatting(selection, true));
TranslatableComponent subStat = subStatNameComponent(selection, subStatName);
String key = language.getStatKey(statName);
if (key == null) {
key = statName;
}
//case for kill_entity
else if (key.equalsIgnoreCase("stat_type.minecraft.killed") && subStat != null) {
TranslatableComponent.Builder totalName = translatable()
.key("commands.kill.success.single") //"Killed %s"
.args(subStat)
.color(statNameColor);
if (statNameStyle != null) {
totalName.decoration(statNameStyle, TextDecoration.State.TRUE);
}
return totalName.build();
}
//case for entity_killed_by
else if (key.equalsIgnoreCase("stat_type.minecraft.killed_by") && subStat != null) {
String newKey = "stat.minecraft.player_kills"; //"Player Kills"
if (selection == Query.PLAYER) {
newKey = "stat.minecraft.deaths"; //"Number of Deaths"
}
TranslatableComponent.Builder totalName = translatable()
.key(newKey)
.append(space())
.append(translatable()
.key("book.byAuthor") //"by %1$s"
.args(subStat))
.color(statNameColor);
if (statNameStyle != null) {
totalName.decoration(statNameStyle, TextDecoration.State.TRUE);
}
return totalName.build();
}
//all other cases
TranslatableComponent.Builder totalName = translatable()
.key(key)
.color(statNameColor);
if (statNameStyle != null) totalName.decoration(statNameStyle, TextDecoration.State.TRUE);
if (subStat != null) {
totalName.append(space()).append(subStat);
}
return totalName.build();
}
protected TextComponent subStatNameComponent(Query selection, String subStatName) {
protected @Nullable TranslatableComponent subStatNameComponent(Query selection, @Nullable String subStatName) {
if (subStatName == null) {
return empty();
return null;
}
String key = null;
if (EnumHandler.isEntity(subStatName)){
key = language.getEntityKey(subStatName);
}
else if (EnumHandler.isBlock(subStatName)) {
key = language.getBlockKey(subStatName);
}
else if (EnumHandler.isItem(subStatName)) {
key = language.getItemKey(subStatName);
}
if (key != null) {
TextDecoration style = getStyleFromString(config.getSubStatNameFormatting(selection, true));
TranslatableComponent.Builder subStat = translatable()
.key(key)
.color(getColorFromString(config.getSubStatNameFormatting(selection, false)));
if (style != null) {
subStat.decoration(style, TextDecoration.State.TRUE);
}
return subStat.build();
}
else {
return getComponent("(" + subStatName.toLowerCase().replace("_", " ") + ")",
getColorFromString(config.getSubStatNameFormatting(selection, false)),
getStyleFromString(config.getSubStatNameFormatting(selection, true)))
.append(space());
return null;
}
}

View File

@ -12,8 +12,8 @@ import static net.kyori.adventure.text.Component.*;
public class PrideMessageFactory extends MessageFactory {
public PrideMessageFactory(ConfigHandler c) {
super(c);
public PrideMessageFactory(ConfigHandler c, LanguageKeyHandler l) {
super(c, l);
}
@Override

View File

@ -94,6 +94,7 @@ public class StatThread extends Thread {
}
} catch (Exception e) {
adventure.sender(sender).sendMessage(messageFactory.formatExceptions(e.toString(), isConsoleSencer));
e.printStackTrace();
}
}