KI18n

main.cpp
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 <QFile>
12#include <QLibraryInfo>
13#include <QLocale>
14#include <QThread>
15#include <QTranslator>
16
17#include <memory>
18
19//
20// NOTE when changing anything in here, also check whether ECMQmLoader.cpp.in in ECM
21// needs to be changed as well!
22//
23
24using namespace Qt::Literals;
25
26[[nodiscard]] static QString translationsPath()
27{
28#ifndef Q_OS_ANDROID
30#else
31 return u"assets://translations/"_s;
32#endif
33}
34
35static bool loadCatalog(QStringView catalog, QStringView language)
36{
37 Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
38 const QString fullPath = translationsPath() + '/'_L1 + catalog + language + ".qm"_L1;
39 if (!QFile::exists(fullPath)) {
40 return false;
41 }
42 auto translator = std::make_unique<QTranslator>(QCoreApplication::instance());
43 if (!translator->load(fullPath)) {
44 qCDebug(KI18N) << "Loading catalog failed:" << fullPath;
45 return false;
46 }
47 QCoreApplication::instance()->installTranslator(translator.release());
48 return true;
49}
50
51// load global Qt translation, needed in KDE e.g. by lots of builtin dialogs (QColorDialog, QFontDialog) that we use
52static bool loadTranslation(QStringView language)
53{
54 // first, try to load the qt_ meta catalog
55 if (loadCatalog(u"qt_", language)) {
56 return true;
57 }
58 // if loading the meta catalog failed, then try loading the catalogs
59 // it depends on, i.e. qtbase, qtmultimedia separately
60 const auto catalogs = {
61 u"qtbase_",
62 u"qtmultimedia_",
63 };
64 bool success = false;
65 for (const auto &catalog : catalogs) {
66 success |= loadCatalog(catalog, language);
67 }
68 return success;
69}
70
71static QStringList getSystemLanguages()
72{
73#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
74 // On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific
75 // language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs.
76 // The following code is a simplified variant of QSystemLocale::fallbackUiLocale()
77 // (in qlocale_unix.cpp) ignoring LC_ALL, LC_MESSAGES, and LANG.
78 if (const auto languages = qEnvironmentVariable("LANGUAGE").split(':'_L1, Qt::SkipEmptyParts); !languages.isEmpty()) {
79 return languages;
80 }
81#endif
83}
84
85static void load()
86{
87 // The way Qt translation system handles plural forms makes it necessary to
88 // have a translation file which contains only plural forms for `en`. That's
89 // why we load the `en` translation unconditionally, then load the
90 // translation for the current locale to overload it.
92 loadCatalog(u"qt_", u"en");
93
94 auto languages = getSystemLanguages();
95 for (qsizetype i = 0; i < languages.size(); ++i) {
96 // normalize into the format used in Qt catalog suffixes
97 languages[i].replace('-'_L1, '_'_L1);
98 // make sure we always also have the generic language variant
99 // depending on the platform that might not be in uiLanguages by default
100 // insert that after the last country-specific entry for the same language
101 const auto idx = languages[i].indexOf('_'_L1);
102 if (idx > 0) {
103 const QString genericLang = languages[i].left(idx);
104 qsizetype j = i + 1;
105 for (; j < languages.size(); ++j) {
106 if (!languages[j].startsWith(genericLang)) {
107 break;
108 }
109 }
110 if (languages[j - 1] != genericLang) {
111 languages.insert(j, genericLang);
112 }
113 }
114 }
116 for (const auto &language : languages) {
117 if (language == "en"_L1 || loadTranslation(language)) {
118 break;
119 }
120 }
121 });
122}
123
124Q_COREAPP_STARTUP_FUNCTION(load)
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
KEDUVOCDOCUMENT_EXPORT QStringList languages()
bool installTranslator(QTranslator *translationFile)
QCoreApplication * instance()
bool exists() const const
QString path(LibraryPath p)
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
void replace(qsizetype i, parameter_type value)
qsizetype size() const const
QLocale system()
QStringList uiLanguages() const const
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
qsizetype removeDuplicates()
SkipEmptyParts
QThread * currentThread()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:05:34 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.