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]: | 
