File: ECMQmLoader.cpp.in

package info (click to toggle)
kf6-extra-cmake-modules 6.20.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,524 kB
  • sloc: python: 668; cpp: 326; ansic: 291; xml: 182; sh: 62; makefile: 8
file content (164 lines) | stat: -rw-r--r-- 5,853 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* This file was generated by ecm_create_qm_loader(). DO NOT EDIT!
 *
 * Building this file in a library ensures translations are automatically loaded
 * when an application makes use of the library.
 *
 *
 * SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
 * SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
 * SPDX-FileCopyrightText: 2023 Ingo Klöcker <kloecker@kde.org>
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include <QCoreApplication>
#include <QLocale>
#include <QStandardPaths>
#include <QThread>
#include <QTranslator>
#include <QDir>

namespace {

    static QLocale getSystemLocale()
    {
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
        // On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific
        // language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs.
        // The following code is a simplified variant of QSystemLocale::fallbackUiLocale()
        // (in qlocale_unix.cpp) ignoring LC_ALL, LC_MESSAGES, and LANG.
        QString language = qEnvironmentVariable("LANGUAGE");
        if (!language.isEmpty()) {
            language = language.split(QLatin1Char{':'}).constFirst();
            if (!language.isEmpty()) {
                return QLocale{language};
            }
        }
#endif
        return QLocale::system();
    }

    enum class LoadOptions { CreateWatcher, DoNotCreateWatcher };

    void load(LoadOptions options);

    class LanguageChangeWatcher : public QObject
    {
    public:
        LanguageChangeWatcher(QObject *parent) : QObject(parent)
        {
            m_loadedLocale = getSystemLocale().name();
            QCoreApplication::instance()->installEventFilter(this);
        }

    private:
        bool eventFilter(QObject *obj, QEvent *event) override
        {
            if (event->type() == QEvent::LanguageChange) {
                const auto systemLocaleName = getSystemLocale().name();
                if (m_loadedLocale != systemLocaleName) {
                    m_loadedLocale = systemLocaleName;
                    load(LoadOptions::DoNotCreateWatcher);
                }
            }
            return QObject::eventFilter(obj, event);
        }


        QString m_loadedLocale;
    };

    bool loadTranslation(const QString &localeDirName)
    {
        QString subPath = QStringLiteral("locale/") + localeDirName + QStringLiteral("/LC_MESSAGES/@QM_LOADER_CATALOG_NAME@.qm");

#if defined(Q_OS_ANDROID)
        const QString fullPath = QStringLiteral("assets:/share/") + subPath;
        if (!QFile::exists(fullPath)) {
            return false;
        }
#else
        const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
        if (fullPath.isEmpty()) {
            return false;
        }
#endif
        QTranslator *translator = new QTranslator(QCoreApplication::instance());
        if (!translator->load(fullPath)) {
            delete translator;
            return false;
        }
        QCoreApplication::instance()->installTranslator(translator);
        return true;
    }

    void load(LoadOptions options)
    {
        // The way Qt translation system handles plural forms makes it necessary to
        // have a translation file which contains only plural forms for `en`. That's
        // why we load the `en` translation unconditionally, then load the
        // translation for the current locale to overload it.
        loadTranslation(QStringLiteral("en"));

        auto langs = getSystemLocale().uiLanguages();

        for (int i = 0; i < langs.size(); i++) {
            langs[i].replace(QLatin1Char('-'), QLatin1Char('_'));
            const auto idx = langs[i].indexOf(QLatin1Char('_'));
            if (idx > 0) {
                // insert the country stripped language to the ideal position,
                // that is, after the same langauge dialects.
                // if langs is [pt_Latn_BR, pt_BR], the pt should be inserted
                // after pt_BR
                const QString genericLang = langs[i].left(idx);
                int j = i + 1;
                int insertIdx = j;
                bool found = false;
                while (j < langs.size()) {
                    if (langs[j] == genericLang) {
                        found = true;
                        break;
                    }
                    if (langs[j].startsWith(genericLang)) {
                        insertIdx = j + 1;
                    }
                    j++;
                }
                if (!found) {
                    langs.insert(insertIdx, genericLang);
                }
            }
        }
        langs.removeDuplicates();
        for (const auto &lang :
#if QT_VERSION_MAJOR == 5
                qAsConst(langs)
#else
                std::as_const(langs)
#endif
                ) {
            if (lang == QLatin1String("en") || loadTranslation(lang)) {
                break;
            }
        }

        if (options == LoadOptions::CreateWatcher) {
            new LanguageChangeWatcher(QCoreApplication::instance());
        }
    }

    void loadOnMainThread()
    {
        // If this library is loaded after the QCoreApplication instance is
        // created (eg: because it is brought in by a plugin), there is no
        // guarantee this function will be called on the main thread.
        // QCoreApplication::installTranslator needs to be called on the main
        // thread, because it uses QCoreApplication::sendEvent.
        if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
            load(LoadOptions::CreateWatcher);
        } else {
            QMetaObject::invokeMethod(QCoreApplication::instance(), [] { load(LoadOptions::CreateWatcher); }, Qt::QueuedConnection);
        }
    }
}

Q_COREAPP_STARTUP_FUNCTION(loadOnMainThread)