diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-02-24 11:59:48 +0200 |
---|---|---|
committer | akleshchev <117672381+akleshchev@users.noreply.github.com> | 2023-02-28 21:46:43 +0200 |
commit | 3fc3627f2d27b181269416f346f29d6451f7009a (patch) | |
tree | 45de7c5949369e58e0b63d6e818bb255c8b9f7ec /indra | |
parent | 3daccc5d2344404af1b3501c35b7cff96468602f (diff) |
SL-19209 WIP Switch MS Bing to MS Azure #2
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/app_settings/settings.xml | 17 | ||||
-rw-r--r-- | indra/newview/llfloatertranslationsettings.cpp | 120 | ||||
-rw-r--r-- | indra/newview/llfloatertranslationsettings.h | 18 | ||||
-rw-r--r-- | indra/newview/lltranslate.cpp | 317 | ||||
-rw-r--r-- | indra/newview/lltranslate.h | 14 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_translation_settings.xml | 95 |
6 files changed, 420 insertions, 161 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 411f77e6a7..ddd4f57f3f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12929,13 +12929,13 @@ <key>TranslationService</key> <map> <key>Comment</key> - <string>Translation API to use. (google|bing)</string> + <string>Translation API to use. (google|azure)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>String</string> <key>Value</key> - <string>bing</string> + <string>azure</string> </map> <key>GoogleTranslateAPIKey</key> <map> @@ -12951,7 +12951,7 @@ <key>BingTranslateAPIKey</key> <map> <key>Comment</key> - <string>Bing AppID to use with the Microsoft Translator API</string> + <string>(Deprecated) Bing AppID to use with the Microsoft Translator API</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -12959,6 +12959,17 @@ <key>Value</key> <string></string> </map> + <key>AzureTranslateAPIKey</key> + <map> + <key>Comment</key> + <string>Azure Translation service data to use with the MS Azure Translator API</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <string></string> + </map> <key>TutorialURL</key> <map> <key>Comment</key> diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp index 082bb888b1..45f46aacf5 100644 --- a/indra/newview/llfloatertranslationsettings.cpp +++ b/indra/newview/llfloatertranslationsettings.cpp @@ -45,14 +45,7 @@ LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key) : LLFloater(key) , mMachineTranslationCB(NULL) -, mLanguageCombo(NULL) -, mTranslationServiceRadioGroup(NULL) -, mBingAPIKeyEditor(NULL) -, mGoogleAPIKeyEditor(NULL) -, mBingVerifyBtn(NULL) -, mGoogleVerifyBtn(NULL) -, mOKBtn(NULL) -, mBingKeyVerified(false) +, mAzureKeyVerified(false) , mGoogleKeyVerified(false) { } @@ -63,9 +56,11 @@ BOOL LLFloaterTranslationSettings::postBuild() mMachineTranslationCB = getChild<LLCheckBoxCtrl>("translate_chat_checkbox"); mLanguageCombo = getChild<LLComboBox>("translate_language_combo"); mTranslationServiceRadioGroup = getChild<LLRadioGroup>("translation_service_rg"); - mBingAPIKeyEditor = getChild<LLLineEditor>("bing_api_key"); + mAzureAPIEndpointEditor = getChild<LLComboBox>("azure_api_endpoint_combo"); + mAzureAPIKeyEditor = getChild<LLLineEditor>("azure_api_key"); + mAzureAPIRegionEditor = getChild<LLLineEditor>("azure_api_region"); mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key"); - mBingVerifyBtn = getChild<LLButton>("verify_bing_api_key_btn"); + mAzureVerifyBtn = getChild<LLButton>("verify_azure_api_key_btn"); mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn"); mOKBtn = getChild<LLButton>("ok_btn"); @@ -73,11 +68,17 @@ BOOL LLFloaterTranslationSettings::postBuild() mTranslationServiceRadioGroup->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this)); mOKBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnOK, this)); getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false)); - mBingVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnBingVerify, this)); + mAzureVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnAzureVerify, this)); mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnGoogleVerify, this)); - mBingAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); - mBingAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onBingKeyEdited, this), NULL); + mAzureAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); + mAzureAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL); + mAzureAPIRegionEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); + mAzureAPIRegionEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL); + + mAzureAPIEndpointEditor->setFocusLostCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this)); + mAzureAPIEndpointEditor->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this)); + mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1)); mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onGoogleKeyEdited, this), NULL); @@ -92,17 +93,27 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key) mLanguageCombo->setSelectedByValue(gSavedSettings.getString("TranslateLanguage"), TRUE); mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE); - std::string bing_key = gSavedSettings.getString("BingTranslateAPIKey"); - if (!bing_key.empty()) + LLSD azure_key = gSavedSettings.getLLSD("AzureTranslateAPIKey"); + if (azure_key.isMap()) { - mBingAPIKeyEditor->setText(bing_key); - mBingAPIKeyEditor->setTentative(FALSE); - verifyKey(LLTranslate::SERVICE_BING, bing_key, false); + mAzureAPIKeyEditor->setText(azure_key["id"].asString()); + mAzureAPIKeyEditor->setTentative(false); + if (azure_key.has("region")) + { + mAzureAPIRegionEditor->setText(azure_key["region"].asString()); + mAzureAPIRegionEditor->setTentative(false); + } + else + { + mAzureAPIRegionEditor->setTentative(true); + } + mAzureAPIEndpointEditor->setValue(azure_key["endpoint"]); + verifyKey(LLTranslate::SERVICE_AZURE, azure_key, false); } else { - mBingAPIKeyEditor->setTentative(TRUE); - mBingKeyVerified = FALSE; + mAzureAPIKeyEditor->setTentative(TRUE); + mAzureKeyVerified = FALSE; } std::string google_key = gSavedSettings.getString("GoogleTranslateAPIKey"); @@ -121,14 +132,14 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key) updateControlsEnabledState(); } -void LLFloaterTranslationSettings::setBingVerified(bool ok, bool alert) +void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert) { if (alert) { - showAlert(ok ? "bing_api_key_verified" : "bing_api_key_not_verified"); + showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified"); } - mBingKeyVerified = ok; + mAzureKeyVerified = ok; updateControlsEnabledState(); } @@ -148,9 +159,19 @@ std::string LLFloaterTranslationSettings::getSelectedService() const return mTranslationServiceRadioGroup->getSelectedValue().asString(); } -std::string LLFloaterTranslationSettings::getEnteredBingKey() const +LLSD LLFloaterTranslationSettings::getEnteredAzureKey() const { - return mBingAPIKeyEditor->getTentative() ? LLStringUtil::null : mBingAPIKeyEditor->getText(); + LLSD key; + if (!mAzureAPIKeyEditor->getTentative()) + { + key["endpoint"] = mAzureAPIEndpointEditor->getValue(); + key["id"] = mAzureAPIKeyEditor->getText(); + if (!mAzureAPIRegionEditor->getTentative()) + { + key["region"] = mAzureAPIRegionEditor->getText(); + } + } + return key; } std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const @@ -170,27 +191,31 @@ void LLFloaterTranslationSettings::updateControlsEnabledState() // Enable/disable controls based on the checkbox value. bool on = mMachineTranslationCB->getValue().asBoolean(); std::string service = getSelectedService(); - bool bing_selected = service == "bing"; + bool azure_selected = service == "azure"; bool google_selected = service == "google"; mTranslationServiceRadioGroup->setEnabled(on); mLanguageCombo->setEnabled(on); - getChild<LLTextBox>("bing_api_key_label")->setEnabled(on); - mBingAPIKeyEditor->setEnabled(on); + getChild<LLTextBox>("azure_api_endoint_label")->setEnabled(on); + mAzureAPIEndpointEditor->setEnabled(on); + getChild<LLTextBox>("azure_api_key_label")->setEnabled(on); + mAzureAPIKeyEditor->setEnabled(on); + getChild<LLTextBox>("azure_api_region_label")->setEnabled(on); + mAzureAPIRegionEditor->setEnabled(on); getChild<LLTextBox>("google_api_key_label")->setEnabled(on); mGoogleAPIKeyEditor->setEnabled(on); - mBingAPIKeyEditor->setEnabled(on && bing_selected); + mAzureAPIKeyEditor->setEnabled(on && azure_selected); mGoogleAPIKeyEditor->setEnabled(on && google_selected); - mBingVerifyBtn->setEnabled(on && bing_selected && - !mBingKeyVerified && !getEnteredBingKey().empty()); + mAzureVerifyBtn->setEnabled(on && azure_selected && + !mAzureKeyVerified && getEnteredAzureKey().isMap()); mGoogleVerifyBtn->setEnabled(on && google_selected && !mGoogleKeyVerified && !getEnteredGoogleKey().empty()); - bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified); + bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified); gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified); mOKBtn->setEnabled(!on || service_verified); @@ -210,8 +235,8 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b switch (service) { - case LLTranslate::SERVICE_BING: - floater->setBingVerified(ok, alert); + case LLTranslate::SERVICE_AZURE: + floater->setAzureVerified(ok, alert); break; case LLTranslate::SERVICE_GOOGLE: floater->setGoogleVerified(ok, alert); @@ -220,7 +245,7 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b } -void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert) +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)); @@ -239,11 +264,14 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control) } } -void LLFloaterTranslationSettings::onBingKeyEdited() +void LLFloaterTranslationSettings::onAzureKeyEdited() { - if (mBingAPIKeyEditor->isDirty()) + if (mAzureAPIKeyEditor->isDirty() + || mAzureAPIRegionEditor->isDirty() + || mAzureAPIEndpointEditor->getValue().isString()) { - setBingVerified(false, false); + // todo: verify mAzureAPIEndpointEditor url + setAzureVerified(false, false); } } @@ -255,12 +283,12 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited() } } -void LLFloaterTranslationSettings::onBtnBingVerify() +void LLFloaterTranslationSettings::onBtnAzureVerify() { - std::string key = getEnteredBingKey(); - if (!key.empty()) + LLSD key = getEnteredAzureKey(); + if (key.isMap()) { - verifyKey(LLTranslate::SERVICE_BING, key); + verifyKey(LLTranslate::SERVICE_AZURE, key); } } @@ -269,16 +297,16 @@ void LLFloaterTranslationSettings::onBtnGoogleVerify() std::string key = getEnteredGoogleKey(); if (!key.empty()) { - verifyKey(LLTranslate::SERVICE_GOOGLE, key); + verifyKey(LLTranslate::SERVICE_GOOGLE, LLSD(key)); } } void LLFloaterTranslationSettings::onClose(bool app_quitting) { std::string service = gSavedSettings.getString("TranslationService"); - bool bing_selected = service == "bing"; + bool azure_selected = service == "azure"; bool google_selected = service == "google"; - bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified); + bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified); gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified); } @@ -287,7 +315,7 @@ void LLFloaterTranslationSettings::onBtnOK() gSavedSettings.setBOOL("TranslateChat", mMachineTranslationCB->getValue().asBoolean()); gSavedSettings.setString("TranslateLanguage", mLanguageCombo->getSelectedValue().asString()); gSavedSettings.setString("TranslationService", getSelectedService()); - gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey()); + gSavedSettings.setLLSD("AzureTranslateAPIKey", getEnteredAzureKey()); gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey()); closeFloater(false); diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h index 2a15eacded..52523f4d4a 100644 --- a/indra/newview/llfloatertranslationsettings.h +++ b/indra/newview/llfloatertranslationsettings.h @@ -42,22 +42,22 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - void setBingVerified(bool ok, bool alert); + void setAzureVerified(bool ok, bool alert); void setGoogleVerified(bool ok, bool alert); void onClose(bool app_quitting); private: std::string getSelectedService() const; - std::string getEnteredBingKey() const; + LLSD getEnteredAzureKey() const; std::string getEnteredGoogleKey() const; void showAlert(const std::string& msg_name) const; void updateControlsEnabledState(); - void verifyKey(int service, const std::string& key, bool alert = true); + void verifyKey(int service, const LLSD& key, bool alert = true); void onEditorFocused(LLFocusableElement* control); - void onBingKeyEdited(); + void onAzureKeyEdited(); void onGoogleKeyEdited(); - void onBtnBingVerify(); + void onBtnAzureVerify(); void onBtnGoogleVerify(); void onBtnOK(); @@ -65,14 +65,16 @@ private: LLCheckBoxCtrl* mMachineTranslationCB; LLComboBox* mLanguageCombo; - LLLineEditor* mBingAPIKeyEditor; + LLComboBox* mAzureAPIEndpointEditor;; + LLLineEditor* mAzureAPIKeyEditor; + LLLineEditor* mAzureAPIRegionEditor; LLLineEditor* mGoogleAPIKeyEditor; LLRadioGroup* mTranslationServiceRadioGroup; - LLButton* mBingVerifyBtn; + LLButton* mAzureVerifyBtn; LLButton* mGoogleVerifyBtn; LLButton* mOKBtn; - bool mBingKeyVerified; + bool mAzureKeyVerified; bool mGoogleKeyVerified; }; diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 3e6bf4fe82..706b4cc6ee 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -80,7 +80,18 @@ public: * @param[in] key Key to verify. */ virtual std::string getKeyVerificationURL( - const std::string &key) const = 0; + const LLSD &key) const = 0; + + /** + * Check API verification response. + * + * @param[out] bool true if valid. + * @param[in] response + * @param[in] status + */ + virtual bool checkVerificationResponse( + const LLSD &response, + int status) const = 0; /** * Parse translation response. @@ -105,22 +116,28 @@ public: virtual LLTranslate::EService getCurrentService() = 0; - virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0; + virtual void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) = 0; virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure); virtual ~LLTranslationAPIHandler() {} - void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc); + void verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc); void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure); virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const = 0; + virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const = 0; virtual LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, LLCore::HttpRequest::ptr_t request, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, const std::string & msg) const = 0; + virtual LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const = 0; }; void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure) @@ -130,8 +147,7 @@ void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::strin } - -void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc) +void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t @@ -148,8 +164,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: LLVersionInfo::instance().getPatch(), LLVersionInfo::instance().getBuild()); - httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); - httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + initHttpHeader(httpHeaders, user_agent, key); httpOpts->setFollowRedirects(true); httpOpts->setSSLVerifyPeer(false); @@ -161,17 +176,22 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: return; } - LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders); + LLSD result = verifyAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); bool bOk = true; - if (!status) + int parseResult = status.getType(); + if (!checkVerificationResponse(httpResults, parseResult)) + { bOk = false; + } if (!fnc.empty()) + { fnc(service, bOk); + } } void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg, @@ -192,7 +212,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s LLVersionInfo::instance().getPatch(), LLVersionInfo::instance().getBuild()); - initHttpHeader(httpHeaders, user_agent);
+ initHttpHeader(httpHeaders, user_agent); httpOpts->setSSLVerifyPeer(false); std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg); @@ -251,6 +271,11 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s } else { + if (err_msg.empty() && httpResults.has("error_body")) + { + err_msg = httpResults["error_body"].asString(); + } + if (err_msg.empty()) { err_msg = LLTrans::getString("TranslationResponseParseError"); @@ -271,25 +296,29 @@ class LLGoogleTranslationHandler : public LLTranslationAPIHandler LOG_CLASS(LLGoogleTranslationHandler); public: - /*virtual*/ std::string getTranslateURL( + std::string getTranslateURL( const std::string &from_lang, const std::string &to_lang, - const std::string &text) const; - /*virtual*/ std::string getKeyVerificationURL( - const std::string &key) const; - /*virtual*/ bool parseResponse( + const std::string &text) const override; + std::string getKeyVerificationURL( + const LLSD &key) const override; + bool checkVerificationResponse( + const LLSD &response, + int status) const override; + bool parseResponse( int& status, const std::string& body, std::string& translation, std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; + std::string& err_msg) const override; + bool isConfigured() const override; - /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_GOOGLE; } + LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_GOOGLE; } - /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc); + void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override; void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override; + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override; LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, LLCore::HttpRequest::ptr_t request, LLCore::HttpOptions::ptr_t options, @@ -297,6 +326,12 @@ public: const std::string & url, const std::string & msg) const override; + LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const override; + private: static void parseErrorResponse( const Json::Value& root, @@ -328,13 +363,21 @@ std::string LLGoogleTranslationHandler::getTranslateURL( // virtual std::string LLGoogleTranslationHandler::getKeyVerificationURL( - const std::string& key) const + const LLSD& key) const { - std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") - + key + "&target=en"; + std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") + + key.asString() +"&target=en"; return url; } +//virtual +bool LLGoogleTranslationHandler::checkVerificationResponse( + const LLSD &response, + int status) const +{ + return status == HTTP_OK; +} + // virtual bool LLGoogleTranslationHandler::parseResponse( int& status, @@ -424,11 +467,12 @@ bool LLGoogleTranslationHandler::parseTranslation( // static std::string LLGoogleTranslationHandler::getAPIKey() { - return gSavedSettings.getString("GoogleTranslateAPIKey"); + static LLCachedControl<std::string> google_key(gSavedSettings, "GoogleTranslateAPIKey"); + return google_key; } /*virtual*/ -void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) +void LLGoogleTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) { LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, this, LLTranslate::SERVICE_GOOGLE, key, fnc)); @@ -441,6 +485,16 @@ void LLGoogleTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t heade headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); } +/*virtual*/ +void LLGoogleTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent, + const LLSD &key) const +{ + headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); +} + LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, LLCore::HttpRequest::ptr_t request, LLCore::HttpOptions::ptr_t options, @@ -451,6 +505,15 @@ LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorou return adapter->getRawAndSuspend(request, url, options, headers); } +LLSD LLGoogleTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const +{ + return adapter->getAndSuspend(request, url, options, headers); +} + //========================================================================= /// Microsoft Translator v2 API handler. class LLAzureTranslationHandler : public LLTranslationAPIHandler @@ -463,7 +526,10 @@ public: const std::string &to_lang, const std::string &text) const override; std::string getKeyVerificationURL( - const std::string &key) const override; + const LLSD &key) const override; + bool checkVerificationResponse( + const LLSD &response, + int status) const override; bool parseResponse( int& status, const std::string& body, @@ -472,19 +538,26 @@ public: std::string& err_msg) const override; bool isConfigured() const override; - LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_BING; } + LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_AZURE; } - void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) override; + void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override; void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override; + void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override; LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, LLCore::HttpRequest::ptr_t request, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers, const std::string & url, const std::string & msg) const override; + + LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const override; private: - static std::string getAPIKey(); + static LLSD getAPIKey(); static std::string getAPILanguageCode(const std::string& lang); }; @@ -496,22 +569,49 @@ std::string LLAzureTranslationHandler::getTranslateURL( const std::string &to_lang, const std::string &text) const { - // Global service. Alternatively regional services exist. - std::string url = std::string("https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=") - + getAPILanguageCode(to_lang) + "&Subscription-Key=" + getAPIKey(); + std::string url; + LLSD key = getAPIKey(); + if (key.isMap()) + { + std::string endpoint = key["endpoint"].asString(); + // todo: validate url + if (*endpoint.rbegin() != '/') + { + endpoint += "/"; + } + url = endpoint + std::string("translate?api-version=3.0&to=") + + getAPILanguageCode(to_lang); + } return url; } // virtual std::string LLAzureTranslationHandler::getKeyVerificationURL( - const std::string& key) const + const LLSD& key) const { - std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=") - + key; + std::string url; + if (key.isMap()) + { + std::string endpoint = key["endpoint"].asString(); + // todo: validate url + if (*endpoint.rbegin() != '/') + { + endpoint += "/"; + } + url = endpoint + std::string("translate?api-version=3.0&to=en"); + } return url; } +//virtual +bool LLAzureTranslationHandler::checkVerificationResponse( + const LLSD &response, + int status) const +{ + return status == HTTP_BAD_REQUEST; // would have been 401 if id was wrong +} + // virtual bool LLAzureTranslationHandler::parseResponse( int& status, @@ -522,52 +622,71 @@ bool LLAzureTranslationHandler::parseResponse( { if (status != HTTP_OK) { - static const std::string MSG_BEGIN_MARKER = "Message: "; - size_t begin = body.find(MSG_BEGIN_MARKER); - if (begin != std::string::npos) - { - begin += MSG_BEGIN_MARKER.size(); - } - else - { - begin = 0; - err_msg.clear(); - } - size_t end = body.find("</p>", begin); - err_msg = body.substr(begin, end-begin); - LLStringUtil::replaceString(err_msg, "
", ""); // strip CR return false; } - // Sample response: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string> - size_t begin = body.find(">"); - if (begin == std::string::npos || begin >= (body.size() - 1)) - { - begin = 0; - } - else - { - ++begin; - } + //Example: + // "[{\"detectedLanguage\":{\"language\":\"en\",\"score\":1.0},\"translations\":[{\"text\":\"Hello, what is your name?\",\"to\":\"en\"}]}]" - size_t end = body.find("</string>", begin); + Json::Value root; + Json::Reader reader; - detected_lang = ""; // unsupported by this API - translation = body.substr(begin, end-begin); - LLStringUtil::replaceString(translation, "
", ""); // strip CR - return true; + if (!reader.parse(body, root)) + { + err_msg = reader.getFormatedErrorMessages(); + return false; + } + + if (!root.isArray()) // empty response? should not happen + { + return false; + } + + // Request succeeded, extract translation from the response. + + const Json::Value& data = root[0U]; + if (!data.isObject() + || !data.isMember("detectedLanguage") + || !data.isMember("translations")) + { + return false; + } + + const Json::Value& detectedLanguage = data["detectedLanguage"]; + if (!detectedLanguage.isObject() || !detectedLanguage.isMember("language")) + { + return false; + } + detected_lang = detectedLanguage["language"].asString(); + + const Json::Value& translations = data["translations"]; + if (!translations.isArray() || translations.size() == 0) + { + return false; + } + + const Json::Value& first = translations[0U]; + if (!first.isObject() || !first.isMember("text")) + { + return false; + } + + translation = first["text"].asString(); + + return true; } // virtual bool LLAzureTranslationHandler::isConfigured() const { - return !getAPIKey().empty(); + return !getAPIKey().isMap(); } // static -std::string LLAzureTranslationHandler::getAPIKey() +LLSD LLAzureTranslationHandler::getAPIKey() { - return gSavedSettings.getString("BingTranslateAPIKey"); + static LLCachedControl<LLSD> azure_key(gSavedSettings, "AzureTranslateAPIKey"); + return azure_key; } // static @@ -577,19 +696,38 @@ std::string LLAzureTranslationHandler::getAPILanguageCode(const std::string& lan } /*virtual*/ -void LLAzureTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) +void LLAzureTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) { - LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, - this, LLTranslate::SERVICE_BING, key, fnc)); + LLCoros::instance().launch("Azure /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, + this, LLTranslate::SERVICE_AZURE, key, fnc)); +} +/*virtual*/ +void LLAzureTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent) const +{ + initHttpHeader(headers, user_agent, getAPIKey()); } /*virtual*/ -void LLAzureTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const +void LLAzureTranslationHandler::initHttpHeader( + LLCore::HttpHeaders::ptr_t headers, + const std::string& user_agent, + const LLSD &key) const { headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_JSON); - // Token based autorization exists - //headers->append("Ocp-Apim-Subscription-Key", getAPIKey()); headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + + if (key.has("id")) + { + // Token based autorization + headers->append("Ocp-Apim-Subscription-Key", key["id"].asString()); + } + if (key.has("region")) + { + // ex: "westeurope" + headers->append("Ocp-Apim-Subscription-Region", key["region"].asString()); + } } LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, @@ -599,9 +737,26 @@ LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorout const std::string & url, const std::string & msg) const { - LLSD body; - body["text"] = "Hello, what is your name?"; - return adapter->postJsonAndSuspend(request, url, body, headers); + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream outs(rawbody.get()); + outs << "[{\"text\":\""; + outs << msg; + outs << "\"}]"; + + return adapter->postRawAndSuspend(request, url, rawbody, options, headers); +} + +LLSD LLAzureTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, + LLCore::HttpRequest::ptr_t request, + LLCore::HttpOptions::ptr_t options, + LLCore::HttpHeaders::ptr_t headers, + const std::string & url) const +{ + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream outs(rawbody.get()); + outs << "[{\"intentionally_invalid_400\"}]"; + + return adapter->postRawAndSuspend(request, url, rawbody, options, headers); } //========================================================================= @@ -616,7 +771,7 @@ void LLTranslate::translateMessage(const std::string &from_lang, const std::stri std::string LLTranslate::addNoTranslateTags(std::string mesg) { - if (getPreferredHandler().getCurrentService() != SERVICE_BING) + if (getPreferredHandler().getCurrentService() != SERVICE_AZURE) { return mesg; } @@ -637,7 +792,7 @@ std::string LLTranslate::addNoTranslateTags(std::string mesg) std::string LLTranslate::removeNoTranslateTags(std::string mesg) { - if (getPreferredHandler().getCurrentService() != SERVICE_BING) + if (getPreferredHandler().getCurrentService() != SERVICE_AZURE) { return mesg; } @@ -667,7 +822,7 @@ std::string LLTranslate::removeNoTranslateTags(std::string mesg) } /*static*/ -void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc) +void LLTranslate::verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc) { LLTranslationAPIHandler& handler = getHandler(service); @@ -696,7 +851,7 @@ bool LLTranslate::isTranslationConfigured() // static LLTranslationAPIHandler& LLTranslate::getPreferredHandler() { - EService service = SERVICE_BING; + EService service = SERVICE_AZURE; std::string service_str = gSavedSettings.getString("TranslationService"); if (service_str == "google") @@ -711,12 +866,12 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler() LLTranslationAPIHandler& LLTranslate::getHandler(EService service) { static LLGoogleTranslationHandler google; - static LLAzureTranslationHandler bing; + static LLAzureTranslationHandler azure; if (service == SERVICE_GOOGLE) { return google; } - return bing; + return azure; } diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index e0722fbd83..870fd54441 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -55,7 +55,7 @@ class LLTranslate public : typedef enum e_service { - SERVICE_BING, + SERVICE_AZURE, SERVICE_GOOGLE, } EService; @@ -74,12 +74,12 @@ public : static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure); /** - * Verify given API key of a translation service. - * - * @param receiver Object to pass verification result to. - * @param key Key to verify. - */ - static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc); + * Verify given API key of a translation service. + * + * @param receiver Object to pass verification result to. + * @param key Key to verify. + */ + static void verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc); /** * @return translation target language 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 a212ce7889..b0e47798e9 100644 --- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml +++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="310" + height="370" layout="topleft" name="floater_translation_settings" help_topic="translation_settings" @@ -9,10 +9,10 @@ title="CHAT TRANSLATION SETTINGS" width="485"> - <string name="bing_api_key_not_verified">Bing appID not verified. Please try again.</string> + <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="bing_api_key_verified">Bing appID verified.</string> + <string name="azure_api_key_verified">Azure service identifier verified.</string> <string name="google_api_key_verified">Google API key verified.</string> <check_box @@ -128,25 +128,67 @@ <radio_group follows="top|left" - height="80" + height="140" layout="topleft" left_delta="10" name="translation_service_rg" top_pad="20" width="320"> <radio_item - initial_value="bing" - label="Bing Translator" + initial_value="azure" + label="Azure Translator" layout="topleft" - name="bing" /> + name="azure" /> <radio_item initial_value="google" label="Google Translate" layout="topleft" name="google" - top_pad="55" /> + top_pad="115" /> </radio_group> + <text + type="string" + length="1" + follows="top|right" + height="20" + layout="topleft" + left="70" + name="azure_api_endoint_label" + top_pad="-115" + width="85"> + Endpoint: + </text> + + <combo_box + allow_text_entry="true" + follows="left|top" + name="azure_api_endpoint_combo" + height="23" + left_pad="10" + right="-10" + top_delta="-4" + max_chars="512" + value="https://api.cognitive.microsofttranslator.com" + combo_button.scale_image="true"> + <combo_box.item + label="https://api.cognitive.microsofttranslator.com" + name="global" + value="https://api.cognitive.microsofttranslator.com" /> + <combo_box.item + label="https://api-apc.cognitive.microsofttranslator.com" + name="api-apc" + value="https://api-apc.cognitive.microsofttranslator.com" /> + <combo_box.item + label="https://api-eur.cognitive.microsofttranslator.com" + name="api-eur" + value="https://api-eur.cognitive.microsofttranslator.com" /> + <combo_box.item + label="https://api-nam.cognitive.microsofttranslator.com" + name="api-nam" + value="https://api-nam.cognitive.microsofttranslator.com" /> + </combo_box> + <text type="string" length="1" @@ -154,20 +196,20 @@ height="20" layout="topleft" left="70" - name="bing_api_key_label" - top_pad="-55" + name="azure_api_key_label" + top_pad="10" width="85"> - Bing [http://www.bing.com/developers/createapp.aspx AppID]: + Azure Key: </text> <line_editor - default_text="Enter Bing AppID and click "Verify"" + default_text="Enter Translator Key and click "Verify"" follows="top|left" height="20" layout="topleft" left_pad="10" max_length_chars="50" top_delta="-4" - name="bing_api_key" + name="azure_api_key" width="210" /> <button follows="left|top" @@ -175,9 +217,30 @@ label="Verify" layout="topleft" left_pad="10" - name="verify_bing_api_key_btn" + name="verify_azure_api_key_btn" top_delta="-2" - width="90" /> + width="90" /> + <text + type="string" + length="1" + follows="top|right" + height="20" + layout="topleft" + left="70" + name="azure_api_region_label" + top_pad="10" + width="85"> + Region: + </text> + <line_editor + follows="top|left" + height="20" + layout="topleft" + left_pad="10" + max_length_chars="50" + top_delta="-4" + name="azure_api_region" + width="210" /> <text follows="top|right" @@ -186,7 +249,7 @@ left="70" length="1" name="google_api_key_label" - top_pad="50" + top_pad="55" type="string" width="85"> Google [http://code.google.com/apis/language/translate/v2/getting_started.html#auth API key]: |