Füge Funktion zur Überprüfung identischer Übersetzungen hinzu und aktualisiere die Benutzeroberfläche
This commit is contained in:
118
mainwindow.cpp
118
mainwindow.cpp
@@ -17,6 +17,8 @@
|
|||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QCryptographicHash>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@@ -454,7 +456,7 @@ void MainWindow::on_nextUntranslatedButton_clicked() {
|
|||||||
for (int j = 0; j < topLevelItem->childCount(); ++j) {
|
for (int j = 0; j < topLevelItem->childCount(); ++j) {
|
||||||
QTreeWidgetItem *childItem = topLevelItem->child(j);
|
QTreeWidgetItem *childItem = topLevelItem->child(j);
|
||||||
// Prüfe, ob Übersetzung (Spalte 3) leer ist
|
// Prüfe, ob Übersetzung (Spalte 3) leer ist
|
||||||
if (childItem->text(3).isEmpty()) {
|
if (isOpenTranslation(childItem)) {
|
||||||
ui->originalTextEdit->setText(childItem->text(2)); // Originaltext aus Spalte 2
|
ui->originalTextEdit->setText(childItem->text(2)); // Originaltext aus Spalte 2
|
||||||
ui->translationEdit->clear();
|
ui->translationEdit->clear();
|
||||||
ui->treeWidget->scrollToItem(childItem);
|
ui->treeWidget->scrollToItem(childItem);
|
||||||
@@ -622,9 +624,10 @@ bool MainWindow::parseAndEditFile(QFile &backupFile, QTreeWidgetItem *fileItem,
|
|||||||
auto oldText = match.captured(4);
|
auto oldText = match.captured(4);
|
||||||
auto newText = match.captured(6);
|
auto newText = match.captured(6);
|
||||||
auto replacedText = findNewText(fileItem, lineNumber, oldText, speaker);
|
auto replacedText = findNewText(fileItem, lineNumber, oldText, speaker);
|
||||||
QString toReplace = QString("\"%1\"").arg(newText).trimmed();
|
QString replacedBlock = block;
|
||||||
QString replacement = QString("\"%1\"").arg(replacedText.isEmpty() ? newText : replacedText);
|
const int translatedTextOffset = match.capturedStart(6) - match.capturedStart(0);
|
||||||
auto replacedBlock = block.replace(toReplace, replacement);
|
replacedBlock.replace(translatedTextOffset, match.capturedLength(6),
|
||||||
|
replacedText.isEmpty() ? newText : replacedText);
|
||||||
content.replace(match.capturedStart(0), match.capturedLength(0), replacedBlock);
|
content.replace(match.capturedStart(0), match.capturedLength(0), replacedBlock);
|
||||||
// The replacement can have a different length. Continue after the new
|
// The replacement can have a different length. Continue after the new
|
||||||
// block, otherwise later translations in this file may be skipped.
|
// block, otherwise later translations in this file may be skipped.
|
||||||
@@ -638,9 +641,10 @@ bool MainWindow::parseAndEditFile(QFile &backupFile, QTreeWidgetItem *fileItem,
|
|||||||
auto oldText = match.captured(3);
|
auto oldText = match.captured(3);
|
||||||
auto newText = match.captured(4);
|
auto newText = match.captured(4);
|
||||||
auto replacedText = findNewText(fileItem, lineNumber, oldText, "");
|
auto replacedText = findNewText(fileItem, lineNumber, oldText, "");
|
||||||
QString toReplace = QString("\"%1\"").arg(newText);
|
QString replacedBlock = block;
|
||||||
QString replacement = QString("\"%1\"").arg(replacedText.isEmpty() ? newText : replacedText);
|
const int translatedTextOffset = match.capturedStart(4) - match.capturedStart(0);
|
||||||
auto replacedBlock = block.replace(toReplace, replacement);
|
replacedBlock.replace(translatedTextOffset, match.capturedLength(4),
|
||||||
|
replacedText.isEmpty() ? newText : replacedText);
|
||||||
content.replace(match.capturedStart(0), match.capturedLength(0), replacedBlock);
|
content.replace(match.capturedStart(0), match.capturedLength(0), replacedBlock);
|
||||||
offset = match.capturedStart(0) + replacedBlock.size();
|
offset = match.capturedStart(0) + replacedBlock.size();
|
||||||
changed = true;
|
changed = true;
|
||||||
@@ -850,6 +854,66 @@ void MainWindow::on_retryTranslationButton_clicked()
|
|||||||
on_autoTranslateButton_clicked();
|
on_autoTranslateButton_clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_reviewIdenticalTranslationsButton_clicked()
|
||||||
|
{
|
||||||
|
QVector<QTreeWidgetItem *> candidates;
|
||||||
|
for (int fileIndex = 0; fileIndex < ui->treeWidget->topLevelItemCount(); ++fileIndex) {
|
||||||
|
QTreeWidgetItem *fileItem = ui->treeWidget->topLevelItem(fileIndex);
|
||||||
|
for (int itemIndex = 0; itemIndex < fileItem->childCount(); ++itemIndex) {
|
||||||
|
QTreeWidgetItem *item = fileItem->child(itemIndex);
|
||||||
|
if (!item->text(2).isEmpty() && item->text(2).trimmed() == item->text(3).trimmed()
|
||||||
|
&& !isIdenticalTranslationApproved(item)) {
|
||||||
|
candidates.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (candidates.isEmpty()) {
|
||||||
|
QMessageBox::information(this, tr("Gleiche Texte prüfen"), tr("Es gibt keine unbestätigten, originalgleichen Übersetzungen."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog dialog(this);
|
||||||
|
dialog.setWindowTitle(tr("Originalgleiche Texte prüfen"));
|
||||||
|
dialog.resize(760, 620);
|
||||||
|
auto *layout = new QVBoxLayout(&dialog);
|
||||||
|
auto *description = new QLabel(tr("Markiere nur Texte, die absichtlich unverändert bleiben sollen. Nicht markierte Texte bleiben offen und werden bei der nächsten Sammelübersetzung erneut angefragt."), &dialog);
|
||||||
|
description->setWordWrap(true);
|
||||||
|
layout->addWidget(description);
|
||||||
|
auto *scrollArea = new QScrollArea(&dialog);
|
||||||
|
scrollArea->setWidgetResizable(true);
|
||||||
|
auto *content = new QWidget(scrollArea);
|
||||||
|
auto *contentLayout = new QVBoxLayout(content);
|
||||||
|
QVector<QCheckBox *> checks;
|
||||||
|
checks.reserve(candidates.size());
|
||||||
|
for (QTreeWidgetItem *item : std::as_const(candidates)) {
|
||||||
|
const QString text = tr("%1 — Zeile %2: %3").arg(item->parent()->text(0), item->text(0), item->text(2));
|
||||||
|
auto *check = new QCheckBox(text, content);
|
||||||
|
contentLayout->addWidget(check);
|
||||||
|
checks.append(check);
|
||||||
|
}
|
||||||
|
contentLayout->addStretch();
|
||||||
|
scrollArea->setWidget(content);
|
||||||
|
layout->addWidget(scrollArea);
|
||||||
|
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Cancel, &dialog);
|
||||||
|
buttons->button(QDialogButtonBox::Apply)->setText(tr("Ausgewählte bestätigen"));
|
||||||
|
connect(buttons->button(QDialogButtonBox::Apply), &QPushButton::clicked, &dialog, &QDialog::accept);
|
||||||
|
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
|
layout->addWidget(buttons);
|
||||||
|
|
||||||
|
if (dialog.exec() != QDialog::Accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QJsonObject approvals = configuration.value("approved-identical-translations").toObject();
|
||||||
|
for (int index = 0; index < candidates.size(); ++index) {
|
||||||
|
if (checks[index]->isChecked()) {
|
||||||
|
approvals[identicalTranslationApprovalKey(candidates[index])] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configuration["approved-identical-translations"] = approvals;
|
||||||
|
saveConfiguration();
|
||||||
|
countAndShowUntranslated();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_bulkAutoTranslateButton_clicked()
|
void MainWindow::on_bulkAutoTranslateButton_clicked()
|
||||||
{
|
{
|
||||||
bulkUsesLibreTranslate = isLibreTranslateProvider();
|
bulkUsesLibreTranslate = isLibreTranslateProvider();
|
||||||
@@ -867,7 +931,7 @@ void MainWindow::on_bulkAutoTranslateButton_clicked()
|
|||||||
QTreeWidgetItem *fileItem = ui->treeWidget->topLevelItem(fileIndex);
|
QTreeWidgetItem *fileItem = ui->treeWidget->topLevelItem(fileIndex);
|
||||||
for (int itemIndex = 0; itemIndex < fileItem->childCount(); ++itemIndex) {
|
for (int itemIndex = 0; itemIndex < fileItem->childCount(); ++itemIndex) {
|
||||||
QTreeWidgetItem *item = fileItem->child(itemIndex);
|
QTreeWidgetItem *item = fileItem->child(itemIndex);
|
||||||
if (!item->text(2).isEmpty() && item->text(3).isEmpty()) {
|
if (isOpenTranslation(item)) {
|
||||||
BulkTranslationItem translation{item, item->text(2), QString(), {}};
|
BulkTranslationItem translation{item, item->text(2), QString(), {}};
|
||||||
bulkTranslations.append(std::move(translation));
|
bulkTranslations.append(std::move(translation));
|
||||||
}
|
}
|
||||||
@@ -1158,7 +1222,12 @@ void MainWindow::showBulkTranslationDialog()
|
|||||||
if (savedBulkFiles.contains(item->parent())) {
|
if (savedBulkFiles.contains(item->parent())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
item->setText(3, edits[index]->toPlainText());
|
const QString translation = edits[index]->toPlainText();
|
||||||
|
// An unchanged source string is not an automatic translation. Leave
|
||||||
|
// it open so it can be retried with a working language pair.
|
||||||
|
item->setText(3, translation.trimmed() == bulkTranslations[index].originalText.trimmed()
|
||||||
|
? QString()
|
||||||
|
: translation);
|
||||||
if (QTreeWidgetItem *parent = item->parent()) {
|
if (QTreeWidgetItem *parent = item->parent()) {
|
||||||
parent->setData(0, Qt::UserRole, true);
|
parent->setData(0, Qt::UserRole, true);
|
||||||
}
|
}
|
||||||
@@ -1301,7 +1370,7 @@ void MainWindow::countAndShowUntranslated() {
|
|||||||
int untranslatedInSectionCount = 0;
|
int untranslatedInSectionCount = 0;
|
||||||
for (int i = 0; i < parentItem->childCount(); ++i) {
|
for (int i = 0; i < parentItem->childCount(); ++i) {
|
||||||
QTreeWidgetItem *childItem = parentItem->child(i);
|
QTreeWidgetItem *childItem = parentItem->child(i);
|
||||||
if (!childItem->text(2).isEmpty() && childItem->text(3).isEmpty()) {
|
if (isOpenTranslation(childItem)) {
|
||||||
untranslatedCount++;
|
untranslatedCount++;
|
||||||
untranslatedInSectionCount++;
|
untranslatedInSectionCount++;
|
||||||
}
|
}
|
||||||
@@ -1317,6 +1386,30 @@ void MainWindow::countAndShowUntranslated() {
|
|||||||
ui->untranslatedLabel->setText(QString("%1").arg(untranslatedCount));
|
ui->untranslatedLabel->setText(QString("%1").arg(untranslatedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::isOpenTranslation(const QTreeWidgetItem *item) const
|
||||||
|
{
|
||||||
|
if (!item || item->text(2).isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const QString original = item->text(2).trimmed();
|
||||||
|
const QString translation = item->text(3).trimmed();
|
||||||
|
return translation.isEmpty() || (translation == original && !isIdenticalTranslationApproved(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::identicalTranslationApprovalKey(const QTreeWidgetItem *item) const
|
||||||
|
{
|
||||||
|
const QTreeWidgetItem *fileItem = item ? item->parent() : nullptr;
|
||||||
|
const QString filePath = fileItem ? fileItem->data(0, Qt::UserRole + 1).toString() : QString();
|
||||||
|
const QString rawKey = filePath + '\n' + (item ? item->text(0) : QString()) + '\n' + (item ? item->text(2) : QString());
|
||||||
|
return QString::fromLatin1(QCryptographicHash::hash(rawKey.toUtf8(), QCryptographicHash::Sha256).toHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::isIdenticalTranslationApproved(const QTreeWidgetItem *item) const
|
||||||
|
{
|
||||||
|
return configuration.value("approved-identical-translations").toObject()
|
||||||
|
.value(identicalTranslationApprovalKey(item)).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_searchButton_clicked() {
|
void MainWindow::on_searchButton_clicked() {
|
||||||
bool ok;
|
bool ok;
|
||||||
QString query = QInputDialog::getText(this, "Search", "Search for:", QLineEdit::Normal, "", &ok);
|
QString query = QInputDialog::getText(this, "Search", "Search for:", QLineEdit::Normal, "", &ok);
|
||||||
@@ -1359,6 +1452,11 @@ void MainWindow::setConfigValue(const QString &key, const QString &value) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
configuration[key] = value;
|
configuration[key] = value;
|
||||||
|
saveConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::saveConfiguration()
|
||||||
|
{
|
||||||
QString configPath = QDir::homePath() + "/.renpytranslate.conf";
|
QString configPath = QDir::homePath() + "/.renpytranslate.conf";
|
||||||
QJsonDocument doc(configuration);
|
QJsonDocument doc(configuration);
|
||||||
QFile configFile(configPath);
|
QFile configFile(configPath);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ 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_retryTranslationButton_clicked();
|
void on_retryTranslationButton_clicked();
|
||||||
|
void on_reviewIdenticalTranslationsButton_clicked();
|
||||||
void on_bulkAutoTranslateButton_clicked();
|
void on_bulkAutoTranslateButton_clicked();
|
||||||
void on_checkDeeplUsageButton_clicked();
|
void on_checkDeeplUsageButton_clicked();
|
||||||
void on_translationProviderCombo_currentIndexChanged(int index);
|
void on_translationProviderCombo_currentIndexChanged(int index);
|
||||||
@@ -96,6 +97,10 @@ private:
|
|||||||
void showBulkTranslationDialog();
|
void showBulkTranslationDialog();
|
||||||
void onDeeplTranslationAuthenticationError(QNetworkReply *reply, QAuthenticator *authenticator);
|
void onDeeplTranslationAuthenticationError(QNetworkReply *reply, QAuthenticator *authenticator);
|
||||||
void countAndShowUntranslated();
|
void countAndShowUntranslated();
|
||||||
|
bool isOpenTranslation(const QTreeWidgetItem *item) const;
|
||||||
|
bool isIdenticalTranslationApproved(const QTreeWidgetItem *item) const;
|
||||||
|
QString identicalTranslationApprovalKey(const QTreeWidgetItem *item) const;
|
||||||
|
void saveConfiguration();
|
||||||
void searchNext();
|
void searchNext();
|
||||||
QVector<TranslationItem> parseTextBlock(const QString &block);
|
QVector<TranslationItem> parseTextBlock(const QString &block);
|
||||||
void setConfigValue(const QString &key, const QString &value);
|
void setConfigValue(const QString &key, const QString &value);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
<layout class="QHBoxLayout" name="automaticActionLayout">
|
<layout class="QHBoxLayout" name="automaticActionLayout">
|
||||||
<item><widget class="QPushButton" name="autoTranslateButton"><property name="text"><string>Aktuellen Text übersetzen</string></property></widget></item>
|
<item><widget class="QPushButton" name="autoTranslateButton"><property name="text"><string>Aktuellen Text übersetzen</string></property></widget></item>
|
||||||
<item><widget class="QPushButton" name="bulkAutoTranslateButton"><property name="text"><string>Alle offenen Texte übersetzen</string></property></widget></item>
|
<item><widget class="QPushButton" name="bulkAutoTranslateButton"><property name="text"><string>Alle offenen Texte übersetzen</string></property></widget></item>
|
||||||
|
<item><widget class="QPushButton" name="reviewIdenticalTranslationsButton"><property name="toolTip"><string>Prüft Texte, deren Übersetzung absichtlich mit dem Original identisch sein soll.</string></property><property name="text"><string>Gleiche Texte prüfen</string></property></widget></item>
|
||||||
<item><spacer name="automaticActionSpacer"><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><spacer name="automaticActionSpacer"><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>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user