Added WebTranslator class.

This commit is contained in:
Gres 2015-10-08 18:36:02 +03:00
parent f3c4f1c5b5
commit 01d969968e
9 changed files with 300 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>603</width>
<height>269</height>
<height>296</height>
</rect>
</property>
<property name="windowTitle">
@ -194,7 +194,7 @@
<string>Перевод</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="doTranslationCombo">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Необходимо ли переводить (вкл) распознанный текст.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -204,20 +204,37 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_9">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Максимальное время, которое может быть затрачено на перевод, чтобы он не считался &amp;quot;зависшим&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Максимальное время перевода:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="translateTimeoutSpin">
<property name="suffix">
<string> сек.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Язык, на который осуществляется перевод.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Язык результата</string>
<string>Язык результата:</string>
</property>
<property name="buddy">
<cstring>translateLangCombo</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1" colspan="2">
<widget class="QComboBox" name="translateLangCombo"/>
</item>
</layout>

124
WebTranslator.cpp Normal file
View File

@ -0,0 +1,124 @@
#include <QWebView>
#include <QWebFrame>
#include <QSettings>
#include <QNetworkReply>
#include <QFile>
#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);
}

53
WebTranslator.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef WEBTRANSLATOR_H
#define WEBTRANSLATOR_H
#include <QObject>
#include <QMap>
#include <QTimer>
#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<ProcessingItem> queue_;
bool isReady_;
QString script_;
QTimer translationTimeout_;
};
#endif // WEBTRANSLATOR_H

25
WebTranslatorProxy.cpp Normal file
View File

@ -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_;
}

38
WebTranslatorProxy.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef WEBTRANSLATORPROXY_H
#define WEBTRANSLATORPROXY_H
#include <QObject>
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

31
translators/google.js Normal file
View File

@ -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;
}