From 073f3a49d5dbb8673679827f2c6c0cec1bd98eb5 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 26 Mar 2023 10:06:38 -0700 Subject: [PATCH] Adds API to enable translations to be set and specific API for flags (#2109) This was a request on Discord so that plugins can set flags and set the name and lore for them too. --- .../bentobox/bentobox/api/flags/Flag.java | 28 ++++++++++ .../bentobox/managers/LocalesManager.java | 19 +++++++ .../bentobox/bentobox/api/flags/FlagTest.java | 51 +++++++++++++++---- .../bentobox/managers/LocalesManagerTest.java | 37 ++++++++++++-- 4 files changed, 121 insertions(+), 14 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/flags/Flag.java b/src/main/java/world/bentobox/bentobox/api/flags/Flag.java index e860b44e1..409296228 100644 --- a/src/main/java/world/bentobox/bentobox/api/flags/Flag.java +++ b/src/main/java/world/bentobox/bentobox/api/flags/Flag.java @@ -2,6 +2,7 @@ package world.bentobox.bentobox.api.flags; import java.util.Arrays; import java.util.HashSet; +import java.util.Locale; import java.util.Optional; import java.util.Set; @@ -466,6 +467,33 @@ public class Flag implements Comparable { public Set getSubflags() { return subflags; } + + /** + * Set the name of this flag for a specified locale. This enables the flag's name to be assigned via API. It will not be stored anywhere + * and must be rewritten using this call every time the flag is built. + * @param locale locale (language) to which this name should be assigned. Assigning to {@code Locale.US} will make this the default + * @param name the translated name for this flag + * @return true if successful, false if the locale is unknown to this server. + * See {@link world.bentobox.bentobox.managers.LocalesManager#getAvailableLocales(boolean sort)} + * @since 1.22.1 + */ + public boolean setTranslatedName(Locale locale, String name) { + return BentoBox.getInstance().getLocalesManager().setTranslation(locale, getNameReference(), name); + } + + /** + * Set the name of this flag for a specified locale. This enables the flag's name to be assigned via API. It will not be stored anywhere + * and must be rewritten using this call every time the flag is built. + * @param locale locale (language) to which this name should be assigned. Assigning to {@code Locale.US} will make this the default + * @param description the translated description for this flag + * @return true if successful, false if the locale is unknown to this server. + * See {@link world.bentobox.bentobox.managers.LocalesManager#getAvailableLocales(boolean sort)} + * @since 1.22.1 + */ + + public boolean setTranslatedDescription(Locale locale, String description) { + return BentoBox.getInstance().getLocalesManager().setTranslation(locale, getDescriptionReference(), description); + } @Override public String toString() { diff --git a/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java b/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java index cb54aa29d..ce5fbeb87 100644 --- a/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java @@ -104,6 +104,25 @@ public class LocalesManager { } return null; } + + /** + * Set the translation for a reference for a specific locale. The locale must be a known locale on this server. + * User {@link #getAvailableLocales(boolean)} to find out what locales are available. + * Note, the usual default locale is {@code Locale.US} + * @param locale locale + * @param reference reference + * @param translation translation + * @return true if successful, false if the locale is not a known locale on this server + * @since 1.22.1 + */ + public boolean setTranslation(Locale locale, String reference, String translation) { + // Set a translation + if (!languages.containsKey(locale)) { + return false; + } + languages.get(locale).set(reference, translation); + return true; + } /** * Gets the translated String corresponding to the reference from the server's or the en-US locale file. diff --git a/src/test/java/world/bentobox/bentobox/api/flags/FlagTest.java b/src/test/java/world/bentobox/bentobox/api/flags/FlagTest.java index eb6545dca..a1d44d8b0 100644 --- a/src/test/java/world/bentobox/bentobox/api/flags/FlagTest.java +++ b/src/test/java/world/bentobox/bentobox/api/flags/FlagTest.java @@ -6,6 +6,8 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -13,6 +15,7 @@ import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -45,6 +48,7 @@ import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.RanksManager; import world.bentobox.bentobox.util.Util; @@ -66,6 +70,8 @@ public class FlagTest { private IslandWorldManager iwm; @Mock private BentoBox plugin; + @Mock + private LocalesManager lm; /** */ @@ -76,7 +82,7 @@ public class FlagTest { PowerMockito.mockStatic(Util.class); // Return world - when(Util.getWorld(Mockito.any())).thenAnswer((Answer) invocation -> invocation.getArgument(0, World.class)); + when(Util.getWorld(any())).thenAnswer((Answer) invocation -> invocation.getArgument(0, World.class)); // World Settings when(plugin.getIWM()).thenReturn(iwm); @@ -92,8 +98,13 @@ public class FlagTest { PowerMockito.mockStatic(Bukkit.class); ItemFactory itemF = mock(ItemFactory.class); ItemMeta im = mock(ItemMeta.class); - when(itemF.getItemMeta(Mockito.any())).thenReturn(im); + when(itemF.getItemMeta(any())).thenReturn(im); when(Bukkit.getItemFactory()).thenReturn(itemF); + + // Locales manager + when(plugin.getLocalesManager()).thenReturn(lm); + // Setting US text is successful + when(lm.setTranslation(eq(Locale.US), anyString(), anyString())).thenReturn(true); // Flag f = new Flag.Builder("flagID", Material.ACACIA_PLANKS).type(Flag.Type.PROTECTION).listener(listener).build(); @@ -346,7 +357,7 @@ public class FlagTest { IslandsManager im = mock(IslandsManager.class); Island island = mock(Island.class); - when(island.getFlag(Mockito.any())).thenReturn(RanksManager.VISITOR_RANK); + when(island.getFlag(any())).thenReturn(RanksManager.VISITOR_RANK); User user = mock(User.class); when(user.getUniqueId()).thenReturn(UUID.randomUUID()); @@ -357,27 +368,45 @@ public class FlagTest { return sb.toString(); }; - when(user.getTranslation(Mockito.any(String.class),Mockito.any(),Mockito.any())).thenAnswer(answer); + when(user.getTranslation(any(String.class),any(),any())).thenAnswer(answer); - when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island); - when(im.getIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(island); + when(im.getIsland(any(), any(UUID.class))).thenReturn(island); + when(im.getIsland(any(), any(User.class))).thenReturn(island); Optional oL = Optional.of(island); - when(im.getIslandAt(Mockito.any(Location.class))).thenReturn(oL); + when(im.getIslandAt(any(Location.class))).thenReturn(oL); when(plugin.getIslands()).thenReturn(im); RanksManager rm = mock(RanksManager.class); when(plugin.getRanksManager()).thenReturn(rm); - when(rm.getRank(Mockito.eq(RanksManager.VISITOR_RANK))).thenReturn("Visitor"); - when(rm.getRank(Mockito.eq(RanksManager.OWNER_RANK))).thenReturn("Owner"); + when(rm.getRank(RanksManager.VISITOR_RANK)).thenReturn("Visitor"); + when(rm.getRank(RanksManager.OWNER_RANK)).thenReturn("Owner"); PanelItem pi = f.toPanelItem(plugin, user, island, false); - verify(user).getTranslation(Mockito.eq("protection.flags.flagID.name")); - verify(user).getTranslation(Mockito.eq("protection.panel.flag-item.name-layout"), any()); + verify(user).getTranslation("protection.flags.flagID.name"); + verify(user).getTranslation(eq("protection.panel.flag-item.name-layout"), any()); assertEquals(Material.ACACIA_PLANKS, pi.getItem().getType()); } + + /** + * Test method for {@link world.bentobox.bentobox.api.flags.Flag#setTranslatedName(java.util.Locale, String)}. + */ + @Test + public void testSetTranslatedName() { + assertFalse(f.setTranslatedName(Locale.CANADA, "Good eh?")); + assertTrue(f.setTranslatedName(Locale.US, "Yihaa")); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.flags.Flag#setTranslatedDescription(java.util.Locale, String)}. + */ + @Test + public void testSetTranslatedDescription() { + assertFalse(f.setTranslatedDescription(Locale.CANADA, "Good eh?")); + assertTrue(f.setTranslatedDescription(Locale.US, "Yihaa")); + } /** * Test method for {@link world.bentobox.bentobox.api.flags.Flag#toString()}. diff --git a/src/test/java/world/bentobox/bentobox/managers/LocalesManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/LocalesManagerTest.java index 51e9da70e..005e72494 100644 --- a/src/test/java/world/bentobox/bentobox/managers/LocalesManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/LocalesManagerTest.java @@ -1,9 +1,11 @@ package world.bentobox.bentobox.managers; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.BufferedInputStream; @@ -64,6 +66,10 @@ public class LocalesManagerTest { when(plugin.getSettings()).thenReturn(settings); } + /** + * Makes fake English and French local files + * @throws IOException if the file saving fails + */ private void makeFakeLocaleFile() throws IOException { File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + BENTOBOX); File english = new File(localeDir, Locale.US.toLanguageTag() + ".yml"); @@ -270,7 +276,7 @@ public class LocalesManagerTest { makeFakeLocaleFile(); LocalesManager lm = new LocalesManager(plugin); lm.reloadLanguages(); - Mockito.verify(am).getAddons(); + verify(am).getAddons(); File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + BENTOBOX); assertTrue(localeDir.exists()); } @@ -313,7 +319,7 @@ public class LocalesManagerTest { lm.reloadLanguages(); // Verify that the resources have been saved (note that they are not actually saved because addon is a mock) - Mockito.verify(addon).saveResource( + verify(addon).saveResource( Mockito.eq("locales/en-US.yml"), Mockito.any(), Mockito.eq(false), @@ -332,6 +338,8 @@ public class LocalesManagerTest { } } + + private void add(File source, JarOutputStream target) throws IOException { @@ -388,9 +396,32 @@ public class LocalesManagerTest { when(plugin.getAddonsManager()).thenReturn(am); LocalesManager lm = new LocalesManager(plugin); lm.reloadLanguages(); - Mockito.verify(am).getAddons(); + verify(am).getAddons(); File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + BENTOBOX); assertTrue(localeDir.exists()); } + /** + * Test method for {@link world.bentobox.bentobox.managers.LocalesManager#setTranslation(Locale, String, String)}. + */ + @Test + public void testSetTranslationUnknownLocale() throws IOException { + makeFakeLocaleFile(); + LocalesManager lm = new LocalesManager(plugin); + assertFalse(lm.setTranslation(Locale.GERMAN, "anything.ref", "a translation")); + + } + + /** + * Test method for {@link world.bentobox.bentobox.managers.LocalesManager#setTranslation(Locale, String, String)}. + */ + @Test + public void testSetTranslationKnownLocale() throws IOException { + makeFakeLocaleFile(); + LocalesManager lm = new LocalesManager(plugin); + assertEquals("test string", lm.get("test.test")); + assertTrue(lm.setTranslation(Locale.US, "test.test", "a translation")); + assertEquals("a translation", lm.get("test.test")); + + } }