summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2023-02-28 00:13:31 +0200
committerakleshchev <117672381+akleshchev@users.noreply.github.com>2023-02-28 21:46:43 +0200
commitf7210db06ee677231b93b750c205cd0317a9901f (patch)
treedd00435fa08e5e82dd996c43fd219606ebd432c1
parent3fc3627f2d27b181269416f346f29d6451f7009a (diff)
SL-19209 Switch MS Bing to MS Azure #3
-rw-r--r--indra/newview/llfloatertranslationsettings.cpp29
-rw-r--r--indra/newview/llfloatertranslationsettings.h8
-rw-r--r--indra/newview/lltranslate.cpp168
-rw-r--r--indra/newview/lltranslate.h2
-rw-r--r--indra/newview/skins/default/xui/en/floater_translation_settings.xml19
5 files changed, 168 insertions, 58 deletions
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index 45f46aacf5..c99de47da0 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -132,22 +132,22 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
updateControlsEnabledState();
}
-void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert, S32 status)
{
if (alert)
{
- showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified");
+ showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified", status);
}
mAzureKeyVerified = ok;
updateControlsEnabledState();
}
-void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert, S32 status)
{
if (alert)
{
- showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified");
+ showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified", status);
}
mGoogleKeyVerified = ok;
@@ -179,10 +179,15 @@ std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const
return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText();
}
-void LLFloaterTranslationSettings::showAlert(const std::string& msg_name) const
+void LLFloaterTranslationSettings::showAlert(const std::string& msg_name, S32 status) const
{
+ LLStringUtil::format_map_t string_args;
+ // For now just show an http error code, whole 'reason' string might be added later
+ string_args["[STATUS]"] = llformat("%d", status);
+ std::string message = getString(msg_name, string_args);
+
LLSD args;
- args["MESSAGE"] = getString(msg_name);
+ args["MESSAGE"] = message;
LLNotificationsUtil::add("GenericAlert", args);
}
@@ -222,7 +227,7 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
}
/*static*/
-void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert)
+void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert, S32 status)
{
LLFloaterTranslationSettings* floater =
LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
@@ -236,10 +241,10 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
switch (service)
{
case LLTranslate::SERVICE_AZURE:
- floater->setAzureVerified(ok, alert);
+ floater->setAzureVerified(ok, alert, status);
break;
case LLTranslate::SERVICE_GOOGLE:
- floater->setGoogleVerified(ok, alert);
+ floater->setGoogleVerified(ok, alert, status);
break;
}
}
@@ -248,7 +253,7 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
void LLFloaterTranslationSettings::verifyKey(int service, const LLSD& key, bool alert)
{
LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key,
- boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert));
+ boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert, _3));
}
void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
@@ -271,7 +276,7 @@ void LLFloaterTranslationSettings::onAzureKeyEdited()
|| mAzureAPIEndpointEditor->getValue().isString())
{
// todo: verify mAzureAPIEndpointEditor url
- setAzureVerified(false, false);
+ setAzureVerified(false, false, 0);
}
}
@@ -279,7 +284,7 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited()
{
if (mGoogleAPIKeyEditor->isDirty())
{
- setGoogleVerified(false, false);
+ setGoogleVerified(false, false, 0);
}
}
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index 52523f4d4a..f039d90e27 100644
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -42,15 +42,15 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
- void setAzureVerified(bool ok, bool alert);
- void setGoogleVerified(bool ok, bool alert);
+ void setAzureVerified(bool ok, bool alert, S32 status);
+ void setGoogleVerified(bool ok, bool alert, S32 status);
void onClose(bool app_quitting);
private:
std::string getSelectedService() const;
LLSD getEnteredAzureKey() const;
std::string getEnteredGoogleKey() const;
- void showAlert(const std::string& msg_name) const;
+ void showAlert(const std::string& msg_name, S32 status) const;
void updateControlsEnabledState();
void verifyKey(int service, const LLSD& key, bool alert = true);
@@ -61,7 +61,7 @@ private:
void onBtnGoogleVerify();
void onBtnOK();
- static void setVerificationStatus(int service, bool alert, bool ok);
+ static void setVerificationStatus(int service, bool alert, bool ok, S32 status);
LLCheckBoxCtrl* mMachineTranslationCB;
LLComboBox* mLanguageCombo;
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 706b4cc6ee..b0c4418ae9 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -41,8 +41,8 @@
#include "llurlregistry.h"
-static const std::string BING_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">");
-static const std::string BING_NOTRANSLATE_CLOSING_TAG("</div>");
+static const std::string AZURE_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">");
+static const std::string AZURE_NOTRANSLATE_CLOSING_TAG("</div>");
/**
* Handler of an HTTP machine translation service.
@@ -103,6 +103,7 @@ public:
* @param[out] err_msg Error message (in case of error).
*/
virtual bool parseResponse(
+ const LLSD& http_response,
int& status,
const std::string& body,
std::string& translation,
@@ -176,6 +177,13 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD
return;
}
+ std::string::size_type delim_pos = url.find("://");
+ if (delim_pos == std::string::npos)
+ {
+ LL_INFOS("Translate") << "URL is missing a scheme" << LL_ENDL;
+ return;
+ }
+
LLSD result = verifyAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
@@ -190,7 +198,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD
if (!fnc.empty())
{
- fnc(service, bOk);
+ fnc(service, bOk, parseResult);
}
}
@@ -221,8 +229,8 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
return;
}
- LL_INFOS() << "Message: " << msg << LL_ENDL;
- LL_INFOS() << "Requesting: " << url << LL_ENDL;
+ LL_DEBUGS("Translate") << "Message: " << msg << LL_ENDL;
+ LL_DEBUGS("Translate") << "Requesting: " << url << LL_ENDL;
LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg);
@@ -245,7 +253,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
try
{
- res = this->parseResponse(parseResult, body, translation, detected_lang, err_msg);
+ res = this->parseResponse(httpResults, parseResult, body, translation, detected_lang, err_msg);
}
catch (std::out_of_range&)
{
@@ -306,6 +314,7 @@ public:
const LLSD &response,
int status) const override;
bool parseResponse(
+ const LLSD& http_response,
int& status,
const std::string& body,
std::string& translation,
@@ -380,6 +389,7 @@ bool LLGoogleTranslationHandler::checkVerificationResponse(
// virtual
bool LLGoogleTranslationHandler::parseResponse(
+ const LLSD& http_response,
int& status,
const std::string& body,
std::string& translation,
@@ -531,6 +541,7 @@ public:
const LLSD &response,
int status) const override;
bool parseResponse(
+ const LLSD& http_response,
int& status,
const std::string& body,
std::string& translation,
@@ -557,6 +568,8 @@ public:
LLCore::HttpHeaders::ptr_t headers,
const std::string & url) const override;
private:
+ static std::string parseErrorResponse(
+ const std::string& body);
static LLSD getAPIKey();
static std::string getAPILanguageCode(const std::string& lang);
@@ -574,7 +587,7 @@ std::string LLAzureTranslationHandler::getTranslateURL(
if (key.isMap())
{
std::string endpoint = key["endpoint"].asString();
- // todo: validate url
+
if (*endpoint.rbegin() != '/')
{
endpoint += "/";
@@ -594,7 +607,6 @@ std::string LLAzureTranslationHandler::getKeyVerificationURL(
if (key.isMap())
{
std::string endpoint = key["endpoint"].asString();
- // todo: validate url
if (*endpoint.rbegin() != '/')
{
endpoint += "/";
@@ -609,11 +621,48 @@ bool LLAzureTranslationHandler::checkVerificationResponse(
const LLSD &response,
int status) const
{
- return status == HTTP_BAD_REQUEST; // would have been 401 if id was wrong
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ LL_DEBUGS("Translate") << "Key unathorised" << LL_ENDL;
+ return false;
+ }
+
+ if (status == HTTP_NOT_FOUND)
+ {
+ LL_DEBUGS("Translate") << "Either endpoint doesn't have requested resource" << LL_ENDL;
+ return false;
+ }
+
+ if (status != HTTP_BAD_REQUEST)
+ {
+ LL_DEBUGS("Translate") << "Unexpected error code" << LL_ENDL;
+ return false;
+ }
+
+ if (!response.has("error_body"))
+ {
+ LL_DEBUGS("Translate") << "Unexpected response, no error returned" << LL_ENDL;
+ return false;
+ }
+
+ // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
+ // But for now just verify response is a valid json with an error
+
+ Json::Value root;
+ Json::Reader reader;
+
+ if (!reader.parse(response["error_body"].asString(), root))
+ {
+ LL_DEBUGS("Translate") << "Failed to parse error_body:" << reader.getFormatedErrorMessages() << LL_ENDL;
+ return false;
+ }
+
+ return true;
}
// virtual
bool LLAzureTranslationHandler::parseResponse(
+ const LLSD& http_response,
int& status,
const std::string& body,
std::string& translation,
@@ -622,6 +671,8 @@ bool LLAzureTranslationHandler::parseResponse(
{
if (status != HTTP_OK)
{
+ if (http_response.has("error_body"))
+ err_msg = parseErrorResponse(http_response["error_body"].asString());
return false;
}
@@ -682,6 +733,36 @@ bool LLAzureTranslationHandler::isConfigured() const
return !getAPIKey().isMap();
}
+//static
+std::string LLAzureTranslationHandler::parseErrorResponse(
+ const std::string& body)
+{
+ // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
+ // But for now just verify response is a valid json with an error
+
+ Json::Value root;
+ Json::Reader reader;
+
+ if (!reader.parse(body, root))
+ {
+ return std::string();
+ }
+
+ if (!root.isObject() || !root.isMember("error"))
+ {
+ return std::string();
+ }
+
+ const Json::Value& error_map = root["error"];
+
+ if (!error_map.isObject() || !error_map.isMember("message"))
+ {
+ return std::string();
+ }
+
+ return error_map["message"].asString();
+}
+
// static
LLSD LLAzureTranslationHandler::getAPIKey()
{
@@ -771,54 +852,65 @@ void LLTranslate::translateMessage(const std::string &from_lang, const std::stri
std::string LLTranslate::addNoTranslateTags(std::string mesg)
{
- if (getPreferredHandler().getCurrentService() != SERVICE_AZURE)
+ if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE)
{
return mesg;
}
- std::string upd_msg(mesg);
- LLUrlMatch match;
- S32 dif = 0;
- //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation
- while (LLUrlRegistry::instance().findUrl(mesg, match))
+ if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
{
- upd_msg.insert(dif + match.getStart(), BING_NOTRANSLATE_OPENING_TAG);
- upd_msg.insert(dif + BING_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, BING_NOTRANSLATE_CLOSING_TAG);
- mesg.erase(match.getStart(), match.getEnd() - match.getStart());
- dif += match.getEnd() - match.getStart() + BING_NOTRANSLATE_OPENING_TAG.size() + BING_NOTRANSLATE_CLOSING_TAG.size();
+ // https://learn.microsoft.com/en-us/azure/cognitive-services/translator/prevent-translation
+ std::string upd_msg(mesg);
+ LLUrlMatch match;
+ S32 dif = 0;
+ //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation
+ while (LLUrlRegistry::instance().findUrl(mesg, match))
+ {
+ upd_msg.insert(dif + match.getStart(), AZURE_NOTRANSLATE_OPENING_TAG);
+ upd_msg.insert(dif + AZURE_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, AZURE_NOTRANSLATE_CLOSING_TAG);
+ mesg.erase(match.getStart(), match.getEnd() - match.getStart());
+ dif += match.getEnd() - match.getStart() + AZURE_NOTRANSLATE_OPENING_TAG.size() + AZURE_NOTRANSLATE_CLOSING_TAG.size();
+ }
+ return upd_msg;
}
- return upd_msg;
+ return mesg;
}
std::string LLTranslate::removeNoTranslateTags(std::string mesg)
{
- if (getPreferredHandler().getCurrentService() != SERVICE_AZURE)
+ if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE)
{
return mesg;
}
- std::string upd_msg(mesg);
- LLUrlMatch match;
- S32 opening_tag_size = BING_NOTRANSLATE_OPENING_TAG.size();
- S32 closing_tag_size = BING_NOTRANSLATE_CLOSING_TAG.size();
- S32 dif = 0;
- //remove 'no-translate' tags we added to the links before
- while (LLUrlRegistry::instance().findUrl(mesg, match))
+
+ if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
{
- if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == BING_NOTRANSLATE_OPENING_TAG)
+ std::string upd_msg(mesg);
+ LLUrlMatch match;
+ S32 opening_tag_size = AZURE_NOTRANSLATE_OPENING_TAG.size();
+ S32 closing_tag_size = AZURE_NOTRANSLATE_CLOSING_TAG.size();
+ S32 dif = 0;
+ //remove 'no-translate' tags we added to the links before
+ while (LLUrlRegistry::instance().findUrl(mesg, match))
{
- upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size);
- dif -= opening_tag_size;
-
- if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == BING_NOTRANSLATE_CLOSING_TAG)
+ if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == AZURE_NOTRANSLATE_OPENING_TAG)
{
- upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " ");
- dif -= closing_tag_size - 1;
+ upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size);
+ dif -= opening_tag_size;
+
+ if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == AZURE_NOTRANSLATE_CLOSING_TAG)
+ {
+ upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " ");
+ dif -= closing_tag_size - 1;
+ }
}
+ mesg.erase(match.getStart(), match.getUrl().size());
+ dif += match.getUrl().size();
}
- mesg.erase(match.getStart(), match.getUrl().size());
- dif += match.getUrl().size();
+ return upd_msg;
}
- return upd_msg;
+
+ return mesg;
}
/*static*/
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 870fd54441..1de5c02f74 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -59,7 +59,7 @@ public :
SERVICE_GOOGLE,
} EService;
- typedef boost::function<void(EService, bool)> KeyVerificationResult_fn;
+ typedef boost::function<void(EService, bool, S32)> KeyVerificationResult_fn;
typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn;
typedef boost::function<void(int, std::string)> TranslationFailure_fn;
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index b0e47798e9..d095451685 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -9,8 +9,8 @@
title="CHAT TRANSLATION SETTINGS"
width="485">
- <string name="azure_api_key_not_verified">Azure service identifier not verified. Please try again.</string>
- <string name="google_api_key_not_verified">Google API key not verified. Please try again.</string>
+ <string name="azure_api_key_not_verified">Azure service identifier not verified. Status: [STATUS]. Please check your settings and try again.</string>
+ <string name="google_api_key_not_verified">Google API key not verified. Status: [STATUS]. Please check your key and try again.</string>
<string name="azure_api_key_verified">Azure service identifier verified.</string>
<string name="google_api_key_verified">Google API key verified.</string>
@@ -148,6 +148,19 @@
</radio_group>
<text
+ follows="top|right"
+ height="20"
+ layout="topleft"
+ left="185"
+ length="1"
+ name="google_links_text"
+ top_pad="-142"
+ type="string"
+ width="100">
+ [https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup]
+ </text>
+
+ <text
type="string"
length="1"
follows="top|right"
@@ -155,7 +168,7 @@
layout="topleft"
left="70"
name="azure_api_endoint_label"
- top_pad="-115"
+ top_pad="8"
width="85">
Endpoint:
</text>