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"