From cbc7782b3a12e713e6792a7d165aa7cd494f2e90 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Tue, 17 Feb 2015 22:00:22 -0500 Subject: [PATCH] [Translate] Introduce an option to translate IMs If Local chat is being translated, IM translation is on by default. IM translation can be toggled from the drop down(flyout) menu of IMs. Option is not shown if translation is not configured. Translators: floater_instant_message.xml and floater_instant_message_concisebuttons.xml have two new strings for you to translate. --- indra/newview/llimpanel.cpp | 122 +++++++++++++----- indra/newview/llimpanel.h | 4 + indra/newview/llpaneltranslationsettings.cpp | 9 ++ indra/newview/llviewermessage.cpp | 2 +- .../xui/en-us/floater_instant_message.xml | 2 + ...floater_instant_message_concisebuttons.xml | 2 + 6 files changed, 110 insertions(+), 31 deletions(-) diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 9ce08dfa0..9a5556abd 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -55,6 +55,7 @@ #include "llspeakers.h" #include "llstylemap.h" #include "lltrans.h" +#include "lltranslate.h" #include "lluictrlfactory.h" #include "llviewertexteditor.h" #include "llviewerstats.h" @@ -296,6 +297,7 @@ LLFloaterIMPanel::LLFloaterIMPanel( mShowSpeakersOnConnect(true), mDing(false), mRPMode(false), + mTranslate(false), mTextIMPossible(true), mCallBackEnabled(true), mSpeakers(NULL), @@ -349,6 +351,8 @@ LLFloaterIMPanel::LLFloaterIMPanel( LLAvatarTracker::instance().addParticularFriendObserver(mOtherParticipantUUID, this); LLMuteList::instance().addObserver(this); mDing = gSavedSettings.getBOOL("LiruNewMessageSoundIMsOn"); + if (LLTranslate::isTranslationConfigured()) + mTranslate = gSavedSettings.getBOOL("TranslateChat"); break; } @@ -696,9 +700,79 @@ bool LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) return TRUE; } +class IMTranslationReceiver : public LLTranslate::TranslationReceiver +{ +public : + IMTranslationReceiver(const std::string& from_lang, const std::string& to_lang, LLFloaterIMPanel* panel, const std::string& msg, LLColor4 color, bool log, const LLUUID& source, const std::string& name, bool irc) : LLTranslate::TranslationReceiver(from_lang, to_lang), + mPanel(panel), mMsg(msg), mColor(color), mLog(log), mSource(source), mName(name), mIRC(irc) + { + } + + static boost::intrusive_ptr build(const std::string& from_lang, const std::string& to_lang, LLFloaterIMPanel* panel, const std::string& msg, LLColor4 color, bool log, const LLUUID& source, const std::string& name, bool irc) + { + return boost::intrusive_ptr(new IMTranslationReceiver(from_lang, to_lang, panel, msg, color, log, source, name, irc)); + } + +protected: + void handleResponse(const std::string& translation, const std::string& detected_language) + { + // filter out non-interesting responses + if (!translation.empty() && mToLang != detected_language && LLStringUtil::compareInsensitive(translation, mMsg)) + mMsg += " (" + translation + ')'; + mPanel->addHistoryLine(mMsg, mColor, mLog, mSource, mName, false, true, mIRC); + } + + void handleFailure(int status, const std::string& err_msg) + { + llwarns << "Translation failed for mesg " << mMsg << " toLang " << mToLang << " fromLang " << mFromLang << llendl; + + std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg)); + LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages + mPanel->addHistoryLine(mMsg + " (" + msg + ')', mColor, mLog, mSource, mName, false, true, mIRC); + } + + /*virtual*/ char const* getName() const { return "IMTranslationReceiver"; } + +private: + LLFloaterIMPanel* mPanel; + std::string mMsg; + const LLColor4 mColor; + const bool mLog; + const LLUUID mSource; + const std::string mName; + const bool mIRC; +}; + void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name) { - bool is_agent(gAgentID == source), from_user(source.notNull()); + bool is_agent(gAgentID == source), from_user(name != SYSTEM_FROM && source.notNull()); + // IRC style text starts with a colon here; empty names and system messages aren't irc style. + bool is_irc = from_user && utf8msg[0] != ':'; + + // Now we're adding the actual line of text, so erase the + // "Foo is typing..." text segment, and the optional timestamp + // if it was present. JC + removeTypingIndicator(NULL); + + std::string show_name = name; + if (from_user) + { + LLAvatarNameCache::getNSName(source, show_name); + if (mTranslate && !is_agent) + { + const std::string from_lang = ""; // leave empty to trigger autodetect + const std::string to_lang = LLTranslate::getTranslateLanguage(); + + LLTranslate::TranslationReceiverPtr result = IMTranslationReceiver::build(from_lang, to_lang, this, utf8msg, incolor, log_to_file, source, show_name, is_irc); + LLTranslate::translateMessage(result, from_lang, to_lang, utf8msg); + return; + } + } + addHistoryLine(utf8msg, incolor, log_to_file, source, show_name, is_agent, from_user, is_irc); +} + +void LLFloaterIMPanel::addHistoryLine(const std::string& utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name, bool is_agent, bool from_user, bool is_irc) +{ if (!is_agent) { static const LLCachedControl mKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false); @@ -729,14 +803,8 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol if (invisible || (!host && focused)) ++mNumUnreadMessages; } - } - // Now we're adding the actual line of text, so erase the - // "Foo is typing..." text segment, and the optional timestamp - // if it was present. JC - removeTypingIndicator(NULL); - // Actually add the line bool prepend_newline = true; if (gSavedSettings.getBOOL("IMShowTimestamps")) @@ -745,27 +813,21 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol prepend_newline = false; } - std::string show_name = name; - bool is_irc = false; + if (is_irc) is_irc = gSavedSettings.getBOOL("LiruItalicizeActions"); // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. if (!name.empty()) // If name exists, then add it to the front of the message. { // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. - if (name == SYSTEM_FROM) + if (!from_user) { mHistoryEditor->appendColoredText(name,false,prepend_newline,incolor); } else { - // IRC style text starts with a colon here; empty names and system messages aren't irc style. - static const LLCachedControl italicize("LiruItalicizeActions"); - is_irc = italicize && utf8msg[0] != ':'; - if (from_user) - LLAvatarNameCache::getNSName(source, show_name); // Convert the name to a hotlink and add to message. LLStyleSP source_style = LLStyleMap::instance().lookupAgent(source); source_style->mItalic = is_irc; - mHistoryEditor->appendStyledText(show_name,false,prepend_newline,source_style); + mHistoryEditor->appendStyledText(name,false,prepend_newline,source_style); } prepend_newline = false; } @@ -779,21 +841,10 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol mHistoryEditor->appendStyledText(utf8msg, false, prepend_newline, style); } - if (log_to_file - && gSavedPerAccountSettings.getBOOL("LogInstantMessages") ) + if (log_to_file && gSavedPerAccountSettings.getBOOL("LogInstantMessages")) { - std::string histstr; - if (gSavedPerAccountSettings.getBOOL("IMLogTimestamp")) - histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + show_name + utf8msg; - else - histstr = show_name + utf8msg; - - // [Ansariel: Display name support] - // Floater title contains display name -> bad idea to use that as filename - // mLogLabel, however, is the old legacy name - //LLLogChat::saveHistory(getTitle(),histstr); - LLLogChat::saveHistory(mLogLabel, histstr); - // [/Ansariel: Display name support] + const std::string histstr(name + utf8msg); + LLLogChat::saveHistory(mLogLabel, gSavedPerAccountSettings.getBOOL("IMLogTimestamp") ? LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + histstr : histstr); } if (from_user) @@ -951,6 +1002,8 @@ void LLFloaterIMPanel::removeDynamics(LLComboBox* flyout) flyout->remove(mRPMode ? getString("rp mode on") : getString("rp mode off")); flyout->remove(LLAvatarActions::isFriend(mOtherParticipantUUID) ? getString("remove friend") : getString("add friend")); flyout->remove(LLAvatarActions::isBlocked(mOtherParticipantUUID) ? getString("unmute") : getString("mute")); + if (mSessionType == P2P_SESSION) + flyout->remove(mTranslate ? getString("translate on") : getString("translate off")); } void LLFloaterIMPanel::addDynamics(LLComboBox* flyout) @@ -959,6 +1012,14 @@ void LLFloaterIMPanel::addDynamics(LLComboBox* flyout) flyout->add(mRPMode ? getString("rp mode on") : getString("rp mode off"), 7); flyout->add(LLAvatarActions::isFriend(mOtherParticipantUUID) ? getString("remove friend") : getString("add friend"), 8); flyout->add(LLAvatarActions::isBlocked(mOtherParticipantUUID) ? getString("unmute") : getString("mute"), 9); + if (mSessionType == P2P_SESSION && LLTranslate::isTranslationConfigured()) + flyout->add(mTranslate ? getString("translate on") : getString("translate off"), 10); +} + +void LLFloaterIMPanel::rebuildDynamics() +{ + if (LLComboBox* flyout = findChild("instant_message_flyout")) + rebuildDynamics(flyout); } void copy_profile_uri(const LLUUID& id, bool group = false); @@ -988,6 +1049,7 @@ void LLFloaterIMPanel::onFlyoutCommit(LLComboBox* flyout, const LLSD& value) else if (option == 7) mRPMode = !mRPMode; else if (option == 8) LLAvatarActions::isFriend(mOtherParticipantUUID) ? LLAvatarActions::removeFriendDialog(mOtherParticipantUUID) : LLAvatarActions::requestFriendshipDialog(mOtherParticipantUUID); else if (option == 9) LLAvatarActions::toggleBlock(mOtherParticipantUUID); + else if (option == 10) mTranslate = !mTranslate; // Last add them back addDynamics(flyout); diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index a1285dbe9..96a63822d 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -84,6 +84,7 @@ public: bool log_to_file = true, const LLUUID& source = LLUUID::null, const std::string& name = LLStringUtil::null); + void addHistoryLine(const std::string& utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name, bool is_agent, bool from_user, bool is_irc); void setInputFocus(bool b); @@ -137,6 +138,8 @@ public: static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); + void rebuildDynamics(); + // LLIMModel Functionality bool getSessionInitialized() const { return mSessionInitialized; } bool mStartCallOnInitialize; @@ -226,6 +229,7 @@ private: bool mDing; // Whether or not to play a ding on new messages bool mRPMode; + bool mTranslate; bool mTextIMPossible; bool mCallBackEnabled; diff --git a/indra/newview/llpaneltranslationsettings.cpp b/indra/newview/llpaneltranslationsettings.cpp index c9419d610..dd2d0e527 100644 --- a/indra/newview/llpaneltranslationsettings.cpp +++ b/indra/newview/llpaneltranslationsettings.cpp @@ -30,6 +30,8 @@ // Viewer includes #include "llfloaterchat.h" +#include "llimpanel.h" +#include "llimview.h" #include "lltranslate.h" #include "llviewercontrol.h" // for gSavedSettings @@ -316,5 +318,12 @@ void LLPanelTranslationSettings::apply() gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey()); gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey()); LLFloaterChat::getInstance()->showTranslationCheckbox(); + std::set > floaters(LLIMMgr::instance().getIMFloaterHandles()); + for(std::set >::iterator i = floaters.begin(); i != floaters.end(); ++i) + { + LLFloaterIMPanel& floater = static_cast(*i->get()); + if (floater.getSessionType() == LLFloaterIMPanel::P2P_SESSION) + floater.rebuildDynamics(); + } } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e27aec30e..b9eefd61a 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4261,7 +4261,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { if (ircstyle) { - mesg.erase(4); + mesg.erase(0, 4); } const std::string from_lang = ""; // leave empty to trigger autodetect const std::string to_lang = LLTranslate::getTranslateLanguage(); diff --git a/indra/newview/skins/default/xui/en-us/floater_instant_message.xml b/indra/newview/skins/default/xui/en-us/floater_instant_message.xml index f9a83507c..05d735318 100644 --- a/indra/newview/skins/default/xui/en-us/floater_instant_message.xml +++ b/indra/newview/skins/default/xui/en-us/floater_instant_message.xml @@ -24,6 +24,8 @@ + +