File indexing completed on 2025-04-27 03:58:38
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2018-02-22 0007 * Description : A text translator using web-services - Google methods. 0008 * 0009 * SPDX-FileCopyrightText: 2018-2022 by Hennadii Chernyshchyk <genaloner at gmail dot com> 0010 * SPDX-FileCopyrightText: 2021-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "donlinetranslator_p.h" 0017 0018 namespace Digikam 0019 { 0020 0021 void DOnlineTranslator::slotRequestGoogleTranslate() 0022 { 0023 const QString sourceText = sender()->property(Private::s_textProperty).toString(); 0024 0025 // Generate API url 0026 0027 QUrl url(QStringLiteral("https://translate.googleapis.com/translate_a/single")); 0028 0029 url.setQuery(QStringLiteral("client=gtx&ie=UTF-8&oe=UTF-8&dt=bd&dt=ex&dt=ld&dt=md&dt=rw&dt=rm&dt=ss&dt=t&dt=at&dt=qc&sl=%1&tl=%2&hl=%3&q=%4") 0030 .arg(languageApiCode(Google, d->sourceLang), 0031 languageApiCode(Google, d->translationLang), 0032 languageApiCode(Google, d->uiLang), 0033 QString::fromUtf8(QUrl::toPercentEncoding(sourceText)))); 0034 0035 d->currentReply = d->networkManager->get(QNetworkRequest(url)); 0036 } 0037 0038 void DOnlineTranslator::slotParseGoogleTranslate() 0039 { 0040 if ((quintptr)d->currentReply.data() != sender()->property("QNetworkReply").value<quintptr>()) 0041 { 0042 return; 0043 } 0044 0045 d->currentReply->deleteLater(); 0046 0047 // Check for error 0048 0049 if (d->currentReply->error() != QNetworkReply::NoError) 0050 { 0051 if (d->currentReply->error() == QNetworkReply::ServiceUnavailableError) 0052 { 0053 resetData(ServiceError, i18n("Error: Engine systems have detected suspicious traffic from your " 0054 "computer network. Please try your request again later.")); 0055 } 0056 else 0057 { 0058 resetData(NetworkError, d->currentReply->errorString()); 0059 } 0060 0061 return; 0062 } 0063 0064 // Check availability of service 0065 0066 const QByteArray data = d->currentReply->readAll(); 0067 0068 if (data.startsWith('<')) 0069 { 0070 resetData(ServiceError, i18n("Error: Engine systems have detected suspicious traffic from your " 0071 "computer network. Please try your request again later.")); 0072 return; 0073 } 0074 0075 // Read Json 0076 0077 const QJsonDocument jsonResponse = QJsonDocument::fromJson(data); 0078 const QJsonArray jsonData = jsonResponse.array(); 0079 0080 if (d->sourceLang == Auto) 0081 { 0082 // Parse language 0083 0084 d->sourceLang = language(Google, jsonData.at(2).toString()); 0085 0086 if (d->sourceLang == NoLanguage) 0087 { 0088 resetData(ParsingError, i18n("Error: Unable to parse autodetected language")); 0089 return; 0090 } 0091 0092 if (d->onlyDetectLanguage) 0093 { 0094 return; 0095 } 0096 } 0097 0098 addSpaceBetweenParts(d->translation); 0099 addSpaceBetweenParts(d->translationTranslit); 0100 addSpaceBetweenParts(d->sourceTranslit); 0101 0102 for (const QJsonValueRef translationData : jsonData.at(0).toArray()) 0103 { 0104 const QJsonArray translationArray = translationData.toArray(); 0105 d->translation.append(translationArray.at(0).toString()); 0106 0107 if (d->translationTranslitEnabled) 0108 { 0109 d->translationTranslit.append(translationArray.at(2).toString()); 0110 } 0111 0112 if (d->sourceTranslitEnabled) 0113 { 0114 d->sourceTranslit.append(translationArray.at(3).toString()); 0115 } 0116 } 0117 0118 if (d->source.size() >= Private::s_googleTranslateLimit) 0119 { 0120 return; 0121 } 0122 0123 // Translation options 0124 0125 if (d->translationOptionsEnabled) 0126 { 0127 for (const QJsonValueRef typeOfSpeechData : jsonData.at(1).toArray()) 0128 { 0129 const QJsonArray typeOfSpeechDataArray = typeOfSpeechData.toArray(); 0130 const QString typeOfSpeech = typeOfSpeechDataArray.at(0).toString(); 0131 0132 for (const QJsonValueRef wordData : typeOfSpeechDataArray.at(2).toArray()) 0133 { 0134 const QJsonArray wordDataArray = wordData.toArray(); 0135 const QString word = wordDataArray.at(0).toString(); 0136 const QString gender = wordDataArray.at(4).toString(); 0137 const QJsonArray translationsArray = wordDataArray.at(1).toArray(); 0138 QStringList translations; 0139 translations.reserve(translationsArray.size()); 0140 0141 for (const QJsonValue &wordTranslation : translationsArray) 0142 { 0143 translations.append(wordTranslation.toString()); 0144 } 0145 0146 d->translationOptions[typeOfSpeech].append({word, gender, translations}); 0147 } 0148 } 0149 } 0150 } 0151 0152 void DOnlineTranslator::buildGoogleStateMachine() 0153 { 0154 // States (Google sends translation, translit and dictionary in one request, 0155 // that will be splited into several by the translation limit) 0156 0157 auto* translationState = new QState(d->stateMachine); 0158 auto* finalState = new QFinalState(d->stateMachine); 0159 d->stateMachine->setInitialState(translationState); 0160 0161 translationState->addTransition(translationState, &QState::finished, finalState); 0162 0163 // Setup translation state 0164 0165 buildSplitNetworkRequest(translationState, 0166 &DOnlineTranslator::slotRequestGoogleTranslate, 0167 &DOnlineTranslator::slotParseGoogleTranslate, 0168 d->source, 0169 Private::s_googleTranslateLimit); 0170 } 0171 0172 void DOnlineTranslator::buildGoogleDetectStateMachine() 0173 { 0174 // States 0175 0176 auto* detectState = new QState(d->stateMachine); 0177 auto* finalState = new QFinalState(d->stateMachine); 0178 d->stateMachine->setInitialState(detectState); 0179 0180 detectState->addTransition(detectState, &QState::finished, finalState); 0181 0182 // Setup detect state 0183 0184 const QString text = d->source.left(getSplitIndex(d->source, Private::s_googleTranslateLimit)); 0185 0186 buildNetworkRequestState(detectState, 0187 &DOnlineTranslator::slotRequestGoogleTranslate , 0188 &DOnlineTranslator::slotParseGoogleTranslate, 0189 text); 0190 } 0191 0192 } // namespace Digikam