diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 70c5c83000..98b1c9529c 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -284,6 +284,11 @@ asm-all 6.0_BETA + + org.json + json + 20180813 + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationConfig.java new file mode 100644 index 0000000000..bf0e7a532b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationConfig.java @@ -0,0 +1,32 @@ +package net.runelite.client.plugins.chattranslation; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("chattranslation") +public interface ChatTranslationConfig extends Config +{ + + @ConfigItem( + keyName = "publicChat", + name = "Translate All Public Chat?", + description = "Would you like to Translate Public Chat?", + position = 0 + ) + default boolean publicChat() { return false; } + + @ConfigItem( + keyName = "targetLanguage", + name = "Target Language", + description = "Language to translate messages too.", + position = 2, + hidden = true, + unhide = "publicChat" + ) + default Languages targetLanguage() + { + return Languages.ENGLISH; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationPlugin.java new file mode 100644 index 0000000000..da770088f9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationPlugin.java @@ -0,0 +1,154 @@ +package net.runelite.client.plugins.chattranslation; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ObjectArrays; +import com.google.inject.Provides; +import net.runelite.api.*; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.PlayerMenuOptionClicked; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.menus.MenuManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import org.apache.commons.lang3.ArrayUtils; + +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Provider; + +@PluginDescriptor( + name = "Chat Translator", + description = "Translates messages from one Language to another.", + tags = {"translate", "language", "english", "spanish", "dutch", "french"}, + type = PluginType.UTILITY +) +public class ChatTranslationPlugin extends Plugin { + + public static final String TRANSLATE = "Translate"; + private static final ImmutableList AFTER_OPTIONS = ImmutableList.of("Message", "Add ignore", "Remove friend", "Kick"); + + @Inject + @Nullable + private Client client; + + @Inject + private Provider menuManager; + + @Inject + private ChatMessageManager chatMessageManager; + + @Inject + private ChatTranslationConfig config; + + @Provides + ChatTranslationConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(ChatTranslationConfig.class); + } + + @Override + protected void startUp() throws Exception + { + if (client != null) + { + menuManager.get().addPlayerMenuItem(TRANSLATE); + } + } + + @Override + protected void shutDown() throws Exception + { + if (client != null) + { + menuManager.get().removePlayerMenuItem(TRANSLATE); + } + } + + @Subscribe + public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event) + { + if (event.getMenuOption().equals(TRANSLATE)) + { + //TODO: Translate selected message. + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + int groupId = WidgetInfo.TO_GROUP(event.getActionParam1()); + String option = event.getOption(); + + if (groupId == WidgetInfo.CHATBOX.getGroupId()) + { + boolean after; + + if (!AFTER_OPTIONS.contains(option)) + { + return; + } + + final MenuEntry lookup = new MenuEntry(); + lookup.setOption(TRANSLATE); + lookup.setTarget(event.getTarget()); + lookup.setType(MenuAction.RUNELITE.getId()); + lookup.setParam0(event.getActionParam0()); + lookup.setParam1(event.getActionParam1()); + lookup.setIdentifier(event.getIdentifier()); + + insertMenuEntry(lookup, client.getMenuEntries()); + } + } + + @Subscribe + public void onChatMessage(ChatMessage chatMessage) + { + if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN) + { + return; + } + switch (chatMessage.getType()) + { + case PUBLICCHAT: + case MODCHAT: + if (!config.publicChat()) + { + return; + } + break; + default: + return; + } + + String message = chatMessage.getMessage(); + + Translator translator = new Translator(); + + try { + //Automatically check language of message and translate to selected language. + String translation = translator.translate("auto", config.targetLanguage().toString(), message); + + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setRuneLiteFormatMessage(translation); + chatMessageManager.update(messageNode); + } catch (Exception e) { + e.printStackTrace(); + } + + client.refreshChat(); + } + + private void insertMenuEntry(MenuEntry newEntry, MenuEntry[] entries) + { + MenuEntry[] newMenu = ObjectArrays.concat(entries, newEntry); + int menuEntryCount = newMenu.length; + ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2); + client.setMenuEntries(newMenu); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Languages.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Languages.java new file mode 100644 index 0000000000..695c1a637d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Languages.java @@ -0,0 +1,23 @@ +package net.runelite.client.plugins.chattranslation; + +public enum Languages { + + ENGLISH("en"), + DUTCH("nl"), + SPANISH("es"), + FRENCH("fr"); + + private final String shortName; + + Languages(String shortName) + { + this.shortName = shortName; + } + + @Override + public String toString() + { + return shortName; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Translator.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Translator.java new file mode 100644 index 0000000000..220ba888e8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Translator.java @@ -0,0 +1,44 @@ +package net.runelite.client.plugins.chattranslation; + +import org.json.JSONArray; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +public class Translator { + + public String translate(String source, String target, String message) throws Exception + { + + String url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" + source + "&tl=" + target + "&dt=t&q=" + URLEncoder.encode(message, "UTF-8"); + + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + return parseResult(response.toString()); + } + + private String parseResult(String inputJson) throws Exception + { + //TODO: find a way to do this using google.gson + JSONArray jsonArray = new JSONArray(inputJson); + JSONArray jsonArray2 = (JSONArray) jsonArray.get(0); + JSONArray jsonArray3 = (JSONArray) jsonArray2.get(0); + + return jsonArray3.get(0).toString(); + } + +}