diff --git a/.gitignore b/.gitignore index 622bc26..3fb9b74 100644 --- a/.gitignore +++ b/.gitignore @@ -125,6 +125,4 @@ run/ ignore/ -null/ - -!libs/GoogleTranslateAPI-1.0-shaded.jar \ No newline at end of file +null/ \ No newline at end of file diff --git a/build.gradle b/build.gradle index 07308e4..560a820 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ import org.apache.tools.ant.filters.ReplaceTokens plugins { id "java" id "com.github.johnrengelman.shadow" version "7.1.2" - id "net.kyori.indra.publishing" version "2.1.1" + id "net.kyori.indra.publishing" version "2.1.0" id "net.kyori.indra.publishing.sonatype" version "2.1.1" id "signing" id "io.github.slimjar" version "1.3.0" @@ -38,7 +38,7 @@ ext { } group = "me.lorenzo0111" -version = "1.7.1" +version = "1.7.2" description = "MultiLang is a library that allows you to easily create multi-language placeholders." java { @@ -66,15 +66,15 @@ dependencies { implementation("space.rocketplugins.pluginslib:bukkit:2.0.3.2") implementation("io.github.slimjar:slimjar:1.2.7") implementation('dev.triumphteam:triumph-gui:3.2') - implementation files("libs/GoogleTranslateAPI-1.0-shaded.jar") compileOnly("org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT") - compileOnly("com.comphenix.protocol:ProtocolLib:4.7.0") + compileOnly("com.comphenix.protocol:ProtocolLib:4.8.0") compileOnly("com.github.MilkBowl:VaultAPI:1.7.1") compileOnly("me.clip:placeholderapi:2.11.1") compileOnly("me.lorenzo0111:RocketPlaceholders:2.1") - compileOnly('org.jetbrains:annotations:23.0.0') + compileOnly("org.jetbrains:annotations:23.0.0") + slim("com.squareup.okhttp3:okhttp:4.9.3") slim("com.zaxxer:HikariCP:4.0.3") - slim('com.github.cryptomorin:XSeries:8.6.1') + slim("com.github.cryptomorin:XSeries:8.7.1") slim("mysql:mysql-connector-java:8.0.28") slim("org.xerial:sqlite-jdbc:3.36.0.3") slim("org.slf4j:slf4j-simple:1.7.36") @@ -90,6 +90,7 @@ slimJar { relocate('dev.triumphteam',"${libsBase}") relocate('com.cryptomorin.xseries',"${libsBase}.xseries") relocate('com.zaxxer.hikari',"${libsBase}.hikari") + relocate('okhttp3', "${libsBase}.okhttp") } shadowJar { @@ -107,7 +108,6 @@ shadowJar { relocate("org.spongepowered.configurate", "${libsBase}.configurate") relocate("org.bstats", "${libsBase}.bstats") relocate("com.google.gson", "${libsBase}.google.gson") - relocate("com.gtranslate", "${libsBase}.google.translate") } diff --git a/libs/GoogleTranslateAPI-1.0-shaded.jar b/libs/GoogleTranslateAPI-1.0-shaded.jar deleted file mode 100644 index eac86a8..0000000 Binary files a/libs/GoogleTranslateAPI-1.0-shaded.jar and /dev/null differ diff --git a/src/main/java/me/lorenzo0111/multilang/MultiLangPlugin.java b/src/main/java/me/lorenzo0111/multilang/MultiLangPlugin.java index 25c4f6a..cad835e 100644 --- a/src/main/java/me/lorenzo0111/multilang/MultiLangPlugin.java +++ b/src/main/java/me/lorenzo0111/multilang/MultiLangPlugin.java @@ -31,13 +31,13 @@ import me.lorenzo0111.multilang.cache.PlayersCache; import me.lorenzo0111.multilang.data.StorageType; import me.lorenzo0111.multilang.database.DatabaseManager; +import me.lorenzo0111.multilang.exceptions.ApiException; import me.lorenzo0111.multilang.exceptions.ReloadException; import me.lorenzo0111.multilang.handlers.ConfigManager; import me.lorenzo0111.multilang.hooks.Hook; import me.lorenzo0111.multilang.listeners.JoinListener; import me.lorenzo0111.multilang.protocol.PacketHandler; -import me.lorenzo0111.multilang.realtime.GoogleTranslator; -import me.lorenzo0111.multilang.realtime.MicrosoftTranslator; +import me.lorenzo0111.multilang.realtime.RealTimeTranslator; import me.lorenzo0111.multilang.realtime.TranslatorConfig; import me.lorenzo0111.multilang.storage.StorageManager; import me.lorenzo0111.multilang.tasks.UpdateTask; @@ -62,10 +62,7 @@ import java.net.URISyntaxException; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import java.util.logging.Level; public final class MultiLangPlugin extends JavaPlugin { @@ -138,9 +135,13 @@ public void onEnable() { e.printStackTrace(); } - this.reloadRealtimeConfig(); - if (translators.isUseCache()) { - Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> translators.loadCache(databaseManager), 60 * 20L); + try { + this.reloadRealtimeConfig(); + if (translators.isUseCache()) { + Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> translators.loadCache(databaseManager), 60 * 20L); + } + } catch (ApiException e) { + this.getLogger().severe("An error has occurred while trying to load the realtime configuration: " + e.getMessage()); } this.cacheFolder = new File(this.getDataFolder(), "cache"); @@ -319,12 +320,18 @@ public void updateConfig() throws IOException { ConfigurationSection section = this.getConfig().createSection("real-time"); section.set("enabled",false); section.set("cache",true); - section.set("api","google"); + section.set("server-messages",false); + section.set("ignore", Collections.singletonList("\\\\/")); + section.set("key", "Get one at https://multilang.lorenzo0111.me/"); section.set("autoupdater-comment","This section has been automatically generated by the plugin. Since the configuration api does not allow us to put comments, please read our documentation for more information. https://wiki.lorenzo0111.me/multilang"); this.getConfig().set("real-time",section); needsSave = true; } + if (!this.getConfig().getString("realtime.api", "realtime").equalsIgnoreCase("realtime")) { + this.getLogger().severe("RealTime google and bing api has been deprecated. Please retrieve a new api key at https://multilang.lorenzo0111.me"); + } + if (needsSave) { this.saveConfig(); } @@ -358,19 +365,19 @@ public PacketHandler getProtocol() { return protocol; } - public void reloadRealtimeConfig() { + public void reloadRealtimeConfig() throws ApiException { if (translators != null && translators.isUseCache()) { translators.saveCache(databaseManager); } translators = new TranslatorConfig(); translators.canRegister(true); - translators.registerTranslator("bing", new MicrosoftTranslator(this.getConfig().getString("real-time.key"))); - translators.registerTranslator("google", new GoogleTranslator()); + translators.registerTranslator("realtime", new RealTimeTranslator(this.getConfig().getString("real-time.key"))); + translators.setInUse("realtime"); translators.setEnabled(this.getConfig().getBoolean("real-time.enabled")); - translators.setInUse(this.getConfig().getString("real-time.api", "google")); translators.setUseCache(this.getConfig().getBoolean("real-time.cache")); translators.setPatterns(this.getConfig().getStringList("real-time.ignore")); + translators.setTranslateServer(this.getConfig().getBoolean("real-time.server-messages")); if (!translators.testConnection()) { this.getLogger().severe("RealTime API is not working. Please check your api url."); this.getLogger().severe("Disabling real-time translation."); diff --git a/src/main/java/me/lorenzo0111/multilang/commands/subcommands/admin/ReloadCommand.java b/src/main/java/me/lorenzo0111/multilang/commands/subcommands/admin/ReloadCommand.java index 670572d..5098b80 100644 --- a/src/main/java/me/lorenzo0111/multilang/commands/subcommands/admin/ReloadCommand.java +++ b/src/main/java/me/lorenzo0111/multilang/commands/subcommands/admin/ReloadCommand.java @@ -28,6 +28,7 @@ import me.lorenzo0111.multilang.MultiLangPlugin; import me.lorenzo0111.multilang.commands.AdminLangCommand; import me.lorenzo0111.multilang.commands.SubCommand; +import me.lorenzo0111.multilang.exceptions.ApiException; import me.lorenzo0111.multilang.exceptions.ReloadException; import me.lorenzo0111.multilang.protocol.adapter.EntityAdapter; import org.bukkit.command.CommandSender; @@ -73,7 +74,7 @@ public void handleSubcommand(CommandSender commandSender, String[] strings) { commandSender.sendMessage(this.format(String.format("&7Plugin reloaded in &9%sms", System.currentTimeMillis() - time))); - } catch (ReloadException | SQLException | IOException ex) { + } catch (ReloadException | SQLException | IOException | ApiException ex) { if (commandSender instanceof Player) { XSound.play((Player) commandSender,"BLOCK_ANVIL_PLACE"); } diff --git a/src/main/java/me/lorenzo0111/multilang/protocol/adapter/ChatAdapter.java b/src/main/java/me/lorenzo0111/multilang/protocol/adapter/ChatAdapter.java index 6f2d3e4..203e2b4 100644 --- a/src/main/java/me/lorenzo0111/multilang/protocol/adapter/ChatAdapter.java +++ b/src/main/java/me/lorenzo0111/multilang/protocol/adapter/ChatAdapter.java @@ -48,6 +48,7 @@ public class ChatAdapter extends BaseAdapter { private static final List TASKS = new ArrayList<>(); + private final List ignore = new ArrayList<>(); public ChatAdapter(MultiLangPlugin plugin, ListenerPriority listenerPriority) { super(plugin, listenerPriority, PacketType.Play.Server.CHAT); @@ -55,6 +56,7 @@ public ChatAdapter(MultiLangPlugin plugin, ListenerPriority listenerPriority) { @Override public void onPacketSending(@NotNull PacketEvent event) { + if (event.isCancelled()) return; PacketContainer packet = event.getPacket(); Player player = event.getPlayer(); @@ -63,6 +65,11 @@ public void onPacketSending(@NotNull PacketEvent event) { WrappedChatComponent component = packet.getChatComponents().read(0); if (component == null) return; + if (ignore.contains(component.getJson())) { + ignore.remove(component.getJson()); + return; + } + if (type == null || type.equals(EnumWrappers.ChatType.SYSTEM)) { this.handle(player,component); } @@ -98,6 +105,8 @@ public void onPacketSending(@NotNull PacketEvent event) { } private boolean translate(PacketEvent event, PacketContainer packet, @NotNull TranslatorConfig translators, @NotNull LocalizedPlayer p, @NotNull JsonObject object) { + if (!translators.isTranslateServer() && event.isServerPacket()) return false; + String text = translators.tryFromCache(p.getLocale(), object.get("text").getAsString()); if (text != null) { this.update(object,text); @@ -114,25 +123,31 @@ public void queue(LocalizedPlayer p, PacketContainer packet) { BukkitRunnable task = new BukkitRunnable() { @Override public void run() { - WrappedChatComponent component = packet.getChatComponents().read(0); - - TranslatorConfig translators = ((MultiLangPlugin) ChatAdapter.this.getPlugin()).getTranslators(); - - ChatAdapter.this.updateTexts(component, (value) -> { - String text = translators.translate(p.getLocale(), value); - return text != null ? text : value; - }); - - packet.getChatComponents().write(0, component); - Bukkit.getScheduler().runTask(ChatAdapter.this.getPlugin(), () -> { - try { - ProtocolManager manager = ((MultiLangPlugin) ChatAdapter.this.getPlugin()).getProtocol().getManager(); + try { + WrappedChatComponent component = packet.getChatComponents().read(0); + + TranslatorConfig translators = ((MultiLangPlugin) ChatAdapter.this.getPlugin()).getTranslators(); + + ChatAdapter.this.updateTexts(component, (value) -> { + String text = translators.translate(p.getLocale(), value); + return text != null ? text : value; + }); + + packet.getChatComponents().write(0, component); + Bukkit.getScheduler().runTask(ChatAdapter.this.getPlugin(), () -> { + try { + ignore.add(component.getJson()); + + ProtocolManager manager = ((MultiLangPlugin) ChatAdapter.this.getPlugin()).getProtocol().getManager(); + manager.sendServerPacket(p.getPlayer(), packet); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } - manager.sendServerPacket(p.getPlayer(), packet); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - }); TASKS.remove(this); } }; diff --git a/src/main/java/me/lorenzo0111/multilang/realtime/GoogleTranslator.java b/src/main/java/me/lorenzo0111/multilang/realtime/GoogleTranslator.java deleted file mode 100644 index b51a0f4..0000000 --- a/src/main/java/me/lorenzo0111/multilang/realtime/GoogleTranslator.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.lorenzo0111.multilang.realtime; - -import com.gtranslate.Translator; -import me.lorenzo0111.multilang.api.objects.ITranslator; -import me.lorenzo0111.multilang.utils.RegexChecker; -import org.bukkit.ChatColor; - -public class GoogleTranslator implements ITranslator { - - @Override - public String translate(String text, String language) { - if (RegexChecker.isUrl(text)) { - return text; - } - - try { - Translator translator = Translator.getInstance(); - return translator.translate(text, translator.detect(ChatColor.stripColor(text)), language); - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } -} diff --git a/src/main/java/me/lorenzo0111/multilang/realtime/MicrosoftTranslator.java b/src/main/java/me/lorenzo0111/multilang/realtime/MicrosoftTranslator.java deleted file mode 100644 index b4cf896..0000000 --- a/src/main/java/me/lorenzo0111/multilang/realtime/MicrosoftTranslator.java +++ /dev/null @@ -1,70 +0,0 @@ -package me.lorenzo0111.multilang.realtime; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import me.lorenzo0111.multilang.api.objects.ITranslator; -import me.lorenzo0111.multilang.utils.RegexChecker; -import org.bukkit.ChatColor; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; - -public class MicrosoftTranslator implements ITranslator { - private final String endpoint; - private final String api; - - public MicrosoftTranslator(String api) { - this.api = api; - this.endpoint = "https://microsoft-translator-text.p.rapidapi.com/translate?api-version=3.0&to=%s&suggestedFrom=en&textType=plain&profanityAction=NoAction"; - } - - @Override - public String translate(String text, String language) { - if (RegexChecker.isUrl(text)) { - return text; - } - - try { - URL url = new URL(String.format(this.endpoint, language)); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestProperty("content-type", "application/json"); - connection.setRequestProperty("x-rapidapi-host", "microsoft-translator-text.p.rapidapi.com"); - connection.setRequestProperty("x-rapidapi-key", api); - connection.setRequestMethod("POST"); - connection.setDoOutput(true); - - JsonArray array = new JsonArray(); - JsonObject object = new JsonObject(); - object.addProperty("Text", ChatColor.stripColor(text)); - array.add(object); - - try (OutputStream os = connection.getOutputStream()) { - byte[] input = array.toString().getBytes(StandardCharsets.UTF_8); - os.write(input, 0, input.length); - } - - try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { - StringBuilder response = new StringBuilder(); - String responseLine; - while ((responseLine = br.readLine()) != null) { - response.append(responseLine.trim()); - } - - JsonArray jArray = new JsonParser().parse(response.toString()).getAsJsonArray(); - JsonObject result = jArray.get(0).getAsJsonObject(); - return result.get("translations").getAsJsonArray().get(0).getAsJsonObject().get("text").getAsString(); - } - - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } - -} diff --git a/src/main/java/me/lorenzo0111/multilang/realtime/RealTimeTranslator.java b/src/main/java/me/lorenzo0111/multilang/realtime/RealTimeTranslator.java new file mode 100644 index 0000000..e248047 --- /dev/null +++ b/src/main/java/me/lorenzo0111/multilang/realtime/RealTimeTranslator.java @@ -0,0 +1,66 @@ +package me.lorenzo0111.multilang.realtime; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.lorenzo0111.multilang.MultiLangPlugin; +import me.lorenzo0111.multilang.api.objects.ITranslator; +import me.lorenzo0111.multilang.utils.RegexChecker; +import okhttp3.*; + +public class RealTimeTranslator implements ITranslator { + private final String api; + private final OkHttpClient client; + private final MediaType mediaType = MediaType.parse("application/json"); + + public RealTimeTranslator(String api) { + this.api = api; + this.client = new OkHttpClient().newBuilder() + .build(); + } + + @SuppressWarnings("deprecation") + @Override + public String translate(String text, String language) { + if (RegexChecker.isUrl(text)) { + return text; + } + + if (text == null || text.isEmpty() || language == null || language.isEmpty()) { + return null; + } + + MultiLangPlugin.getInstance().debug("Translating: " + text + " to " + language); + + try { + JsonObject object = new JsonObject(); + object.addProperty("text", text); + object.addProperty("to", language); + + RequestBody body = RequestBody.create(object.toString(), mediaType); + Request request = new Request.Builder() + .url("https://multilang.lorenzo0111.me/api/translate") + .method("POST", body) + .addHeader("authorization", api) + .addHeader("Content-Type", "application/json") + .build(); + + Response response = client.newCall(request).execute(); + + JsonObject json = new JsonParser().parse(response.body().string()).getAsJsonObject(); + if (json.has("error")) { + MultiLangPlugin.getInstance().getLogger().severe("RealTime server returned an error: " + json.get("error").getAsString()); + return null; + } else if (json.has("text")) { + MultiLangPlugin.getInstance().debug("Request returned: " + json.get("text").getAsString()); + return json.get("text").getAsString(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + MultiLangPlugin.getInstance().debug("Request failed. Returning null"); + + return null; + } + +} diff --git a/src/main/java/me/lorenzo0111/multilang/realtime/TranslatorConfig.java b/src/main/java/me/lorenzo0111/multilang/realtime/TranslatorConfig.java index eff5c46..97d6806 100644 --- a/src/main/java/me/lorenzo0111/multilang/realtime/TranslatorConfig.java +++ b/src/main/java/me/lorenzo0111/multilang/realtime/TranslatorConfig.java @@ -26,6 +26,7 @@ public class TranslatorConfig { private boolean canRegister = false; private boolean useCache = false; private String inUse = null; + private boolean translateServer = false; public void registerTranslator(String id, ITranslator translator) { if (!this.canRegister) { @@ -70,6 +71,14 @@ public void setPatterns(@NotNull List patterns) { } } + public void setTranslateServer(boolean translateServer) { + this.translateServer = translateServer; + } + + public boolean isTranslateServer() { + return translateServer; + } + public @Nullable String translate(Locale locale, String text) { if (inUse == null) { return null; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 06631e9..073863d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -30,10 +30,11 @@ languages: real-time: enabled: false # Set to true to enable the feature cache: true # Cache the translated messages in the database for faster translations - api: "bing" # Available translation apis: bing, google. You can register a new one with our api. - key: "" # The api key for the selected api. Needed for Bing(By RapidAPI). If you need help creating a key for free join our discord server https://discord.io/RocketPlugins + key: "" # The api key for the api. You can create one at https://multilang.lorenzo0111.me + server-messages: false # Set to true if it should edit plugin messages ignore: # List of regex to not translate - "ignoreme" + - "\\/" # Warning: This feature is still experimental. It may not work with some languages. auto-detect: false