1/* This file is part of the KDE libraries
2 SPDX-FileCopyrightText: 2015 Lukáš Tinkl <ltinkl@redhat.com>
3 SPDX-FileCopyrightText: 2021,2023 Ingo Klöcker <kloecker@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "ki18n_logging.h"
9
10#include <QCoreApplication>
11#include <QLibraryInfo>
12#include <QLocale>
13#include <QThread>
14#include <QTranslator>
15
16#include <memory>
17
18static bool loadCatalog(const QString &catalog, const QLocale &locale)
19{
20 Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
21 auto translator = std::make_unique<QTranslator>(args: QCoreApplication::instance());
22 if (!translator->load(locale, filename: catalog, prefix: QString(), directory: QLibraryInfo::path(p: QLibraryInfo::TranslationsPath))) {
23 qCDebug(KI18N) << "Loading the" << catalog << "catalog failed for locale" << locale;
24 return false;
25 }
26 QCoreApplication::instance()->installTranslator(messageFile: translator.release());
27 return true;
28}
29
30static bool loadCatalog(const QString &catalog, const QLocale &locale, const QLocale &fallbackLocale)
31{
32 // try to load the catalog for locale
33 if (loadCatalog(catalog, locale)) {
34 return true;
35 }
36 // if this fails, then try the fallback locale (if it's different from locale)
37 if (fallbackLocale != locale) {
38 return loadCatalog(catalog, locale: fallbackLocale);
39 }
40 return false;
41}
42
43// load global Qt translation, needed in KDE e.g. by lots of builtin dialogs (QColorDialog, QFontDialog) that we use
44static void loadTranslation(const QString &localeName, const QString &fallbackLocaleName)
45{
46 const QLocale locale{localeName};
47 const QLocale fallbackLocale{fallbackLocaleName};
48 // first, try to load the qt_ meta catalog
49 if (loadCatalog(QStringLiteral("qt_"), locale, fallbackLocale)) {
50 return;
51 }
52 // if loading the meta catalog failed, then try loading the four catalogs
53 // it depends on, i.e. qtbase, qtscript, qtmultimedia, qtxmlpatterns, separately
54 const auto catalogs = {
55 QStringLiteral("qtbase_"),
56 QStringLiteral("qtscript_"),
57 QStringLiteral("qtmultimedia_"),
58 QStringLiteral("qtxmlpatterns_"),
59 };
60 for (const auto &catalog : catalogs) {
61 loadCatalog(catalog, locale, fallbackLocale);
62 }
63}
64
65static QLocale getSystemLocale()
66{
67#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
68 // On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific
69 // language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs.
70 // The following code is a simplified variant of QSystemLocale::fallbackUiLocale()
71 // (in qlocale_unix.cpp) ignoring LC_ALL, LC_MESSAGES, and LANG.
72 QString language = qEnvironmentVariable("LANGUAGE");
73 if (!language.isEmpty()) {
74 language = language.split(QLatin1Char{':'}).constFirst();
75 if (!language.isEmpty()) {
76 return QLocale{language};
77 }
78 }
79#endif
80 return QLocale::system();
81}
82
83static void load()
84{
85 // The way Qt translation system handles plural forms makes it necessary to
86 // have a translation file which contains only plural forms for `en`. That's
87 // why we load the `en` translation unconditionally, then load the
88 // translation for the current locale to overload it.
89 QMetaObject::invokeMethod(object: QCoreApplication::instance(), function: [] {
90 loadCatalog(QStringLiteral("qt_"), locale: QLocale{QStringLiteral("en")});
91
92 const QLocale locale = getSystemLocale();
93 if (locale.name() != QStringLiteral("en")) {
94 loadTranslation(localeName: locale.name(), fallbackLocaleName: locale.bcp47Name());
95 }
96 });
97}
98
99Q_COREAPP_STARTUP_FUNCTION(load)
100

source code of ki18n/src/i18n/main.cpp