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