#include "mainwindow.h" #include "./ui_mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { loadDeeplTranslationPossibilities(); ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_selectProjectDirButton_clicked() { QString selectedDir = QFileDialog::getExistingDirectory(this, tr("Verzeichnis auswählen"), QDir::homePath()); if (!selectedDir.isEmpty()) { ui->projectDir->setText(selectedDir); crawlProject(); } } void MainWindow::crawlProject() { QString projectDir = ui->projectDir->text(); QDir dir(projectDir); if (!dir.exists()) { QMessageBox::critical(this, tr("Error"), tr("The project directory does not exist!")); return; } QString tlDirPath = QDir::cleanPath(projectDir + QDir::separator() + "game" + QDir::separator() + "tl"); if (!QDir(tlDirPath).exists()) { QMessageBox::information(this, tr("Information"), tr("No translations available.")); return; } QStringList languageDirs = QDir(tlDirPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot); if (languageDirs.isEmpty()) { QMessageBox::information(this, tr("Information"), tr("No translations available.")); return; } ui->languageCombo->clear(); ui->languageCombo->addItems(languageDirs); ui->languageCombo->setCurrentIndex(-1); } void MainWindow::on_reloadButton_clicked() { crawlProject(); } void MainWindow::on_languageCombo_currentTextChanged(const QString &selectedLanguage) { fileContentsMap.clear(); ui->treeWidget->clear(); if (ui->languageCombo->currentIndex() == -1) { return; } QString projectDir = ui->projectDir->text(); QString languageDirPath = QDir::cleanPath(projectDir + QDir::separator() + "game" + QDir::separator() + "tl" + QDir::separator() + selectedLanguage); QDirIterator it(languageDirPath, QStringList() << "*.rpy", QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { QString filePath = it.next(); QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) continue; QTextStream in(&file); QString fileContent = in.readAll(); file.close(); fileContentsMap[filePath] = fileContent; populateTreeWidgetFromMap(); } } void MainWindow::populateTreeWidgetFromMap() { ui->treeWidget->clear(); for (const auto &pair : fileContentsMap) { QTreeWidgetItem *fileItem = new QTreeWidgetItem(ui->treeWidget); QString fileName = QFileInfo(pair.first).fileName(); fileItem->setText(0, fileName); fileItem->setData(0, Qt::UserRole, false); QStringList blocks = pair.second.split("\n # "); for (const QString &block : blocks) { if (block.trimmed().isEmpty()) { continue; } if (block.contains("\n old") && block.contains("\n new")) { QStringList lines = block.trimmed().split('\n'); if (lines.size() >= 3) { QString lineNumber = lines[0].section(':', 1, 1).trimmed(); QString originalText = lines[1].section('"', 1, 1).trimmed(); QString newText = lines[2].section('"', 1, 1).trimmed(); QTreeWidgetItem *blockItem = new QTreeWidgetItem(fileItem); blockItem->setText(0, lineNumber); blockItem->setText(1, originalText); blockItem->setText(2, newText); } } } } ui->treeWidget->resizeColumnToContents(0); int firstColumnWidth = ui->treeWidget->columnWidth(0); int remainingWidth = ui->treeWidget->viewport()->width() - firstColumnWidth; int columnWidth = remainingWidth / 2; ui->treeWidget->setColumnWidth(1, columnWidth); ui->treeWidget->setColumnWidth(2, columnWidth); countAndShowUntranslated(); } void MainWindow::on_reloadTranslationsButton_clicked() { crawlProject(); } void MainWindow::on_reloadFilesButton_clicked() { populateTreeWidgetFromMap(); } void MainWindow::on_nextUntranslatedButton_clicked() { for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem *topLevelItem = ui->treeWidget->topLevelItem(i); for (int j = 0; j < topLevelItem->childCount(); ++j) { QTreeWidgetItem *childItem = topLevelItem->child(j); if (childItem->text(2).isEmpty()) { ui->originalTextEdit->setText(childItem->text(1)); ui->translationEdit->clear(); ui->treeWidget->scrollToItem(childItem); ui->treeWidget->setCurrentItem(childItem); return; } } } QMessageBox::information(this, tr("Information"), tr("No untranslated item found.")); } void MainWindow::on_treeWidget_itemSelectionChanged() { QTreeWidgetItem *selectedItem = ui->treeWidget->currentItem(); if (selectedItem) { if (selectedItem->treeWidget()->indexOfTopLevelItem(selectedItem) < 0) { ui->originalTextEdit->setText(selectedItem->text(1)); ui->translationEdit->setText(selectedItem->text(2)); } } } void MainWindow::on_setTranslationButton_clicked() { QTreeWidgetItem *selectedItem = ui->treeWidget->currentItem(); if (selectedItem) { if (selectedItem->treeWidget()->indexOfTopLevelItem(selectedItem) < 0) { selectedItem->setText(2, ui->translationEdit->text()); QTreeWidgetItem *parentItem = selectedItem->parent(); if (parentItem) { parentItem->setData(0, Qt::UserRole, true); } } } countAndShowUntranslated(); } void MainWindow::on_setTranslationAndJumpNextButton_clicked() { on_setTranslationButton_clicked(); on_nextUntranslatedButton_clicked(); } void MainWindow::on_setAndNextAndAutoTranslate_clicked() { on_setTranslationAndJumpNextButton_clicked(); on_autoTranslateButton_clicked(); } void MainWindow::on_translationEdit_returnPressed() { qDebug() << ui->enterActionCombo->currentIndex(); switch (ui->enterActionCombo->currentIndex()) { case 0: on_setAndNextAndAutoTranslate_clicked(); break; case 1: on_setTranslationAndJumpNextButton_clicked(); break; case 2: on_setTranslationButton_clicked(); break; } } void MainWindow::on_saveButton_clicked() { QStringList failedFiles; saveFiles(failedFiles); if (!failedFiles.isEmpty()) { QString errorMessage = "Failed to save the following files:\n\n"; errorMessage += failedFiles.join("\n"); QMessageBox::critical(this, tr("Error"), errorMessage); } else { QMessageBox::information(this, "Information", "The translations were saved succesfully."); } } void MainWindow::saveFiles(QStringList &failedFiles) { auto projectDir = ui->projectDir->text(); for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem *fileItem = ui->treeWidget->topLevelItem(i); if (fileItem->data(0, Qt::UserRole).toBool()) { QString fileName = fileItem->text(0); QString filePath = QString("%1/game/tl/%2/%3").arg(projectDir, ui->languageCombo->currentText(), fileName); QString backupFileName = QString("%1/game/tl/%2/%3.bak.%4") .arg(projectDir, ui->languageCombo->currentText(), fileName, QDateTime::currentDateTime().toString("yyyyMMddHHmmss")); if (!createBackup(filePath, backupFileName)) { failedFiles << filePath + ": Failed to create backup"; continue; } if (!editAndSaveFile(fileItem, backupFileName, filePath)) { failedFiles << filePath + ": Failed to edit and save file"; } fileItem->setData(0, Qt::UserRole, false); } } } bool MainWindow::createBackup(const QString &filePath, const QString &backupFileName) { if (!QFile::rename(filePath, backupFileName)) { qDebug() << "Failed to create backup file: " << backupFileName; qDebug() << "Original name: " << filePath; return false; } return true; } bool MainWindow::editAndSaveFile(QTreeWidgetItem *fileItem, const QString &backupFileName, const QString &fileName) { QFile backupFile(backupFileName); if (!backupFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Failed to open backup file for reading: " << backupFileName; return false; } QStringList lines; bool changed = false; if (!parseAndEditFile(backupFile, fileItem, lines, changed)) { qDebug() << "Failed to parse and edit file: " << backupFileName; return false; } backupFile.close(); if (changed) { if (!saveToFile(fileName, lines)) { qDebug() << "Failed to save file: " << backupFileName; return false; } } return true; } bool MainWindow::parseAndEditFile(QFile &backupFile, QTreeWidgetItem *fileItem, QStringList &lines, bool &changed) { QTextStream backupStream(&backupFile); QString fileName = fileItem->text(0); while (!backupStream.atEnd()) { QString line = backupStream.readLine().trimmed(); // Trim the line before processing if (line.startsWith("#") && line.contains(fileName)) { QString originalIdentifierLine(line.trimmed()); QString lineNumber = line.section(':', 1, 1).trimmed(); QString nextLine = backupStream.readLine(); if (nextLine.trimmed().startsWith("old")) { QString originalOldText = nextLine.section('"', 1, 1).trimmed(); QString originalNewText = backupStream.readLine(); QString newText = findNewText(fileItem, lineNumber, originalOldText); if (newText.isEmpty()) { newText = originalNewText.trimmed(); } lines.append(QString(" %1").arg(originalIdentifierLine)); lines.append(QString(" old \"%1\"").arg(originalOldText)); if (newText.isEmpty()) { lines.append(" new \"\""); } else { lines.append(QString(" new \"%1\"").arg(newText)); } changed = true; } else { lines.append(line); lines.append(nextLine); } } else { lines.append(line); } } return true; } QString MainWindow::findNewText(QTreeWidgetItem *fileItem, const QString &lineNumber, const QString &originalText) { for (int i = 0; i < fileItem->childCount(); ++i) { QTreeWidgetItem *childItem = fileItem->child(i); if (childItem->text(0) == lineNumber && childItem->text(1) == originalText) { return childItem->text(2); } } return QString(); } void MainWindow::loadDeeplTranslationPossibilities() { QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, &MainWindow::onDeeplTranslationPossibilitiesLoaded); QNetworkRequest request(QUrl("https://api-free.deepl.com/v2/glossary-language-pairs")); request.setRawHeader("Authorization", "DeepL-Auth-Key " + deeplAuthKey.toUtf8()); // Replace with your DeepL API key manager->get(request); } void MainWindow::renderDeeplSources() { ui->deeplTranslateFrom->clear(); for (const auto& pair : translationsMap) { ui->deeplTranslateFrom->addItem(pair.first); } } void MainWindow::onDeeplTranslationPossibilitiesLoaded(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData); if (jsonResponse.isObject()) { QJsonObject jsonResponseObject = jsonResponse.object(); if (jsonResponseObject["supported_languages"].isArray()) { QJsonArray languagePairsArray = jsonResponseObject["supported_languages"].toArray(); for (const QJsonValue &value : languagePairsArray) { QJsonObject languagePair = value.toObject(); QString sourceLang = languagePair["source_lang"].toString(); QString targetLang = languagePair["target_lang"].toString(); translationsMap[sourceLang].push_back(targetLang); } renderDeeplSources(); } else { qDebug() << "Invalid JSON format: Data not found"; qDebug() << responseData; } } else { qDebug() << "Invalid JSON format: Response is not an object"; } } else { qDebug() << "Network error:" << reply->errorString(); } reply->deleteLater(); } bool MainWindow::saveToFile(const QString &backupFileName, const QStringList &lines) { QFile backupFile(backupFileName); if (!backupFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { qDebug() << "Failed to open backup file for writing: " << backupFileName; return false; } QTextStream out(&backupFile); out << lines.join("\n") << Qt::endl; backupFile.close(); return true; } void MainWindow::on_cleanupButton_clicked() { QString projectDir = ui->projectDir->text(); QString language = ui->languageCombo->currentText(); QString tlDirPath = QDir::cleanPath(projectDir + QDir::separator() + "game" + QDir::separator() + "tl" + QDir::separator() + language); QDir tlDir(tlDirPath); QStringList filters; filters << "*.bak.*"; tlDir.setNameFilters(filters); QStringList fileList = tlDir.entryList(QDir::Files); for (int i = 0; i < fileList.size(); ++i) { const QString &fileName = fileList.at(i); if (!tlDir.remove(fileName)) { qDebug() << "Failed to remove" << fileName; } } } void MainWindow::on_cleanupAndSaveButton_clicked() { on_cleanupButton_clicked(); on_saveButton_clicked(); } void MainWindow::on_deeplTranslateFrom_currentTextChanged(const QString &sourceLanguage) { ui->deeplTranslateTo->clear(); auto it = translationsMap.find(sourceLanguage); if (it != translationsMap.end()) { for (const auto& targetLang : it->second) { ui->deeplTranslateTo->addItem(targetLang); } } } void MainWindow::on_autoTranslateButton_clicked() { QString originalText = ui->originalTextEdit->text(); QString sourceLang = ui->deeplTranslateFrom->currentText(); QString targetLang = ui->deeplTranslateTo->currentText(); QJsonObject jsonData; jsonData["text"] = QJsonArray::fromStringList({originalText}); jsonData["source_lang"] = sourceLang; jsonData["target_lang"] = targetLang; QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, &MainWindow::translationRequestFinished); QUrl url("https://api-free.deepl.com/v2/translate"); QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Authorization", "DeepL-Auth-Key " + deeplAuthKey.toUtf8()); manager->post(request, QJsonDocument(jsonData).toJson()); } void MainWindow::translationRequestFinished(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData); if (!jsonResponse.isNull() && jsonResponse.isObject()) { QJsonObject jsonObject = jsonResponse.object(); QJsonArray translationsArray = jsonObject["translations"].toArray(); if (!translationsArray.isEmpty()) { QJsonObject translationObject = translationsArray[0].toObject(); QString translatedText = translationObject["text"].toString(); ui->translationEdit->setText(translatedText); } } } else { qDebug() << "Translation request failed:" << reply->errorString(); } reply->deleteLater(); } void MainWindow::countAndShowUntranslated() { int untranslatedCount = 0; std::function countUntranslated = [&](QTreeWidgetItem *parentItem) { for (int i = 0; i < parentItem->childCount(); ++i) { QTreeWidgetItem *childItem = parentItem->child(i); if (!childItem->text(1).isEmpty() && childItem->text(2).isEmpty()) { untranslatedCount++; } countUntranslated(childItem); } }; for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem *topLevelItem = ui->treeWidget->topLevelItem(i); countUntranslated(topLevelItem); } ui->untranslatedLabel->setText(QString("%1").arg(untranslatedCount)); }