File indexing completed on 2024-11-24 04:16:56
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 "deeplengineplugin.h" 0010 #include "deeplengineutil.h" 0011 #include "deepltranslator_debug.h" 0012 0013 #include <KConfigGroup> 0014 #include <KLocalizedString> 0015 #include <KSharedConfig> 0016 #include <QJsonArray> 0017 #include <QJsonDocument> 0018 #include <QJsonObject> 0019 #include <QUrlQuery> 0020 #include <TextTranslator/TranslatorEngineAccessManager> 0021 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0022 #include <qt5keychain/keychain.h> 0023 #else 0024 #include <qt6keychain/keychain.h> 0025 #endif 0026 0027 DeeplEnginePlugin::DeeplEnginePlugin(QObject *parent) 0028 : TextTranslator::TranslatorEnginePlugin(parent) 0029 { 0030 loadSettings(); 0031 } 0032 0033 DeeplEnginePlugin::~DeeplEnginePlugin() = default; 0034 0035 void DeeplEnginePlugin::translate() 0036 { 0037 if (verifyFromAndToLanguage()) { 0038 return; 0039 } 0040 if (mApiKey.isEmpty()) { 0041 Q_EMIT translateFailed(i18n("Server needs Api Key.")); 0042 return; 0043 } 0044 translateText(); 0045 } 0046 0047 void DeeplEnginePlugin::translateText() 0048 { 0049 clear(); 0050 0051 QUrl url(mServerUrl); 0052 QUrlQuery query; 0053 query.addQueryItem(QStringLiteral("text"), inputText()); 0054 query.addQueryItem(QStringLiteral("source_lang"), languageCode(from())); 0055 query.addQueryItem(QStringLiteral("target_lang"), languageCode(to())); 0056 url.setQuery(query); 0057 0058 QNetworkRequest request(url); 0059 request.setRawHeader(QByteArrayLiteral("Authorization"), "DeepL-Auth-Key " + mApiKey.toLocal8Bit()); 0060 request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded")); 0061 0062 QNetworkReply *reply = TextTranslator::TranslatorEngineAccessManager::self()->networkManager()->post(request, QByteArray()); 0063 connect(reply, &QNetworkReply::errorOccurred, this, [this, reply](QNetworkReply::NetworkError error) { 0064 slotError(error); 0065 reply->deleteLater(); 0066 }); 0067 connect(reply, &QNetworkReply::finished, this, [this, reply]() { 0068 reply->deleteLater(); 0069 parseTranslation(reply); 0070 }); 0071 } 0072 0073 void DeeplEnginePlugin::parseTranslation(QNetworkReply *reply) 0074 { 0075 if (reply->error() != QNetworkReply::NoError) { 0076 Q_EMIT translateFailed(reply->errorString()); 0077 reply->deleteLater(); 0078 return; 0079 } 0080 0081 const QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll()); 0082 if (hasDebug()) { 0083 setJsonDebug(QString::fromUtf8(jsonResponse.toJson(QJsonDocument::Indented))); 0084 } 0085 const QJsonObject responseObject = jsonResponse.object(); 0086 // QJsonObject({"translations":[{"detected_source_language":"EN","text":"Bonjour le monde"}]}) 0087 qCDebug(TRANSLATOR_DEEPL_LOG) << " responseObject " << responseObject; 0088 const QJsonArray arrayTranslation = responseObject.value(QStringLiteral("translations")).toArray(); 0089 qCDebug(TRANSLATOR_DEEPL_LOG) << " arrayTranslation " << arrayTranslation; 0090 const QJsonObject obj = arrayTranslation.at(0).toObject(); 0091 0092 setResult(obj.value(QStringLiteral("text")).toString()); 0093 reply->deleteLater(); 0094 qCDebug(TRANSLATOR_DEEPL_LOG) << " result " << result(); 0095 Q_EMIT translateDone(); 0096 } 0097 0098 void DeeplEnginePlugin::loadSettings() 0099 { 0100 KConfigGroup myGroup(KSharedConfig::openConfig(), DeeplEngineUtil::groupName()); 0101 mUseFreeLicense = myGroup.readEntry(DeeplEngineUtil::freeLicenseKey(), false); 0102 mServerUrl = mUseFreeLicense ? QStringLiteral("https://api-free.deepl.com/v2/translate") : QStringLiteral("https://api.deepl.com/v2/translate"); 0103 auto readJob = new QKeychain::ReadPasswordJob(DeeplEngineUtil::translatorGroupName(), this); 0104 connect(readJob, &QKeychain::Job::finished, this, &DeeplEnginePlugin::slotApiKeyRead); 0105 readJob->setKey(DeeplEngineUtil::apiGroupName()); 0106 readJob->start(); 0107 } 0108 0109 void DeeplEnginePlugin::slotApiKeyRead(QKeychain::Job *baseJob) 0110 { 0111 auto job = qobject_cast<QKeychain::ReadPasswordJob *>(baseJob); 0112 Q_ASSERT(job); 0113 if (!job->error()) { 0114 mApiKey = job->textData(); 0115 } else { 0116 qCWarning(TRANSLATOR_DEEPL_LOG) << "We have an error during reading password " << job->errorString(); 0117 } 0118 } 0119 0120 void DeeplEnginePlugin::slotConfigureChanged() 0121 { 0122 loadSettings(); 0123 } 0124 0125 QString DeeplEnginePlugin::languageCode(const QString &langStr) 0126 { 0127 if (langStr == QLatin1String("auto")) { 0128 return QStringLiteral("auto-detect"); 0129 } else if (langStr == QLatin1String("zh-CN")) { 0130 return QStringLiteral("zh"); 0131 } 0132 return langStr; 0133 } 0134 0135 #include "moc_deeplengineplugin.cpp"