145 lines
5.7 KiB
C++
145 lines
5.7 KiB
C++
// Copyright 2021-2023 The Mumble Developers. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file at the root of the
|
|
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
#include "Translations.h"
|
|
|
|
#include <QApplication>
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QLibraryInfo>
|
|
#include <QtCore/QStandardPaths>
|
|
#include <QtCore/QTranslator>
|
|
|
|
namespace Mumble {
|
|
namespace Translations {
|
|
|
|
LifetimeGuard::LifetimeGuard(LifetimeGuard &&old)
|
|
: m_bundledTranslator(old.m_bundledTranslator), m_overwriteTranslator(old.m_overwriteTranslator),
|
|
m_qtTranslator(old.m_qtTranslator) {
|
|
// Reset values of old
|
|
old.m_bundledTranslator = nullptr;
|
|
old.m_overwriteTranslator = nullptr;
|
|
old.m_qtTranslator = nullptr;
|
|
}
|
|
|
|
LifetimeGuard::~LifetimeGuard() {
|
|
delete m_bundledTranslator;
|
|
delete m_overwriteTranslator;
|
|
delete m_qtTranslator;
|
|
}
|
|
|
|
QStringList getDefaultTranslationDirectories() {
|
|
QStringList translationDirs;
|
|
|
|
const QString translationDirName = "MumbleTranslations";
|
|
|
|
// AppData directories
|
|
for (const QString ¤tConfigPath : QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)) {
|
|
translationDirs.append(QDir::cleanPath(currentConfigPath));
|
|
}
|
|
// Directories in the config locations
|
|
for (const QString ¤tConfigPath : QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)) {
|
|
translationDirs.append(QDir::cleanPath(currentConfigPath + QDir::separator() + translationDirName));
|
|
}
|
|
// A directory in the home directory
|
|
for (const QString ¤tHomePath : QStandardPaths::standardLocations(QStandardPaths::HomeLocation)) {
|
|
translationDirs.append(QDir::cleanPath(currentHomePath + QDir::separator() + translationDirName));
|
|
}
|
|
|
|
return translationDirs;
|
|
}
|
|
|
|
QStringList getTranslationDirectories(const QApplication &app, const QStringList &extraDirectories) {
|
|
QStringList directories;
|
|
|
|
// The extra directories have highest priority
|
|
directories += extraDirectories;
|
|
|
|
// Next up is the application's root path
|
|
directories.append(app.applicationDirPath());
|
|
|
|
// And finally the default locations
|
|
directories += getDefaultTranslationDirectories();
|
|
|
|
return directories;
|
|
}
|
|
|
|
LifetimeGuard installTranslators(const QLocale &locale, QApplication &app, const QStringList &extraDirectories) {
|
|
LifetimeGuard guard;
|
|
|
|
// First install a translator that uses the bundled translations
|
|
guard.m_bundledTranslator = new QTranslator();
|
|
if (guard.m_bundledTranslator->load(locale, ":mumble_")) {
|
|
app.installTranslator(guard.m_bundledTranslator);
|
|
} else {
|
|
qWarning("Unable to find bundled translations for locale \"%s\"", qUtf8Printable(locale.name()));
|
|
|
|
delete guard.m_bundledTranslator;
|
|
guard.m_bundledTranslator = nullptr;
|
|
}
|
|
|
|
// Now try to add another translator that can overwrite the bundled translations based
|
|
// on translations found in one of the translation directories.
|
|
// The first matching translation file that is found, will be used (first come, first served)
|
|
guard.m_overwriteTranslator = new QTranslator();
|
|
|
|
const QString prefix = "";
|
|
|
|
bool overwriteTranslatorFound = false;
|
|
for (const QString ¤tDir : getTranslationDirectories(app, extraDirectories)) {
|
|
if (guard.m_overwriteTranslator->load(locale, "mumble_", prefix, currentDir)) {
|
|
app.installTranslator(guard.m_overwriteTranslator);
|
|
|
|
qWarning("Using extra translation file for locale \"%s\" from directory \"%s\"",
|
|
qUtf8Printable(locale.name()), qUtf8Printable(currentDir));
|
|
|
|
overwriteTranslatorFound = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!overwriteTranslatorFound) {
|
|
delete guard.m_overwriteTranslator;
|
|
guard.m_overwriteTranslator = nullptr;
|
|
}
|
|
|
|
// With modularization of Qt 5 some - but not all - of the qt_<locale>.ts files have become
|
|
// so-called meta catalogues which no longer contain actual translations but refer to other
|
|
// more specific ts files like qtbase_<locale>.ts . To successfully load a meta catalogue all
|
|
// of its referenced translations must be available. As we do not want to bundle them all
|
|
// we now try to load the old qt_<locale>.ts file first and then fall back to loading
|
|
// qtbase_<locale>.ts if that failed.
|
|
//
|
|
// See http://doc.qt.io/qt-5/linguist-programmers.html#deploying-translations for more information
|
|
guard.m_qtTranslator = new QTranslator();
|
|
// First we try and see if there is a translation packaged with Mumble that shall overwrite any potentially
|
|
// existing Qt translations. If not, we try to load the qt-translations installed on the host-machine and if
|
|
// that fails as well, we try to load translations bundled in Mumble. Note: Resource starting with :/ are
|
|
// bundled resources specified in a .qrc file
|
|
if (guard.m_qtTranslator->load(locale, ":/mumble_overwrite_qt_")) {
|
|
app.installTranslator(guard.m_qtTranslator);
|
|
} else if (guard.m_qtTranslator->load(locale, ":/mumble_overwrite_qtbase_")) {
|
|
app.installTranslator(guard.m_qtTranslator);
|
|
} else if (guard.m_qtTranslator->load(locale, "qt_", prefix,
|
|
QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
|
app.installTranslator(guard.m_qtTranslator);
|
|
} else if (guard.m_qtTranslator->load(locale, "qtbase_", prefix,
|
|
QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
|
app.installTranslator(guard.m_qtTranslator);
|
|
} else if (guard.m_qtTranslator->load(locale, ":/qt_")) {
|
|
app.installTranslator(guard.m_qtTranslator);
|
|
} else if (guard.m_qtTranslator->load(locale, ":/qtbase_")) {
|
|
app.installTranslator(guard.m_qtTranslator);
|
|
} else {
|
|
// Did not install Qt translator
|
|
delete guard.m_qtTranslator;
|
|
guard.m_qtTranslator = nullptr;
|
|
}
|
|
|
|
return guard;
|
|
}
|
|
} // namespace Translations
|
|
} // namespace Mumble
|