1 /***********************************************************************
2 *
3 * Copyright (C) 2010, 2011, 2012, 2014, 2015, 2016, 2018, 2019, 2020 Graeme Gott <graeme@gottcode.org>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***********************************************************************/
19
20 #include "locale_dialog.h"
21
22 #include <QComboBox>
23 #include <QDialogButtonBox>
24 #include <QDir>
25 #include <QFile>
26 #include <QGuiApplication>
27 #include <QHash>
28 #include <QLabel>
29 #include <QLibraryInfo>
30 #include <QLocale>
31 #include <QMessageBox>
32 #include <QSettings>
33 #include <QTranslator>
34 #include <QVBoxLayout>
35
36 #include <algorithm>
37
38 //-----------------------------------------------------------------------------
39
40 QString LocaleDialog::m_current;
41 QString LocaleDialog::m_path;
42 QString LocaleDialog::m_appname;
43
44 //-----------------------------------------------------------------------------
45
LocaleDialog(QWidget * parent)46 LocaleDialog::LocaleDialog(QWidget* parent) :
47 QDialog(parent, Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
48 {
49 QString title = parent ? parent->window()->windowTitle() : QString();
50 setWindowTitle(!title.isEmpty() ? title : QCoreApplication::applicationName());
51
52 QLabel* text = new QLabel(tr("Select application language:"), this);
53
54 m_translations = new QComboBox(this);
55 m_translations->addItem(tr("<System Language>"));
56 QStringList translations = findTranslations();
57 for (QString translation : translations) {
58 if (translation.startsWith("qt")) {
59 continue;
60 }
61 translation.remove(m_appname);
62 m_translations->addItem(languageName(translation), translation);
63 }
64 int index = std::max(0, m_translations->findData(m_current));
65 m_translations->setCurrentIndex(index);
66
67 QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
68 connect(buttons, &QDialogButtonBox::accepted, this, &LocaleDialog::accept);
69 connect(buttons, &QDialogButtonBox::rejected, this, &LocaleDialog::reject);
70
71 QVBoxLayout* layout = new QVBoxLayout(this);
72 layout->setSizeConstraint(QLayout::SetFixedSize);
73 layout->addWidget(text);
74 layout->addWidget(m_translations);
75 layout->addWidget(buttons);
76 }
77
78 //-----------------------------------------------------------------------------
79
loadTranslator(const QString & name,const QStringList & datadirs)80 void LocaleDialog::loadTranslator(const QString& name, const QStringList& datadirs)
81 {
82 m_appname = name;
83
84 // Find translator path
85 QStringList paths = datadirs;
86 if (paths.isEmpty()) {
87 QString appdir = QCoreApplication::applicationDirPath();
88 paths.append(appdir);
89 paths.append(appdir + "/../share/" + QCoreApplication::applicationName().toLower());
90 paths.append(appdir + "/../Resources");
91 }
92 for (const QString& path : paths) {
93 if (QFile::exists(path + "/translations/")) {
94 m_path = path + "/translations/";
95 break;
96 }
97 }
98
99 // Find current locale
100 m_current = QSettings().value("Locale/Language").toString();
101 if (!m_current.isEmpty()) {
102 QLocale::setDefault(m_current);
103 }
104 const QString locale = QLocale().name();
105
106 // Load translators
107 static QTranslator translator;
108 if (translator.load(m_appname + locale, m_path)) {
109 QCoreApplication::installTranslator(&translator);
110
111 const QString path = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
112
113 static QTranslator qtbase_translator;
114 if (qtbase_translator.load("qtbase_" + locale, m_path) || qtbase_translator.load("qtbase_" + locale, path)) {
115 QCoreApplication::installTranslator(&qtbase_translator);
116 }
117
118 static QTranslator qt_translator;
119 if (qt_translator.load("qt_" + locale, m_path) || qt_translator.load("qt_" + locale, path)) {
120 QCoreApplication::installTranslator(&qt_translator);
121 }
122 }
123 }
124
125 //-----------------------------------------------------------------------------
126
languageName(const QString & language)127 QString LocaleDialog::languageName(const QString& language)
128 {
129 QString name;
130 const QLocale locale(language);
131 if (language.contains('_')) {
132 if (locale.name() == language) {
133 name = locale.nativeLanguageName() + " (" + locale.nativeCountryName() + ")";
134 } else {
135 name = locale.nativeLanguageName() + " (" + language + ")";
136 }
137 } else {
138 name = locale.nativeLanguageName();
139 }
140 if (name.isEmpty() || name == "C") {
141 if (language == "eo") {
142 name = "Esperanto";
143 } else {
144 name = language;
145 }
146 }
147 if (locale.textDirection() == Qt::RightToLeft) {
148 name.prepend(QChar(0x202b));
149 }
150 return name;
151 }
152
153 //-----------------------------------------------------------------------------
154
findTranslations()155 QStringList LocaleDialog::findTranslations()
156 {
157 QStringList result = QDir(m_path, "*.qm").entryList(QDir::Files);
158 result.replaceInStrings(".qm", "");
159 return result;
160 }
161
162 //-----------------------------------------------------------------------------
163
accept()164 void LocaleDialog::accept()
165 {
166 int current = m_translations->findData(m_current);
167 if (current == m_translations->currentIndex()) {
168 return reject();
169 }
170 QDialog::accept();
171
172 m_current = m_translations->itemData(m_translations->currentIndex()).toString();
173 QSettings().setValue("Locale/Language", m_current);
174 QMessageBox::information(this, tr("Note"), tr("Please restart this application for the change in language to take effect."), QMessageBox::Ok);
175 }
176
177 //-----------------------------------------------------------------------------
178