1 /*
2 * \copyright Copyright (c) 2014-2021 Governikus GmbH & Co. KG, Germany
3 */
4
5 #include "LanguageLoader.h"
6
7 #include "FileDestination.h"
8 #include "SingletonHelper.h"
9
10 #include <QCoreApplication>
11 #include <QDir>
12 #include <QLoggingCategory>
13 #include <QRegularExpression>
14
15 Q_DECLARE_LOGGING_CATEGORY(language)
16
17 using namespace governikus;
18
19 defineSingleton(LanguageLoader)
20
21 const QLocale::Language LanguageLoader::mFallbackLanguage = QLocale::Language::English;
22
23 QLocale LanguageLoader::mDefaultLanguage = QLocale::system();
24
LanguageLoader()25 LanguageLoader::LanguageLoader()
26 : mPath(FileDestination::getPath(QStringLiteral("translations"), QStandardPaths::LocateDirectory))
27 , mTranslatorList()
28 , mComponentList(
29 {
30 QStringLiteral("ausweisapp2"), QStringLiteral("qtbase")
31 })
32 , mUsedLocale(mFallbackLanguage)
33 {
34 }
35
36
~LanguageLoader()37 LanguageLoader::~LanguageLoader()
38 {
39 }
40
41
getDefaultLanguage()42 const QLocale& LanguageLoader::getDefaultLanguage()
43 {
44 return mDefaultLanguage;
45 }
46
47
setDefaultLanguage(const QLocale & pLocale)48 void LanguageLoader::setDefaultLanguage(const QLocale& pLocale)
49 {
50 mDefaultLanguage = pLocale;
51 }
52
53
getLocalCode(const QLocale & pLocale)54 QString LanguageLoader::getLocalCode(const QLocale& pLocale)
55 {
56 return pLocale.bcp47Name().left(2);
57 }
58
59
60 #ifndef QT_NO_DEBUG
getPath() const61 const QString& LanguageLoader::getPath() const
62 {
63 return mPath;
64 }
65
66
setPath(const QString & pPath)67 void LanguageLoader::setPath(const QString& pPath)
68 {
69 mPath = pPath;
70 }
71
72
73 #endif
74
75
createTranslator(const QLocale & pLocale,const QString & pComponent)76 QSharedPointer<QTranslator> LanguageLoader::createTranslator(const QLocale& pLocale, const QString& pComponent)
77 {
78 auto translator = QSharedPointer<QTranslator>::create();
79 translator->setObjectName(pLocale.name() + QLatin1Char('/') + pComponent);
80 bool loaded = translator->load(pLocale, pComponent, QStringLiteral("_"), mPath);
81 qCDebug(language) << "Load translation:" << pComponent << '|' << loaded;
82
83 if (!loaded)
84 {
85 translator.clear();
86 }
87
88 return translator;
89 }
90
91
getAvailableLocales() const92 QList<QLocale> LanguageLoader::getAvailableLocales() const
93 {
94 qCDebug(language) << "Use path:" << mPath;
95
96 QList<QLocale> list;
97 list << mFallbackLanguage;
98
99 QDir path(mPath);
100 path.setFilter(QDir::Files);
101
102 const QRegularExpression regex(QStringLiteral("^ausweisapp2_([a-z]{2}(_[A-Z]{2})?)\\.qm$"));
103 const auto entryList = path.entryInfoList();
104 for (const auto& info : entryList)
105 {
106 QRegularExpressionMatch match = regex.match(info.fileName());
107 if (match.hasMatch() && !match.captured(1).isNull())
108 {
109 QLocale locale(match.captured(1));
110 if (locale != QLocale::C && !list.contains(locale))
111 {
112 list << locale;
113 }
114 }
115 }
116
117 return list;
118 }
119
120
isLoaded() const121 bool LanguageLoader::isLoaded() const
122 {
123 return !mTranslatorList.isEmpty();
124 }
125
126
load(const QLocale & pLocale)127 void LanguageLoader::load(const QLocale& pLocale)
128 {
129 if (!mTranslatorList.isEmpty())
130 {
131 qCWarning(language) << "Loader is already in use. You need to unload before you load again...";
132 return;
133 }
134
135 qCDebug(language) << "Use path:" << mPath;
136 bool loaded = false;
137
138 const auto uiLanguages = pLocale.uiLanguages();
139 for (const auto& lang : uiLanguages)
140 {
141 qCDebug(language) << "UI language:" << lang;
142 if (!loaded)
143 {
144 loaded = loadTranslationFiles(QLocale(lang));
145 }
146 }
147
148 if (!loaded && !pLocale.uiLanguages().contains(pLocale.name().replace(QLatin1Char('_'), QLatin1Char('-'))))
149 {
150 qCDebug(language) << "No UI translation found... try to use system locale:" << pLocale.name();
151 loadTranslationFiles(QLocale(pLocale.name()));
152 }
153 }
154
155
unload()156 void LanguageLoader::unload()
157 {
158 if (mTranslatorList.isEmpty())
159 {
160 qCWarning(language) << "Cannot unload translation because it is nothing loaded";
161 }
162 else
163 {
164 qCDebug(language) << "Unload translations";
165 for (const auto& translator : qAsConst(mTranslatorList))
166 {
167 QCoreApplication::removeTranslator(translator.data());
168 }
169
170 mTranslatorList.clear();
171 mUsedLocale = mFallbackLanguage;
172 }
173 }
174
175
getUsedLocale() const176 const QLocale& LanguageLoader::getUsedLocale() const
177 {
178 return mUsedLocale;
179 }
180
181
getFallbackLanguage() const182 QLocale::Language LanguageLoader::getFallbackLanguage() const
183 {
184 return mFallbackLanguage;
185 }
186
187
loadTranslationFiles(const QLocale & pLocale)188 bool LanguageLoader::loadTranslationFiles(const QLocale& pLocale)
189 {
190 if (pLocale.language() == mFallbackLanguage)
191 {
192 qCDebug(language) << "Using fallback language:" << QLocale::languageToString(mFallbackLanguage);
193 return true;
194 }
195
196 qCDebug(language) << "Try to load translation:" << pLocale;
197 bool loaded = false;
198
199 for (const auto& component : mComponentList)
200 {
201 QSharedPointer<QTranslator> translator = createTranslator(pLocale, component);
202
203 if (!translator.isNull())
204 {
205 mTranslatorList += translator;
206 QCoreApplication::installTranslator(translator.data());
207 mUsedLocale = pLocale;
208 loaded = true;
209 }
210 }
211
212 return loaded;
213 }
214