aboutsummaryrefslogtreecommitdiff
path: root/api/logic/translations
diff options
context:
space:
mode:
Diffstat (limited to 'api/logic/translations')
-rw-r--r--api/logic/translations/POTranslator.cpp373
-rw-r--r--api/logic/translations/POTranslator.h16
-rw-r--r--api/logic/translations/TranslationsModel.cpp653
-rw-r--r--api/logic/translations/TranslationsModel.h65
4 files changed, 0 insertions, 1107 deletions
diff --git a/api/logic/translations/POTranslator.cpp b/api/logic/translations/POTranslator.cpp
deleted file mode 100644
index 1ffcb9a4..00000000
--- a/api/logic/translations/POTranslator.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-#include "POTranslator.h"
-
-#include <QDebug>
-#include "FileSystem.h"
-
-struct POEntry
-{
- QString text;
- bool fuzzy;
-};
-
-struct POTranslatorPrivate
-{
- QString filename;
- QHash<QByteArray, POEntry> mapping;
- QHash<QByteArray, POEntry> mapping_disambiguatrion;
- bool loaded = false;
-
- void reload();
-};
-
-class ParserArray : public QByteArray
-{
-public:
- ParserArray(const QByteArray &in) : QByteArray(in)
- {
- }
- bool chomp(const char * data, int length)
- {
- if(startsWith(data))
- {
- remove(0, length);
- return true;
- }
- return false;
- }
- bool chompString(QByteArray & appendHere)
- {
- QByteArray msg;
- bool escape = false;
- if(size() < 2)
- {
- qDebug() << "String fragment is too short";
- return false;
- }
- if(!startsWith('"'))
- {
- qDebug() << "String fragment does not start with \"";
- return false;
- }
- if(!endsWith('"'))
- {
- qDebug() << "String fragment does not end with \", instead, there is" << at(size() - 1);
- return false;
- }
- for(int i = 1; i < size() - 1; i++)
- {
- char c = operator[](i);
- if(escape)
- {
- switch(c)
- {
- case 'r':
- msg += '\r';
- break;
- case 'n':
- msg += '\n';
- break;
- case 't':
- msg += '\t';
- break;
- case 'v':
- msg += '\v';
- break;
- case 'a':
- msg += '\a';
- break;
- case 'b':
- msg += '\b';
- break;
- case 'f':
- msg += '\f';
- break;
- case '"':
- msg += '"';
- break;
- case '\\':
- msg.append('\\');
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- int octal_start = i;
- while ((c = operator[](i)) >= '0' && c <= '7')
- {
- i++;
- if (i == length() - 1)
- {
- qDebug() << "Something went bad while parsing an octal escape string...";
- return false;
- }
- }
- msg += mid(octal_start, i - octal_start).toUInt(0, 8);
- break;
- }
- case 'x':
- {
- // chomp the 'x'
- i++;
- int hex_start = i;
- while (isxdigit(operator[](i)))
- {
- i++;
- if (i == length() - 1)
- {
- qDebug() << "Something went bad while parsing a hex escape string...";
- return false;
- }
- }
- msg += mid(hex_start, i - hex_start).toUInt(0, 16);
- break;
- }
- default:
- {
- qDebug() << "Invalid escape sequence character:" << c;
- return false;
- }
- }
- escape = false;
- }
- else if(c == '\\')
- {
- escape = true;
- }
- else
- {
- msg += c;
- }
- }
- if(escape)
- {
- qDebug() << "Unterminated escape sequence...";
- return false;
- }
- appendHere += msg;
- return true;
- }
-};
-
-void POTranslatorPrivate::reload()
-{
- QFile file(filename);
- if(!file.open(QFile::OpenMode::enum_type::ReadOnly | QFile::OpenMode::enum_type::Text))
- {
- qDebug() << "Failed to open PO file:" << filename;
- return;
- }
-
- QByteArray context;
- QByteArray disambiguation;
- QByteArray id;
- QByteArray str;
- bool fuzzy = false;
- bool nextFuzzy = false;
-
- enum class Mode
- {
- First,
- MessageContext,
- MessageId,
- MessageString
- } mode = Mode::First;
-
- int lineNumber = 0;
- QHash<QByteArray, POEntry> newMapping;
- QHash<QByteArray, POEntry> newMapping_disambiguation;
- auto endEntry = [&]() {
- auto strStr = QString::fromUtf8(str);
- // NOTE: PO header has empty id. We skip it.
- if(!id.isEmpty())
- {
- auto normalKey = context + "|" + id;
- newMapping.insert(normalKey, {strStr, fuzzy});
- if(!disambiguation.isEmpty())
- {
- auto disambiguationKey = context + "|" + id + "@" + disambiguation;
- newMapping_disambiguation.insert(disambiguationKey, {strStr, fuzzy});
- }
- }
- context.clear();
- disambiguation.clear();
- id.clear();
- str.clear();
- fuzzy = nextFuzzy;
- nextFuzzy = false;
- };
- while (!file.atEnd())
- {
- ParserArray line = file.readLine();
- if(line.endsWith('\n'))
- {
- line.resize(line.size() - 1);
- }
- if(line.endsWith('\r'))
- {
- line.resize(line.size() - 1);
- }
-
- if(!line.size())
- {
- // NIL
- }
- else if(line[0] == '#')
- {
- if(line.contains(", fuzzy"))
- {
- nextFuzzy = true;
- }
- }
- else if(line.startsWith('"'))
- {
- QByteArray temp;
- QByteArray *out = &temp;
-
- switch(mode)
- {
- case Mode::First:
- qDebug() << "Unexpected escaped string during initial state... line:" << lineNumber;
- return;
- case Mode::MessageString:
- out = &str;
- break;
- case Mode::MessageContext:
- out = &context;
- break;
- case Mode::MessageId:
- out = &id;
- break;
- }
- if(!line.chompString(*out))
- {
- qDebug() << "Badly formatted string on line:" << lineNumber;
- return;
- }
- }
- else if(line.chomp("msgctxt ", 8))
- {
- switch(mode)
- {
- case Mode::First:
- break;
- case Mode::MessageString:
- endEntry();
- break;
- case Mode::MessageContext:
- case Mode::MessageId:
- qDebug() << "Unexpected msgctxt line:" << lineNumber;
- return;
- }
- if(line.chompString(context))
- {
- auto parts = context.split('|');
- context = parts[0];
- if(parts.size() > 1 && !parts[1].isEmpty())
- {
- disambiguation = parts[1];
- }
- mode = Mode::MessageContext;
- }
- }
- else if (line.chomp("msgid ", 6))
- {
- switch(mode)
- {
- case Mode::MessageContext:
- case Mode::First:
- break;
- case Mode::MessageString:
- endEntry();
- break;
- case Mode::MessageId:
- qDebug() << "Unexpected msgid line:" << lineNumber;
- return;
- }
- if(line.chompString(id))
- {
- mode = Mode::MessageId;
- }
- }
- else if (line.chomp("msgstr ", 7))
- {
- switch(mode)
- {
- case Mode::First:
- case Mode::MessageString:
- case Mode::MessageContext:
- qDebug() << "Unexpected msgstr line:" << lineNumber;
- return;
- case Mode::MessageId:
- break;
- }
- if(line.chompString(str))
- {
- mode = Mode::MessageString;
- }
- }
- else
- {
- qDebug() << "I did not understand line: " << lineNumber << ":" << QString::fromUtf8(line);
- }
- lineNumber++;
- }
- endEntry();
- mapping = std::move(newMapping);
- mapping_disambiguatrion = std::move(newMapping_disambiguation);
- loaded = true;
-}
-
-POTranslator::POTranslator(const QString& filename, QObject* parent) : QTranslator(parent)
-{
- d = new POTranslatorPrivate;
- d->filename = filename;
- d->reload();
-}
-
-QString POTranslator::translate(const char* context, const char* sourceText, const char* disambiguation, int n) const
-{
- if(disambiguation)
- {
- auto disambiguationKey = QByteArray(context) + "|" + QByteArray(sourceText) + "@" + QByteArray(disambiguation);
- auto iter = d->mapping_disambiguatrion.find(disambiguationKey);
- if(iter != d->mapping_disambiguatrion.end())
- {
- auto & entry = *iter;
- if(entry.text.isEmpty())
- {
- qDebug() << "Translation entry has no content:" << disambiguationKey;
- }
- if(entry.fuzzy)
- {
- qDebug() << "Translation entry is fuzzy:" << disambiguationKey << "->" << entry.text;
- }
- return entry.text;
- }
- }
- auto key = QByteArray(context) + "|" + QByteArray(sourceText);
- auto iter = d->mapping.find(key);
- if(iter != d->mapping.end())
- {
- auto & entry = *iter;
- if(entry.text.isEmpty())
- {
- qDebug() << "Translation entry has no content:" << key;
- }
- if(entry.fuzzy)
- {
- qDebug() << "Translation entry is fuzzy:" << key << "->" << entry.text;
- }
- return entry.text;
- }
- return QString();
-}
-
-bool POTranslator::isEmpty() const
-{
- return !d->loaded;
-}
diff --git a/api/logic/translations/POTranslator.h b/api/logic/translations/POTranslator.h
deleted file mode 100644
index 6d518560..00000000
--- a/api/logic/translations/POTranslator.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <QTranslator>
-
-struct POTranslatorPrivate;
-
-class POTranslator : public QTranslator
-{
- Q_OBJECT
-public:
- explicit POTranslator(const QString& filename, QObject * parent = nullptr);
- QString translate(const char * context, const char * sourceText, const char * disambiguation, int n) const override;
- bool isEmpty() const override;
-private:
- POTranslatorPrivate * d;
-};
diff --git a/api/logic/translations/TranslationsModel.cpp b/api/logic/translations/TranslationsModel.cpp
deleted file mode 100644
index 29a952b0..00000000
--- a/api/logic/translations/TranslationsModel.cpp
+++ /dev/null
@@ -1,653 +0,0 @@
-#include "TranslationsModel.h"
-
-#include <QCoreApplication>
-#include <QTranslator>
-#include <QLocale>
-#include <QDir>
-#include <QLibraryInfo>
-#include <QDebug>
-#include <FileSystem.h>
-#include <net/NetJob.h>
-#include <net/ChecksumValidator.h>
-#include <Env.h>
-#include <BuildConfig.h>
-#include "Json.h"
-
-#include "POTranslator.h"
-
-const static QLatin1Literal defaultLangCode("en_US");
-
-enum class FileType
-{
- NONE,
- QM,
- PO
-};
-
-struct Language
-{
- Language()
- {
- updated = true;
- }
- Language(const QString & _key)
- {
- key = _key;
- locale = QLocale(key);
- updated = (key == defaultLangCode);
- }
-
- float percentTranslated() const
- {
- if (total == 0)
- {
- return 100.0f;
- }
- return 100.0f * float(translated) / float(total);
- }
-
- void setTranslationStats(unsigned _translated, unsigned _untranslated, unsigned _fuzzy)
- {
- translated = _translated;
- untranslated = _untranslated;
- fuzzy = _fuzzy;
- total = translated + untranslated + fuzzy;
- }
-
- bool isOfSameNameAs(const Language& other) const
- {
- return key == other.key;
- }
-
- bool isIdenticalTo(const Language& other) const
- {
- return
- (
- key == other.key &&
- file_name == other.file_name &&
- file_size == other.file_size &&
- file_sha1 == other.file_sha1 &&
- translated == other.translated &&
- fuzzy == other.fuzzy &&
- total == other.fuzzy &&
- localFileType == other.localFileType
- );
- }
-
- Language & apply(Language & other)
- {
- if(!isOfSameNameAs(other))
- {
- return *this;
- }
- file_name = other.file_name;
- file_size = other.file_size;
- file_sha1 = other.file_sha1;
- translated = other.translated;
- fuzzy = other.fuzzy;
- total = other.total;
- localFileType = other.localFileType;
- return *this;
- }
-
- QString key;
- QLocale locale;
- bool updated;
-
- QString file_name = QString();
- std::size_t file_size = 0;
- QString file_sha1 = QString();
-
- unsigned translated = 0;
- unsigned untranslated = 0;
- unsigned fuzzy = 0;
- unsigned total = 0;
-
- FileType localFileType = FileType::NONE;
-};
-
-
-
-struct TranslationsModel::Private
-{
- QDir m_dir;
-
- // initial state is just english
- QVector<Language> m_languages = {Language (defaultLangCode)};
-
- QString m_selectedLanguage = defaultLangCode;
- std::unique_ptr<QTranslator> m_qt_translator;
- std::unique_ptr<QTranslator> m_app_translator;
-
- std::shared_ptr<Net::Download> m_index_task;
- QString m_downloadingTranslation;
- NetJobPtr m_dl_job;
- NetJobPtr m_index_job;
- QString m_nextDownload;
-
- std::unique_ptr<POTranslator> m_po_translator;
- QFileSystemWatcher *watcher;
-};
-
-TranslationsModel::TranslationsModel(QString path, QObject* parent): QAbstractListModel(parent)
-{
- d.reset(new Private);
- d->m_dir.setPath(path);
- FS::ensureFolderPathExists(path);
- reloadLocalFiles();
-
- d->watcher = new QFileSystemWatcher(this);
- connect(d->watcher, &QFileSystemWatcher::directoryChanged, this, &TranslationsModel::translationDirChanged);
- d->watcher->addPath(d->m_dir.canonicalPath());
-}
-
-TranslationsModel::~TranslationsModel()
-{
-}
-
-void TranslationsModel::translationDirChanged(const QString& path)
-{
- qDebug() << "Dir changed:" << path;
- reloadLocalFiles();
- selectLanguage(selectedLanguage());
-}
-
-void TranslationsModel::indexReceived()
-{
- qDebug() << "Got translations index!";
- d->m_index_job.reset();
- if(d->m_selectedLanguage != defaultLangCode)
- {
- downloadTranslation(d->m_selectedLanguage);
- }
-}
-
-namespace {
-void readIndex(const QString & path, QMap<QString, Language>& languages)
-{
- QByteArray data;
- try
- {
- data = FS::read(path);
- }
- catch (const Exception &e)
- {
- qCritical() << "Translations Download Failed: index file not readable";
- return;
- }
-
- int index = 1;
- try
- {
- auto toplevel_doc = Json::requireDocument(data);
- auto doc = Json::requireObject(toplevel_doc);
- auto file_type = Json::requireString(doc, "file_type");
- if(file_type != "MMC-TRANSLATION-INDEX")
- {
- qCritical() << "Translations Download Failed: index file is of unknown file type" << file_type;
- return;
- }
- auto version = Json::requireInteger(doc, "version");
- if(version > 2)
- {
- qCritical() << "Translations Download Failed: index file is of unknown format version" << file_type;
- return;
- }
- auto langObjs = Json::requireObject(doc, "languages");
- for(auto iter = langObjs.begin(); iter != langObjs.end(); iter++)
- {
- Language lang(iter.key());
-
- auto langObj = Json::requireObject(iter.value());
- lang.setTranslationStats(
- Json::ensureInteger(langObj, "translated", 0),
- Json::ensureInteger(langObj, "untranslated", 0),
- Json::ensureInteger(langObj, "fuzzy", 0)
- );
- lang.file_name = Json::requireString(langObj, "file");
- lang.file_sha1 = Json::requireString(langObj, "sha1");
- lang.file_size = Json::requireInteger(langObj, "size");
-
- languages.insert(lang.key, lang);
- index++;
- }
- }
- catch (Json::JsonException & e)
- {
- qCritical() << "Translations Download Failed: index file could not be parsed as json";
- }
-}
-}
-
-void TranslationsModel::reloadLocalFiles()
-{
- QMap<QString, Language> languages = {{defaultLangCode, Language(defaultLangCode)}};
-
- readIndex(d->m_dir.absoluteFilePath("index_v2.json"), languages);
- auto entries = d->m_dir.entryInfoList({"mmc_*.qm", "*.po"}, QDir::Files | QDir::NoDotAndDotDot);
- for(auto & entry: entries)
- {
- auto completeSuffix = entry.completeSuffix();
- QString langCode;
- FileType fileType = FileType::NONE;
- if(completeSuffix == "qm")
- {
- langCode = entry.baseName().remove(0,4);
- fileType = FileType::QM;
- }
- else if(completeSuffix == "po")
- {
- langCode = entry.baseName();
- fileType = FileType::PO;
- }
- else
- {
- continue;
- }
-
- auto langIter = languages.find(langCode);
- if(langIter != languages.end())
- {
- auto & language = *langIter;
- if(int(fileType) > int(language.localFileType))
- {
- language.localFileType = fileType;
- }
- }
- else
- {
- if(fileType == FileType::PO)
- {
- Language localFound(langCode);
- localFound.localFileType = FileType::PO;
- languages.insert(langCode, localFound);
- }
- }
- }
-
- // changed and removed languages
- for(auto iter = d->m_languages.begin(); iter != d->m_languages.end();)
- {
- auto &language = *iter;
- auto row = iter - d->m_languages.begin();
-
- auto updatedLanguageIter = languages.find(language.key);
- if(updatedLanguageIter != languages.end())
- {
- if(language.isIdenticalTo(*updatedLanguageIter))
- {
- languages.remove(language.key);
- }
- else
- {
- language.apply(*updatedLanguageIter);
- emit dataChanged(index(row), index(row));
- languages.remove(language.key);
- }
- iter++;
- }
- else
- {
- beginRemoveRows(QModelIndex(), row, row);
- iter = d->m_languages.erase(iter);
- endRemoveRows();
- }
- }
- // added languages
- if(languages.isEmpty())
- {
- return;
- }
- beginInsertRows(QModelIndex(), 0, d->m_languages.size() + languages.size() - 1);
- for(auto & language: languages)
- {
- d->m_languages.append(language);
- }
- std::sort(d->m_languages.begin(), d->m_languages.end(), [](const Language& a, const Language& b) {
- return a.key.compare(b.key) < 0;
- });
- endInsertRows();
-}
-
-namespace {
-enum class Column
-{
- Language,
- Completeness
-};
-}
-
-
-QVariant TranslationsModel::data(const QModelIndex& index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- int row = index.row();
- auto column = static_cast<Column>(index.column());
-
- if (row < 0 || row >= d->m_languages.size())
- return QVariant();
-
- auto & lang = d->m_languages[row];
- switch (role)
- {
- case Qt::DisplayRole:
- {
- switch(column)
- {
- case Column::Language:
- {
- return lang.locale.nativeLanguageName();
- }
- case Column::Completeness:
- {
- QString text;
- text.sprintf("%3.1f %%", lang.percentTranslated());
- return text;
- }
- }
- }
- case Qt::ToolTipRole:
- {
- return tr("%1:\n%2 translated\n%3 fuzzy\n%4 total").arg(lang.key, QString::number(lang.translated), QString::number(lang.fuzzy), QString::number(lang.total));
- }
- case Qt::UserRole:
- return lang.key;
- default:
- return QVariant();
- }
-}
-
-QVariant TranslationsModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- auto column = static_cast<Column>(section);
- if(role == Qt::DisplayRole)
- {
- switch(column)
- {
- case Column::Language:
- {
- return tr("Language");
- }
- case Column::Completeness:
- {
- return tr("Completeness");
- }
- }
- }
- else if(role == Qt::ToolTipRole)
- {
- switch(column)
- {
- case Column::Language:
- {
- return tr("The native language name.");
- }
- case Column::Completeness:
- {
- return tr("Completeness is the percentage of fully translated strings, not counting automatically guessed ones.");
- }
- }
- }
- return QAbstractListModel::headerData(section, orientation, role);
-}
-
-int TranslationsModel::rowCount(const QModelIndex& parent) const
-{
- return d->m_languages.size();
-}
-
-int TranslationsModel::columnCount(const QModelIndex& parent) const
-{
- return 2;
-}
-
-Language * TranslationsModel::findLanguage(const QString& key)
-{
- auto found = std::find_if(d->m_languages.begin(), d->m_languages.end(), [&](Language & lang)
- {
- return lang.key == key;
- });
- if(found == d->m_languages.end())
- {
- return nullptr;
- }
- else
- {
- return found;
- }
-}
-
-bool TranslationsModel::selectLanguage(QString key)
-{
- QString &langCode = key;
- auto langPtr = findLanguage(key);
- if(!langPtr)
- {
- qWarning() << "Selected invalid language" << key << ", defaulting to" << defaultLangCode;
- langCode = defaultLangCode;
- }
- else
- {
- langCode = langPtr->key;
- }
-
- // uninstall existing translators if there are any
- if (d->m_app_translator)
- {
- QCoreApplication::removeTranslator(d->m_app_translator.get());
- d->m_app_translator.reset();
- }
- if (d->m_qt_translator)
- {
- QCoreApplication::removeTranslator(d->m_qt_translator.get());
- d->m_qt_translator.reset();
- }
-
- /*
- * FIXME: potential source of crashes:
- * In a multithreaded application, the default locale should be set at application startup, before any non-GUI threads are created.
- * This function is not reentrant.
- */
- QLocale locale = QLocale(langCode);
- QLocale::setDefault(locale);
-
- // if it's the default UI language, finish
- if(langCode == defaultLangCode)
- {
- d->m_selectedLanguage = langCode;
- return true;
- }
-
- // otherwise install new translations
- bool successful = false;
- // FIXME: this is likely never present. FIX IT.
- d->m_qt_translator.reset(new QTranslator());
- if (d->m_qt_translator->load("qt_" + langCode, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
- {
- qDebug() << "Loading Qt Language File for" << langCode.toLocal8Bit().constData() << "...";
- if (!QCoreApplication::installTranslator(d->m_qt_translator.get()))
- {
- qCritical() << "Loading Qt Language File failed.";
- d->m_qt_translator.reset();
- }
- else
- {
- successful = true;
- }
- }
- else
- {
- d->m_qt_translator.reset();
- }
-
- if(langPtr->localFileType == FileType::PO)
- {
- qDebug() << "Loading Application Language File for" << langCode.toLocal8Bit().constData() << "...";
- auto poTranslator = new POTranslator(FS::PathCombine(d->m_dir.path(), langCode + ".po"));
- if(!poTranslator->isEmpty())
- {
- if (!QCoreApplication::installTranslator(poTranslator))
- {
- delete poTranslator;
- qCritical() << "Installing Application Language File failed.";
- }
- else
- {
- d->m_app_translator.reset(poTranslator);
- successful = true;
- }
- }
- else
- {
- qCritical() << "Loading Application Language File failed.";
- d->m_app_translator.reset();
- }
- }
- else if(langPtr->localFileType == FileType::QM)
- {
- d->m_app_translator.reset(new QTranslator());
- if (d->m_app_translator->load("mmc_" + langCode, d->m_dir.path()))
- {
- qDebug() << "Loading Application Language File for" << langCode.toLocal8Bit().constData() << "...";
- if (!QCoreApplication::installTranslator(d->m_app_translator.get()))
- {
- qCritical() << "Installing Application Language File failed.";
- d->m_app_translator.reset();
- }
- else
- {
- successful = true;
- }
- }
- else
- {
- d->m_app_translator.reset();
- }
- }
- else
- {
- d->m_app_translator.reset();
- }
- d->m_selectedLanguage = langCode;
- return successful;
-}
-
-QModelIndex TranslationsModel::selectedIndex()
-{
- auto found = findLanguage(d->m_selectedLanguage);
- if(found)
- {
- // QVector iterator freely converts to pointer to contained type
- return index(found - d->m_languages.begin(), 0, QModelIndex());
- }
- return QModelIndex();
-}
-
-QString TranslationsModel::selectedLanguage()
-{
- return d->m_selectedLanguage;
-}
-
-void TranslationsModel::downloadIndex()
-{
- if(d->m_index_job || d->m_dl_job)
- {
- return;
- }
- qDebug() << "Downloading Translations Index...";
- d->m_index_job.reset(new NetJob("Translations Index"));
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("translations", "index_v2.json");
- entry->setStale(true);
- d->m_index_task = Net::Download::makeCached(QUrl("https://files.multimc.org/translations/index_v2.json"), entry);
- d->m_index_job->addNetAction(d->m_index_task);
- connect(d->m_index_job.get(), &NetJob::failed, this, &TranslationsModel::indexFailed);
- connect(d->m_index_job.get(), &NetJob::succeeded, this, &TranslationsModel::indexReceived);
- d->m_index_job->start();
-}
-
-void TranslationsModel::updateLanguage(QString key)
-{
- if(key == defaultLangCode)
- {
- qWarning() << "Cannot update builtin language" << key;
- return;
- }
- auto found = findLanguage(key);
- if(!found)
- {
- qWarning() << "Cannot update invalid language" << key;
- return;
- }
- if(!found->updated)
- {
- downloadTranslation(key);
- }
-}
-
-void TranslationsModel::downloadTranslation(QString key)
-{
- if(d->m_dl_job)
- {
- d->m_nextDownload = key;
- return;
- }
- auto lang = findLanguage(key);
- if(!lang)
- {
- qWarning() << "Will not download an unknown translation" << key;
- return;
- }
-
- d->m_downloadingTranslation = key;
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("translations", "mmc_" + key + ".qm");
- entry->setStale(true);
-
- auto dl = Net::Download::makeCached(QUrl(BuildConfig.TRANSLATIONS_BASE_URL + lang->file_name), entry);
- auto rawHash = QByteArray::fromHex(lang->file_sha1.toLatin1());
- dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
- dl->m_total_progress = lang->file_size;
-
- d->m_dl_job.reset(new NetJob("Translation for " + key));
- d->m_dl_job->addNetAction(dl);
-
- connect(d->m_dl_job.get(), &NetJob::succeeded, this, &TranslationsModel::dlGood);
- connect(d->m_dl_job.get(), &NetJob::failed, this, &TranslationsModel::dlFailed);
-
- d->m_dl_job->start();
-}
-
-void TranslationsModel::downloadNext()
-{
- if(!d->m_nextDownload.isEmpty())
- {
- downloadTranslation(d->m_nextDownload);
- d->m_nextDownload.clear();
- }
-}
-
-void TranslationsModel::dlFailed(QString reason)
-{
- qCritical() << "Translations Download Failed:" << reason;
- d->m_dl_job.reset();
- downloadNext();
-}
-
-void TranslationsModel::dlGood()
-{
- qDebug() << "Got translation:" << d->m_downloadingTranslation;
-
- if(d->m_downloadingTranslation == d->m_selectedLanguage)
- {
- selectLanguage(d->m_selectedLanguage);
- }
- d->m_dl_job.reset();
- downloadNext();
-}
-
-void TranslationsModel::indexFailed(QString reason)
-{
- qCritical() << "Translations Index Download Failed:" << reason;
- d->m_index_job.reset();
-}
diff --git a/api/logic/translations/TranslationsModel.h b/api/logic/translations/TranslationsModel.h
deleted file mode 100644
index 17e5b124..00000000
--- a/api/logic/translations/TranslationsModel.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright 2013-2021 MultiMC Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <QAbstractListModel>
-#include <memory>
-#include "multimc_logic_export.h"
-
-struct Language;
-
-class MULTIMC_LOGIC_EXPORT TranslationsModel : public QAbstractListModel
-{
- Q_OBJECT
-public:
- explicit TranslationsModel(QString path, QObject *parent = 0);
- virtual ~TranslationsModel();
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex & parent) const override;
-
- bool selectLanguage(QString key);
- void updateLanguage(QString key);
- QModelIndex selectedIndex();
- QString selectedLanguage();
-
- void downloadIndex();
-
-private:
- Language *findLanguage(const QString & key);
- void reloadLocalFiles();
- void downloadTranslation(QString key);
- void downloadNext();
-
- // hide copy constructor
- TranslationsModel(const TranslationsModel &) = delete;
- // hide assign op
- TranslationsModel &operator=(const TranslationsModel &) = delete;
-
-private slots:
- void indexReceived();
- void indexFailed(QString reason);
- void dlFailed(QString reason);
- void dlGood();
- void translationDirChanged(const QString &path);
-
-
-private: /* data */
- struct Private;
- std::unique_ptr<Private> d;
-};