KSeExpr 6.0.0.0
ECMQmLoader-seexpr2_qt.cpp
Go to the documentation of this file.
1/* This file was generated by ecm_create_qm_loader().
2 * It was edited for KSeExpr.
3 *
4 * Building this file in a library ensures translations are automatically loaded
5 * when an application makes use of the library.
6 *
7 *
8 * SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
9 * SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
10 * SPDX-FileCopyrightText: 2020-2021 L. E. Segovia <amy@amyspark.me>
11 *
12 * SPDX-License-Identifier: BSD-3-Clause
13 */
14#include <Debug.h>
15
16#include <QCoreApplication>
17#include <QDir>
18#include <QLocale>
19#include <QObject>
20#include <QStandardPaths>
21#include <QThread>
22#include <QTranslator>
23
24#if defined(KSeExpr_HAVE_I18N_FALLBACK_LANGUAGES_DETECTION)
25#include <KLocalizedString>
26#include <algorithm>
27#endif
28
29namespace KSeExpr {
30
32 {
33 QString subPath = QStringLiteral("locale/") + localeDirName + QStringLiteral("/LC_MESSAGES/seexpr2_qt.qm");
34
35 dbgSeExpr << "Attempting to load: " << subPath;
36
37#if defined(Q_OS_ANDROID)
38 const QString fullPath = QStringLiteral("assets:/share/") + subPath;
39 if (!QFile::exists(fullPath)) {
40 return false;
41 }
42#else
43 // Use application's own data directory (e.g. Krita on AppImage, Windows)
44 QString fullPath = QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, subPath);
45 if (fullPath.isEmpty()) {
46 // Try falling back to stock folder
47 fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
48 if (fullPath.isEmpty())
49 return false;
50 }
51#endif
52 QTranslator *translator = new QTranslator(QCoreApplication::instance());
53 if (!translator->load(fullPath)) {
54 delete translator;
55 return false;
56 }
57#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
58 dbgSeExpr << "Installing translation for: " << fullPath << "(" << translator->language() << ")";
59#else
60 dbgSeExpr << "Installing translation for: " << fullPath;
61#endif
62 dbgSeExpr << "Test: " << translator->translate("ExprControlCollection", "Add new variable");
63
64 QCoreApplication::instance()->installTranslator(translator);
65 return true;
66 }
67
68 void load()
69 {
70#if defined(Q_OS_ANDROID)
71 const auto paths = QStringLiteral("assets:/share/");
72#else
73 auto paths = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
74 paths << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
75#endif
76 dbgSeExpr << "Base paths for translations: " << paths;
77
78#if defined(KSeExpr_HAVE_I18N_FALLBACK_LANGUAGES_DETECTION)
79 dbgSeExpr << "Qt UI languages: " << KLocalizedString::languages() << QLocale().uiLanguages() << qgetenv("LANG");
80#else
81 dbgSeExpr << "Qt UI languages: " << QLocale().uiLanguages() << qgetenv("LANG");
82#endif
83
84 // The way Qt translation system handles plural forms makes it necessary to
85 // have a translation file which contains only plural forms for `en`. That's
86 // why we load the `en` translation unconditionally, then load the
87 // translation for the current locale to overload it.
89
90 // Use the default locale and any available fallback languages.
91 // Fallback languages must be reverse iterated in order of priority.
92#if defined(KSeExpr_HAVE_I18N_FALLBACK_LANGUAGES_DETECTION)
93 const auto fallbackLanguages { KLocalizedString::languages()};
94 for (auto it = fallbackLanguages.rbegin(); it != fallbackLanguages.rend(); ++it) {
95 if(!loadTranslation(*it)) {
96 const auto localeParts = it->split('@');
97 QLocale locale(localeParts.constFirst());
98 if (!loadTranslation(locale.name())) {
99 if (!loadTranslation(locale.bcp47Name())) {
100 const int i = locale.name().indexOf(QLatin1Char('_'));
101 if (i > 0) {
102 loadTranslation(locale.name().left(i));
103 }
104 }
105 }
106 }
107 }
108#else
109 for (const auto &locale : { QLocale() }) {
110 dbgSeExpr << "Attempting to load translations for locale: " << locale.name();
111 if (!loadTranslation(locale.name())) {
112 if (!loadTranslation(locale.bcp47Name())) {
113 const int i = locale.name().indexOf(QLatin1Char('_'));
114 if (i > 0) {
115 loadTranslation(locale.name().left(i));
116 }
117 }
118 }
119 }
120#endif
121
122 dbgSeExpr << "Test: " << QCoreApplication::translate("ExprControlCollection", "Add new variable");
123 }
124
125 // Helper to call load() on the main thread.
126 //
127 // Calling functions on another thread without using moc is non-trivial in
128 // Qt until 5.4 (when some useful QTimer::singleShot overloads were added).
129 //
130 // Instead, we have to use QEvents. Ideally, we'd use a custom QEvent, but
131 // there's a chance this could cause trouble with applications that claim
132 // QEvent codes themselves, but don't register them with Qt (and we also
133 // want to avoid registering a new QEvent code for every plugin that might
134 // be loaded). We use QTimer because it's unlikely to be filtered by
135 // applications, and is also unlikely to cause Qt to do something it
136 // shouldn't.
137 class Loader : public QObject
138 {
139 protected:
141 {
142 load();
143 this->deleteLater();
144 }
145 };
146
148 {
149 // If this library is loaded after the QCoreApplication instance is
150 // created (eg: because it is brought in by a plugin), there is no
151 // guarantee this function will be called on the main thread.
152 // QCoreApplication::installTranslator needs to be called on the main
153 // thread, because it uses QCoreApplication::sendEvent.
154 if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
155 load();
156 } else {
157 // QObjects inherit their parent object's thread
158 Loader *loader = new Loader();
159 loader->moveToThread(QCoreApplication::instance()->thread());
160 QCoreApplication::instance()->postEvent(loader, new QTimerEvent(0), Qt::HighEventPriority);
161 }
162 }
163
164 Q_COREAPP_STARTUP_FUNCTION(loadOnMainThread)
165} // namespace KSeExpr
#define dbgSeExpr
Definition Debug.h:17
void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE
bool loadTranslation(const QString &localeDirName)