Warning, /frameworks/extra-cmake-modules/modules/ECMQmLoader.cpp.in is written in an unsupported language. File is not indexed.

0001 /* This file was generated by ecm_create_qm_loader(). DO NOT EDIT!
0002  *
0003  * Building this file in a library ensures translations are automatically loaded
0004  * when an application makes use of the library.
0005  *
0006  *
0007  * SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
0008  * SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
0009  * SPDX-FileCopyrightText: 2023 Ingo Klöcker <kloecker@kde.org>
0010  *
0011  * SPDX-License-Identifier: BSD-3-Clause
0012  */
0013 #include <QCoreApplication>
0014 #include <QLocale>
0015 #include <QStandardPaths>
0016 #include <QThread>
0017 #include <QTranslator>
0018 #include <QDir>
0019 
0020 namespace {
0021 
0022     static QLocale getSystemLocale()
0023     {
0024 #if defined(Q_OS_WIN) || defined(Q_OS_MAC)
0025         // On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific
0026         // language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs.
0027         // The following code is a simplified variant of QSystemLocale::fallbackUiLocale()
0028         // (in qlocale_unix.cpp) ignoring LC_ALL, LC_MESSAGES, and LANG.
0029         QString language = qEnvironmentVariable("LANGUAGE");
0030         if (!language.isEmpty()) {
0031             language = language.split(QLatin1Char{':'}).constFirst();
0032             if (!language.isEmpty()) {
0033                 return QLocale{language};
0034             }
0035         }
0036 #endif
0037         return QLocale::system();
0038     }
0039 
0040     enum class LoadOptions { CreateWatcher, DoNotCreateWatcher };
0041 
0042     void load(LoadOptions options);
0043 
0044     class LanguageChangeWatcher : public QObject
0045     {
0046     public:
0047         LanguageChangeWatcher(QObject *parent) : QObject(parent)
0048         {
0049             m_loadedLocale = getSystemLocale().name();
0050             QCoreApplication::instance()->installEventFilter(this);
0051         }
0052 
0053     private:
0054         bool eventFilter(QObject *obj, QEvent *event) override
0055         {
0056             if (event->type() == QEvent::LanguageChange) {
0057                 const auto systemLocaleName = getSystemLocale().name();
0058                 if (m_loadedLocale != systemLocaleName) {
0059                     m_loadedLocale = systemLocaleName;
0060                     load(LoadOptions::DoNotCreateWatcher);
0061                 }
0062             }
0063             return QObject::eventFilter(obj, event);
0064         }
0065 
0066 
0067         QString m_loadedLocale;
0068     };
0069 
0070     bool loadTranslation(const QString &localeDirName)
0071     {
0072         QString subPath = QStringLiteral("locale/") + localeDirName + QStringLiteral("/LC_MESSAGES/@QM_LOADER_CATALOG_NAME@.qm");
0073 
0074 #if defined(Q_OS_ANDROID)
0075         const QString fullPath = QStringLiteral("assets:/share/") + subPath;
0076         if (!QFile::exists(fullPath)) {
0077             return false;
0078         }
0079 #else
0080         const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
0081         if (fullPath.isEmpty()) {
0082             return false;
0083         }
0084 #endif
0085         QTranslator *translator = new QTranslator(QCoreApplication::instance());
0086         if (!translator->load(fullPath)) {
0087             delete translator;
0088             return false;
0089         }
0090         QCoreApplication::instance()->installTranslator(translator);
0091         return true;
0092     }
0093 
0094     void load(LoadOptions options)
0095     {
0096         // The way Qt translation system handles plural forms makes it necessary to
0097         // have a translation file which contains only plural forms for `en`. That's
0098         // why we load the `en` translation unconditionally, then load the
0099         // translation for the current locale to overload it.
0100         loadTranslation(QStringLiteral("en"));
0101 
0102         const QLocale locale = getSystemLocale();
0103         if (locale.name() != QStringLiteral("en")) {
0104             if (!loadTranslation(locale.name())) {
0105                 if (!loadTranslation(locale.bcp47Name())) {
0106                     const int i = locale.name().indexOf(QLatin1Char('_'));
0107                     if (i > 0) {
0108                         loadTranslation(locale.name().left(i));
0109                     }
0110                 }
0111             }
0112         }
0113 
0114         if (options == LoadOptions::CreateWatcher) {
0115             new LanguageChangeWatcher(QCoreApplication::instance());
0116         }
0117     }
0118 
0119     // Helper to call load() on the main thread.
0120     //
0121     // Calling functions on another thread without using moc is non-trivial in
0122     // Qt until 5.4 (when some useful QTimer::singleShot overloads were added).
0123     //
0124     // Instead, we have to use QEvents. Ideally, we'd use a custom QEvent, but
0125     // there's a chance this could cause trouble with applications that claim
0126     // QEvent codes themselves, but don't register them with Qt (and we also
0127     // want to avoid registering a new QEvent code for every plugin that might
0128     // be loaded). We use QTimer because it's unlikely to be filtered by
0129     // applications, and is also unlikely to cause Qt to do something it
0130     // shouldn't.
0131     class Loader : public QObject
0132     {
0133     protected:
0134         void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE
0135         {
0136             load(LoadOptions::CreateWatcher);
0137             this->deleteLater();
0138         }
0139     };
0140 
0141     void loadOnMainThread()
0142     {
0143         // If this library is loaded after the QCoreApplication instance is
0144         // created (eg: because it is brought in by a plugin), there is no
0145         // guarantee this function will be called on the main thread.
0146         // QCoreApplication::installTranslator needs to be called on the main
0147         // thread, because it uses QCoreApplication::sendEvent.
0148         if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
0149             load(LoadOptions::CreateWatcher);
0150         } else {
0151             // QObjects inherit their parent object's thread
0152             Loader *loader = new Loader();
0153             loader->moveToThread(QCoreApplication::instance()->thread());
0154             QCoreApplication::instance()->postEvent(loader, new QTimerEvent(0), Qt::HighEventPriority);
0155         }
0156     }
0157 }
0158 
0159 Q_COREAPP_STARTUP_FUNCTION(loadOnMainThread)