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 @@ + +