1 /*
2 SPDX-FileCopyrightText: 2010-2020 Graeme Gott <graeme@gottcode.org>
3
4 SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7 #include "locale_dialog.h"
8
9 #include <QComboBox>
10 #include <QDialogButtonBox>
11 #include <QDir>
12 #include <QFile>
13 #include <QGuiApplication>
14 #include <QHash>
15 #include <QLabel>
16 #include <QLibraryInfo>
17 #include <QLocale>
18 #include <QMessageBox>
19 #include <QSettings>
20 #include <QTranslator>
21 #include <QVBoxLayout>
22
23 #include <algorithm>
24
25 //-----------------------------------------------------------------------------
26
27 QString LocaleDialog::m_current;
28 QString LocaleDialog::m_path;
29 QString LocaleDialog::m_appname;
30
31 //-----------------------------------------------------------------------------
32
LocaleDialog(QWidget * parent)33 LocaleDialog::LocaleDialog(QWidget* parent)
34 : QDialog(parent, Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
35 {
36 QString title = parent ? parent->window()->windowTitle() : QString();
37 setWindowTitle(!title.isEmpty() ? title : QCoreApplication::applicationName());
38
39 QLabel* text = new QLabel(tr("Select application language:"), this);
40
41 m_translations = new QComboBox(this);
42 m_translations->addItem(tr("<System Language>"));
43 const QStringList translations = findTranslations();
44 for (QString translation : translations) {
45 if (translation.startsWith("qt")) {
46 continue;
47 }
48 translation.remove(m_appname);
49 m_translations->addItem(languageName(translation), translation);
50 }
51 int index = std::max(0, m_translations->findData(m_current));
52 m_translations->setCurrentIndex(index);
53
54 QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
55 connect(buttons, &QDialogButtonBox::accepted, this, &LocaleDialog::accept);
56 connect(buttons, &QDialogButtonBox::rejected, this, &LocaleDialog::reject);
57
58 QVBoxLayout* layout = new QVBoxLayout(this);
59 layout->setSizeConstraint(QLayout::SetFixedSize);
60 layout->addWidget(text);
61 layout->addWidget(m_translations);
62 layout->addWidget(buttons);
63 }
64
65 //-----------------------------------------------------------------------------
66
loadTranslator(const QString & name,const QStringList & datadirs)67 void LocaleDialog::loadTranslator(const QString& name, const QStringList& datadirs)
68 {
69 m_appname = name;
70
71 // Find translator path
72 QStringList paths = datadirs;
73 if (paths.isEmpty()) {
74 QString appdir = QCoreApplication::applicationDirPath();
75 paths.append(appdir);
76 paths.append(appdir + "/../share/" + QCoreApplication::applicationName().toLower());
77 paths.append(appdir + "/../Resources");
78 }
79 for (const QString& path : paths) {
80 if (QFile::exists(path + "/translations/")) {
81 m_path = path + "/translations/";
82 break;
83 }
84 }
85
86 // Find current locale
87 m_current = QSettings().value("Locale/Language").toString();
88 if (!m_current.isEmpty()) {
89 QLocale::setDefault(QLocale(m_current));
90 }
91 const QString locale = QLocale().name();
92
93 // Load translators
94 static QTranslator translator;
95 if (translator.load(m_appname + locale, m_path)) {
96 QCoreApplication::installTranslator(&translator);
97
98 #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
99 const QString path = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
100 #else
101 const QString path = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
102 #endif
103
104 static QTranslator qtbase_translator;
105 if (qtbase_translator.load("qtbase_" + locale, m_path) || qtbase_translator.load("qtbase_" + locale, path)) {
106 QCoreApplication::installTranslator(&qtbase_translator);
107 }
108
109 static QTranslator qt_translator;
110 if (qt_translator.load("qt_" + locale, m_path) || qt_translator.load("qt_" + locale, path)) {
111 QCoreApplication::installTranslator(&qt_translator);
112 }
113 }
114 }
115
116 //-----------------------------------------------------------------------------
117
languageName(const QString & language)118 QString LocaleDialog::languageName(const QString& language)
119 {
120 QString name;
121 const QLocale locale(language);
122 if (language.contains('_')) {
123 if (locale.name() == language) {
124 name = locale.nativeLanguageName() + " (" + locale.nativeCountryName() + ")";
125 } else {
126 name = locale.nativeLanguageName() + " (" + language + ")";
127 }
128 } else {
129 name = locale.nativeLanguageName();
130 }
131 if (name.isEmpty() || name == "C") {
132 if (language == "eo") {
133 name = "Esperanto";
134 } else {
135 name = language;
136 }
137 }
138 if (locale.textDirection() == Qt::RightToLeft) {
139 name.prepend(QChar(0x202b));
140 }
141 return name;
142 }
143
144 //-----------------------------------------------------------------------------
145
findTranslations()146 QStringList LocaleDialog::findTranslations()
147 {
148 QStringList result = QDir(m_path, "*.qm").entryList(QDir::Files);
149 result.replaceInStrings(".qm", "");
150 return result;
151 }
152
153 //-----------------------------------------------------------------------------
154
accept()155 void LocaleDialog::accept()
156 {
157 int current = m_translations->findData(m_current);
158 if (current == m_translations->currentIndex()) {
159 return reject();
160 }
161 QDialog::accept();
162
163 m_current = m_translations->itemData(m_translations->currentIndex()).toString();
164 QSettings().setValue("Locale/Language", m_current);
165 QMessageBox::information(this, tr("Note"), tr("Please restart this application for the change in language to take effect."), QMessageBox::Ok);
166 }
167
168 //-----------------------------------------------------------------------------
169