/* === This file is part of Calamares - === * * SPDX-FileCopyrightText: 2014 Teo Mrnjavac * SPDX-License-Identifier: GPL-3.0-or-later * * Calamares is Free Software: see the License-Identifier above. * * */ #include "Retranslator.h" #include "Settings.h" #include "utils/Dirs.h" #include "utils/Logger.h" #include #include #include #include namespace { static bool s_allowLocalTranslations = false; /** @brief Helper class for loading translations * * This is used by the loadSingletonTranslator() function to hand off * work to translation-type specific code. */ struct TranslationLoader { TranslationLoader( const QString& locale ) : m_localeName( locale ) { } virtual ~TranslationLoader(); /// @brief Loads @p translator with the specific translations of this type virtual bool tryLoad( QTranslator* translator ) = 0; QString m_localeName; }; /// @brief Loads translations for branding struct BrandingLoader : public TranslationLoader { BrandingLoader( const QString& locale, const QString& prefix ) : TranslationLoader( locale ) , m_prefix( prefix ) { } bool tryLoad( QTranslator* translator ) override; QString m_prefix; }; /// @brief Loads regular Calamares translations (program text) struct CalamaresLoader : public TranslationLoader { using TranslationLoader::TranslationLoader; bool tryLoad( QTranslator* translator ) override; }; /// @brief Loads timezone name translations struct TZLoader : public TranslationLoader { using TranslationLoader::TranslationLoader; bool tryLoad( QTranslator* translator ) override; }; TranslationLoader::~TranslationLoader() {} bool BrandingLoader::tryLoad( QTranslator* translator ) { if ( m_prefix.isEmpty() ) { return false; } // This is working backwards against m_prefix containing both // a path and a branding-name. Split it in path + branding-name. const int lastDirSeparator = m_prefix.lastIndexOf( QDir::separator() ); QString brandingTranslationsDirPath( m_prefix ); brandingTranslationsDirPath.truncate( lastDirSeparator ); QString filenameBase( m_prefix ); filenameBase.remove( 0, lastDirSeparator + 1 ); if ( QDir( brandingTranslationsDirPath ).exists() ) { const QString fileName = QStringLiteral( "%1_%2" ).arg( filenameBase, m_localeName ); cDebug() << Logger::SubEntry << "Loading" << fileName << "from" << brandingTranslationsDirPath; if ( translator->load( fileName, brandingTranslationsDirPath ) ) { cDebug() << Logger::SubEntry << "Branding using locale:" << m_localeName; return true; } else { cDebug() << Logger::SubEntry << "Branding no translation for" << m_localeName << "using default (en)"; // TODO: this loads something completely different return translator->load( m_prefix + "en" ); } } return false; } static bool tryLoad( QTranslator* translator, const QString& prefix, const QString& localeName ) { // In debug-mode, try loading from the current directory if ( s_allowLocalTranslations && translator->load( prefix + localeName ) ) { cDebug() << Logger::SubEntry << "Loaded local translation" << prefix << localeName; return true; } // Or load from appDataDir -- often /usr/share/calamares -- subdirectory land/ QDir localeData( CalamaresUtils::appDataDir() ); if ( localeData.exists() && translator->load( localeData.absolutePath() + QStringLiteral( "/lang/" ) + prefix + localeName ) ) { cDebug() << Logger::SubEntry << "Loaded appdata translation" << prefix << localeName; return true; } // Or from QRC (most common) if ( translator->load( QStringLiteral( ":/lang/" ) + prefix + localeName ) ) { cDebug() << Logger::SubEntry << "Loaded QRC translation" << prefix << localeName; return true; } else { cDebug() << Logger::SubEntry << "No translation for" << prefix << localeName << "using default (en)"; return translator->load( QStringLiteral( ":/lang/" ) + prefix + QStringLiteral( "en" ) ); } } bool CalamaresLoader::tryLoad( QTranslator* translator ) { return ::tryLoad( translator, QStringLiteral( "calamares_" ), m_localeName ); } bool TZLoader::tryLoad( QTranslator* translator ) { return ::tryLoad( translator, QStringLiteral( "tz_" ), m_localeName ); } static void loadSingletonTranslator( TranslationLoader&& loader, QTranslator*& translator_p ) { if ( !translator_p ) { QTranslator* translator = new QTranslator(); loader.tryLoad( translator ); QCoreApplication::installTranslator( translator ); translator_p = translator; } else { loader.tryLoad( translator_p ); } } } // namespace namespace CalamaresUtils { static QTranslator* s_brandingTranslator = nullptr; static QTranslator* s_translator = nullptr; static QTranslator* s_tztranslator = nullptr; static QString s_translatorLocaleName; void installTranslator( const Calamares::Locale::Translation::Id& locale, const QString& brandingTranslationsPrefix ) { s_translatorLocaleName = locale.name; loadSingletonTranslator( BrandingLoader( locale.name, brandingTranslationsPrefix ), s_brandingTranslator ); loadSingletonTranslator( TZLoader( locale.name ), s_tztranslator ); loadSingletonTranslator( CalamaresLoader( locale.name ), s_translator ); } void installTranslator() { installTranslator( Calamares::Locale::Translation().id(), QString() ); } Calamares::Locale::Translation::Id translatorLocaleName() { return { s_translatorLocaleName }; } bool loadTranslator( const Calamares::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator ) { return ::tryLoad( translator, prefix, locale.name ); } Retranslator::Retranslator( QObject* parent ) : QObject( parent ) { } bool Retranslator::eventFilter( QObject* obj, QEvent* e ) { if ( e->type() == QEvent::LanguageChange ) { emit languageChanged(); } // pass the event on to the base return QObject::eventFilter( obj, e ); } Retranslator* Retranslator::instance() { static Retranslator s_instance( nullptr ); return &s_instance; } void Retranslator::attach( QObject* o, std::function< void() > f ) { connect( instance(), &Retranslator::languageChanged, o, f ); f(); } void setAllowLocalTranslation( bool allow ) { s_allowLocalTranslations = allow; } } // namespace CalamaresUtils