1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
// Copyright 2021 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "Translations.h"
#include <QApplication>
#include <QtCore/QDir>
#include <QtCore/QLibraryInfo>
#include <QtCore/QStandardPaths>
#include <QtCore/QTranslator>
namespace Mumble {
namespace Translations {
LifetimeGuard::LifetimeGuard(LifetimeGuard &&old) : m_bundledTranslator(old.m_bundledTranslator),
m_overwriteTranslator(old.m_overwriteTranslator), m_qtTranslator(old.m_qtTranslator) {
// Reset values of old
old.m_bundledTranslator = nullptr;
old.m_overwriteTranslator = nullptr;
old.m_qtTranslator = nullptr;
}
LifetimeGuard::~LifetimeGuard() {
delete m_bundledTranslator;
delete m_overwriteTranslator;
delete m_qtTranslator;
}
QStringList getDefaultTranslationDirectories() {
QStringList translationDirs;
const QString translationDirName = "MumbleTranslations";
// AppData directories
for (const QString ¤tConfigPath : QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)) {
translationDirs.append(QDir::cleanPath(currentConfigPath));
}
// Directories in the config locations
for (const QString ¤tConfigPath : QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)) {
translationDirs.append(QDir::cleanPath(currentConfigPath + QDir::separator() + translationDirName));
}
// A directory in the home directory
for (const QString ¤tHomePath : QStandardPaths::standardLocations(QStandardPaths::HomeLocation)) {
translationDirs.append(QDir::cleanPath(currentHomePath + QDir::separator() + translationDirName));
}
return translationDirs;
}
QStringList getTranslationDirectories(const QApplication &app, const QStringList &extraDirectories) {
QStringList directories;
// The extra directories have highest priority
directories += extraDirectories;
// Next up is the application's root path
directories.append(app.applicationDirPath());
// And finally the default locations
directories += getDefaultTranslationDirectories();
return directories;
}
LifetimeGuard installTranslators(const QLocale &locale, QApplication &app, const QStringList &extraDirectories) {
LifetimeGuard guard;
// First install a translator that uses the bundled translations
guard.m_bundledTranslator = new QTranslator();
if (guard.m_bundledTranslator->load(locale, ":mumble_")) {
app.installTranslator(guard.m_bundledTranslator);
} else {
qWarning("Unable to find bundled translations for locale \"%s\"", qUtf8Printable(locale.name()));
delete guard.m_bundledTranslator;
guard.m_bundledTranslator = nullptr;
}
// Now try to add another translator that can overwrite the bundled translations based
// on translations found in one of the translation directories.
// The first matching translation file that is found, will be used (first come, first served)
guard.m_overwriteTranslator = new QTranslator();
const QString prefix = "";
bool overwriteTranslatorFound = false;
for (const QString ¤tDir : getTranslationDirectories(app, extraDirectories)) {
if (guard.m_overwriteTranslator->load(locale, "mumble_", prefix, currentDir)) {
app.installTranslator(guard.m_overwriteTranslator);
qWarning("Using extra translation file for locale \"%s\" from directory \"%s\"",
qUtf8Printable(locale.name()), qUtf8Printable(currentDir));
overwriteTranslatorFound = true;
break;
}
}
if (!overwriteTranslatorFound) {
delete guard.m_overwriteTranslator;
guard.m_overwriteTranslator = nullptr;
}
// With modularization of Qt 5 some - but not all - of the qt_<locale>.ts files have become
// so-called meta catalogues which no longer contain actual translations but refer to other
// more specific ts files like qtbase_<locale>.ts . To successfully load a meta catalogue all
// of its referenced translations must be available. As we do not want to bundle them all
// we now try to load the old qt_<locale>.ts file first and then fall back to loading
// qtbase_<locale>.ts if that failed.
//
// See http://doc.qt.io/qt-5/linguist-programmers.html#deploying-translations for more information
guard.m_qtTranslator = new QTranslator();
// First we try and see if there is a translation packaged with Mumble that shall overwrite any potentially
// existing Qt translations. If not, we try to load the qt-translations installed on the host-machine and if
// that fails as well, we try to load translations bundled in Mumble. Note: Resource starting with :/ are
// bundled resources specified in a .qrc file
if (guard.m_qtTranslator->load(locale, ":/mumble_overwrite_qt_")) {
app.installTranslator(guard.m_qtTranslator);
} else if (guard.m_qtTranslator->load(locale, ":/mumble_overwrite_qtbase_")) {
app.installTranslator(guard.m_qtTranslator);
} else if (guard.m_qtTranslator->load(locale, "qt_", prefix, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
app.installTranslator(guard.m_qtTranslator);
} else if (guard.m_qtTranslator->load(locale, "qtbase_", prefix, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
app.installTranslator(guard.m_qtTranslator);
} else if (guard.m_qtTranslator->load(locale, ":/qt_")) {
app.installTranslator(guard.m_qtTranslator);
} else if (guard.m_qtTranslator->load(locale, ":/qtbase_")) {
app.installTranslator(guard.m_qtTranslator);
} else {
// Did not install Qt translator
delete guard.m_qtTranslator;
guard.m_qtTranslator = nullptr;
}
return guard;
}
}; // namespace Translations
}; // namespace Mumble
|