i18n: re-do the whole Retranslator infrastructure
Just have **one** Retranslator object, and install it as event-filter (this needs to be done manually on a top-level widget) and use signals / slots to do the actual work, rather than filtering in multiple places and doing our own mediocre version of binding- signal-to-lambda.
This commit is contained in:
parent
f32671ebab
commit
613d076a60
18
CHANGES
18
CHANGES
@ -7,6 +7,24 @@ contributors are listed. Note that Calamares does not have a historical
|
||||
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||
website will have to do for older versions.
|
||||
|
||||
# 3.2.41 (unreleased) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Anke Boersma
|
||||
|
||||
## Core ##
|
||||
- The (re)translation framework has been internally re-vamped to be
|
||||
less resource-intensive and to work with all QObjects, not just
|
||||
widgets. Consumers of the translations framework are expected to
|
||||
set up the event filter on the top-level widget(s) manually.
|
||||
|
||||
## Modules ##
|
||||
- The *usersq* module has had a fair bit of QML rewritten to make it easier
|
||||
to customize the colors used by the module in a consistent way.
|
||||
(Thanks Anke)
|
||||
|
||||
|
||||
|
||||
# 3.2.40 (2021-07-14) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
|
@ -357,6 +357,8 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
|
||||
, m_debugManager( new Calamares::DebugWindowManager( this ) )
|
||||
, m_viewManager( nullptr )
|
||||
{
|
||||
installEventFilter( CalamaresUtils::Retranslator::instance() );
|
||||
|
||||
// If we can never cancel, don't show the window-close button
|
||||
if ( Calamares::Settings::instance()->disableCancel() )
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "modulesystem/ModuleManager.h"
|
||||
#include "modulesystem/ViewModule.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
#include "utils/Yaml.h"
|
||||
#include "viewpages/ExecutionViewStep.h"
|
||||
|
||||
@ -489,6 +490,10 @@ main( int argc, char* argv[] )
|
||||
aw = replace_app;
|
||||
}
|
||||
mw = module.m_ui ? new QMainWindow() : nullptr;
|
||||
if ( mw )
|
||||
{
|
||||
mw->installEventFilter( CalamaresUtils::Retranslator::instance() );
|
||||
}
|
||||
|
||||
(void)new Calamares::Branding( module.m_branding );
|
||||
auto* modulemanager = new Calamares::ModuleManager( QStringList(), nullptr );
|
||||
|
@ -211,55 +211,29 @@ loadTranslator( const QLocale& locale, const QString& prefix, QTranslator* trans
|
||||
return ::tryLoad( translator, prefix, locale.name() );
|
||||
}
|
||||
|
||||
Retranslator*
|
||||
Retranslator::retranslatorFor( QObject* parent )
|
||||
{
|
||||
Retranslator* r = nullptr;
|
||||
for ( QObject* child : parent->children() )
|
||||
{
|
||||
r = qobject_cast< Retranslator* >( child );
|
||||
if ( r )
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return new Retranslator( parent );
|
||||
}
|
||||
|
||||
void
|
||||
Retranslator::attachRetranslator( QObject* parent, std::function< void( void ) > retranslateFunc )
|
||||
{
|
||||
retranslatorFor( parent )->m_retranslateFuncList.append( retranslateFunc );
|
||||
retranslateFunc();
|
||||
}
|
||||
|
||||
|
||||
Retranslator::Retranslator( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
parent->installEventFilter( this );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Retranslator::eventFilter( QObject* obj, QEvent* e )
|
||||
{
|
||||
if ( obj == parent() )
|
||||
if ( e->type() == QEvent::LanguageChange )
|
||||
{
|
||||
if ( e->type() == QEvent::LanguageChange )
|
||||
{
|
||||
foreach ( std::function< void() > func, m_retranslateFuncList )
|
||||
{
|
||||
func();
|
||||
}
|
||||
emit 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
|
||||
setAllowLocalTranslation( bool allow )
|
||||
{
|
||||
|
@ -64,40 +64,64 @@ DLLEXPORT bool loadTranslator( const QLocale& locale, const QString& prefix, QTr
|
||||
*/
|
||||
DLLEXPORT void setAllowLocalTranslation( bool allow );
|
||||
|
||||
|
||||
/** @brief Handles change-of-language events
|
||||
*
|
||||
* There is one single Retranslator object. Use `instance()` to get it.
|
||||
* The top-level widget of the application should call
|
||||
* `installEventFilter( Retranslator::instance() )`
|
||||
* to set up event-handling for translation events. The Retranslator
|
||||
* will emit signal `languageChanged()` if there is such an event.
|
||||
*
|
||||
* Normal consumers should not have to use the Retranslator directly,
|
||||
* but use the macros `CALAMARES_RETRANSLATE*` to set things up
|
||||
* in code -- the macros will connect to the Retranslator's signals.
|
||||
*/
|
||||
class Retranslator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/// @brief Call @p retranslateFunc when the language changes
|
||||
static void attachRetranslator( QObject* parent, std::function< void( void ) > retranslateFunc );
|
||||
/// @brief What retranslator belongs to @p parent (may create one)
|
||||
static Retranslator* retranslatorFor( QObject* parent );
|
||||
static Retranslator* instance();
|
||||
|
||||
signals:
|
||||
void languageChange();
|
||||
void languageChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter( QObject* obj, QEvent* e ) override;
|
||||
|
||||
private:
|
||||
explicit Retranslator( QObject* parent );
|
||||
|
||||
QList< std::function< void( void ) > > m_retranslateFuncList;
|
||||
};
|
||||
|
||||
|
||||
} // namespace CalamaresUtils
|
||||
|
||||
#define CALAMARES_RETRANSLATE( body ) CalamaresUtils::Retranslator::attachRetranslator( this, [=] { body } )
|
||||
#define CALAMARES_RETRANSLATE_WIDGET( widget, body ) \
|
||||
CalamaresUtils::Retranslator::attachRetranslator( widget, [=] { body } )
|
||||
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
|
||||
do \
|
||||
{ \
|
||||
this->connect( CalamaresUtils::Retranslator::retranslatorFor( this ), \
|
||||
&CalamaresUtils::Retranslator::languageChange, \
|
||||
this, \
|
||||
slotfunc ); \
|
||||
} while ( 0 )
|
||||
// Implementation detail: connects the retranslator to a slot or function
|
||||
#define CALAMARES_RETRANSLATE_FOR( object, body ) \
|
||||
QObject::connect( CalamaresUtils::Retranslator::instance(), &CalamaresUtils::Retranslator::languageChanged, object, body )
|
||||
|
||||
/** @brief Call code for this object when language changes
|
||||
*
|
||||
* @p body should be a code block (it does not need braces) that can be wrapped
|
||||
* up as a lambda. When the language changes, the lambda is called. Note that
|
||||
* this macro should be used in constructors or other code that is run only
|
||||
* once, since otherwise you will end up with multiple calls to @p body.
|
||||
*/
|
||||
#define CALAMARES_RETRANSLATE( body ) CALAMARES_RETRANSLATE_FOR( this, [=] { body } )
|
||||
/** @brief Call code for the given object (widget) when language changes
|
||||
*
|
||||
* This is identical to CALAMARES_RETRANSLATE, except the @p body is called
|
||||
* for the given widget, not this object.
|
||||
*
|
||||
* NOTE: this macro is deprecated.
|
||||
*/
|
||||
#define CALAMARES_RETRANSLATE_WIDGET( widget, body ) CALAMARES_RETRANSLATE_FOR( widget, [=] { body } )
|
||||
/** @brief Call a slot in this object when language changes
|
||||
*
|
||||
* Given a slot (in method-function-pointer notation), call that slot when the
|
||||
* language changes. This is shorthand for connecting the Retranslator's
|
||||
* signal to the given slot.
|
||||
*/
|
||||
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) CALAMARES_RETRANSLATE_FOR( this, slotfunc )
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user