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();
+ }
+
+}