File indexing completed on 2024-11-24 04:16:57
0001 /* 0002 SPDX-FileCopyrightText: 2022-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 0006 based on digikam onlinetranslator code 0007 */ 0008 0009 #include "yandexengineplugin.h" 0010 0011 #include <TextTranslator/TranslatorEngineAccessManager> 0012 0013 #include <KLocalizedString> 0014 0015 #include <QJsonArray> 0016 #include <QJsonDocument> 0017 #include <QJsonObject> 0018 #include <QUrlQuery> 0019 0020 QString YandexEnginePlugin::sYandexKey; 0021 0022 YandexEnginePlugin::YandexEnginePlugin(QObject *parent) 0023 : TextTranslator::TranslatorEnginePlugin(parent) 0024 { 0025 } 0026 0027 YandexEnginePlugin::~YandexEnginePlugin() = default; 0028 0029 void YandexEnginePlugin::translate() 0030 { 0031 if (sYandexKey.isEmpty()) { 0032 const QUrl url(QStringLiteral("https://translate.yandex.com")); 0033 0034 QNetworkReply *reply = TextTranslator::TranslatorEngineAccessManager::self()->networkManager()->get(QNetworkRequest(url)); 0035 connect(reply, &QNetworkReply::finished, this, [this, reply]() { 0036 parseCredentials(reply); 0037 }); 0038 connect(reply, &QNetworkReply::errorOccurred, this, [this, reply](QNetworkReply::NetworkError error) { 0039 slotError(error); 0040 reply->deleteLater(); 0041 }); 0042 } else { 0043 translateText(); 0044 } 0045 } 0046 0047 void YandexEnginePlugin::parseCredentials(QNetworkReply *reply) 0048 { 0049 // Check availability of service 0050 const QByteArray webSiteData = reply->readAll(); 0051 reply->deleteLater(); 0052 if (webSiteData.isEmpty() || webSiteData.contains("<title>Oops!</title>") || webSiteData.contains("<title>302 Found</title>")) { 0053 Q_EMIT translateFailed( 0054 i18n("Error: Engine systems have detected suspicious traffic " 0055 "from your computer network. Please try your request again later.")); 0056 return; 0057 } 0058 // qCDebug(TRANSLATOR_YANDEX_LOG) << "webSiteData " << webSiteData; 0059 const QByteArray sidBeginString = "SID: '"; 0060 const int sidBeginStringPos = webSiteData.indexOf(sidBeginString); 0061 0062 if (sidBeginStringPos == -1) { 0063 Q_EMIT translateFailed(i18n("Error: Unable to find Yandex SID in web version.")); 0064 return; 0065 } 0066 0067 const int sidBeginPosition = sidBeginStringPos + sidBeginString.size(); 0068 const int sidEndPosition = webSiteData.indexOf('\'', sidBeginPosition); 0069 0070 if (sidEndPosition == -1) { 0071 Q_EMIT translateFailed(i18n("Error: Unable to extract Yandex SID from web version.")); 0072 return; 0073 } 0074 0075 // Yandex show reversed parts of session ID, need to decode 0076 0077 const QString sid = QString::fromUtf8(webSiteData.mid(sidBeginPosition, sidEndPosition - sidBeginPosition)); 0078 0079 QStringList sidParts = sid.split(QLatin1Char('.')); 0080 0081 for (int i = 0, total = sidParts.size(); i < total; ++i) { 0082 std::reverse(sidParts[i].begin(), sidParts[i].end()); 0083 } 0084 0085 sYandexKey = sidParts.join(QLatin1Char('.')); 0086 translateText(); 0087 } 0088 0089 void YandexEnginePlugin::translateText() 0090 { 0091 if (verifyFromAndToLanguage()) { 0092 return; 0093 } 0094 0095 clear(); 0096 QString lang; 0097 if (from() == QLatin1String("auto")) { 0098 lang = languageCode(to()); 0099 } else { 0100 lang = languageCode(from()) + QLatin1Char('-') + languageCode(to()); 0101 } 0102 // qDebug() << " lang " << lang; 0103 // Generate API url 0104 QUrl url(QStringLiteral("https://translate.yandex.net/api/v1/tr.json/translate")); 0105 QUrlQuery query; 0106 query.addQueryItem(QStringLiteral("id"), sYandexKey + QLatin1String("-2-0")); 0107 query.addQueryItem(QStringLiteral("srv"), QStringLiteral("tr-text")); 0108 query.addQueryItem(QStringLiteral("text"), inputText()); 0109 query.addQueryItem(QStringLiteral("lang"), lang); 0110 url.setQuery(query); 0111 0112 // Setup request 0113 QNetworkRequest request; 0114 request.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); 0115 request.setUrl(url); 0116 0117 // Make reply 0118 QNetworkReply *reply = TextTranslator::TranslatorEngineAccessManager::self()->networkManager()->post(request, QByteArray()); 0119 connect(reply, &QNetworkReply::errorOccurred, this, [this, reply](QNetworkReply::NetworkError error) { 0120 slotError(error); 0121 reply->deleteLater(); 0122 }); 0123 0124 connect(reply, &QNetworkReply::finished, this, [this, reply]() { 0125 reply->deleteLater(); 0126 parseTranslation(reply); 0127 }); 0128 } 0129 0130 void YandexEnginePlugin::parseTranslation(QNetworkReply *reply) 0131 { 0132 const QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll()); 0133 if (hasDebug()) { 0134 setJsonDebug(QString::fromUtf8(jsonResponse.toJson(QJsonDocument::Indented))); 0135 } 0136 const QJsonObject jsonData = jsonResponse.object(); 0137 reply->deleteLater(); 0138 0139 // Parse language 0140 if (from() == QLatin1String("auto")) { 0141 QString sourceCode = jsonData.value(QStringLiteral("lang")).toString(); 0142 sourceCode = sourceCode.left(sourceCode.indexOf(QLatin1Char('-'))); 0143 qDebug() << " sourceCode " << sourceCode; 0144 } 0145 0146 // qDebug() << "jsonData " << jsonData; 0147 appendResult(jsonData.value(QStringLiteral("text")).toArray().at(0).toString()); 0148 Q_EMIT translateDone(); 0149 } 0150 0151 QString YandexEnginePlugin::languageCode(const QString &langStr) 0152 { 0153 if (langStr == QLatin1String("zh")) { 0154 return QStringLiteral("zn"); 0155 } else if (langStr == QLatin1String("ja")) { 0156 return QStringLiteral("jv"); 0157 } 0158 return langStr; 0159 } 0160 0161 #include "moc_yandexengineplugin.cpp"