Add tltrdesktop utility

This commit is contained in:
Victor Tran 2021-03-02 01:12:16 +11:00
parent 1899e0fb68
commit a0e6373fd6
No known key found for this signature in database
GPG key ID: 1F0729FE016CDC3E
10 changed files with 473 additions and 1 deletions

View file

@ -6,3 +6,6 @@ include(installtranslations.pri)
# Check if this is a Blueprint build
include(checkblueprint.pri)
# Generate .desktop translations
include(processdesktoptranslations.pri)

View file

@ -29,4 +29,5 @@ isEmpty(SKIP_GENTRANSLATION) {
}
DISTFILES += \
$$PWD/checkblueprint.pri
$$PWD/checkblueprint.pri \
$$PWD/processdesktoptranslations.pri

View file

@ -0,0 +1,33 @@
unix:!macx {
desktopgen.output = ${QMAKE_FILE_BASE}.desktop
desktopgen.commands = tltrdesktop --desktop-generate --desktop-template ${QMAKE_FILE_NAME} --json-directory $$_PRO_FILE_PWD_/translations/desktop/${QMAKE_FILE_NAME}/ --desktop-output ${QMAKE_FILE_OUT}
desktopgen.input = DESKTOP_FILE
desktopgen.CONFIG = no_link target_predeps
desktopgen.variable_out = DESKTOP_FILE_GENERATED
desktopgenbp.output = ${QMAKE_FILE_BASE}.desktop
desktopgenbp.commands = tltrdesktop --desktop-generate --desktop-template ${QMAKE_FILE_NAME} --json-directory $$_PRO_FILE_PWD_/translations/desktop/${QMAKE_FILE_NAME}/ --desktop-output ${QMAKE_FILE_OUT}
desktopgenbp.input = DESKTOP_FILE_BLUEPRINT
desktopgenbp.CONFIG = no_link target_predeps
desktopgenbp.variable_out = DESKTOP_FILE_BLUEPRINT_GENERATED
QMAKE_EXTRA_COMPILERS = desktopgen desktopgenbp
!isEmpty(DESKTOP_FILE):!blueprint {
desktop.files = DESKTOP_FILE_GENERATED
desktop.path = /usr/share/applications
desktop.extra = $$QMAKE_COPY $${OUT_PWD}/$$DESKTOP_FILE $(INSTALL_ROOT)/usr/share/applications
INSTALLS += desktop
message(Will install $$DESKTOP_FILE as the desktop file)
}
!isEmpty(DESKTOP_FILE_BLUEPRINT):blueprint {
desktop.files = DESKTOP_FILE_GENERATED_BLUEPRINT
desktop.path = /usr/share/applications
desktop.extra = $$QMAKE_COPY $${OUT_PWD}/$$DESKTOP_FILE_BLUEPRINT $(INSTALL_ROOT)/usr/share/applications
INSTALLS += desktop
message(Will install $$DESKTOP_FILE_BLUEPRINT as the desktop file)
}
}

View file

@ -7,6 +7,10 @@ unittest.depends = library
SUBDIRS += library
unix:!macx {
SUBDIRS += tltrdesktop
}
#!android {
# unittest
#}

102
tltrdesktop/desktopfile.cpp Normal file
View file

@ -0,0 +1,102 @@
/****************************************
*
* INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE
* Copyright (C) 2021 Victor Tran
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
#include "desktopfile.h"
#include <QFile>
#include <QTextStream>
struct DesktopFilePrivate {
QStringList lines;
QStringList outputLines;
int currentLine = -1;
bool lineWritten = true;
QString currentLineText();
};
DesktopFile::DesktopFile(QString file) {
d = new DesktopFilePrivate();
QFile f(file);
f.open(QFile::ReadOnly);
d->lines = QString(f.readAll()).split('\n');
}
DesktopFile::~DesktopFile() {
delete d;
}
bool DesktopFile::nextLine() {
if (!d->lineWritten) {
//Copy this line verbatim to the output if it's not a translator's comment
if (!d->currentLineText().startsWith("#T:")) d->outputLines.append(d->currentLineText());
}
d->currentLine++;
d->lineWritten = false;
return d->lines.count() > d->currentLine;
}
bool DesktopFile::isKeyValue() {
return d->currentLineText().contains("=");
}
QString DesktopFile::key() {
QString key = d->currentLineText().left(d->currentLineText().indexOf("="));
if (key.endsWith("[]")) key.chop(2);
return key;
}
QString DesktopFile::value() {
return d->currentLineText().mid(d->currentLineText().indexOf("=") + 1);
}
QString DesktopFile::comment() {
if (d->currentLine == 0) return "";
QString previousLine = d->lines.value(d->currentLine - 1);
if (!previousLine.startsWith("#T:")) return "";
return previousLine.mid(3);
}
bool DesktopFile::isLineTranslatable() {
if (!isKeyValue()) return false;
return d->currentLineText().left(d->currentLineText().indexOf("=")).endsWith("[]");
}
void DesktopFile::insert(QString key, QString value, QString locale) {
QString line = QStringLiteral("%1%2=%3").arg(key);
if (locale.isEmpty()) {
line = line.arg("");
} else {
line = line.arg(QStringLiteral("[%1]").arg(locale));
}
line = line.arg(value);
d->outputLines.append(line);
d->lineWritten = true;
}
QString DesktopFile::outputText() {
return d->outputLines.join("\n");
}
QString DesktopFilePrivate::currentLineText() {
return lines.at(currentLine);
}

46
tltrdesktop/desktopfile.h Normal file
View file

@ -0,0 +1,46 @@
/****************************************
*
* INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE
* Copyright (C) 2021 Victor Tran
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
#ifndef DESKTOPFILE_H
#define DESKTOPFILE_H
#include <QString>
struct DesktopFilePrivate;
class DesktopFile {
public:
DesktopFile(QString file);
~DesktopFile();
bool nextLine();
bool isKeyValue();
QString key();
QString value();
QString comment();
bool isLineTranslatable();
void insert(QString key, QString value, QString locale = "");
QString outputText();
private:
DesktopFilePrivate* d;
};
#endif // DESKTOPFILE_H

80
tltrdesktop/jsonfile.cpp Normal file
View file

@ -0,0 +1,80 @@
/****************************************
*
* INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE
* Copyright (C) 2021 Victor Tran
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
#include "jsonfile.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
struct JsonFilePrivate {
uint refcount = 0;
QJsonObject rootObject;
};
JsonFile::JsonFile() {
d = new JsonFilePrivate();
d->refcount++;
}
JsonFile::JsonFile(QString file) {
d = new JsonFilePrivate();
d->refcount++;
QFile f(file);
f.open(QFile::ReadOnly);
d->rootObject = QJsonDocument::fromJson(f.readAll()).object();
}
JsonFile::JsonFile(const JsonFile& other) {
this->d = other.d;
d->refcount++;
}
JsonFile::~JsonFile() {
d->refcount--;
if (d->refcount == 0) delete d;
}
void JsonFile::insertString(QString key, QString message, QString description) {
QJsonObject stringObject;
stringObject.insert("message", message);
if (!description.isEmpty()) stringObject.insert("description", description);
d->rootObject.insert(key, stringObject);
}
QString JsonFile::message(QString key) const {
QJsonValue stringValue = d->rootObject.value(key);
if (!stringValue.isObject()) return "";
return stringValue.toObject().value("message").toString();
}
QByteArray JsonFile::output() {
return QJsonDocument(d->rootObject).toJson();
}
JsonFile& JsonFile::operator =(const JsonFile& other) {
d->refcount--;
if (d->refcount == 0) delete d;
d = other.d;
d->refcount++;
return *this;
}

45
tltrdesktop/jsonfile.h Normal file
View file

@ -0,0 +1,45 @@
/****************************************
*
* INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE
* Copyright (C) 2021 Victor Tran
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
#ifndef JSONFILE_H
#define JSONFILE_H
#include <QString>
struct JsonFilePrivate;
class JsonFile {
public:
JsonFile();
JsonFile(QString file);
JsonFile(const JsonFile& other);
~JsonFile();
void insertString(QString key, QString message, QString description = "");
QString message(QString key) const;
QByteArray output();
JsonFile& operator=(const JsonFile& other);
private:
JsonFilePrivate* d;
};
#endif // JSONFILE_H

136
tltrdesktop/main.cpp Normal file
View file

@ -0,0 +1,136 @@
/****************************************
*
* INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE
* Copyright (C) 2021 Victor Tran
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
#include <QCoreApplication>
#include <QTextStream>
#include <QCommandLineParser>
#include <QDir>
#include "desktopfile.h"
#include "jsonfile.h"
void genJsonFile(QString desktopFile, QDir outputDirectory) {
QTextStream output(stdout);
JsonFile file;
DesktopFile desktop(desktopFile);
while (desktop.nextLine()) {
if (desktop.isLineTranslatable()) {
//Export this line to the translation file
file.insertString(desktop.key(), desktop.value(), desktop.comment());
}
}
//Write the output to en.json
QString outputFile = outputDirectory.absoluteFilePath("en.json");
output << "Generating file " << outputFile << "...\n";
QFile f(outputFile);
f.open(QFile::WriteOnly);
f.write(file.output());
f.close();
}
void genDesktopFile(QString templateFile, QDir jsonDirectory, QString outputFile) {
QTextStream output(stdout);
QMap<QString, JsonFile> jsonFiles;
for (const QFileInfo& file : jsonDirectory.entryInfoList({"*.json"}, QDir::Files)) {
JsonFile jsonFile(file.absoluteFilePath());
jsonFiles.insert(file.baseName(), jsonFile);
}
DesktopFile desktop(templateFile);
while (desktop.nextLine()) {
if (desktop.isLineTranslatable()) {
//Insert the translations into the desktop file
//First, insert the translation without a locale
desktop.insert(desktop.key(), desktop.value());
for (const QString& locale : jsonFiles.keys()) {
QString value = jsonFiles.value(locale).message(desktop.key());
desktop.insert(desktop.key(), value, locale);
}
}
}
//Output to the output file
output << "Generating file " << outputFile << "...\n";
QFile f(outputFile);
f.open(QFile::WriteOnly);
f.write(desktop.outputText().toUtf8());
f.close();
}
int main(int argc, char* argv[]) {
QCoreApplication a(argc, argv);
QCommandLineParser parser;
parser.addOption({{"j", "json-generate"}, "Generate JSON Translation files from .desktop files"});
parser.addOption({{"k", "desktop-generate"}, "Generate .desktop files from JSON Translation files"});
parser.addOption({{"d", "json-directory"}, "Directory of JSON Translation files", "json-directory"});
parser.addOption({{"t", "desktop-template"}, ".desktop template file", "desktop template"});
parser.addOption({{"o", "desktop-output"}, ".desktop output file", "desktop output"});
QCommandLineOption helpOption = parser.addHelpOption();
parser.parse(a.arguments());
QTextStream output(stdout);
QTextStream eoutput(stderr);
if (parser.isSet(helpOption)) {
output << parser.helpText() << "\n";
return 0;
}
bool genJson = parser.isSet("json-generate");
bool genDesktop = parser.isSet("desktop-generate");
if (!genJson && !genDesktop) {
eoutput << "error: At least one of --json-generate or --desktop-generate must be specified.\n";
return 1;
}
if (!parser.isSet("desktop-template")) {
eoutput << "error: A desktop template file must be specified with --desktop-template.\n";
return 1;
}
if (!parser.isSet("json-directory")) {
eoutput << "error: A JSON output directory must be specified with --json-directory.\n";
return 1;
}
if (!parser.isSet("desktop-output") && genDesktop) {
eoutput << "error: A .desktop output file must be specified with --desktop-output.\n";
return 1;
}
QString desktopTemplate = parser.value("desktop-template");
QDir outputDirectory(parser.value("json-directory"));
if (!outputDirectory.exists()) outputDirectory.mkpath(".");
if (genJson) {
//Generate the en JSON file from a .desktop file
genJsonFile(desktopTemplate, outputDirectory);
}
if (genDesktop) {
//Generate the final .desktop file from JSON files
genDesktopFile(desktopTemplate, outputDirectory, parser.value("desktop-output"));
}
return 0;
}

View file

@ -0,0 +1,22 @@
QT -= gui
CONFIG += c++11 console
CONFIG -= app_bundle
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
desktopfile.cpp \
jsonfile.cpp \
main.cpp
unix:!macx {
target.path = /usr/bin
INSTALLS += target
}
HEADERS += \
desktopfile.h \
jsonfile.h