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 <QInputDialog>
|
||||
#include <QClipboard>
|
||||
#include <QCheckBox>
|
||||
#include <QCryptographicHash>
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
@@ -454,7 +456,7 @@ void MainWindow::on_nextUntranslatedButton_clicked() {
|
||||
for (int j = 0; j < topLevelItem->childCount(); ++j) {
|
||||
QTreeWidgetItem *childItem = topLevelItem->child(j);
|
||||
// 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->translationEdit->clear();
|
||||
ui->treeWidget->scrollToItem(childItem);
|
||||
@@ -622,9 +624,10 @@ bool MainWindow::parseAndEditFile(QFile &backupFile, QTreeWidgetItem *fileItem,
|
||||
auto oldText = match.captured(4);
|
||||
auto newText = match.captured(6);
|
||||
auto replacedText = findNewText(fileItem, lineNumber, oldText, speaker);
|
||||
QString toReplace = QString("\"%1\"").arg(newText).trimmed();
|
||||
QString replacement = QString("\"%1\"").arg(replacedText.isEmpty() ? newText : replacedText);
|
||||
auto replacedBlock = block.replace(toReplace, replacement);
|
||||
QString replacedBlock = block;
|
||||
const int translatedTextOffset = match.capturedStart(6) - match.capturedStart(0);
|
||||
replacedBlock.replace(translatedTextOffset, match.capturedLength(6),
|
||||
replacedText.isEmpty() ? newText : replacedText);
|
||||
content.replace(match.capturedStart(0), match.capturedLength(0), replacedBlock);
|
||||
// The replacement can have a different length. Continue after the new
|
||||
// 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 newText = match.captured(4);
|
||||
auto replacedText = findNewText(fileItem, lineNumber, oldText, "");
|
||||
QString toReplace = QString("\"%1\"").arg(newText);
|
||||
QString replacement = QString("\"%1\"").arg(replacedText.isEmpty() ? newText : replacedText);
|
||||
auto replacedBlock = block.replace(toReplace, replacement);
|
||||
QString replacedBlock = block;
|
||||
const int translatedTextOffset = match.capturedStart(4) - match.capturedStart(0);
|
||||
replacedBlock.replace(translatedTextOffset, match.capturedLength(4),
|
||||
replacedText.isEmpty() ? newText : replacedText);
|
||||
content.replace(match.capturedStart(0), match.capturedLength(0), replacedBlock);
|
||||
offset = match.capturedStart(0) + replacedBlock.size();
|
||||
changed = true;
|
||||
@@ -850,6 +854,66 @@ void MainWindow::on_retryTranslationButton_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()
|
||||
{
|
||||
bulkUsesLibreTranslate = isLibreTranslateProvider();
|
||||
@@ -867,7 +931,7 @@ void MainWindow::on_bulkAutoTranslateButton_clicked()
|
||||
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(3).isEmpty()) {
|
||||
if (isOpenTranslation(item)) {
|
||||
BulkTranslationItem translation{item, item->text(2), QString(), {}};
|
||||
bulkTranslations.append(std::move(translation));
|
||||
}
|
||||
@@ -1158,7 +1222,12 @@ void MainWindow::showBulkTranslationDialog()
|
||||
if (savedBulkFiles.contains(item->parent())) {
|
||||
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()) {
|
||||
parent->setData(0, Qt::UserRole, true);
|
||||
}
|
||||
@@ -1301,7 +1370,7 @@ void MainWindow::countAndShowUntranslated() {
|
||||
int untranslatedInSectionCount = 0;
|
||||
for (int i = 0; i < parentItem->childCount(); ++i) {
|
||||
QTreeWidgetItem *childItem = parentItem->child(i);
|
||||
if (!childItem->text(2).isEmpty() && childItem->text(3).isEmpty()) {
|
||||
if (isOpenTranslation(childItem)) {
|
||||
untranslatedCount++;
|
||||
untranslatedInSectionCount++;
|
||||
}
|
||||
@@ -1317,6 +1386,30 @@ void MainWindow::countAndShowUntranslated() {
|
||||
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() {
|
||||
bool 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;
|
||||
}
|
||||
configuration[key] = value;
|
||||
saveConfiguration();
|
||||
}
|
||||
|
||||
void MainWindow::saveConfiguration()
|
||||
{
|
||||
QString configPath = QDir::homePath() + "/.renpytranslate.conf";
|
||||
QJsonDocument doc(configuration);
|
||||
QFile configFile(configPath);
|
||||
|
||||
@@ -42,6 +42,7 @@ private slots:
|
||||
void on_deeplTranslateFrom_currentTextChanged(const QString &sourceLanguage);
|
||||
void on_autoTranslateButton_clicked();
|
||||
void on_retryTranslationButton_clicked();
|
||||
void on_reviewIdenticalTranslationsButton_clicked();
|
||||
void on_bulkAutoTranslateButton_clicked();
|
||||
void on_checkDeeplUsageButton_clicked();
|
||||
void on_translationProviderCombo_currentIndexChanged(int index);
|
||||
@@ -96,6 +97,10 @@ private:
|
||||
void showBulkTranslationDialog();
|
||||
void onDeeplTranslationAuthenticationError(QNetworkReply *reply, QAuthenticator *authenticator);
|
||||
void countAndShowUntranslated();
|
||||
bool isOpenTranslation(const QTreeWidgetItem *item) const;
|
||||
bool isIdenticalTranslationApproved(const QTreeWidgetItem *item) const;
|
||||
QString identicalTranslationApprovalKey(const QTreeWidgetItem *item) const;
|
||||
void saveConfiguration();
|
||||
void searchNext();
|
||||
QVector<TranslationItem> parseTextBlock(const QString &block);
|
||||
void setConfigValue(const QString &key, const QString &value);
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
<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="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>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
Reference in New Issue
Block a user