Füge Unterstützung für LibreTranslate hinzu und verbessere die Benutzeroberfläche
This commit is contained in:
77
docs/libretranslate.md
Normal file
77
docs/libretranslate.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Lokaler LibreTranslate-Server
|
||||||
|
|
||||||
|
LibreTranslate stellt eine HTTP-API auf dem eigenen Rechner bereit. Es werden keine
|
||||||
|
Texte an einen externen Übersetzungsdienst gesendet. Die Standardadresse ist
|
||||||
|
`http://localhost:5000`.
|
||||||
|
|
||||||
|
## Installation unter Linux
|
||||||
|
|
||||||
|
Voraussetzung: Python 3.8 oder neuer. In einem Terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv ~/.local/share/libretranslate-venv
|
||||||
|
~/.local/share/libretranslate-venv/bin/pip install --upgrade pip libretranslate
|
||||||
|
~/.local/share/libretranslate-venv/bin/libretranslate
|
||||||
|
```
|
||||||
|
|
||||||
|
Beim ersten Start werden Sprachmodelle geladen. Für weniger Speicherbedarf kann man
|
||||||
|
nur benötigte Sprachen laden, beispielsweise Englisch und Deutsch:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/.local/share/libretranslate-venv/bin/libretranslate --load-only en,de
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Server bleibt im Terminal aktiv. Anschließend in Renpy Translation Helper im
|
||||||
|
Auswahlfeld **Provider** `LibreTranslate (local)` wählen. Die voreingestellte lokale
|
||||||
|
URL `http://localhost:5000` übernehmen oder anpassen. Die verfügbaren Sprachpaare
|
||||||
|
werden automatisch geladen.
|
||||||
|
|
||||||
|
## Nur Englisch und Deutsch nachinstallieren
|
||||||
|
|
||||||
|
Wurde ein erster Start ohne `--load-only` abgebrochen, können bereits einige
|
||||||
|
unpassende Modelle installiert sein. Den Server mit `Strg+C` beenden und die zwei
|
||||||
|
benötigten Richtungen explizit installieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/.local/share/libretranslate-venv/bin/argospm update
|
||||||
|
~/.local/share/libretranslate-venv/bin/argospm install translate-en_de
|
||||||
|
~/.local/share/libretranslate-venv/bin/argospm install translate-de_en
|
||||||
|
~/.local/share/libretranslate-venv/bin/libretranslate --load-only en,de
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit `curl http://127.0.0.1:5000/languages` prüfen, ob sowohl `en` mit Ziel `de`
|
||||||
|
als auch `de` mit Ziel `en` aufgelistet wird. Erst dann kann die App diese
|
||||||
|
Sprachrichtung anbieten.
|
||||||
|
|
||||||
|
## Nutzung durch andere Anwendungen
|
||||||
|
|
||||||
|
Sprachen abfragen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:5000/languages
|
||||||
|
```
|
||||||
|
|
||||||
|
Einen Text übersetzen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/translate \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"q":"Hello world","source":"en","target":"de","format":"text"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Für mehrere Texte kann `q` ein Array sein:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/translate \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"q":["Hello","Good night"],"source":"en","target":"de","format":"text"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Antwort enthält `translatedText` – bei mehreren Eingaben ebenfalls als Array.
|
||||||
|
|
||||||
|
## Hinweis zu AMD-Grafikkarten
|
||||||
|
|
||||||
|
LibreTranslate/Argos Translate verwendet regulär die CPU. Die offiziell dokumentierte
|
||||||
|
GPU-Beschleunigung setzt CUDA voraus und ist damit für Nvidia vorgesehen. Eine
|
||||||
|
AMD-GPU wird in diesem Standard-Setup nicht genutzt; für normale Ren'Py-Dialoge ist
|
||||||
|
der CPU-Betrieb dennoch brauchbar.
|
||||||
178
mainwindow.cpp
178
mainwindow.cpp
@@ -22,6 +22,7 @@
|
|||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QLocale>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
@@ -154,6 +155,13 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
ui->deeplApiKey->setText(configuration["deepl-key"].toString());
|
ui->deeplApiKey->setText(configuration["deepl-key"].toString());
|
||||||
loadDeeplTranslationPossibilities();
|
loadDeeplTranslationPossibilities();
|
||||||
}
|
}
|
||||||
|
if (configuration.contains("libretranslate-url")) {
|
||||||
|
ui->libreTranslateUrl->setText(configuration["libretranslate-url"].toString());
|
||||||
|
}
|
||||||
|
if (configuration.contains("translation-provider")) {
|
||||||
|
ui->translationProviderCombo->setCurrentText(configuration["translation-provider"].toString());
|
||||||
|
}
|
||||||
|
on_translationProviderCombo_currentIndexChanged(ui->translationProviderCombo->currentIndex());
|
||||||
if (configuration.contains("last-dir") && (QDir()).exists(configuration["last-dir"].toString())) {
|
if (configuration.contains("last-dir") && (QDir()).exists(configuration["last-dir"].toString())) {
|
||||||
ui->projectDir->setText(configuration["last-dir"].toString());
|
ui->projectDir->setText(configuration["last-dir"].toString());
|
||||||
crawlProject();
|
crawlProject();
|
||||||
@@ -164,6 +172,67 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
noConfigChange = false;
|
noConfigChange = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::isLibreTranslateProvider() const
|
||||||
|
{
|
||||||
|
return ui->translationProviderCombo->currentIndex() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::libreTranslateUrl(const QString &path) const
|
||||||
|
{
|
||||||
|
return ui->libreTranslateUrl->text().trimmed().replace(QRegularExpression("/+$/"), "") + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_translationProviderCombo_currentIndexChanged(int)
|
||||||
|
{
|
||||||
|
const bool libreTranslate = isLibreTranslateProvider();
|
||||||
|
ui->label_9->setVisible(!libreTranslate);
|
||||||
|
ui->deeplApiKey->setVisible(!libreTranslate);
|
||||||
|
ui->checkDeeplUsageButton->setVisible(!libreTranslate);
|
||||||
|
ui->libreTranslateUrlLabel->setVisible(libreTranslate);
|
||||||
|
ui->libreTranslateUrl->setVisible(libreTranslate);
|
||||||
|
setConfigValue("translation-provider", ui->translationProviderCombo->currentText());
|
||||||
|
if (libreTranslate) {
|
||||||
|
loadLibreTranslateLanguages();
|
||||||
|
} else {
|
||||||
|
translationsMap.clear();
|
||||||
|
loadDeeplTranslationPossibilities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_libreTranslateUrl_editingFinished()
|
||||||
|
{
|
||||||
|
setConfigValue("libretranslate-url", ui->libreTranslateUrl->text().trimmed());
|
||||||
|
if (isLibreTranslateProvider()) {
|
||||||
|
loadLibreTranslateLanguages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadLibreTranslateLanguages()
|
||||||
|
{
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||||
|
connect(manager, &QNetworkAccessManager::finished, this, [this, manager](QNetworkReply *reply) {
|
||||||
|
if (!isLibreTranslateProvider()) {
|
||||||
|
// The provider changed while this request was in flight.
|
||||||
|
} else if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
ui->statusbar->showMessage(tr("LibreTranslate nicht erreichbar: %1").arg(reply->errorString()), 6000);
|
||||||
|
} else {
|
||||||
|
translationsMap.clear();
|
||||||
|
const QJsonArray languages = QJsonDocument::fromJson(reply->readAll()).array();
|
||||||
|
for (const QJsonValue &value : languages) {
|
||||||
|
const QJsonObject language = value.toObject();
|
||||||
|
const QString source = language.value("code").toString();
|
||||||
|
for (const QJsonValue &target : language.value("targets").toArray()) {
|
||||||
|
translationsMap[source].push_back(target.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderDeeplSources();
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
});
|
||||||
|
manager->get(QNetworkRequest(QUrl(libreTranslateUrl("/languages"))));
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
@@ -559,6 +628,9 @@ void MainWindow::renderDeeplSources()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onDeeplTranslationPossibilitiesLoaded(QNetworkReply *reply) {
|
void MainWindow::onDeeplTranslationPossibilitiesLoaded(QNetworkReply *reply) {
|
||||||
|
if (isLibreTranslateProvider()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
QByteArray responseData = reply->readAll();
|
QByteArray responseData = reply->readAll();
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||||
@@ -638,7 +710,8 @@ void MainWindow::on_deeplTranslateFrom_currentTextChanged(const QString &sourceL
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_autoTranslateButton_clicked() {
|
void MainWindow::on_autoTranslateButton_clicked() {
|
||||||
if (ui->deeplApiKey->text().isEmpty()) {
|
const bool libreTranslate = isLibreTranslateProvider();
|
||||||
|
if (!libreTranslate && ui->deeplApiKey->text().isEmpty()) {
|
||||||
QMessageBox::information(this, "Deepl error", "For auto translation, you need to add a deepl API key.");
|
QMessageBox::information(this, "Deepl error", "For auto translation, you need to add a deepl API key.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -648,21 +721,29 @@ void MainWindow::on_autoTranslateButton_clicked() {
|
|||||||
QJsonObject jsonData;
|
QJsonObject jsonData;
|
||||||
// Protect Mustache-/Platzhalter vor DeepL-Übersetzung
|
// Protect Mustache-/Platzhalter vor DeepL-Übersetzung
|
||||||
QString protectedText = protectPlaceholdersForDeepl(originalText);
|
QString protectedText = protectPlaceholdersForDeepl(originalText);
|
||||||
|
if (libreTranslate) {
|
||||||
|
jsonData["q"] = protectedText;
|
||||||
|
jsonData["source"] = sourceLang;
|
||||||
|
jsonData["target"] = targetLang;
|
||||||
|
jsonData["format"] = "text";
|
||||||
|
} else {
|
||||||
jsonData["text"] = QJsonArray::fromStringList({protectedText});
|
jsonData["text"] = QJsonArray::fromStringList({protectedText});
|
||||||
jsonData["source_lang"] = sourceLang;
|
jsonData["source_lang"] = sourceLang;
|
||||||
jsonData["target_lang"] = targetLang;
|
jsonData["target_lang"] = targetLang;
|
||||||
jsonData["formality"] = "less";
|
jsonData["formality"] = "less";
|
||||||
// Use XML tag handling so our <x id="N"/> placeholders are preserved
|
|
||||||
jsonData["tag_handling"] = "xml";
|
jsonData["tag_handling"] = "xml";
|
||||||
jsonData["tag_handling_version"] = "v2";
|
jsonData["tag_handling_version"] = "v2";
|
||||||
QUrl url("https://api-free.deepl.com/v2/translate");
|
}
|
||||||
|
QUrl url(libreTranslate ? libreTranslateUrl("/translate") : QStringLiteral("https://api-free.deepl.com/v2/translate"));
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
if (!libreTranslate) {
|
||||||
request.setRawHeader("Authorization", "DeepL-Auth-Key " + ui->deeplApiKey->text().toUtf8());
|
request.setRawHeader("Authorization", "DeepL-Auth-Key " + ui->deeplApiKey->text().toUtf8());
|
||||||
|
}
|
||||||
static int attempt = 1;
|
static int attempt = 1;
|
||||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||||
connect(manager, &QNetworkAccessManager::finished, this,
|
connect(manager, &QNetworkAccessManager::finished, this,
|
||||||
[this, manager, jsonData, request](QNetworkReply *reply) mutable {
|
[this, manager, jsonData, request, libreTranslate](QNetworkReply *reply) mutable {
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
qDebug() << "Translation request failed:" << reply->errorString();
|
qDebug() << "Translation request failed:" << reply->errorString();
|
||||||
qDebug() << "Attempt:" << attempt;
|
qDebug() << "Attempt:" << attempt;
|
||||||
@@ -675,7 +756,7 @@ void MainWindow::on_autoTranslateButton_clicked() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
attempt = 1;
|
attempt = 1;
|
||||||
translationRequestFinished(reply);
|
translationRequestFinished(reply, libreTranslate);
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
manager->deleteLater();
|
manager->deleteLater();
|
||||||
@@ -686,7 +767,8 @@ void MainWindow::on_autoTranslateButton_clicked() {
|
|||||||
|
|
||||||
void MainWindow::on_bulkAutoTranslateButton_clicked()
|
void MainWindow::on_bulkAutoTranslateButton_clicked()
|
||||||
{
|
{
|
||||||
if (ui->deeplApiKey->text().isEmpty()) {
|
bulkUsesLibreTranslate = isLibreTranslateProvider();
|
||||||
|
if (!bulkUsesLibreTranslate && ui->deeplApiKey->text().isEmpty()) {
|
||||||
QMessageBox::information(this, tr("DeepL error"), tr("Für die automatische Übersetzung wird ein DeepL-API-Key benötigt."));
|
QMessageBox::information(this, tr("DeepL error"), tr("Für die automatische Übersetzung wird ein DeepL-API-Key benötigt."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -718,6 +800,54 @@ void MainWindow::on_bulkAutoTranslateButton_clicked()
|
|||||||
requestNextBulkTranslationBatch();
|
requestNextBulkTranslationBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_checkDeeplUsageButton_clicked()
|
||||||
|
{
|
||||||
|
if (ui->deeplApiKey->text().isEmpty()) {
|
||||||
|
QMessageBox::information(this, tr("DeepL error"), tr("Bitte hinterlege zuerst einen DeepL-API-Key."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->checkDeeplUsageButton->setEnabled(false);
|
||||||
|
ui->statusbar->showMessage(tr("DeepL-Kontingent wird geprüft …"));
|
||||||
|
QNetworkRequest request(QUrl("https://api-free.deepl.com/v2/usage"));
|
||||||
|
request.setRawHeader("Authorization", "DeepL-Auth-Key " + ui->deeplApiKey->text().toUtf8());
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||||
|
connect(manager, &QNetworkAccessManager::finished, this, [this, manager](QNetworkReply *reply) {
|
||||||
|
ui->checkDeeplUsageButton->setEnabled(true);
|
||||||
|
ui->statusbar->clearMessage();
|
||||||
|
const QByteArray responseBody = reply->readAll();
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
QString details;
|
||||||
|
const QJsonDocument response = QJsonDocument::fromJson(responseBody);
|
||||||
|
if (response.isObject()) {
|
||||||
|
details = response.object().value("message").toString();
|
||||||
|
}
|
||||||
|
QMessageBox::critical(this, tr("DeepL error"),
|
||||||
|
tr("Das DeepL-Kontingent konnte nicht abgefragt werden: %1")
|
||||||
|
.arg(details.isEmpty() ? reply->errorString() : details));
|
||||||
|
} else {
|
||||||
|
const QJsonObject usage = QJsonDocument::fromJson(responseBody).object();
|
||||||
|
const qint64 usedCharacters = usage.value("character_count").toVariant().toLongLong();
|
||||||
|
const qint64 characterLimit = usage.value("character_limit").toVariant().toLongLong();
|
||||||
|
if (characterLimit <= 0) {
|
||||||
|
QMessageBox::critical(this, tr("DeepL error"), tr("DeepL hat keine gültigen Kontingentdaten geliefert."));
|
||||||
|
} else {
|
||||||
|
const qint64 remainingCharacters = characterLimit - usedCharacters;
|
||||||
|
const double usedPercentage = 100.0 * usedCharacters / characterLimit;
|
||||||
|
QMessageBox::information(this, tr("DeepL-Kontingent"),
|
||||||
|
tr("Verbraucht: %1 von %2 Zeichen (%3 %).\nVerfügbar: %4 Zeichen.")
|
||||||
|
.arg(QLocale().toString(usedCharacters),
|
||||||
|
QLocale().toString(characterLimit),
|
||||||
|
QLocale().toString(usedPercentage, 'f', 1),
|
||||||
|
QLocale().toString(remainingCharacters)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
});
|
||||||
|
manager->get(request);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::requestNextBulkTranslationBatch()
|
void MainWindow::requestNextBulkTranslationBatch()
|
||||||
{
|
{
|
||||||
if (nextBulkTranslationIndex >= bulkTranslations.size()) {
|
if (nextBulkTranslationIndex >= bulkTranslations.size()) {
|
||||||
@@ -744,16 +874,25 @@ void MainWindow::requestNextBulkTranslationBatch()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject payload;
|
QJsonObject payload;
|
||||||
|
if (bulkUsesLibreTranslate) {
|
||||||
|
payload["q"] = QJsonArray::fromStringList(texts);
|
||||||
|
payload["source"] = ui->deeplTranslateFrom->currentText();
|
||||||
|
payload["target"] = ui->deeplTranslateTo->currentText();
|
||||||
|
payload["format"] = "text";
|
||||||
|
} else {
|
||||||
payload["text"] = QJsonArray::fromStringList(texts);
|
payload["text"] = QJsonArray::fromStringList(texts);
|
||||||
payload["source_lang"] = ui->deeplTranslateFrom->currentText();
|
payload["source_lang"] = ui->deeplTranslateFrom->currentText();
|
||||||
payload["target_lang"] = ui->deeplTranslateTo->currentText();
|
payload["target_lang"] = ui->deeplTranslateTo->currentText();
|
||||||
payload["formality"] = "less";
|
payload["formality"] = "less";
|
||||||
payload["tag_handling"] = "xml";
|
payload["tag_handling"] = "xml";
|
||||||
payload["tag_handling_version"] = "v2";
|
payload["tag_handling_version"] = "v2";
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkRequest request(QUrl("https://api-free.deepl.com/v2/translate"));
|
QNetworkRequest request(QUrl(bulkUsesLibreTranslate ? libreTranslateUrl("/translate") : QStringLiteral("https://api-free.deepl.com/v2/translate")));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
if (!bulkUsesLibreTranslate) {
|
||||||
request.setRawHeader("Authorization", "DeepL-Auth-Key " + ui->deeplApiKey->text().toUtf8());
|
request.setRawHeader("Authorization", "DeepL-Auth-Key " + ui->deeplApiKey->text().toUtf8());
|
||||||
|
}
|
||||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||||
connect(manager, &QNetworkAccessManager::finished, this,
|
connect(manager, &QNetworkAccessManager::finished, this,
|
||||||
[this, manager, firstItem, itemCount = texts.size()](QNetworkReply *reply) {
|
[this, manager, firstItem, itemCount = texts.size()](QNetworkReply *reply) {
|
||||||
@@ -769,13 +908,21 @@ void MainWindow::handleBulkTranslationReply(QNetworkReply *reply, int firstItem,
|
|||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
ui->bulkAutoTranslateButton->setEnabled(true);
|
ui->bulkAutoTranslateButton->setEnabled(true);
|
||||||
ui->statusbar->clearMessage();
|
ui->statusbar->clearMessage();
|
||||||
QMessageBox::critical(this, tr("DeepL error"), tr("Die Sammelübersetzung ist fehlgeschlagen: %1").arg(reply->errorString()));
|
const int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
const QString errorMessage = httpStatus == 456
|
||||||
|
? tr("Das DeepL-Zeichenkontingent für diesen API-Key ist ausgeschöpft. "
|
||||||
|
"Bei API Free wird es im nächsten Abrechnungszeitraum zurückgesetzt; bei API Pro prüfe bitte das Cost-Control-Limit.")
|
||||||
|
: tr("Die Sammelübersetzung ist fehlgeschlagen: %1").arg(reply->errorString());
|
||||||
|
QMessageBox::critical(this, tr("DeepL error"), errorMessage);
|
||||||
bulkTranslations.clear();
|
bulkTranslations.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
|
const QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
|
||||||
const QJsonArray translations = response.object().value("translations").toArray();
|
const QJsonObject responseObject = response.object();
|
||||||
|
const QJsonArray translations = bulkUsesLibreTranslate
|
||||||
|
? responseObject.value("translatedText").toArray()
|
||||||
|
: responseObject.value("translations").toArray();
|
||||||
if (translations.size() != itemCount) {
|
if (translations.size() != itemCount) {
|
||||||
ui->bulkAutoTranslateButton->setEnabled(true);
|
ui->bulkAutoTranslateButton->setEnabled(true);
|
||||||
ui->statusbar->clearMessage();
|
ui->statusbar->clearMessage();
|
||||||
@@ -785,7 +932,9 @@ void MainWindow::handleBulkTranslationReply(QNetworkReply *reply, int firstItem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < translations.size(); ++index) {
|
for (int index = 0; index < translations.size(); ++index) {
|
||||||
QString translatedText = translations.at(index).toObject().value("text").toString();
|
QString translatedText = bulkUsesLibreTranslate
|
||||||
|
? translations.at(index).toString()
|
||||||
|
: translations.at(index).toObject().value("text").toString();
|
||||||
BulkTranslationItem &item = bulkTranslations[firstItem + index];
|
BulkTranslationItem &item = bulkTranslations[firstItem + index];
|
||||||
item.translatedText = restoreBulkPlaceholders(translatedText, item.placeholders);
|
item.translatedText = restoreBulkPlaceholders(translatedText, item.placeholders);
|
||||||
item.translatedText.replace('"', '\'');
|
item.translatedText.replace('"', '\'');
|
||||||
@@ -915,16 +1064,17 @@ void MainWindow::showBulkTranslationDialog()
|
|||||||
bulkTranslations.clear();
|
bulkTranslations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::translationRequestFinished(QNetworkReply *reply) {
|
void MainWindow::translationRequestFinished(QNetworkReply *reply, bool isLibreTranslate) {
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
QByteArray responseData = reply->readAll();
|
QByteArray responseData = reply->readAll();
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
||||||
if (!jsonResponse.isNull() && jsonResponse.isObject()) {
|
if (!jsonResponse.isNull() && jsonResponse.isObject()) {
|
||||||
QJsonObject jsonObject = jsonResponse.object();
|
QJsonObject jsonObject = jsonResponse.object();
|
||||||
QJsonArray translationsArray = jsonObject["translations"].toArray();
|
QJsonArray translationsArray = jsonObject["translations"].toArray();
|
||||||
if (!translationsArray.isEmpty()) {
|
if (isLibreTranslate || !translationsArray.isEmpty()) {
|
||||||
QJsonObject translationObject = translationsArray[0].toObject();
|
QString translatedText = isLibreTranslate
|
||||||
QString translatedText = translationObject["text"].toString();
|
? jsonObject["translatedText"].toString()
|
||||||
|
: translationsArray[0].toObject()["text"].toString();
|
||||||
// Restore any placeholders that were protected before the request
|
// Restore any placeholders that were protected before the request
|
||||||
QString restored = restorePlaceholdersFromDeepl(translatedText);
|
QString restored = restorePlaceholdersFromDeepl(translatedText);
|
||||||
restored.replace("\"", "'");
|
restored.replace("\"", "'");
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ private slots:
|
|||||||
void on_deeplTranslateFrom_currentTextChanged(const QString &sourceLanguage);
|
void on_deeplTranslateFrom_currentTextChanged(const QString &sourceLanguage);
|
||||||
void on_autoTranslateButton_clicked();
|
void on_autoTranslateButton_clicked();
|
||||||
void on_bulkAutoTranslateButton_clicked();
|
void on_bulkAutoTranslateButton_clicked();
|
||||||
|
void on_checkDeeplUsageButton_clicked();
|
||||||
|
void on_translationProviderCombo_currentIndexChanged(int index);
|
||||||
|
void on_libreTranslateUrl_editingFinished();
|
||||||
void on_searchButton_clicked();
|
void on_searchButton_clicked();
|
||||||
void on_searchNextButton_clicked();
|
void on_searchNextButton_clicked();
|
||||||
void on_deeplApiKey_editingFinished();
|
void on_deeplApiKey_editingFinished();
|
||||||
@@ -83,7 +86,10 @@ private:
|
|||||||
QString findNewText(QTreeWidgetItem *fileItem, const QString &lineNumber, const QString &originalText, const QString &speaker);
|
QString findNewText(QTreeWidgetItem *fileItem, const QString &lineNumber, const QString &originalText, const QString &speaker);
|
||||||
void loadDeeplTranslationPossibilities();
|
void loadDeeplTranslationPossibilities();
|
||||||
void renderDeeplSources();
|
void renderDeeplSources();
|
||||||
void translationRequestFinished(QNetworkReply *reply);
|
void translationRequestFinished(QNetworkReply *reply, bool isLibreTranslate = false);
|
||||||
|
void loadLibreTranslateLanguages();
|
||||||
|
bool isLibreTranslateProvider() const;
|
||||||
|
QString libreTranslateUrl(const QString &path) const;
|
||||||
void requestNextBulkTranslationBatch();
|
void requestNextBulkTranslationBatch();
|
||||||
void handleBulkTranslationReply(QNetworkReply *reply, int firstItem, int itemCount);
|
void handleBulkTranslationReply(QNetworkReply *reply, int firstItem, int itemCount);
|
||||||
void showBulkTranslationDialog();
|
void showBulkTranslationDialog();
|
||||||
@@ -98,5 +104,6 @@ private:
|
|||||||
QString restorePlaceholdersFromDeepl(const QString &input);
|
QString restorePlaceholdersFromDeepl(const QString &input);
|
||||||
QVector<BulkTranslationItem> bulkTranslations;
|
QVector<BulkTranslationItem> bulkTranslations;
|
||||||
int nextBulkTranslationIndex{0};
|
int nextBulkTranslationIndex{0};
|
||||||
|
bool bulkUsesLibreTranslate{false};
|
||||||
};
|
};
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|||||||
466
mainwindow.ui
Executable file → Normal file
466
mainwindow.ui
Executable file → Normal file
@@ -2,412 +2,106 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>MainWindow</class>
|
<class>MainWindow</class>
|
||||||
<widget class="QMainWindow" name="MainWindow">
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
<property name="geometry">
|
<property name="geometry"><rect><x>0</x><y>0</y><width>1280</width><height>820</height></rect></property>
|
||||||
<rect>
|
<property name="windowTitle"><string>Ren'Py Translation Helper</string></property>
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1266</width>
|
|
||||||
<height>774</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Renpy Translation Helper</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
<widget class="QWidget" name="layoutWidget">
|
<layout class="QVBoxLayout" name="mainLayout">
|
||||||
<property name="geometry">
|
<property name="spacing"><number>10</number></property>
|
||||||
<rect>
|
<property name="leftMargin"><number>12</number></property>
|
||||||
<x>10</x>
|
<property name="topMargin"><number>12</number></property>
|
||||||
<y>10</y>
|
<property name="rightMargin"><number>12</number></property>
|
||||||
<width>1233</width>
|
<property name="bottomMargin"><number>12</number></property>
|
||||||
<height>732</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<widget class="QGroupBox" name="projectGroup">
|
||||||
<item>
|
<property name="title"><string>Projekt</string></property>
|
||||||
<widget class="QLabel" name="label">
|
<layout class="QHBoxLayout" name="projectLayout">
|
||||||
<property name="text">
|
<item><widget class="QLabel" name="projectDirectoryLabel"><property name="text"><string>Projektordner</string></property></widget></item>
|
||||||
<string>Project Directory</string>
|
<item><widget class="QLineEdit" name="projectDir"><property name="minimumSize"><size><width>480</width><height>0</height></size></property></widget></item>
|
||||||
</property>
|
<item><widget class="QPushButton" name="selectProjectDirButton"><property name="toolTip"><string>Projektordner auswählen</string></property><property name="text"><string>…</string></property></widget></item>
|
||||||
</widget>
|
<item><widget class="QPushButton" name="reloadTranslationsButton"><property name="text"><string>Übersetzungen laden</string></property></widget></item>
|
||||||
</item>
|
<item><spacer name="projectSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>16</width><height>20</height></size></property></spacer></item>
|
||||||
<item>
|
<item><widget class="QLabel" name="languageLabel"><property name="text"><string>Sprache</string></property></widget></item>
|
||||||
<widget class="QLineEdit" name="projectDir">
|
<item><widget class="QComboBox" name="languageCombo"><property name="minimumSize"><size><width>180</width><height>0</height></size></property></widget></item>
|
||||||
<property name="minimumSize">
|
<item><widget class="QPushButton" name="reloadFilesButton"><property name="text"><string>Dateien neu laden</string></property></widget></item>
|
||||||
<size>
|
|
||||||
<width>500</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="selectProjectDirButton">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>27</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="reloadTranslationsButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Reload</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Language</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="languageCombo">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>200</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="reloadFilesButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Reload</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTreeWidget" name="treeWidget">
|
<widget class="QTreeWidget" name="treeWidget">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize"><size><width>0</width><height>300</height></size></property>
|
||||||
<size>
|
<property name="alternatingRowColors"><bool>true</bool></property>
|
||||||
<width>1231</width>
|
<property name="uniformRowHeights"><bool>true</bool></property>
|
||||||
<height>400</height>
|
<column><property name="text"><string>Datei / Zeile</string></property></column>
|
||||||
</size>
|
<column><property name="text"><string>Sprecher</string></property></column>
|
||||||
</property>
|
<column><property name="text"><string>Original</string></property></column>
|
||||||
<column>
|
<column><property name="text"><string>Übersetzung</string></property></column>
|
||||||
<property name="text">
|
|
||||||
<string>File</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Speaker</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Original</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Translation</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>All items</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<widget class="QGroupBox" name="editorGroup">
|
||||||
|
<property name="title"><string>Übersetzung bearbeiten</string></property>
|
||||||
|
<layout class="QVBoxLayout" name="editorLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="nextUntranslatedButton">
|
<layout class="QHBoxLayout" name="navigationLayout">
|
||||||
<property name="text">
|
<item><widget class="QPushButton" name="nextUntranslatedButton"><property name="text"><string>Nächster offener Text</string></property></widget></item>
|
||||||
<string>Jump to next untranslated item</string>
|
<item><widget class="QToolButton" name="searchButton"><property name="text"><string>Suchen</string></property></widget></item>
|
||||||
</property>
|
<item><widget class="QToolButton" name="searchNextButton"><property name="text"><string>Weiter</string></property></widget></item>
|
||||||
</widget>
|
<item><spacer name="navigationSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item>
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>137</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Deepl Translate from</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="deeplTranslateFrom"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>to</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="deeplTranslateTo"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_9">
|
|
||||||
<property name="text">
|
|
||||||
<string>Deepl API Key</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="deeplApiKey">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>200</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="autoTranslateButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Auto translate</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="bulkAutoTranslateButton">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Translate all untranslated texts and review the suggestions before applying them.</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Translate all open texts</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
<layout class="QFormLayout" name="textFormLayout">
|
||||||
<item>
|
<item row="0" column="0"><widget class="QLabel" name="originalTextLabel"><property name="text"><string>Originaltext</string></property></widget></item>
|
||||||
<widget class="QToolButton" name="searchButton">
|
<item row="0" column="1"><widget class="QLineEdit" name="originalTextEdit"/></item>
|
||||||
<property name="text">
|
<item row="0" column="2"><widget class="QPushButton" name="copyButton"><property name="text"><string>Kopieren</string></property></widget></item>
|
||||||
<string>Search</string>
|
<item row="1" column="0"><widget class="QLabel" name="translationLabel"><property name="text"><string>Übersetzung</string></property></widget></item>
|
||||||
</property>
|
<item row="1" column="1" colspan="2"><widget class="QLineEdit" name="translationEdit"/></item>
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="searchNextButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Next</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="translationActionLayout">
|
||||||
<item>
|
<item><widget class="QPushButton" name="setTranslationButton"><property name="text"><string>Übernehmen</string></property></widget></item>
|
||||||
<widget class="QLabel" name="label_3">
|
<item><widget class="QPushButton" name="setTranslationAndJumpNextButton"><property name="text"><string>Übernehmen && weiter</string></property></widget></item>
|
||||||
<property name="text">
|
<item><widget class="QPushButton" name="setAndNextAndAutoTranslate"><property name="text"><string>Übernehmen, weiter && automatisch übersetzen</string></property></widget></item>
|
||||||
<string>Original Text:</string>
|
<item><spacer name="translationActionSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="originalTextEdit">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="copyButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Copy</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Translation:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="translationEdit"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="setTranslationButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Set translation</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="setTranslationAndJumpNextButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Set translation and jump to next untranslated</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="setAndNextAndAutoTranslate">
|
|
||||||
<property name="text">
|
|
||||||
<string>Set translation, jump to next untranslated and auto translate</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enter action:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="enterActionCombo">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>400</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Set translation, jump to next untranslated and auto translate</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Set translation and jump to next untranslated</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Set translation</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_8">
|
|
||||||
<property name="text">
|
|
||||||
<string>Untranslated:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="untranslatedLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>0</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="saveButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save translations</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="cleanupAndSaveButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Delete backups and save translations</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="cleanupButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Delete backups</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="providerGroup">
|
||||||
|
<property name="title"><string>Automatische Übersetzung</string></property>
|
||||||
|
<layout class="QGridLayout" name="providerLayout">
|
||||||
|
<item row="0" column="0"><widget class="QLabel" name="translationProviderLabel"><property name="text"><string>Anbieter</string></property></widget></item>
|
||||||
|
<item row="0" column="1"><widget class="QComboBox" name="translationProviderCombo"><item><property name="text"><string>DeepL</string></property></item><item><property name="text"><string>LibreTranslate (lokal)</string></property></item></widget></item>
|
||||||
|
<item row="0" column="2"><widget class="QLabel" name="label_4"><property name="text"><string>Von</string></property></widget></item>
|
||||||
|
<item row="0" column="3"><widget class="QComboBox" name="deeplTranslateFrom"/></item>
|
||||||
|
<item row="0" column="4"><widget class="QLabel" name="label_5"><property name="text"><string>Nach</string></property></widget></item>
|
||||||
|
<item row="0" column="5"><widget class="QComboBox" name="deeplTranslateTo"/></item>
|
||||||
|
<item row="0" column="6"><widget class="QPushButton" name="autoTranslateButton"><property name="text"><string>Aktuellen Text übersetzen</string></property></widget></item>
|
||||||
|
<item row="1" column="0"><widget class="QLabel" name="label_9"><property name="text"><string>DeepL-API-Key</string></property></widget></item>
|
||||||
|
<item row="1" column="1" colspan="3"><widget class="QLineEdit" name="deeplApiKey"/></item>
|
||||||
|
<item row="1" column="4"><widget class="QPushButton" name="checkDeeplUsageButton"><property name="text"><string>Kontingent prüfen</string></property></widget></item>
|
||||||
|
<item row="1" column="5" colspan="2"><widget class="QPushButton" name="bulkAutoTranslateButton"><property name="text"><string>Alle offenen Texte übersetzen</string></property></widget></item>
|
||||||
|
<item row="2" column="0"><widget class="QLabel" name="libreTranslateUrlLabel"><property name="text"><string>Lokale URL</string></property></widget></item>
|
||||||
|
<item row="2" column="1" colspan="5"><widget class="QLineEdit" name="libreTranslateUrl"><property name="text"><string>http://localhost:5000</string></property></widget></item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="footerLayout">
|
||||||
|
<item><widget class="QLabel" name="label_7"><property name="text"><string>Eingabetaste</string></property></widget></item>
|
||||||
|
<item><widget class="QComboBox" name="enterActionCombo"><property name="minimumSize"><size><width>360</width><height>0</height></size></property><item><property name="text"><string>Übernehmen, weiter && automatisch übersetzen</string></property></item><item><property name="text"><string>Übernehmen && weiter</string></property></item><item><property name="text"><string>Nur übernehmen</string></property></item></widget></item>
|
||||||
|
<item><spacer name="footerSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item>
|
||||||
|
<item><widget class="QLabel" name="label_8"><property name="text"><string>Offen</string></property></widget></item>
|
||||||
|
<item><widget class="QLabel" name="untranslatedLabel"><property name="text"><string>0</string></property></widget></item>
|
||||||
|
<item><widget class="QPushButton" name="saveButton"><property name="text"><string>Übersetzungen speichern</string></property></widget></item>
|
||||||
|
<item><widget class="QPushButton" name="cleanupAndSaveButton"><property name="text"><string>Backups löschen && speichern</string></property></widget></item>
|
||||||
|
<item><widget class="QPushButton" name="cleanupButton"><property name="text"><string>Backups löschen</string></property></widget></item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
|||||||
Reference in New Issue
Block a user