File: ECMQmLoader.cpp.in

package info (click to toggle)
extra-cmake-modules 5.103.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,116 kB
  • sloc: python: 1,744; cpp: 646; ansic: 258; xml: 182; sh: 36; makefile: 5
file content (139 lines) | stat: -rw-r--r-- 5,009 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
/* 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-License-Identifier: BSD-3-Clause
 */
#include <QCoreApplication>
#include <QLocale>
#include <QStandardPaths>
#include <QThread>
#include <QTranslator>
#include <QDir>

namespace {

    enum class LoadOptions { CreateWatcher, DoNotCreateWatcher };

    void load(LoadOptions options);

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

    private:
        bool eventFilter(QObject *obj, QEvent *event) override
        {
            if (event->type() == QEvent::LanguageChange) {
                if (m_loadedLocale != QLocale::system().name()) {
                    m_loadedLocale = QLocale::system().name();
                    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"));

        QLocale locale = QLocale::system();
        if (locale.name() != QStringLiteral("en")) {
            if (!loadTranslation(locale.name())) {
                if (!loadTranslation(locale.bcp47Name())) {
                    const int i = locale.name().indexOf(QLatin1Char('_'));
                    if (i > 0) {
                        loadTranslation(locale.name().left(i));
                    }
                }
            }
        }

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

    // Helper to call load() on the main thread.
    //
    // Calling functions on another thread without using moc is non-trivial in
    // Qt until 5.4 (when some useful QTimer::singleShot overloads were added).
    //
    // Instead, we have to use QEvents. Ideally, we'd use a custom QEvent, but
    // there's a chance this could cause trouble with applications that claim
    // QEvent codes themselves, but don't register them with Qt (and we also
    // want to avoid registering a new QEvent code for every plugin that might
    // be loaded). We use QTimer because it's unlikely to be filtered by
    // applications, and is also unlikely to cause Qt to do something it
    // shouldn't.
    class Loader : public QObject
    {
    protected:
        void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE
        {
            load(LoadOptions::CreateWatcher);
            this->deleteLater();
        }
    };

    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 {
            // QObjects inherit their parent object's thread
            Loader *loader = new Loader();
            loader->moveToThread(QCoreApplication::instance()->thread());
            QCoreApplication::instance()->postEvent(loader, new QTimerEvent(0), Qt::HighEventPriority);
        }
    }
}

Q_COREAPP_STARTUP_FUNCTION(loadOnMainThread)