subsurface/core/qt-init.cpp
Dirk Hohndel 9745f80431 translations: load parent language translations
Many language have country specific differences. We recognize different
flavors of English (US, UK (and South Africa)), German (Germany and
Switzerland), and Portuguese (Brazil and Portugal). For many other
flavors of the languages that we have translations for we have no
support and the way we hard-coded the fallbacks in the past was odd and
meant that in the cases where we do have two flavors, missing strings in
one weren't taken from the other (English as the default language being
the exception).

This tries to do a better job of recognizing some of those parent
languages and loading translators for them, first. Which means if we
then find a translator for the specific language (i.e., de_CH), strings
missing in that translation are next searched in the parent language
(de_DE), before finally providing the source language string (en_US).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-03-26 14:10:16 -07:00

138 lines
5.9 KiB
C++

// SPDX-License-Identifier: GPL-2.0
#include <QApplication>
#include <Qt>
#include <QNetworkProxy>
#include <QLibraryInfo>
#include <QTextCodec>
#include <QTranslator>
#include "qthelper.h"
#include "errorhelper.h"
#include "core/settings/qPref.h"
char *settings_suffix = NULL;
static QTranslator qtTranslator, ssrfTranslator, parentLanguageTranslator;
void init_qt_late()
{
QApplication *application = qApp;
// tell Qt to use system proxies
// note: on Linux, "system" == "environment variables"
QNetworkProxyFactory::setUseSystemConfiguration(true);
// Set the locale codec to UTF-8.
// This makes QFile::encodeName() work on Windows and qPrintable() is equivalent to qUtf8Printable().
QTextCodec::setCodecForLocale(QTextCodec::codecForMib(106));
QCoreApplication::setOrganizationName("Subsurface");
QCoreApplication::setOrganizationDomain("subsurface.hohndel.org");
#if defined(Q_OS_LINUX)
QGuiApplication::setDesktopFileName("subsurface");
#endif
// enable user specific settings (based on command line argument)
if (settings_suffix) {
if (verbose)
#if defined(SUBSURFACE_MOBILE) && ((defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || (defined(Q_OS_DARWIN) && !defined(Q_OS_IOS)))
qDebug() << "using custom config for" << QString("Subsurface-Mobile-%1").arg(settings_suffix);
#else
qDebug() << "using custom config for" << QString("Subsurface-%1").arg(settings_suffix);
#endif
#if defined(SUBSURFACE_MOBILE) && ((defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || (defined(Q_OS_DARWIN) && !defined(Q_OS_IOS)))
QCoreApplication::setApplicationName(QString("Subsurface-Mobile-%1").arg(settings_suffix));
#else
QCoreApplication::setApplicationName(QString("Subsurface-%1").arg(settings_suffix));
#endif
} else {
#if defined(SUBSURFACE_MOBILE) && ((defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || (defined(Q_OS_DARWIN) && !defined(Q_OS_IOS)))
QCoreApplication::setApplicationName("Subsurface-Mobile");
#else
QCoreApplication::setApplicationName("Subsurface");
#endif
}
// Disables the WindowContextHelpButtonHint by default on Qt::Sheet and Qt::Dialog widgets.
// This hides the ? button on Windows, which only makes sense if you use QWhatsThis functionality.
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
qPref::load();
// find plugins installed in the application directory (without this SVGs don't work on Windows)
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
QLocale loc;
// assign en_GB for use in South African locale
if (loc.country() == QLocale::SouthAfrica) {
loc.setDefault(QLocale("en_GB"));
loc = QLocale();
}
initUiLanguage();
QString uiLang = getUiLanguage();
loc = getLocale();
QLocale::setDefault(loc);
QString translationLocation;
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
translationLocation = QLatin1String(":/");
#else
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
translationLocation = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
#else
translationLocation = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
#endif
#endif
if (uiLang != "en_US" && uiLang != "en-US") {
if (qtTranslator.load(loc, "qtbase", "_", translationLocation) ||
qtTranslator.load(loc, "qtbase", "_", getSubsurfaceDataPath("translations")) ||
qtTranslator.load(loc, "qtbase", "_", getSubsurfaceDataPath("../translations"))) {
application->installTranslator(&qtTranslator);
} else {
// it's possible that this is one of the couple of languages that still have qt_XX translations
// and no qtbase_XX translations - as of this writing this is true for Swedish and Portuguese
if (qtTranslator.load(loc, "qt", "_", translationLocation) ||
qtTranslator.load(loc, "qt", "_", getSubsurfaceDataPath("translations")) ||
qtTranslator.load(loc, "qt", "_", getSubsurfaceDataPath("../translations"))) {
application->installTranslator(&qtTranslator);
} else {
qDebug() << "can't find Qt base localization for locale" << uiLang << "searching in" << translationLocation;
}
}
}
// when creating our language names, we didn't define generic languages with additional
// country specific extensions, instead we included the "primary" country in the
// translation designations. This breaks the way Qt finds fall-back translations.
// Changing this now seems rather tedious, so instead we manually create a few
// obvious fallbacks
QPair<QLocale::Language, QLocale::Country> parents[] = {
{ QLocale::German, QLocale::Germany },
{ QLocale::Portuguese, QLocale::Brazil },
{ QLocale::French, QLocale::France},
{ QLocale::Spanish, QLocale::Spain}
};
for (auto parent: parents) {
if (loc.language() == parent.first && loc.country() != parent.second) {
// first load de_DE so it's used as fall-back
QLocale parentLoc = QLocale(parent.first, parent.second);
if (parentLanguageTranslator.load(parentLoc, "subsurface", "_") ||
parentLanguageTranslator.load(parentLoc, "subsurface", "_", translationLocation) ||
parentLanguageTranslator.load(parentLoc, "subsurface", "_", getSubsurfaceDataPath("translations")) ||
parentLanguageTranslator.load(parentLoc, "subsurface", "_", getSubsurfaceDataPath("../translations"))) {
if (verbose)
qDebug() << "loading" << parentLoc.name() << "translations";
application->installTranslator(&parentLanguageTranslator);
} else {
qDebug() << "can't find Subsurface localization for locale" << parentLoc.name();
}
}
}
if (ssrfTranslator.load(loc, "subsurface", "_") ||
ssrfTranslator.load(loc, "subsurface", "_", translationLocation) ||
ssrfTranslator.load(loc, "subsurface", "_", getSubsurfaceDataPath("translations")) ||
ssrfTranslator.load(loc, "subsurface", "_", getSubsurfaceDataPath("../translations"))) {
if (verbose)
qDebug() << "loading" << uiLang << "translations";
application->installTranslator(&ssrfTranslator);
} else {
qDebug() << "can't find Subsurface localization for locale" << uiLang;
}
}