From b64f56a0bb0d62a5d08f5aba9800ad5754fdab85 Mon Sep 17 00:00:00 2001 From: ineanto Date: Thu, 27 Jul 2023 23:29:57 +0200 Subject: [PATCH] feat: item translation --- .../nicko/event/PlayerJoinListener.java | 1 + .../nicko/gui/items/common/GoBackItem.java | 5 +- .../items/settings/BungeeCordCyclingItem.java | 25 ++++---- .../items/settings/LanguageCyclingItem.java | 3 +- src/main/java/xyz/atnrch/nicko/i18n/I18N.java | 61 ++++++++++++++----- .../atnrch/nicko/i18n/ItemTranslation.java | 8 +-- src/main/resources/en.yml | 3 + src/main/resources/fr.yml | 11 +++- ...Test.java => I18NItemTranslationTest.java} | 27 +++++--- 9 files changed, 97 insertions(+), 47 deletions(-) rename src/test/java/xyz/atnrch/nicko/test/i18n/{I18NLoreTest.java => I18NItemTranslationTest.java} (60%) diff --git a/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java b/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java index b4a3a19..7b998c3 100644 --- a/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java +++ b/src/main/java/xyz/atnrch/nicko/event/PlayerJoinListener.java @@ -33,5 +33,6 @@ public class PlayerJoinListener implements Listener { } } }, 20L); + System.out.println("i18n.getPlayerLocale().getCode() = " + i18n.getPlayerLocale().getCode()); } } diff --git a/src/main/java/xyz/atnrch/nicko/gui/items/common/GoBackItem.java b/src/main/java/xyz/atnrch/nicko/gui/items/common/GoBackItem.java index 9a3c643..db9ea70 100644 --- a/src/main/java/xyz/atnrch/nicko/gui/items/common/GoBackItem.java +++ b/src/main/java/xyz/atnrch/nicko/gui/items/common/GoBackItem.java @@ -11,20 +11,17 @@ import xyz.xenondevs.invui.item.impl.SuppliedItem; import xyz.xenondevs.invui.window.Window; public class GoBackItem { - private final Player player; private final I18N i18n; public GoBackItem(Player player) { - this.player = player; this.i18n = new I18N(player); } public SuppliedItem get(Gui gui, String parentTitle) { - final ItemTranslation translation = i18n.translateItem(I18NDict.GUI.GO_BACK); return new SuppliedItem(() -> { final ItemBuilder builder = new ItemBuilder(Material.ARROW); + final ItemTranslation translation = i18n.translateItem(I18NDict.GUI.GO_BACK); builder.setDisplayName(translation.getName()); - translation.getLore().forEach(builder::addLoreLines); return builder; }, click -> { click.getEvent().getView().close(); diff --git a/src/main/java/xyz/atnrch/nicko/gui/items/settings/BungeeCordCyclingItem.java b/src/main/java/xyz/atnrch/nicko/gui/items/settings/BungeeCordCyclingItem.java index ed4b0d9..1c3efc0 100644 --- a/src/main/java/xyz/atnrch/nicko/gui/items/settings/BungeeCordCyclingItem.java +++ b/src/main/java/xyz/atnrch/nicko/gui/items/settings/BungeeCordCyclingItem.java @@ -1,13 +1,13 @@ package xyz.atnrch.nicko.gui.items.settings; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; import xyz.atnrch.nicko.NickoBukkit; import xyz.atnrch.nicko.i18n.I18N; import xyz.atnrch.nicko.i18n.I18NDict; import xyz.atnrch.nicko.i18n.ItemTranslation; import xyz.atnrch.nicko.profile.NickoProfile; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.entity.Player; import xyz.xenondevs.invui.item.ItemProvider; import xyz.xenondevs.invui.item.builder.ItemBuilder; import xyz.xenondevs.invui.item.impl.AbstractItem; @@ -49,14 +49,17 @@ public class BungeeCordCyclingItem { final ItemTranslation translation = i18n.translateItem(I18NDict.GUI.Settings.BUNGEECORD); builder.setDisplayName(translation.getName()); - if (enabled) { - builder.addLoreLines("§7> §cDisabled"); - builder.addLoreLines("§6§l> §a§lEnabled"); - } else { - builder.addLoreLines("§6§l> §c§lDisabled"); - builder.addLoreLines("§7> §aEnabled"); - } - builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking."); + translation.getLore().forEach(builder::addLoreLines); + /* + if (enabled) { + builder.addLoreLines("§7> §cDisabled"); + builder.addLoreLines("§6§l> §a§lEnabled"); + } else { + builder.addLoreLines("§6§l> §c§lDisabled"); + builder.addLoreLines("§7> §aEnabled"); + } + builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking."); + */ return builder; } } diff --git a/src/main/java/xyz/atnrch/nicko/gui/items/settings/LanguageCyclingItem.java b/src/main/java/xyz/atnrch/nicko/gui/items/settings/LanguageCyclingItem.java index addb9f9..f3419cc 100644 --- a/src/main/java/xyz/atnrch/nicko/gui/items/settings/LanguageCyclingItem.java +++ b/src/main/java/xyz/atnrch/nicko/gui/items/settings/LanguageCyclingItem.java @@ -43,9 +43,10 @@ public class LanguageCyclingItem { observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C // TODO (Ineanto, 7/14/23): This checks a 2nd time for the profile. if (dataStore.updateCache(player.getUniqueId(), nickoProfile).isError()) { - final I18N i18n = new I18N(player); player.sendMessage(i18n.translate(I18NDict.Event.Settings.ERROR)); player.getOpenInventory().close(); + } else { + player.sendMessage("Updated language to " + nickoProfile.getLocale().getCode()); } }, localeOrdinal, providers); } diff --git a/src/main/java/xyz/atnrch/nicko/i18n/I18N.java b/src/main/java/xyz/atnrch/nicko/i18n/I18N.java index 57c3d90..4859efe 100644 --- a/src/main/java/xyz/atnrch/nicko/i18n/I18N.java +++ b/src/main/java/xyz/atnrch/nicko/i18n/I18N.java @@ -9,11 +9,16 @@ import java.io.InputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class I18N { private final MessageFormat formatter = new MessageFormat(""); - private final YamlConfig yamlConfig; + private final Logger logger = Logger.getLogger("I18N"); private final NickoBukkit instance = NickoBukkit.getInstance(); + private final Pattern replacementPattern = Pattern.compile("\\{\\d+}"); + private final YamlConfig yamlConfig; private final Player player; private final Locale playerLocale; @@ -30,37 +35,63 @@ public class I18N { } public ItemTranslation translateItem(String key, String... args) { - final String name = readString(key + ".name"); - final ArrayList lore = readList(key + ".lore"); + final String nameKey = key + ".name"; + final String loreKey = key + ".lore"; + final String name = readString(nameKey); + final ArrayList lore = readList(loreKey); + + if (name == null) { + logger.warning(nameKey + " doesn't exists! Please translate this entry."); + return new ItemTranslation(nameKey, new ArrayList() {{ + add(loreKey); + }}); + } // Add all elements to a list final ArrayList toTranslate = new ArrayList<>(); toTranslate.add(name); - toTranslate.addAll(lore); + if (lore != null && !lore.isEmpty()) { + toTranslate.addAll(lore); + } // Set starting index to 0 - int index = 0; + int lineIndex = 0; + int replacementIndex = 0; // While iterator next value exists/isn't null final Iterator iterator = toTranslate.iterator(); - while (!iterator.hasNext() || iterator.next() == null) { + while (iterator.hasNext() && iterator.next() != null) { // Get the current line - final String currentLine = toTranslate.get(index); + final String currentLine = toTranslate.get(lineIndex); - // Replace with the corresponding varargs index - toTranslate.set(index, currentLine.replace("{" + index + "}", args[index])); + // If the line doesn't contain {i}, skip it + final Matcher matcher = replacementPattern.matcher(currentLine); + if (!matcher.matches()) { + lineIndex++; + continue; + } + + // If it does, replace the content with the args at position replacementIndex + if (replacementIndex < args.length && args[replacementIndex] != null) { + // Replace with the corresponding varargs index + toTranslate.set(lineIndex, currentLine.replace("{" + replacementIndex + "}", args[replacementIndex])); + replacementIndex++; + } // Increment the index - index++; + lineIndex++; } - return new ItemTranslation(toTranslate.get(0), toTranslate.subList(1, toTranslate.size())); + + if (lore == null || lore.isEmpty()) { + return new ItemTranslation(toTranslate.get(0), new ArrayList<>()); + } + return new ItemTranslation(toTranslate.get(0), new ArrayList<>(toTranslate.subList(1, toTranslate.size()))); } public String translate(String key, Object... arguments) { - final String string = readString(key); - + final String translation = readString(key); try { - formatter.applyPattern(string); + formatter.applyPattern(translation); return instance.getNickoConfig().getPrefix() + formatter.format(arguments); } catch (Exception e) { return instance.getNickoConfig().getPrefix() + key; @@ -94,7 +125,7 @@ public class I18N { } } - private Locale getPlayerLocale() { + public Locale getPlayerLocale() { try { final AppearanceManager appearanceManager = AppearanceManager.get(player); return !appearanceManager.hasData() ? Locale.FALLBACK_LOCALE : appearanceManager.getLocale(); diff --git a/src/main/java/xyz/atnrch/nicko/i18n/ItemTranslation.java b/src/main/java/xyz/atnrch/nicko/i18n/ItemTranslation.java index 464b629..035724e 100644 --- a/src/main/java/xyz/atnrch/nicko/i18n/ItemTranslation.java +++ b/src/main/java/xyz/atnrch/nicko/i18n/ItemTranslation.java @@ -1,12 +1,12 @@ package xyz.atnrch.nicko.i18n; -import java.util.List; +import java.util.ArrayList; public class ItemTranslation { private final String name; - private final List lore; + private final ArrayList lore; - public ItemTranslation(String name, List lore) { + public ItemTranslation(String name, ArrayList lore) { this.name = name; this.lore = lore; } @@ -15,7 +15,7 @@ public class ItemTranslation { return name; } - public List getLore() { + public ArrayList getLore() { return lore; } } diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml index 310a121..4144e12 100644 --- a/src/main/resources/en.yml +++ b/src/main/resources/en.yml @@ -29,6 +29,8 @@ event: gui: exit: "Exit" + go_back: + name: "Back" home: admin: name: "Administration panel" @@ -58,5 +60,6 @@ gui: bungeecord: name: "Bungeecord Transfer" lore: + - "{0}" - "§7§oGet through the values" - "§7§oby left or right clicking." \ No newline at end of file diff --git a/src/main/resources/fr.yml b/src/main/resources/fr.yml index 1c95045..5954d3a 100644 --- a/src/main/resources/fr.yml +++ b/src/main/resources/fr.yml @@ -9,6 +9,8 @@ error: json: "Erreur JSON" event: + settings: + error: "§cImpossible de mettre à jour vos paramètres. §7§o({0})" appearance: set: error: "§cImpossible d''appliquer votre déguisement. §7§o({0})" @@ -27,6 +29,8 @@ event: gui: exit: "Quitter" + go_back: + name: "Retour" home: admin: name: "Panel d''administration" @@ -54,7 +58,8 @@ gui: - "§7§oParcourez les valeurs" - "§7§oavec un clique gauche/droit." bungeecord: - name: "Bungeecord Transfer" + name: "Transfert Bungeecord" lore: - - "§7§oGet through the values" - - "§7§oby left or right clicking." \ No newline at end of file + - "{0}" + - "§7§oParcourez les valeurs" + - "§7§oavec un clique gauche/droit." \ No newline at end of file diff --git a/src/test/java/xyz/atnrch/nicko/test/i18n/I18NLoreTest.java b/src/test/java/xyz/atnrch/nicko/test/i18n/I18NItemTranslationTest.java similarity index 60% rename from src/test/java/xyz/atnrch/nicko/test/i18n/I18NLoreTest.java rename to src/test/java/xyz/atnrch/nicko/test/i18n/I18NItemTranslationTest.java index 4d30b13..31f85a9 100644 --- a/src/test/java/xyz/atnrch/nicko/test/i18n/I18NLoreTest.java +++ b/src/test/java/xyz/atnrch/nicko/test/i18n/I18NItemTranslationTest.java @@ -1,7 +1,6 @@ package xyz.atnrch.nicko.test.i18n; import be.seeseemelk.mockbukkit.MockBukkit; -import be.seeseemelk.mockbukkit.ServerMock; import be.seeseemelk.mockbukkit.entity.PlayerMock; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -15,8 +14,10 @@ import xyz.atnrch.nicko.i18n.I18NDict; import xyz.atnrch.nicko.i18n.ItemTranslation; import xyz.atnrch.nicko.i18n.Locale; -public class I18NLoreTest { - private static NickoBukkit plugin; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class I18NItemTranslationTest { private static PlayerMock player; @BeforeAll @@ -26,17 +27,25 @@ public class I18NLoreTest { DataSourceConfiguration.REDIS_EMPTY, "", false); - final ServerMock server = MockBukkit.mock(); - plugin = MockBukkit.load(NickoBukkit.class, config); + MockBukkit.mock(); + MockBukkit.load(NickoBukkit.class, config); } @Test - @DisplayName("Translate Item Lore") + @DisplayName("Translate Item Without Lore") + public void translateItemTranslationWithoutLore() { + final I18N i18n = new I18N(Locale.FRENCH); + final ItemTranslation translation = i18n.translateItem(I18NDict.GUI.GO_BACK); + assertTrue(translation.getLore().isEmpty()); + assertEquals(translation.getName(), "Retour"); + } + + @Test + @DisplayName("Translate Item") public void translateItemLore() { final I18N i18n = new I18N(Locale.FRENCH); - final ItemTranslation translation = i18n.translateItem(I18NDict.GUI.Home.ADMIN); - System.out.println("name = " + translation.getName()); - System.out.println("lore = " + translation.getLore()); + final ItemTranslation translation = i18n.translateItem(I18NDict.GUI.Settings.BUNGEECORD, "Test"); + assertEquals("Test", translation.getLore().get(0)); } @AfterAll