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)