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
|
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||||
website will have to do for older versions.
|
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) #
|
# 3.2.40 (2021-07-14) #
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
This release contains contributions from (alphabetically by first name):
|
||||||
|
@ -357,6 +357,8 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
|
|||||||
, m_debugManager( new Calamares::DebugWindowManager( this ) )
|
, m_debugManager( new Calamares::DebugWindowManager( this ) )
|
||||||
, m_viewManager( nullptr )
|
, m_viewManager( nullptr )
|
||||||
{
|
{
|
||||||
|
installEventFilter( CalamaresUtils::Retranslator::instance() );
|
||||||
|
|
||||||
// If we can never cancel, don't show the window-close button
|
// If we can never cancel, don't show the window-close button
|
||||||
if ( Calamares::Settings::instance()->disableCancel() )
|
if ( Calamares::Settings::instance()->disableCancel() )
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "modulesystem/ModuleManager.h"
|
#include "modulesystem/ModuleManager.h"
|
||||||
#include "modulesystem/ViewModule.h"
|
#include "modulesystem/ViewModule.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Retranslator.h"
|
||||||
#include "utils/Yaml.h"
|
#include "utils/Yaml.h"
|
||||||
#include "viewpages/ExecutionViewStep.h"
|
#include "viewpages/ExecutionViewStep.h"
|
||||||
|
|
||||||
@ -489,6 +490,10 @@ main( int argc, char* argv[] )
|
|||||||
aw = replace_app;
|
aw = replace_app;
|
||||||
}
|
}
|
||||||
mw = module.m_ui ? new QMainWindow() : nullptr;
|
mw = module.m_ui ? new QMainWindow() : nullptr;
|
||||||
|
if ( mw )
|
||||||
|
{
|
||||||
|
mw->installEventFilter( CalamaresUtils::Retranslator::instance() );
|
||||||
|
}
|
||||||
|
|
||||||
(void)new Calamares::Branding( module.m_branding );
|
(void)new Calamares::Branding( module.m_branding );
|
||||||
auto* modulemanager = new Calamares::ModuleManager( QStringList(), nullptr );
|
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() );
|
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 )
|
Retranslator::Retranslator( QObject* parent )
|
||||||
: QObject( parent )
|
: QObject( parent )
|
||||||
{
|
{
|
||||||
parent->installEventFilter( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Retranslator::eventFilter( QObject* obj, QEvent* e )
|
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 )
|
emit languageChanged();
|
||||||
{
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
emit languageChange();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// pass the event on to the base
|
// pass the event on to the base
|
||||||
return QObject::eventFilter( obj, e );
|
return QObject::eventFilter( obj, e );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Retranslator* Retranslator::instance()
|
||||||
|
{
|
||||||
|
static Retranslator s_instance(nullptr);
|
||||||
|
return &s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
setAllowLocalTranslation( bool allow )
|
setAllowLocalTranslation( bool allow )
|
||||||
{
|
{
|
||||||
|
@ -64,40 +64,64 @@ DLLEXPORT bool loadTranslator( const QLocale& locale, const QString& prefix, QTr
|
|||||||
*/
|
*/
|
||||||
DLLEXPORT void setAllowLocalTranslation( bool allow );
|
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
|
class Retranslator : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
/// @brief Call @p retranslateFunc when the language changes
|
static Retranslator* instance();
|
||||||
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 );
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void languageChange();
|
void languageChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter( QObject* obj, QEvent* e ) override;
|
bool eventFilter( QObject* obj, QEvent* e ) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Retranslator( QObject* parent );
|
explicit Retranslator( QObject* parent );
|
||||||
|
|
||||||
QList< std::function< void( void ) > > m_retranslateFuncList;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
|
||||||
#define CALAMARES_RETRANSLATE( body ) CalamaresUtils::Retranslator::attachRetranslator( this, [=] { body } )
|
// Implementation detail: connects the retranslator to a slot or function
|
||||||
#define CALAMARES_RETRANSLATE_WIDGET( widget, body ) \
|
#define CALAMARES_RETRANSLATE_FOR( object, body ) \
|
||||||
CalamaresUtils::Retranslator::attachRetranslator( widget, [=] { body } )
|
QObject::connect( CalamaresUtils::Retranslator::instance(), &CalamaresUtils::Retranslator::languageChanged, object, body )
|
||||||
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
|
|
||||||
do \
|
/** @brief Call code for this object when language changes
|
||||||
{ \
|
*
|
||||||
this->connect( CalamaresUtils::Retranslator::retranslatorFor( this ), \
|
* @p body should be a code block (it does not need braces) that can be wrapped
|
||||||
&CalamaresUtils::Retranslator::languageChange, \
|
* up as a lambda. When the language changes, the lambda is called. Note that
|
||||||
this, \
|
* this macro should be used in constructors or other code that is run only
|
||||||
slotfunc ); \
|
* once, since otherwise you will end up with multiple calls to @p body.
|
||||||
} while ( 0 )
|
*/
|
||||||
|
#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
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user