view src/gui/locale.cc @ 340:74e2365326c6

dep/animone: add experimental accessibility strategy I also moved most of the functions out of util/win32.cc, because that file is meant for things that are shared between the different functions, and currently that is only wide string conversion helpers.
author Paper <paper@paper.us.eu.org>
date Wed, 19 Jun 2024 23:13:55 -0400
parents b1f625b0227c
children
line wrap: on
line source

#include "gui/locale.h"
#include "core/strings.h"

#include <QApplication>
#include <QDir>
#include <QLocale>
#include <QString>
#include <QTranslator>

#include <QtGlobal>

namespace Locale {

std::string GetLocaleFullName(const QLocale& locale) {
	QString res = QLocale::languageToString(locale.language());
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
	/* silence deprecation warning for locale.country() */
	if (locale.territory() != QLocale::AnyTerritory)
		res += " (" + QLocale::territoryToString(locale.territory()) + ")";
#else
	if (locale.country() != QLocale::AnyCountry)
		res += " (" + QLocale::countryToString(locale.country()) + ")";
#endif
	return Strings::ToUtf8String(res);
}

Locale::Locale() {
	RefreshAvailableLocales();
	SetActiveLocale(QLocale("en_US"));
}

Locale::Locale(const std::string& name) {
	RefreshAvailableLocales();
	SetActiveLocale(QLocale(Strings::ToQString(name)));
}

QLocale Locale::GetLocale() const {
	return _locale;
}

std::vector<QLocale> Locale::GetAvailableLocales() const {
	return _available_translations;
}

void Locale::RefreshAvailableLocales() {
	_available_translations.clear();

	/* we will always have en_US */
	_available_translations.push_back(QLocale("en_US"));

	QDir dir(":/locale");
	if (!dir.exists())
		return;

	QStringList translations = dir.entryList({"*.qm"}, QDir::Files);

	_available_translations.reserve(translations.size());
	for (const QString& str : translations)
		_available_translations.push_back(QLocale(str.mid(0, str.lastIndexOf("."))));
}

bool Locale::IsLocaleAvailable(const QLocale& locale) const {
	for (const QLocale& l : _available_translations)
		if (l == locale)
			return true;
	return false;
}

bool Locale::SetActiveLocale(const QLocale& locale) {
	if (!IsLocaleAvailable(locale) || !qApp)
		return false;

	if (_locale == locale)
		return true; /* we're... already on this locale :) */

	_locale = locale;
	QLocale::setDefault(_locale);

	/* we can still do stuff even if one thing fails! */
	bool return_value = true;

	const QString name = _locale.name();
	if (!SwitchTranslator(_translator, QString(":/locale/%1.qm").arg(name)))
		return_value = false;

	const QString path = qApp->applicationDirPath();
	if (!SwitchTranslator(_translator_qt, path + QString("/translations/qt_%1.qm").arg(name))) {
		/* Sometimes Qt will have proper translations for the language, but not the specific
		 * country. In that case, we still want to use that language. */
		const int underscore_index = name.lastIndexOf("_");
		if (!underscore_index)
			return false;

		const QString short_name = name.mid(0, underscore_index);
		if (!SwitchTranslator(_translator_qt, path + QString("/translations/qt_%1.qm").arg(short_name)))
			return_value = false;
	}

	return return_value;
}

bool Locale::SwitchTranslator(QTranslator& translator, const QString& path) {
	qApp->removeTranslator(&translator);

	if (!translator.load(path))
		return false;

	qApp->installTranslator(&translator);
	return true;
}

} // namespace Locale