Chat Translator plugin (#824)

* Initial push for Chat Translation Plugin.

* Need help adding the 'Translate' menu option for translating selected Players messages.

Finished outgoing message translation however if the user has been limited by Google for the likes of using the Public Chat translation in over populated and spammy areas such as the GE they will not be able to send a message for upto 5 minutes while the Player Chat Translation config is enabled.

Need to think more about ways to handle this though once the selective translation has been completed we can safely remove the 'All' public chat messages part of the plugin to prevent users from being Limited by Google.

* Clean-up for Travis.

* Hidden the Public Chat Translation until a better implementation is added to prevent users from being accidentally locked out by Google.

* Hidden the Public Chat Translation until a better implementation is added to prevent users from being accidentally locked out by Google.

* Added config options for adding the 'Translate' right-click menu option in the Chatbox.
(More so to hide it while the Public Chat Translate part of the plugin is disabled/hidden.)

* Update ChatTranslationConfig.java
This commit is contained in:
Ian William O'Neill
2019-07-01 01:23:21 +01:00
committed by James
parent 358b8d05d0
commit 69dbeb523d
5 changed files with 389 additions and 0 deletions

View File

@@ -284,6 +284,11 @@
<artifactId>asm-all</artifactId>
<version>6.0_BETA</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,78 @@
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 incoming Messages",
description = "Would you like to Translate Public Chat?",
position = 0,
group = "Public Chat Translation",
hidden = true
)
default boolean publicChat()
{
return false;
}
@ConfigItem(
keyName = "translateOptionVisable",
name = "Show 'Translate' menu option",
description = "Adds 'Translate' to the right-click menu in the Chatbox.",
position = 1,
group = "Public Chat Translation",
hidden = true
// unhide = "publicChat"
)
default boolean translateOptionVisable()
{
return false;
}
@ConfigItem(
keyName = "publicTargetLanguage",
name = "Target Language",
description = "Language to translate messages too.",
position = 2,
group = "Public Chat Translation",
hidden = true
// unhide = "publicChat"
)
default Languages publicTargetLanguage()
{
return Languages.ENGLISH;
}
@ConfigItem(
keyName = "playerChat",
name = "Translate outgoing Messages",
description = "Would you like to Translate your Messages?",
position = 3,
group = "Player Message Translation"
)
default boolean playerChat()
{
return false;
}
@ConfigItem(
keyName = "playerTargetLanguage",
name = "Target Language",
description = "Language to translate messages too.",
position = 4,
group = "Player Message Translation",
hidden = true,
unhide = "playerChat"
)
default Languages playerTargetLanguage()
{
return Languages.SPANISH;
}
}

View File

@@ -0,0 +1,236 @@
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.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
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.inject.Inject;
import javax.inject.Provider;
import java.awt.event.KeyEvent;
@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 implements KeyListener
{
private static final String TRANSLATE = "Translate";
private static final ImmutableList<String> AFTER_OPTIONS = ImmutableList.of("Message", "Add ignore", "Remove friend", "Kick");
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private Provider<MenuManager> menuManager;
@Inject
private ChatMessageManager chatMessageManager;
@Inject
private KeyManager keyManager;
@Inject
private ChatTranslationConfig config;
@Provides
ChatTranslationConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(ChatTranslationConfig.class);
}
@Override
protected void startUp() throws Exception
{
if (client != null)
{
if (config.translateOptionVisable())
{
menuManager.get().addPlayerMenuItem(TRANSLATE);
}
}
keyManager.registerKeyListener(this);
}
@Override
protected void shutDown() throws Exception
{
if (client != null)
{
if (config.translateOptionVisable())
{
menuManager.get().removePlayerMenuItem(TRANSLATE);
}
}
keyManager.unregisterKeyListener(this);
}
@Subscribe
public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event)
{
if (event.getMenuOption().equals(TRANSLATE))
{
//TODO: Translate selected message.
}
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
if (!config.translateOptionVisable())
{
return;
}
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());
MenuEntry[] newMenu = ObjectArrays.concat(lookup, client.getMenuEntries());
int menuEntryCount = newMenu.length;
ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2);
client.setMenuEntries(newMenu);
}
}
@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.publicTargetLanguage().toString(), message);
if (translation != null)
{
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(translation);
chatMessageManager.update(messageNode);
}
}
catch (Exception e)
{
e.printStackTrace();
}
client.refreshChat();
}
@Override
public void keyPressed(KeyEvent event)
{
if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN)
{
return;
}
if (!config.playerChat())
{
return;
}
Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT);
if (chatboxParent != null && chatboxParent.getOnKeyListener() != null)
{
if (event.getKeyCode() == 0xA)
{
event.consume();
Translator translator = new Translator();
String message = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT);
try
{
//Automatically check language of message and translate to selected language.
String translation = translator.translate("auto", config.playerTargetLanguage().toString(), message);
if (translation != null)
{
client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, translation);
clientThread.invoke(() ->
{
client.runScript(96, 0, translation);
});
}
client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, "");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
// Nothing.
}
@Override
public void keyTyped(KeyEvent e)
{
// Nothing.
}
}

View File

@@ -0,0 +1,24 @@
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;
}
}

View File

@@ -0,0 +1,46 @@
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();
}
}