diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-02-28 00:13:31 +0200 |
---|---|---|
committer | akleshchev <117672381+akleshchev@users.noreply.github.com> | 2023-02-28 21:46:43 +0200 |
commit | f7210db06ee677231b93b750c205cd0317a9901f (patch) | |
tree | dd00435fa08e5e82dd996c43fd219606ebd432c1 | |
parent | 3fc3627f2d27b181269416f346f29d6451f7009a (diff) |
SL-19209 Switch MS Bing to MS Azure #3
-rw-r--r-- | indra/newview/llfloatertranslationsettings.cpp | 29 | ||||
-rw-r--r-- | indra/newview/llfloatertranslationsettings.h | 8 | ||||
-rw-r--r-- | indra/newview/lltranslate.cpp | 168 | ||||
-rw-r--r-- | indra/newview/lltranslate.h | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_translation_settings.xml | 19 |
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> |