QuasarAppLib
locales.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2018-2025 QuasarApp.
3 * Distributed under the lgplv3 software license, see the accompanying
4 * Everyone is permitted to copy and distribute verbatim copies
5 * of this license document, but changing it is not allowed.
6*/
7
8
9#include "locales.h"
10
11#include <QCoreApplication>
12#include <QTranslator>
13#include <QLocale>
14#include <QLibraryInfo>
15#include <QRegularExpression>
16#include <QLocale>
17#include <QMap>
18
19using namespace QuasarAppUtils;
20
21bool QuasarAppUtils::Locales::findQmPrivate(const QString &prefix,
22 QList<QTranslator*> &qmFiles) {
23
24 for (const auto &location: std::as_const(_locations)) {
25
26 const auto availableFiles = QDir(location).entryInfoList(
27 {prefix + ".qm"}, QDir::Files);
28
29 for (const auto &file : availableFiles) {
30 auto qmFile = new QTranslator();
31
32 if(!qmFile->load(file.absoluteFilePath())) {
33 qWarning() << "Failed to load translation file : "
34 + file.absoluteFilePath();
35 delete qmFile;
36 continue;
37 }
38
39 if (qmFile->isEmpty()) {
40 qDebug() << "Translation file is Empty: " +
41 file.absoluteFilePath();
42 delete qmFile;
43 continue;
44 }
45
46 auto language = qmFile->language();
47 if (language.size() && !language.contains(prefix, Qt::CaseInsensitive)) {
48 auto message = QString("The target language (%0) and a choosed qm file (%1) "
49 "is different, Loading will be skiped: ").
50 arg(language, file.absoluteFilePath());
51 qDebug() << message;
52
53 delete qmFile;
54 continue;
55 }
56
57 qmFiles += qmFile;
58 }
59 }
60 return qmFiles.size();
61}
62
63bool QuasarAppUtils::Locales::findQm(QString localePrefix,
64 QList<QTranslator *> &qmFiles) {
65
66 if (localePrefix.size() < 2) {
67 if (localePrefix.compare('c', Qt::CaseInsensitive) == 0) {
68 return findQmPrivate("en", qmFiles);
69
70 }
71
72 return false;
73 } else if (localePrefix.size() >= 4) {
74 return findQmPrivate(localePrefix.replace('-', '_'), qmFiles);
75 }
76
77 return findQmPrivate(localePrefix, qmFiles);
78}
79
80void QuasarAppUtils::Locales::installTranslations( QList<QTranslator *> &qmFiles)
81{
82 for (const auto & translator: std::as_const(qmFiles)) {
83 if (!QCoreApplication::installTranslator(translator)) {
84
85 qWarning() << "Failed to install translation file : " + translator->filePath();
86 delete translator;
87 // we use a link of qmFiles so remove all invalid translations.
88 qmFiles.removeAll(translator);
89
90 continue;
91 }
92 }
93}
94
95QString Locales::translatePrivate(const char *source, const QLocale &locale) {
96 auto translations = _translations.value(locale);
97
98 for (const auto& tr : translations) {
99 auto result = tr->translate("QuasarAppUtils::Locales", source);
100 if (result.size()) {
101 return result;
102 }
103 }
104
105 return source;
106}
107
108bool Locales::setLocalePrivate(const QLocale &locale, bool force, bool install) {
109 if (force) {
110 clearCache(locale);
111 }
112
113 removeOldTranslation(_currentLocate);
114
115 // take a link to list of translations.
116 QList<QTranslator *> &qmFiles = _translations[locale];
117
118 if (qmFiles.isEmpty()) {
119 // fill list of translations
120 const auto list = locale.uiLanguages();
121
122 auto it = list.rbegin();
123 while (qmFiles.isEmpty() && it != list.rend() && !findQm(*it, qmFiles)) {
124 it++;
125 }
126
127 if (qmFiles.isEmpty())
128 return false;
129
130 }
131
132 if (install)
133 installTranslations(qmFiles);
134
136
137 _currentLocate = locale;
138
139 return _translations[locale].size();
140}
141
142const QLocale &Locales::currentLocate() {
143 auto obj = instance();
144 return obj->currentLocatePrivate();
145}
146
147QString Locales::tr(const char *source, const QLocale &locale) {
148 auto obj = instance();
149 return obj->translatePrivate(source, locale);
150}
151
152bool Locales::setLocale(const QLocale &locale, bool force) {
153 auto obj = instance();
154 return obj->setLocalePrivate(locale, force);
155}
156
157bool Locales::init(const QList<QLocale> &locales, const QSet<QString> &location) {
158 auto obj = instance();
159 return obj->initPrivate(locales, location);
160}
161
162bool Locales::init(const QLocale &locale, const QSet<QString> & location) {
163 auto obj = instance();
164 return obj->initPrivate(locale, location);
165}
166
167bool Locales::initPrivate(const QLocale &locale, const QSet<QString> & locations) {
168
169#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
170 auto defaultTr = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
171#else
172 auto defaultTr = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
173#endif
174 _locations = locations;
175 if (!_locations.contains(defaultTr)) {
176 _locations += defaultTr;
177 }
178
179 return setLocalePrivate(locale);
180}
181
182bool Locales::initPrivate(const QList<QLocale> &locales, const QSet<QString> &locations) {
183#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
184 auto defaultTr = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
185#else
186 auto defaultTr = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
187#endif
188 _locations = locations;
189 if (!_locations.contains(defaultTr)) {
190 _locations += defaultTr;
191 }
192
193 for (const auto& locale: locales) {
194 if (!setLocalePrivate(locale, false, false)) {
195 return false;
196 }
197 }
198
199 return true;
200}
201
202void Locales::clearCache(const QLocale &locale) {
203 for (const auto & tr :std::as_const(_translations[locale])) {
204 QCoreApplication::removeTranslator(tr);
205 delete tr;
206 }
207
208 _translations[locale].clear();
209}
210
211void Locales::clearCache() {
212 for (auto it = _translations.keyBegin(); it != _translations.keyEnd(); it = std::next(it)) {
213 clearCache(*it);
214 }
215 _translations.clear();
216}
217
219 static auto instance = new Locales();
220 return instance;
221}
222
223void Locales::removeOldTranslation(const QLocale &locale) {
224 for (const auto & tr :std::as_const(_translations[locale])) {
225 QCoreApplication::removeTranslator(tr);
226 }
227}
228
229void Locales::addLocationPrivate(const QString &location) {
230 _locations += location;
231}
232
233const QLocale &Locales::currentLocatePrivate() const {
234 return _currentLocate;
235
236}
237void Locales::addLocation(const QString &location) {
238 auto obj = instance();
239 obj->addLocationPrivate(location);
240}
241
242Locales::~Locales() {
243 clearCache();
244}
The Locales class for parese local files Example :
Definition locales.h:40
static bool setLocale(const QLocale &locale, bool force=false)
setLocale This method sets locale for application and loaded all translations for this locale.
Definition locales.cpp:152
static void addLocation(const QString &location)
addLocation This method add location for qm files. Use This method if you create a own library with t...
Definition locales.cpp:237
static QString tr(const char *source, const QLocale &locale)
tr This method will translate single string to choosed language.
Definition locales.cpp:147
void sigTranslationChanged()
sigTranslationChanged Emited when set new locale for application.
static bool init(const QList< QLocale > &locales, const QSet< QString > &location={})
init This method initialize translations of applictaion.
Definition locales.cpp:157
static Locales * instance()
instance This method return pointer to the Locales service.
Definition locales.cpp:218
static const QLocale & currentLocate()
currentLocate This method return current locate of applicatuon.
Definition locales.cpp:142
The QuasaraAppUtils class This lib include base functions for the all applications of QuasarApp group...
Definition helpdata.cpp:18