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