From 01d969968e2d768099163c01fa2f383770fe776d Mon Sep 17 00:00:00 2001 From: Gres Date: Thu, 8 Oct 2015 18:36:02 +0300 Subject: [PATCH] Added WebTranslator class. --- ScreenTranslator.pro | 3 + Settings.h | 2 + SettingsEditor.cpp | 2 + SettingsEditor.ui | 27 +++++++-- WebTranslator.cpp | 124 +++++++++++++++++++++++++++++++++++++++++ WebTranslator.h | 53 ++++++++++++++++++ WebTranslatorProxy.cpp | 25 +++++++++ WebTranslatorProxy.h | 38 +++++++++++++ translators/google.js | 31 +++++++++++ 9 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 WebTranslator.cpp create mode 100644 WebTranslator.h create mode 100644 WebTranslatorProxy.cpp create mode 100644 WebTranslatorProxy.h create mode 100644 translators/google.js diff --git a/ScreenTranslator.pro b/ScreenTranslator.pro index 8af33c0..4d9d2ef 100644 --- a/ScreenTranslator.pro +++ b/ScreenTranslator.pro @@ -37,6 +37,7 @@ SOURCES += main.cpp\ ProcessingItem.cpp \ ImageProcessing.cpp \ LanguageHelper.cpp \ + WebTranslator.cpp \ GoogleWebTranslator.cpp HEADERS += \ @@ -51,6 +52,7 @@ HEADERS += \ ResultDialog.h \ ImageProcessing.h \ LanguageHelper.h \ + WebTranslator.h \ GoogleWebTranslator.h \ StAssert.h @@ -71,4 +73,5 @@ OTHER_FILES += \ images/icon.ico \ README.md \ uncrustify.cfg\ + translators/google.js \ TODO.md diff --git a/Settings.h b/Settings.h index b7cf46f..da45ae3 100644 --- a/Settings.h +++ b/Settings.h @@ -24,6 +24,7 @@ namespace settings_names { const QString doTranslation = "doTranslation"; const QString sourceLanguage = "source_language"; const QString translationLanguage = "translation_language"; + const QString translationTimeout = "translation_timeout"; } @@ -47,6 +48,7 @@ namespace settings_values { const bool doTranslation = true; const QString sourceLanguage = "auto"; const QString translationLanguage = "ru"; + const int translationTimeout = 15; // secs } #endif // SETTINGS_H diff --git a/SettingsEditor.cpp b/SettingsEditor.cpp index 5c3c89c..0fc694f 100644 --- a/SettingsEditor.cpp +++ b/SettingsEditor.cpp @@ -64,6 +64,7 @@ void SettingsEditor::saveSettings () const { settings.setValue (translationLanguage, trLanguage); QString sourceLanguage = dictionary_.translateForOcrCode (ocrLanguage); settings.setValue (sourceLanguage, sourceLanguage); + settings.setValue (translationTimeout, ui->translateTimeoutSpin->value ()); settings.endGroup (); } @@ -104,6 +105,7 @@ void SettingsEditor::loadSettings () { ui->doTranslationCombo->setChecked (GET (doTranslation).toBool ()); QString trLanguage = dictionary_.translateCodeToUi (GET (translationLanguage).toString ()); ui->translateLangCombo->setCurrentText (trLanguage); + ui->translateTimeoutSpin->setValue (GET (translationTimeout).toInt ()); settings.endGroup (); #undef GET } diff --git a/SettingsEditor.ui b/SettingsEditor.ui index 4db4394..c255e6a 100644 --- a/SettingsEditor.ui +++ b/SettingsEditor.ui @@ -7,7 +7,7 @@ 0 0 603 - 269 + 296 @@ -194,7 +194,7 @@ Перевод - + <html><head/><body><p>Необходимо ли переводить (вкл) распознанный текст.</p></body></html> @@ -204,20 +204,37 @@ - + + + + <html><head/><body><p>Максимальное время, которое может быть затрачено на перевод, чтобы он не считался &quot;зависшим&quot;.</p></body></html> + + + Максимальное время перевода: + + + + + + + сек. + + + + <html><head/><body><p>Язык, на который осуществляется перевод.</p></body></html> - Язык результата + Язык результата: translateLangCombo - + diff --git a/WebTranslator.cpp b/WebTranslator.cpp new file mode 100644 index 0000000..a5b3cf9 --- /dev/null +++ b/WebTranslator.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#include "WebTranslator.h" +#include "ProcessingItem.h" +#include "Settings.h" +#include "StAssert.h" +#include "WebTranslatorProxy.h" + +WebTranslator::WebTranslator () + : QObject (), + proxy_ (new WebTranslatorProxy (this)), view_ (new QWebView), isReady_ (true) { + + view_->settings ()->setAttribute (QWebSettings::AutoLoadImages, false); + view_->settings ()->setAttribute (QWebSettings::DeveloperExtrasEnabled, true); + + connect (view_, SIGNAL (loadFinished (bool)), SLOT (loadFinished (bool))); + connect (view_->page ()->mainFrame (), SIGNAL (javaScriptWindowObjectCleared ()), + this, SLOT (addProxyToView ())); + connect (view_->page ()->networkAccessManager (), SIGNAL (finished (QNetworkReply *)), + this, SLOT (replyFinished (QNetworkReply *))); + + translationTimeout_.setSingleShot (true); + connect (&translationTimeout_, SIGNAL (timeout ()), SLOT (abortTranslation ())); + + connect (proxy_, SIGNAL (error (QString)), SLOT (proxyError (QString))); + connect (proxy_, SIGNAL (translated (QString)), SLOT (proxyTranslated (QString))); + + applySettings (); +} + +WebTranslator::~WebTranslator () { + delete view_; +} + +void WebTranslator::addProxyToView () { + view_->page ()->mainFrame ()->addToJavaScriptWindowObject ("st_wtp", proxy_); + view_->page ()->mainFrame ()->evaluateJavaScript (script_); +} + +void WebTranslator::translate (ProcessingItem item) { + queue_.push_back (item); + translateQueued (); +} + +void WebTranslator::translateQueued () { + if (isReady_ && !script_.isEmpty () && !queue_.isEmpty ()) { + isReady_ = false; + runScriptForItem (queue_.first ()); + translationTimeout_.start (); + } +} + +void WebTranslator::runScriptForItem (const ProcessingItem &item) { + ST_ASSERT (!script_.isEmpty ()); + proxy_->setItem (item); + view_->page ()->mainFrame ()->evaluateJavaScript ("translate();"); +} + +void WebTranslator::proxyError (const QString &message) { + emit error (message); + finishTranslation (); +} + +void WebTranslator::proxyTranslated (const QString &text) { + if (!queue_.isEmpty () && queue_.first ().recognized == proxy_->sourceText ()) { + ProcessingItem &item = queue_.first (); + item.translated = text; + emit translated (item); + } + finishTranslation (); +} + +void WebTranslator::abortTranslation () { + emit error (tr ("Перевод отменен по таймауту.")); + finishTranslation (); +} + +void WebTranslator::loadFinished (bool ok) { + if (!ok) { + QString url = view_->url ().toString (); + emit error (tr ("Ошибка загрузки страницы (%1) для перевода.").arg (url)); + finishTranslation (); + } +} + +void WebTranslator::finishTranslation () { + translationTimeout_.stop (); + if (!queue_.isEmpty ()) { + queue_.pop_front (); + } + isReady_ = true; + translateQueued (); +} + +void WebTranslator::replyFinished (QNetworkReply *reply) { + emit proxy_->resourceLoaded (reply->url ().toString ()); +} + +void WebTranslator::applySettings () { + QSettings settings; + settings.beginGroup (settings_names::translationGroup); +#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME) + translationTimeout_.setInterval (GET (translationTimeout).toInt () * 1000); +#undef GET + + QFile f ("translators/google.js"); + if (f.open (QFile::ReadOnly)) { + script_ = QString::fromUtf8 (f.readAll ()); + if (script_.isEmpty ()) { + emit error (tr ("Пустой сценарий для перевода. Перевод недоступен.")); + } + } + else { + emit error (tr ("Не считан сценарий для перевода. Перевод недоступен.")); + } +} + +void WebTranslator::setDebugMode (bool isOn) { + view_->setVisible (isOn); +} diff --git a/WebTranslator.h b/WebTranslator.h new file mode 100644 index 0000000..7f79114 --- /dev/null +++ b/WebTranslator.h @@ -0,0 +1,53 @@ +#ifndef WEBTRANSLATOR_H +#define WEBTRANSLATOR_H + +#include +#include +#include + +#include "ProcessingItem.h" + +class QWebView; +class QNetworkReply; + +class WebTranslatorProxy; + +class WebTranslator : public QObject { + Q_OBJECT + + public: + explicit WebTranslator (); + ~WebTranslator (); + + signals: + void translated (ProcessingItem item); + void error (QString text); + + public slots: + void translate (ProcessingItem item); + void applySettings (); + void setDebugMode (bool isOn); + + private slots: + void loadFinished (bool ok); + void replyFinished (QNetworkReply *reply); + void addProxyToView (); + void abortTranslation (); + void proxyError (const QString &message); + void proxyTranslated (const QString &text); + + private: + void translateQueued (); + void runScriptForItem (const ProcessingItem &item); + void finishTranslation (); + + private: + WebTranslatorProxy *proxy_; + QWebView *view_; + QVector queue_; + bool isReady_; + QString script_; + QTimer translationTimeout_; +}; + +#endif // WEBTRANSLATOR_H diff --git a/WebTranslatorProxy.cpp b/WebTranslatorProxy.cpp new file mode 100644 index 0000000..b298baa --- /dev/null +++ b/WebTranslatorProxy.cpp @@ -0,0 +1,25 @@ +#include "WebTranslatorProxy.h" +#include "ProcessingItem.h" + +WebTranslatorProxy::WebTranslatorProxy (QObject *parent) + : QObject (parent) { +} + +void WebTranslatorProxy::setItem (const ProcessingItem &item) { + sourceText_ = item.recognized; + sourceLanguage_ = item.ocrLanguage; + resultLanguage_ = item.translateLanguage; +} + +const QString &WebTranslatorProxy::sourceText () const { + return sourceText_; +} + +const QString &WebTranslatorProxy::sourceLanguage () const { + return sourceLanguage_; +} + +const QString &WebTranslatorProxy::resultLanguage () const { + return resultLanguage_; +} + diff --git a/WebTranslatorProxy.h b/WebTranslatorProxy.h new file mode 100644 index 0000000..1ff4220 --- /dev/null +++ b/WebTranslatorProxy.h @@ -0,0 +1,38 @@ +#ifndef WEBTRANSLATORPROXY_H +#define WEBTRANSLATORPROXY_H + +#include + +class ProcessingItem; + +/*! + * \brief Proxy class between WebTranslator and QWebView. + */ +class WebTranslatorProxy : public QObject { + Q_OBJECT + Q_PROPERTY (QString sourceText READ sourceText) + Q_PROPERTY (QString sourceLanguage READ sourceLanguage) + Q_PROPERTY (QString resultLanguage READ resultLanguage) + + public: + explicit WebTranslatorProxy (QObject *parent = 0); + + void setItem (const ProcessingItem &item); + + const QString &sourceText () const; + const QString &sourceLanguage () const; + const QString &resultLanguage () const; + + signals: + void translated (const QString &text); + void error (const QString &message); + + void resourceLoaded (const QString &url); + + private: + QString sourceText_; + QString sourceLanguage_; + QString resultLanguage_; +}; + +#endif // WEBTRANSLATORPROXY_H diff --git a/translators/google.js b/translators/google.js new file mode 100644 index 0000000..11f0499 --- /dev/null +++ b/translators/google.js @@ -0,0 +1,31 @@ +var isPageLoaded = false; +var isTranslationFinished = false; // async translation request + +function checkFinished () { + if (!isPageLoaded || !isTranslationFinished) return; + setTimeout(function () { + var spans = [].slice.call (document.querySelectorAll ('#result_box > span')); + var text = spans.reduce (function (res, i) { + return res + ' ' + i.innerText; + }, ''); + st_wtp.translated (text); + }, 500); // wait for gui fill +} +function onResourceLoad (url) { + if (url.indexOf ('/translate_a/single') > -1) { + isTranslationFinished = true; + checkFinished (); + } +} +st_wtp.resourceLoaded.connect (onResourceLoad); +function onPageLoad () { + isPageLoaded = true; + checkFinished (); +} +window.onload = onPageLoad(); + +function translate (){ + var url = 'https://translate.google.com/#auto/' + + st_wtp.resultLanguage + '/' + st_wtp.sourceText; + window.location = url; +}