summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2023-02-24 11:59:48 +0200
committerakleshchev <117672381+akleshchev@users.noreply.github.com>2023-02-28 21:46:43 +0200
commit3fc3627f2d27b181269416f346f29d6451f7009a (patch)
tree45de7c5949369e58e0b63d6e818bb255c8b9f7ec /indra
parent3daccc5d2344404af1b3501c35b7cff96468602f (diff)
SL-19209 WIP Switch MS Bing to MS Azure #2
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/app_settings/settings.xml17
-rw-r--r--indra/newview/llfloatertranslationsettings.cpp120
-rw-r--r--indra/newview/llfloatertranslationsettings.h18
-rw-r--r--indra/newview/lltranslate.cpp317
-rw-r--r--indra/newview/lltranslate.h14
-rw-r--r--indra/newview/skins/default/xui/en/floater_translation_settings.xml95
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, "&#xD;", ""); // 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, "&#xD;", ""); // 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 &quot;Verify&quot;"
+ default_text="Enter Translator Key and click &quot;Verify&quot;"
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]: