translation of all project, and new translation mechanism

This commit is contained in:
2026-09-03 09:18:48 +03:00
parent 00e7c957e4
commit 01af372ef2
32 changed files with 2813 additions and 537 deletions
+33 -35
View File
@@ -1,4 +1,5 @@
#include "modloaderinstaller.h"
#include "localization.h"
#include "gamelauncher.h"
#include "javalocator.h"
@@ -106,11 +107,11 @@ void ModLoaderInstaller::install(const QString &gameDir,
const QString &javaPreference)
{
if (m_running) {
emit failed(loaderTitle(loader), tr("Установка модлоадера уже идёт"));
emit failed(loaderTitle(loader), Loc::text("loader.error.installInProgress"));
return;
}
if (gameVersion.trimmed().isEmpty() || loaderVersion.trimmed().isEmpty()) {
emit failed(loaderTitle(loader), tr("Не выбрана версия %1").arg(loaderTitle(loader)));
emit failed(loaderTitle(loader), Loc::text("loader.error.noVersionSelected").arg(loaderTitle(loader)));
return;
}
@@ -128,7 +129,7 @@ void ModLoaderInstaller::install(const QString &gameDir,
m_running = true;
emit started(m_label);
setStage(tr("Подготовка %1").arg(loaderTitle(loader)));
setStage(Loc::text("loader.progress.preparing").arg(loaderTitle(loader)));
// Список версий нужен и для ссылки на installer.jar, и для точного id
// профиля. После перезапуска лаунчера он ещё не прочитан с диска, поэтому
@@ -137,7 +138,7 @@ void ModLoaderInstaller::install(const QString &gameDir,
if (!m_running || m_canceling)
return;
if (!ok) {
fail(warning.isEmpty() ? tr("Список версий %1 недоступен").arg(loaderTitle(loader))
fail(warning.isEmpty() ? Loc::text("loader.error.listUnavailable").arg(loaderTitle(loader))
: warning);
return;
}
@@ -191,14 +192,14 @@ void ModLoaderInstaller::beginFabricLike()
+ m_loaderVersion + u'-' + m_gameVersion;
if (!isSafeSegment(expectedId)) {
fail(tr("Недопустимый идентификатор версии «%1»").arg(expectedId));
fail(Loc::text("loader.error.invalidVersionId").arg(expectedId));
return;
}
const QString base = m_loader == ModLoader::Fabric ? kFabricProfile : kQuiltProfile;
const QUrl url(base + m_gameVersion + u'/' + m_loaderVersion + QStringLiteral("/profile/json"));
setStage(tr("Описание версии %1").arg(loaderTitle(m_loader)));
setStage(Loc::text("loader.progress.description").arg(loaderTitle(m_loader)));
m_currentFile = expectedId + QStringLiteral(".json");
emit progressChanged();
@@ -216,7 +217,7 @@ void ModLoaderInstaller::beginFabricLike()
return;
if (reply->error() != QNetworkReply::NoError) {
fail(tr("Не удалось получить описание %1: %2")
fail(Loc::text("loader.error.descriptionFetchFailed")
.arg(loaderTitle(m_loader), reply->errorString()));
return;
}
@@ -229,21 +230,21 @@ void ModLoaderInstaller::beginFabricLike()
// Описание приходит из сети и превращается в путь на диске — проверяем
// и id, и то, что версия действительно наследует выбранную ванильную.
if (id.isEmpty() || !isSafeSegment(id)) {
fail(tr("Описание %1 испорчено: недопустимый идентификатор версии")
fail(Loc::text("loader.error.descriptionBadId")
.arg(loaderTitle(m_loader)));
return;
}
if (inherits != m_gameVersion) {
fail(tr("Описание %1 рассчитано на Minecraft %2, а не %3")
fail(Loc::text("loader.error.descriptionWrongMinecraft")
.arg(loaderTitle(m_loader), inherits, m_gameVersion));
return;
}
if (id != expectedId)
emit log(tr("Идентификатор версии: %1").arg(id));
emit log(Loc::text("loader.status.versionId").arg(id));
const QString directory = m_gameDir + QStringLiteral("/versions/") + id;
if (!QDir().mkpath(directory)) {
fail(tr("Не удалось создать %1").arg(QDir::toNativeSeparators(directory)));
fail(Loc::text("common.error.createFailed").arg(QDir::toNativeSeparators(directory)));
return;
}
@@ -251,7 +252,7 @@ void ModLoaderInstaller::beginFabricLike()
if (!file.open(QIODevice::WriteOnly) || file.write(payload) != payload.size()
|| !file.commit()) {
file.cancelWriting();
fail(tr("Не удалось сохранить описание версии «%1»").arg(id));
fail(Loc::text("common.error.versionSaveFailed").arg(id));
return;
}
@@ -265,12 +266,12 @@ void ModLoaderInstaller::beginInstallerJar()
{
const auto entry = m_meta->find(m_loader, m_gameVersion, m_loaderVersion);
if (!entry || !entry->installerUrl.isValid()) {
fail(tr("%1 %2 не подходит к Minecraft %3 — выберите версию из списка")
fail(Loc::text("loader.error.incompatible")
.arg(loaderTitle(m_loader), m_loaderVersion, m_gameVersion));
return;
}
if (entry->installerUrl.scheme() != QLatin1String("https")) {
fail(tr("Установщик %1 доступен только по недопустимой ссылке").arg(loaderTitle(m_loader)));
fail(Loc::text("loader.error.installerBadUrl").arg(loaderTitle(m_loader)));
return;
}
@@ -296,7 +297,7 @@ void ModLoaderInstaller::ensureBaseVersion(std::function<void()> next)
}
}
setStage(tr("Установка Minecraft %1").arg(m_gameVersion));
setStage(Loc::text("loader.progress.installingMinecraft").arg(m_gameVersion));
m_currentFile = m_gameVersion;
emit progressChanged();
@@ -329,7 +330,7 @@ void ModLoaderInstaller::ensureBaseVersion(std::function<void()> next)
void ModLoaderInstaller::downloadInstaller(const QUrl &url, std::function<void(const QString &)> next)
{
if (!LauncherPaths::ensureRootExists()) {
fail(tr("Нет доступа к папке лаунчера"));
fail(Loc::text("loader.error.launcherDirUnavailable"));
return;
}
@@ -337,7 +338,7 @@ void ModLoaderInstaller::downloadInstaller(const QUrl &url, std::function<void(c
+ QString(m_loaderVersion).replace(u'/', u'_')
+ QStringLiteral("-installer.jar");
setStage(tr("Загрузка установщика %1").arg(loaderTitle(m_loader)));
setStage(Loc::text("loader.progress.downloadingInstaller").arg(loaderTitle(m_loader)));
m_currentFile = QFileInfo(target).fileName();
emit progressChanged();
@@ -361,7 +362,7 @@ void ModLoaderInstaller::downloadInstaller(const QUrl &url, std::function<void(c
return;
if (reply->error() != QNetworkReply::NoError) {
fail(tr("Не удалось скачать установщик %1: %2")
fail(Loc::text("loader.error.installerDownloadFailed")
.arg(loaderTitle(m_loader), reply->errorString()));
return;
}
@@ -371,7 +372,7 @@ void ModLoaderInstaller::downloadInstaller(const QUrl &url, std::function<void(c
if (!file.open(QIODevice::WriteOnly) || file.write(payload) != payload.size()
|| !file.commit()) {
file.cancelWriting();
fail(tr("Не удалось сохранить установщик %1").arg(loaderTitle(m_loader)));
fail(Loc::text("loader.error.installerSaveFailed").arg(loaderTitle(m_loader)));
return;
}
next(target);
@@ -413,7 +414,7 @@ bool ModLoaderInstaller::writeLauncherProfilesStub()
void ModLoaderInstaller::runInstaller(const QString &installerPath)
{
if (!writeLauncherProfilesStub()) {
fail(tr("Не удалось создать launcher_profiles.json — без него установщик %1 не работает")
fail(Loc::text("loader.error.noLauncherProfiles")
.arg(loaderTitle(m_loader)));
return;
}
@@ -427,7 +428,7 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
QString javaError;
const QString java = JavaLocator::select(m_gameDir, requiredMajor, m_javaPreference, &javaError);
if (java.isEmpty()) {
fail(javaError.isEmpty() ? tr("Java не найдена — установщик %1 запустить нечем")
fail(javaError.isEmpty() ? Loc::text("loader.error.noJava")
.arg(loaderTitle(m_loader))
: javaError);
return;
@@ -448,8 +449,8 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
m_installerLogPath.clear();
}
setStage(tr("Установка %1").arg(loaderTitle(m_loader)));
m_currentFile = tr("работает установщик, это может занять несколько минут");
setStage(Loc::text("loader.progress.installing").arg(loaderTitle(m_loader)));
m_currentFile = Loc::text("loader.progress.installerRunning");
// Прогресс установщика неизвестен: панель покажет «…».
m_bytesDone = 0;
m_bytesTotal = 0;
@@ -493,13 +494,13 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
connect(m_process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
if (m_canceling || error == QProcess::Crashed)
return; // Crashed придёт ещё и в finished
fail(tr("Не удалось запустить установщик %1: %2")
fail(Loc::text("loader.error.installerStartFailed")
.arg(loaderTitle(m_loader), m_process->errorString()));
});
m_process->start();
if (!m_process->waitForStarted(kTransferTimeoutMs)) {
fail(tr("Установщик %1 не запустился: %2")
fail(Loc::text("loader.error.installerFailedToStart")
.arg(loaderTitle(m_loader), m_process->errorString()));
return;
}
@@ -508,7 +509,7 @@ void ModLoaderInstaller::runInstaller(const QString &installerPath)
QTimer::singleShot(kInstallerTimeoutMs, this, [this] {
if (m_process && m_process->state() != QProcess::NotRunning) {
m_process->kill();
fail(tr("Установщик %1 не завершился за отведённое время").arg(loaderTitle(m_loader)));
fail(Loc::text("loader.error.installerTimeout").arg(loaderTitle(m_loader)));
}
});
}
@@ -525,7 +526,7 @@ void ModLoaderInstaller::handleInstallerFinished(int exitCode, bool crashed)
if (crashed || exitCode != 0) {
removeVersionsAddedByInstaller();
QString message = tr("Установщик %1 завершился с ошибкой (код %2).")
QString message = Loc::text("loader.error.installerExitCode")
.arg(loaderTitle(m_loader))
.arg(exitCode);
const QString hint = installerFailureHint();
@@ -535,7 +536,7 @@ void ModLoaderInstaller::handleInstallerFinished(int exitCode, bool crashed)
message += u'\n' + m_installerLog.join(u'\n');
if (!m_installerLogPath.isEmpty())
message += u'\n'
+ tr("Полный лог: %1").arg(QDir::toNativeSeparators(m_installerLogPath));
+ Loc::text("loader.error.fullLog").arg(QDir::toNativeSeparators(m_installerLogPath));
fail(message);
return;
}
@@ -555,7 +556,7 @@ void ModLoaderInstaller::handleInstallerFinished(int exitCode, bool crashed)
}
if (added.isEmpty()) {
QString message = tr("Установщик %1 отработал, но новая версия в %2 не появилась.")
QString message = Loc::text("loader.error.noVersionProduced")
.arg(loaderTitle(m_loader),
QDir::toNativeSeparators(m_gameDir
+ QStringLiteral("/versions")));
@@ -603,7 +604,7 @@ void ModLoaderInstaller::removeVersionsAddedByInstaller()
for (const QString &id : added) {
QString error;
if (!VersionLoader::remove(m_gameDir, id, &error))
emit log(tr("Не удалось убрать незавершённый профиль «%1»: %2").arg(id, error));
emit log(Loc::text("loader.error.cleanupFailed").arg(id, error));
}
m_versionsBefore.clear();
m_installerStarted = false;
@@ -622,10 +623,7 @@ QString ModLoaderInstaller::installerFailureHint() const
if (!checksumFailure)
return {};
return tr("Системный libz.so.1 — это zlib-ng: он сжимает иначе, чем обычный zlib, "
"поэтому sha1 собранных установщиком файлов не совпадает с эталоном. "
"Пересоберите лаунчер, чтобы рядом с ним появился эталонный libz.so.1, "
"либо замените zlib-ng в системе: sudo pacman -S zlib lib32-zlib");
return Loc::text("loader.error.zlibNg");
}
void ModLoaderInstaller::appendInstallerLog(const QString &line)
@@ -650,7 +648,7 @@ void ModLoaderInstaller::closeInstallerLog()
void ModLoaderInstaller::handOffToVersionInstaller(const QString &versionId)
{
m_awaitingVersionId = versionId;
setStage(tr("Загрузка файлов версии"));
setStage(Loc::text("loader.progress.downloadingVersionFiles"));
m_currentFile = versionId;
emit progressChanged();
m_versionInstaller->install(m_gameDir, versionId);