From 891457c11a8dd339558ea69c32273369dde3936b Mon Sep 17 00:00:00 2001
From: Inusaito Sayori
Date: Wed, 19 Dec 2012 01:51:53 -0500
Subject: [PATCH] Translate, with help from Sovereign (translation backend
needs an update/fixing)
Add Translate Chat checkbox back to chat floater, and enable it when applicable(with showTranslationCheckbox()).
Spend the night making it compile with AICurl~
Make the links work all nice despite our old link-unfriendly UI code.
Coax UI bits into agreeing with their new environment.
Updated the links because v-d seems to still have old ones...
Adv. Chat->Translation tab added..
Guess it's your move, again, Sovereign.
This was old, so I updated it, yayyy~
---
indra/llmessage/aihttptimeoutpolicy.cpp | 1 -
indra/newview/CMakeLists.txt | 3 +
indra/newview/app_settings/settings.xml | 55 ++
indra/newview/ascentprefschat.cpp | 7 +-
indra/newview/llfloaterchat.cpp | 7 +
indra/newview/llfloaterchat.h | 1 +
indra/newview/llpaneltranslationsettings.cpp | 320 ++++++++++++
indra/newview/llpaneltranslationsettings.h | 75 +++
indra/newview/lltranslate.cpp | 470 ++++++++++++++----
indra/newview/lltranslate.h | 376 ++++++++++----
indra/newview/llviewermessage.cpp | 99 ++--
.../xui/en-us/floater_chat_history.xml | 2 +-
.../en-us/panel_preferences_ascent_chat.xml | 1 +
.../xui/en-us/panel_translation_settings.xml | 51 ++
14 files changed, 1212 insertions(+), 256 deletions(-)
create mode 100644 indra/newview/llpaneltranslationsettings.cpp
create mode 100644 indra/newview/llpaneltranslationsettings.h
create mode 100644 indra/newview/skins/default/xui/en-us/panel_translation_settings.xml
diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp
index 4c71111f5..409ff9215 100644
--- a/indra/llmessage/aihttptimeoutpolicy.cpp
+++ b/indra/llmessage/aihttptimeoutpolicy.cpp
@@ -955,7 +955,6 @@ P(responderIgnore);
P(setDisplayNameResponder);
P2(simulatorFeaturesReceived, transfer_22s_connect_10s);
P2(startGroupVoteResponder, transfer_300s);
-P(translationReceiver);
P(uploadModelPremissionsResponder);
P(verifiedDestinationResponder);
P(viewerChatterBoxInvitationAcceptResponder);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0ff76cb36..25df1702e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -403,6 +403,7 @@ set(viewer_SOURCE_FILES
llpanelprimmediacontrols.cpp
llpanelprofile.cpp
llpanelskins.cpp
+ llpaneltranslationsettings.cpp
llpanelvoicedevicesettings.cpp
llpanelvoiceeffect.cpp
llpanelvolume.cpp
@@ -482,6 +483,7 @@ set(viewer_SOURCE_FILES
lltoolselectrect.cpp
lltoolview.cpp
lltracker.cpp
+ lltranslate.cpp
lluploaddialog.cpp
lluploadfloaterobservers.cpp
llurl.cpp
@@ -934,6 +936,7 @@ set(viewer_HEADER_FILES
llpanelprimmediacontrols.h
llpanelprofile.h
llpanelskins.h
+ llpaneltranslationsettings.h
llpanelvoicedevicesettings.h
llpanelvoiceeffect.h
llpanelvolume.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 81e21494c..55d20bc41 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -16872,6 +16872,61 @@ This should be as low as possible, but too low may break functionality
Value
1
+ TranslateLanguage
+
+ TranslateChat
+
+ TranslationService
+
+ GoogleTranslateAPIKey
+
+ BingTranslateAPIKey
+
InterpolationTime
", begin);
+ err_msg = body.substr(begin, end-begin);
+ LLStringUtil::replaceString(err_msg, "
", ""); // strip CR
+ return false;
+ }
+
+ // Sample response: Hola
+ size_t begin = body.find(">");
+ if (begin == std::string::npos || begin >= (body.size() - 1))
+ {
+ begin = 0;
+ }
+ else
+ {
+ ++begin;
+ }
+
+ size_t end = body.find("", begin);
+
+ detected_lang = ""; // unsupported by this API
+ translation = body.substr(begin, end-begin);
+ LLStringUtil::replaceString(translation, "
", ""); // strip CR
+ return true;
+}
+
+// virtual
+bool LLBingTranslationHandler::isConfigured() const
+{
+ return !getAPIKey().empty();
+}
+
+// static
+std::string LLBingTranslationHandler::getAPIKey()
+{
+ return gSavedSettings.getString("BingTranslateAPIKey");
+}
+
+// static
+std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang)
+{
+ return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
+}
+
+LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang)
+: mFromLang(from_lang)
+, mToLang(to_lang)
+, mHandler(LLTranslate::getPreferredHandler())
+{
+}
+
+// virtual
+void LLTranslate::TranslationReceiver::completedRaw(
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ LLBufferStream istr(channels, buffer.get());
+ std::stringstream strstrm;
+ strstrm << istr.rdbuf();
+
+ const std::string body = strstrm.str();
+ std::string translation, detected_lang, err_msg;
+ int status = getStatus();
+ LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL;
+ LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;
+ if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))
+ {
+ // Fix up the response
+ LLStringUtil::replaceString(translation, "<", "<");
+ LLStringUtil::replaceString(translation, ">",">");
+ LLStringUtil::replaceString(translation, ""","\"");
+ LLStringUtil::replaceString(translation, "'","'");
+ LLStringUtil::replaceString(translation, "&","&");
+ LLStringUtil::replaceString(translation, "'","'");
+
+ handleResponse(translation, detected_lang);
+ }
+ else
+ {
+ if (err_msg.empty())
+ {
+ err_msg = LLTrans::getString("TranslationResponseParseError");
+ }
+
+ llwarns << "Translation request failed: " << err_msg << llendl;
+ handleFailure(status, err_msg);
+ }
+}
+
+LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service)
+: mService(service)
+{
+}
+
+LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
+{
+ return mService;
+}
+
+// virtual
+void LLTranslate::KeyVerificationReceiver::completedRaw(
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ bool ok = (getStatus() == 200);
+ setVerificationStatus(ok);
+}
+
+//static
+void LLTranslate::translateMessage(
+ TranslationReceiverPtr &receiver,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &mesg)
+{
+ std::string url;
+ receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg);
+
+ LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL;
+ sendRequest(url, receiver);
+}
+
+// static
+void LLTranslate::verifyKey(
+ KeyVerificationReceiverPtr& receiver,
+ const std::string& key)
+{
+ std::string url;
+ const LLTranslationAPIHandler& handler = getHandler(receiver->getService());
+ handler.getKeyVerificationURL(url, key);
+
+ LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL;
+ sendRequest(url, receiver);
}
//static
std::string LLTranslate::getTranslateLanguage()
{
- std::string language = "en";
- if (LLUI::sConfigGroup)
+ std::string language = gSavedSettings.getString("TranslateLanguage");
+ if (language.empty() || language == "default")
{
- language = LLUI::sConfigGroup->getString("TranslateLanguage");
- if (language.empty() || language == "default")
- {
- language = LLUI::getLanguage();
- }
+ language = LLUI::getLanguage();
}
language = language.substr(0,2);
return language;
}
+// static
+bool LLTranslate::isTranslationConfigured()
+{
+ return getPreferredHandler().isConfigured();
+}
+
+// static
+const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
+{
+ EService service = SERVICE_BING;
+
+ std::string service_str = gSavedSettings.getString("TranslationService");
+ if (service_str == "google")
+ {
+ service = SERVICE_GOOGLE;
+ }
+
+ return getHandler(service);
+}
+
+// static
+const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
+{
+ static LLGoogleTranslationHandler google;
+ static LLBingTranslationHandler bing;
+
+ if (service == SERVICE_GOOGLE)
+ {
+ return google;
+ }
+
+ return bing;
+}
+
+// static
+void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder)
+{
+ static LLSD sHeader;
+
+ if (!sHeader.size())
+ {
+ std::string user_agent = llformat("%s %d.%d.%d (%d)",
+ gVersionChannel,
+ gVersionMajor,
+ gVersionMinor,
+ gVersionPatch,
+ gVersionBuild);
+
+ sHeader.insert("Accept", "text/plain");
+ sHeader.insert("User-Agent", user_agent);
+ }
+
+ LLHTTPClient::get(url, sHeader, responder);
+}
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index f5638b6e2..2deb1952d 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -2,127 +2,301 @@
* @file lltranslate.h
* @brief Human language translation class and JSON response receiver.
*
-* $LicenseInfo:firstyear=2009&license=viewergpl$
-*
-* Copyright (c) 2009, Linden Research, Inc.
-*
-* Second Life Viewer Source Code
-* The source code in this file ("Source Code") is provided by Linden Lab
-* to you under the terms of the GNU General Public License, version 2.0
-* ("GPL"), unless you have obtained a separate licensing agreement
-* ("Other License"), formally executed by you and Linden Lab. Terms of
-* the GPL can be found in doc/GPL-license.txt in this distribution, or
-* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
-*
-* There are special exceptions to the terms and conditions of the GPL as
-* it is applied to this Source Code. View the full text of the exception
-* in the file doc/FLOSS-exception.txt in this software distribution, or
-* online at
-* http://secondlifegrid.net/programs/open_source/licensing/flossexception
-*
-* By copying, modifying or distributing this software, you acknowledge
-* that you have read and understood your obligations described above,
-* and agree to abide by those obligations.
-*
-* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-* COMPLETENESS OR PERFORMANCE.
-* $/LicenseInfo$
-*/
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
#ifndef LL_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
#include "llhttpclient.h"
#include "llbufferstream.h"
-#include "json/reader.h"
+#include "lliopipe.h"
-class AIHTTPTimeoutPolicy;
-extern AIHTTPTimeoutPolicy translationReceiver_timeout;
-
-class LLTranslate
+namespace Json
{
-public :
- class TranslationReceiver : public LLHTTPClient::ResponderWithResult
- {
- protected:
- TranslationReceiver(const std::string &fromLang, const std::string &toLang)
- : m_fromLang(fromLang),
- m_toLang(toLang)
- {
- }
+ class Value;
+}
- virtual void handleResponse(const std::string &translation, const std::string &recognizedLang) {}
- virtual void handleFailure() {};
+/**
+ * Handler of an HTTP machine translation service.
+ *
+ * Derived classes know the service URL
+ * and how to parse the translation result.
+ */
+class LLTranslationAPIHandler
+{
+public:
+ /**
+ * Get URL for translation of the given string.
+ *
+ * Sending HTTP GET request to the URL will initiate translation.
+ *
+ * @param[out] url Place holder for the result.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param text Text to translate.
+ */
+ virtual void getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const = 0;
- public:
- ~TranslationReceiver()
- {
- }
+ /**
+ * Get URL to verify the given API key.
+ *
+ * Sending request to the URL verifies the key.
+ * Positive HTTP response (code 200) means that the key is valid.
+ *
+ * @param[out] url Place holder for the URL.
+ * @param[in] key Key to verify.
+ */
+ virtual void getKeyVerificationURL(
+ std::string &url,
+ const std::string &key) const = 0;
- /*virtual*/ void httpFailure(void)
- {
- LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL;
- handleFailure();
- }
+ /**
+ * Parse translation response.
+ *
+ * @param[in,out] status HTTP status. May be modified while parsing.
+ * @param body Response text.
+ * @param[out] translation Translated text.
+ * @param[out] detected_lang Detected source language. May be empty.
+ * @param[out] err_msg Error message (in case of error).
+ */
+ virtual bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const = 0;
- /*virtual*/ void completedRaw(
- LLChannelDescriptors const& channels,
- LLIOPipe::buffer_ptr_t const& buffer)
- {
- LLBufferStream istr(channels, buffer.get());
+ /**
+ * @return if the handler is configured to function properly
+ */
+ virtual bool isConfigured() const = 0;
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string result = strstrm.str();
+ virtual ~LLTranslationAPIHandler() {}
- std::string translation;
- std::string detectedLanguage;
+protected:
+ static const int STATUS_OK = 200;
+};
- if (!parseGoogleTranslate(result, translation, detectedLanguage))
- {
- handleFailure();
- return;
- }
+/// Google Translate v2 API handler.
+class LLGoogleTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLGoogleTranslationHandler);
- // Fix up the response
- stringReplaceAll( translation, "<","<");
- stringReplaceAll( translation, ">",">");
- stringReplaceAll( translation, ""","\"");
- stringReplaceAll( translation, "'","'");
- stringReplaceAll( translation, "&","&");
- stringReplaceAll( translation, "'","'");
-
- handleResponse(translation, detectedLanguage);
- }
-
- /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return translationReceiver_timeout; }
-
- protected:
- const std::string m_toLang;
- const std::string m_fromLang;
- };
-
- static void translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg);
- static float m_GoogleTimeout;
- static std::string getTranslateLanguage();
+public:
+ /*virtual*/ void getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ void getKeyVerificationURL(
+ std::string &url,
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
private:
- static void getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &text);
- static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to);
- static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage);
+ static void parseErrorResponse(
+ const Json::Value& root,
+ int& status,
+ std::string& err_msg);
+ static bool parseTranslation(
+ const Json::Value& root,
+ std::string& translation,
+ std::string& detected_lang);
+ static std::string getAPIKey();
+};
- static AIHTTPHeaders m_Header;
- static const char* m_GoogleURL;
- static const char* m_GoogleLangSpec;
- static const char* m_AcceptHeader;
- static const char* m_AcceptType;
- static const char* m_AgentHeader;
- static const char* m_UserAgent;
+/// Microsoft Translator v2 API handler.
+class LLBingTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLBingTranslationHandler);
- static const char* m_GoogleData;
- static const char* m_GoogleTranslation;
- static const char* m_GoogleLanguage;
+public:
+ /*virtual*/ void getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ void getKeyVerificationURL(
+ std::string &url,
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
+private:
+ static std::string getAPIKey();
+ static std::string getAPILanguageCode(const std::string& lang);
+};
+
+/**
+ * Entry point for machine translation services.
+ *
+ * Basically, to translate a string, we need to know the URL
+ * of a translation service, have a valid API for the service
+ * and be given the target language.
+ *
+ * Callers specify the string to translate and the target language,
+ * LLTranslate takes care of the rest.
+ *
+ * API keys for translation are taken from saved settings.
+ */
+class LLTranslate
+{
+ LOG_CLASS(LLTranslate);
+
+public :
+
+ typedef enum e_service {
+ SERVICE_BING,
+ SERVICE_GOOGLE,
+ } EService;
+
+ /**
+ * Subclasses are supposed to handle translation results (e.g. show them in chat)
+ */
+ class TranslationReceiver: public LLHTTPClient::ResponderWithCompleted
+ {
+ public:
+ /**
+ * Using mHandler, parse incoming response.
+ *
+ * Calls either handleResponse() or handleFailure()
+ * depending on the HTTP status code and parsing success.
+ *
+ * @see handleResponse()
+ * @see handleFailure()
+ * @see mHandler
+ */
+ /*virtual*/ void completedRaw(
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+ protected:
+ friend class LLTranslate;
+
+ /// Remember source and target languages for subclasses to be able to filter inappropriate results.
+ TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
+
+ virtual void result(LLSD const& content) {};
+
+ /// Override point to handle successful translation.
+ virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
+
+ /// Override point to handle unsuccessful translation.
+ virtual void handleFailure(int status, const std::string& err_msg) = 0;
+
+ std::string mFromLang;
+ std::string mToLang;
+ const LLTranslationAPIHandler& mHandler;
+ };
+
+ /**
+ * Subclasses are supposed to handle API key verification result.
+ */
+ class KeyVerificationReceiver: public LLHTTPClient::ResponderWithCompleted
+ {
+ public:
+ EService getService() const;
+
+ protected:
+ virtual void result(LLSD const& content) {};
+ /**
+ * Save the translation service the key belongs to.
+ *
+ * Subclasses need to know it.
+ *
+ * @see getService()
+ */
+ KeyVerificationReceiver(EService service);
+
+ /**
+ * Parse verification response.
+ *
+ * Calls setVerificationStatus() with the verification status,
+ * which is true if HTTP status code is 200.
+ *
+ * @see setVerificationStatus()
+ */
+ /*virtual*/ void completedRaw(
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+ /**
+ * Override point for subclasses to handle key verification status.
+ */
+ virtual void setVerificationStatus(bool ok) = 0;
+
+ EService mService;
+ };
+
+ typedef boost::intrusive_ptr TranslationReceiverPtr;
+ typedef boost::intrusive_ptr KeyVerificationReceiverPtr;
+
+ /**
+ * Translate given text.
+ *
+ * @param receiver Object to pass translation result to.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param mesg Text to translate.
+ */
+ static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
+
+ /**
+ * Verify given API key of a translation service.
+ *
+ * @param receiver Object to pass verification result to.
+ * @param key Key to verify.
+ */
+ static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
+
+ /**
+ * @return translation target language
+ */
+ static std::string getTranslateLanguage();
+
+ /**
+ * @return true if translation is configured properly.
+ */
+ static bool isTranslationConfigured();
+
+private:
+ static const LLTranslationAPIHandler& getPreferredHandler();
+ static const LLTranslationAPIHandler& getHandler(EService service);
+ static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder);
};
#endif
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 2779f1404..e27aec30e 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -91,6 +91,7 @@
#include "llimview.h"
#include "llspeakers.h"
#include "lltrans.h"
+#include "lltranslate.h"
#include "llviewerfoldertype.h"
#include "llviewergenericmessage.h"
#include "llviewermenu.h"
@@ -3612,52 +3613,55 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)
LLNotificationsUtil::add("CallingCardDeclined");
}
-#if 0 // Google translate doesn't work anymore
class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
{
public :
- ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat,
- const BOOL history)
- : LLTranslate::TranslationReceiver(fromLang, toLang),
+ ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg,
+ const LLChat &chat, const BOOL history)
+ : LLTranslate::TranslationReceiver(from_lang, to_lang),
m_chat(chat),
- m_history(history)
+ m_history(history),
+ m_origMesg(mesg)
{
}
- static boost::intrusive_ptr build(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history)
+ static boost::intrusive_ptr build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, BOOL history)
{
- return boost::intrusive_ptr(new ChatTranslationReceiver(fromLang, toLang, chat, history));
+ return boost::intrusive_ptr(new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, history));
}
protected:
- void handleResponse(const std::string &translation, const std::string &detectedLanguage)
- {
- if (m_toLang != detectedLanguage)
- m_chat->mText += " (" + translation + ")";
+ void handleResponse(const std::string &translation, const std::string &detected_language)
+ {
+ // filter out non-interesting responeses
+ if ( !translation.empty()
+ && (mToLang != detected_language)
+ && (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) )
+ {
+ m_chat.mText += " (" + translation + ")";
+ }
- add_floater_chat(*m_chat, m_history);
-
- delete m_chat;
+ add_floater_chat(m_chat, m_history);
}
- void handleFailure()
+ void handleFailure(int status, const std::string& err_msg)
{
- LLTranslate::TranslationReceiver::handleFailure();
+ llwarns << "Translation failed for mesg " << m_origMesg << " toLang " << mToLang << " fromLang " << mFromLang << llendl;
- m_chat->mText += " (?)";
+ std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
+ LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
+ m_chat.mText += " (" + msg + ")";
- add_floater_chat(*m_chat, m_history);
-
- delete m_chat;
+ add_floater_chat(m_chat, m_history);
}
/*virtual*/ char const* getName(void) const { return "ChatTranslationReceiver"; }
private:
- LLChat *m_chat;
- const BOOL m_history;
+ LLChat m_chat;
+ std::string m_origMesg;
+ BOOL m_history;
};
-#endif
void add_floater_chat(const LLChat &chat, const BOOL history)
{
@@ -3673,29 +3677,6 @@ void add_floater_chat(const LLChat &chat, const BOOL history)
}
}
-#if 0 // Google translate doesn't work anymore
-void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL history)
-{
- const bool translate = LLUI::sConfigGroup->getBOOL("TranslateChat");
-
- if (translate && chat.mSourceType != CHAT_SOURCE_SYSTEM)
- {
- // fromLang hardcoded to "" (autodetection) pending implementation of
- // SVC-4879
- const std::string &fromLang = "";
- const std::string &toLang = LLTranslate::getTranslateLanguage();
- LLChat *newChat = new LLChat(chat);
-
- LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(fromLang, toLang, newChat, history);
- LLTranslate::translateMessage(result, fromLang, toLang, mesg);
- }
- else
- {
- add_floater_chat(chat, history);
- }
-}
-#endif
-
// defined in llchatbar.cpp, but not declared in any header
void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel);
@@ -4263,16 +4244,34 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
chat.mPosAgent = chatter->getPositionAgent();
}
+ // truth table:
+ // LINDEN MUTED BUSY OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY
+ // F T * * * No No
+ // F F T F * No Yes
+ // * F F * * Yes Yes
+ // * F * T * Yes Yes
+ // T * * * F Yes Yes
+
chat.mMuted = is_muted && !is_linden;
bool only_history = visible_in_chat_bubble || (!is_linden && !is_owned_by_me && is_do_not_disturb);
-#if 0 // Google translate doesn't work anymore
if (!chat.mMuted)
{
- check_translate_chat(mesg, chat, only_history);
+ LLSD args;
+ if (chat.mSourceType != CHAT_SOURCE_SYSTEM && gSavedSettings.getBOOL("TranslateChat"))
+ {
+ if (ircstyle)
+ {
+ mesg.erase(4);
+ }
+ const std::string from_lang = ""; // leave empty to trigger autodetect
+ const std::string to_lang = LLTranslate::getTranslateLanguage();
+
+ LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, only_history);
+ LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
+ return;
+ }
}
-#else
add_floater_chat(chat, only_history);
-#endif
}
}
diff --git a/indra/newview/skins/default/xui/en-us/floater_chat_history.xml b/indra/newview/skins/default/xui/en-us/floater_chat_history.xml
index f7b05c724..773a0e41a 100644
--- a/indra/newview/skins/default/xui/en-us/floater_chat_history.xml
+++ b/indra/newview/skins/default/xui/en-us/floater_chat_history.xml
@@ -16,7 +16,7 @@
Gestures
-
+
diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml
index 7a49ea9db..33a0709a7 100644
--- a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml
+++ b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml
@@ -196,5 +196,6 @@ To use spellcheck, right-click a misspelled word
+
diff --git a/indra/newview/skins/default/xui/en-us/panel_translation_settings.xml b/indra/newview/skins/default/xui/en-us/panel_translation_settings.xml
new file mode 100644
index 000000000..8200d8963
--- /dev/null
+++ b/indra/newview/skins/default/xui/en-us/panel_translation_settings.xml
@@ -0,0 +1,51 @@
+
+
+ Bing appID not verified. Please try again.
+ Google API key not verified. Please try again.
+ Bing appID verified.
+ Google API key verified.
+
+
+ Translate chat into:
+
+ System Default
+ English
+
+ Dansk (Danish)
+ Deutsch (German)
+ Español (Spanish)
+ Français (French)
+ Italiano (Italian)
+ Magyar (Hungarian)
+ Nederlands (Dutch)
+ Polski (Polish)
+ Português (Portuguese)
+ Русский (Russian)
+ Türkçe (Turkish)
+ Українська (Ukrainian)
+ 中文 (正體) (Chinese)
+ 日本語 (Japanese)
+ 한국어 (Korean)
+
+
+ Choose translation service:
+
+ Bing Translator
+ Google Translate
+
+
+
+ Bing
+
+
+
+
+
+ Google
+
+
+
+
+ Pricing
+ Stats
+