diff --git a/CMakeLists.txt b/CMakeLists.txt index 99ee4330e..b4ac77946 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -404,7 +404,10 @@ set(Calamares_WITH_QML ${WITH_QML}) ### Transifex Translation status # -# Construct language lists for use. +# Construct language lists for use. This massages the language lists +# for use with older Qt (which does not support Esperanto) and checks +# for some obvious error. The actual work of compiling translations +# is done in the lang/ directory. # if( Qt5_VERSION VERSION_GREATER 5.12.1 ) # At least Qt 5.12.2 seems to support Esperanto in QLocale diff --git a/lang/CMakeLists.txt b/lang/CMakeLists.txt index 8658653ab..72aae9588 100644 --- a/lang/CMakeLists.txt +++ b/lang/CMakeLists.txt @@ -4,6 +4,14 @@ # SPDX-License-Identifier: BSD-2-Clause # ### +# +# This CMakeList handles the following i18n / language targets: +# +# - creating a translation test-tool +# - building the Python (gettext-based) translations +# - compiling all the Qt translations into a C++ file calamares-i18n.cxx +# - defines an OBJECT LIBRARY calamares-i18n for linking the compiled +# translations into an executable. include( CalamaresAddTranslations ) @@ -18,3 +26,39 @@ install_calamares_gettext_translations( python FILENAME python.mo RENAME calamares-python.mo ) + +### TRANSLATIONS +# +# +set( TS_FILES "" ) +set( calamares_i18n_qrc_content "" ) + +# calamares and qt language files +foreach( lang ${CALAMARES_TRANSLATION_LANGUAGES} ) + foreach( tlsource "calamares_${lang}" "tz_${lang}" "kb_${lang}" ) + if( EXISTS "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" ) + string( APPEND calamares_i18n_qrc_content "${tlsource}.qm\n" ) + list( APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" ) + endif() + endforeach() +endforeach() + +set( trans_file calamares_i18n ) +set( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc ) +set( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/calamares-i18n.cxx ) +set( CALAMARES_TRANSLATIONS_SOURCE ${trans_outfile} ) + +configure_file( ${CMAKE_SOURCE_DIR}/lang/calamares_i18n.qrc.in ${trans_infile} @ONLY ) + +qt5_add_translation(QM_FILES ${TS_FILES}) + +# Run the resource compiler (rcc_options should already be set) +add_custom_command( + OUTPUT ${trans_outfile} + COMMAND "${Qt5Core_RCC_EXECUTABLE}" + ARGS ${rcc_options} --format-version 1 -name ${trans_file} -o ${trans_outfile} ${trans_infile} + MAIN_DEPENDENCY ${trans_infile} + DEPENDS ${QM_FILES} +) + +add_library(calamares-i18n OBJECT ${trans_outfile}) diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index cf00dca37..d06a53d83 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -34,45 +34,15 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -### TRANSLATIONS -# -# -set( TS_FILES "" ) -set( calamares_i18n_qrc_content "" ) - -# calamares and qt language files -foreach( lang ${CALAMARES_TRANSLATION_LANGUAGES} ) - foreach( tlsource "calamares_${lang}" "tz_${lang}" "kb_${lang}" ) - if( EXISTS "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" ) - set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}${tlsource}.qm\n" ) - list( APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" ) - endif() - endforeach() -endforeach() - -set( trans_file calamares_i18n ) -set( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc ) -set( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${trans_file}.cxx ) - -configure_file( ${CMAKE_SOURCE_DIR}/lang/calamares_i18n.qrc.in ${trans_infile} @ONLY ) - -qt5_add_translation(QM_FILES ${TS_FILES}) - -# Run the resource compiler (rcc_options should already be set) -add_custom_command( - OUTPUT ${trans_outfile} - COMMAND "${Qt5Core_RCC_EXECUTABLE}" - ARGS ${rcc_options} --format-version 1 -name ${trans_file} -o ${trans_outfile} ${trans_infile} - MAIN_DEPENDENCY ${trans_infile} - DEPENDS ${QM_FILES} -) - ### EXECUTABLE # # "calamares_bin" is the main application, not to be confused with # the target "calamares" which is the non-GUI library part. # -add_executable( calamares_bin ${calamaresSources} calamares.qrc ${trans_outfile} ) +# The calamares-i18n.cxx file -- full path in CALAMARES_TRANSLATIONS_SOURCE -- +# is created as a target in the lang/ directory. This is compiled to a +# library (it's just the result of a QRC compile). +add_executable( calamares_bin ${calamaresSources} calamares.qrc ) target_include_directories( calamares_bin PRIVATE ${CMAKE_SOURCE_DIR} ) set_target_properties(calamares_bin PROPERTIES @@ -91,6 +61,7 @@ target_link_libraries( calamares_bin PRIVATE calamares calamaresui + calamares-i18n Qt5::Core Qt5::Widgets KF5::CoreAddons diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt index 20fae9a19..a704b7484 100644 --- a/src/libcalamaresui/CMakeLists.txt +++ b/src/libcalamaresui/CMakeLists.txt @@ -29,6 +29,7 @@ set( calamaresui_SOURCES widgets/ClickableLabel.cpp widgets/FixedAspectRatioLabel.cpp widgets/PrettyRadioButton.cpp + widgets/TranslationFix.cpp widgets/WaitingWidget.cpp ${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp diff --git a/src/libcalamaresui/ViewManager.cpp b/src/libcalamaresui/ViewManager.cpp index f6edbfc2a..57570ad64 100644 --- a/src/libcalamaresui/ViewManager.cpp +++ b/src/libcalamaresui/ViewManager.cpp @@ -24,6 +24,7 @@ #include "viewpages/BlankViewStep.h" #include "viewpages/ExecutionViewStep.h" #include "viewpages/ViewStep.h" +#include "widgets/TranslationFix.h" #include #include @@ -82,6 +83,12 @@ ViewManager::ViewManager( QObject* parent ) connect( JobQueue::instance(), &JobQueue::finished, this, &ViewManager::next ); CALAMARES_RETRANSLATE_SLOT( &ViewManager::updateButtonLabels ); + +#ifdef PRESERVE_FOR_TRANSLATION_PURPOSES + tr( "&Yes" ); + tr( "&No" ); + tr( "&Close" ); +#endif } @@ -176,15 +183,13 @@ ViewManager::onInstallationFailed( const QString& message, const QString& detail { msgBox->setStandardButtons( QMessageBox::Yes | QMessageBox::No ); msgBox->setDefaultButton( QMessageBox::No ); - msgBox->button( QMessageBox::Yes )->setText( tr( "&Yes" ) ); - msgBox->button( QMessageBox::No )->setText( tr( "&No" ) ); } else { msgBox->setStandardButtons( QMessageBox::Close ); msgBox->setDefaultButton( QMessageBox::Close ); - msgBox->button( QMessageBox::Close )->setText( tr( "&Close" ) ); } + Calamares::fixButtonLabels( msgBox ); msgBox->show(); cDebug() << "Calamares will quit when the dialog closes."; @@ -516,8 +521,7 @@ ViewManager::confirmCancelInstallation() "The installer will quit and all changes will be lost." ); QMessageBox mb( QMessageBox::Question, title, question, QMessageBox::Yes | QMessageBox::No, m_widget ); mb.setDefaultButton( QMessageBox::No ); - mb.button( QMessageBox::Yes )->setText( tr( "&Yes" ) ); - mb.button( QMessageBox::No )->setText( tr( "&No" ) ); + Calamares::fixButtonLabels( &mb ); int response = mb.exec(); return response == QMessageBox::Yes; } diff --git a/src/libcalamaresui/utils/Paste.cpp b/src/libcalamaresui/utils/Paste.cpp index a29d6d362..9190fcf5c 100644 --- a/src/libcalamaresui/utils/Paste.cpp +++ b/src/libcalamaresui/utils/Paste.cpp @@ -13,6 +13,7 @@ #include "DllMacro.h" #include "utils/Logger.h" #include "utils/Units.h" +#include "widgets/TranslationFix.h" #include #include @@ -166,8 +167,12 @@ CalamaresUtils::Paste::doLogUploadUI( QWidget* parent ) pasteUrlMessage = pasteUrlFmt.arg( pasteUrl ); } - QMessageBox::critical( - nullptr, QCoreApplication::translate( "Calamares::ViewManager", "Install Log Paste URL" ), pasteUrlMessage ); + QMessageBox mb( QMessageBox::Critical, + QCoreApplication::translate( "Calamares::ViewManager", "Install Log Paste URL" ), + pasteUrlMessage, + QMessageBox::Ok ); + Calamares::fixButtonLabels( &mb ); + mb.exec(); return pasteUrl; } diff --git a/src/libcalamaresui/widgets/TranslationFix.cpp b/src/libcalamaresui/widgets/TranslationFix.cpp new file mode 100644 index 000000000..1262fceb5 --- /dev/null +++ b/src/libcalamaresui/widgets/TranslationFix.cpp @@ -0,0 +1,45 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#include "TranslationFix.h" + +#include +#include +#include + +namespace Calamares +{ + +void +fixButtonLabels( QMessageBox* box ) +{ + if ( !box ) + { + return; + } + + static std::pair< decltype( QMessageBox::Ok ), const char* > maps[] = { + { QMessageBox::Ok, QT_TRANSLATE_NOOP( "StandardButtons", "&OK" ) }, + { QMessageBox::Yes, QT_TRANSLATE_NOOP( "StandardButtons", "&Yes" ) }, + { QMessageBox::No, QT_TRANSLATE_NOOP( "StandardButtons", "&No" ) }, + { QMessageBox::Cancel, QT_TRANSLATE_NOOP( "StandardButtons", "&Cancel" ) }, + { QMessageBox::Close, QT_TRANSLATE_NOOP( "StandardButtons", "&Close" ) }, + }; + + for ( auto [ sb, label ] : maps ) + { + auto* button = box->button( sb ); + if ( button ) + { + button->setText( QCoreApplication::translate( "StandardButtons", label ) ); + } + } +} + +} // namespace Calamares diff --git a/src/libcalamaresui/widgets/TranslationFix.h b/src/libcalamaresui/widgets/TranslationFix.h new file mode 100644 index 000000000..107dad67d --- /dev/null +++ b/src/libcalamaresui/widgets/TranslationFix.h @@ -0,0 +1,31 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#ifndef LIBCALAMARESUI_WIDGETS_TRANSLATIONFIX_H +#define LIBCALAMARESUI_WIDGETS_TRANSLATIONFIX_H + +#include "DllMacro.h" + +class QMessageBox; + +namespace Calamares +{ + +/** @brief Fixes the labels on the standard buttons of the message box + * + * Updates OK / Cancel / Yes / No because there does not + * seem to be a way to do so in the Retranslator code + * (in libcalamares) since the translated strings may come + * from a variety of platform-plugin sources and we can't + * guess the context. + */ +void UIDLLEXPORT fixButtonLabels( QMessageBox* ); +} // namespace Calamares + +#endif diff --git a/src/modules/interactiveterminal/InteractiveTerminalPage.cpp b/src/modules/interactiveterminal/InteractiveTerminalPage.cpp index 65818aa03..afd39936b 100644 --- a/src/modules/interactiveterminal/InteractiveTerminalPage.cpp +++ b/src/modules/interactiveterminal/InteractiveTerminalPage.cpp @@ -13,6 +13,7 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" #include "viewpages/ViewStep.h" +#include "widgets/TranslationFix.h" #include #include @@ -40,8 +41,10 @@ InteractiveTerminalPage::InteractiveTerminalPage( QWidget* parent ) void InteractiveTerminalPage::errorKonsoleNotInstalled() { - QMessageBox::critical( - this, tr( "Konsole not installed" ), tr( "Please install KDE Konsole and try again!" ), QMessageBox::Ok ); + QMessageBox mb(QMessageBox::Critical, + tr( "Konsole not installed" ), tr( "Please install KDE Konsole and try again!" ), QMessageBox::Ok ); + Calamares::fixButtonLabels( &mb ); + mb.exec(); } void diff --git a/src/modules/license/LicensePage.cpp b/src/modules/license/LicensePage.cpp index cb5481a1e..8700aad60 100644 --- a/src/modules/license/LicensePage.cpp +++ b/src/modules/license/LicensePage.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include diff --git a/src/modules/partition/PartitionViewStep.cpp b/src/modules/partition/PartitionViewStep.cpp index 1fe7bdfab..c17954810 100644 --- a/src/modules/partition/PartitionViewStep.cpp +++ b/src/modules/partition/PartitionViewStep.cpp @@ -30,6 +30,7 @@ #include "utils/QtCompat.h" #include "utils/Retranslator.h" #include "utils/Variant.h" +#include "widgets/TranslationFix.h" #include "widgets/WaitingWidget.h" #include @@ -51,7 +52,8 @@ PartitionViewStep::PartitionViewStep( QObject* parent ) m_waitingWidget = new WaitingWidget( QString() ); m_widget->addWidget( m_waitingWidget ); - CALAMARES_RETRANSLATE( if (m_waitingWidget) { m_waitingWidget->setText( tr( "Gathering system information..." ) ); } ); + CALAMARES_RETRANSLATE( + if ( m_waitingWidget ) { m_waitingWidget->setText( tr( "Gathering system information..." ) ); } ); m_core = new PartitionCoreModule( this ); // Unusable before init is complete! // We're not done loading, but we need the configuration map first. @@ -527,47 +529,57 @@ PartitionViewStep::onLeave() { message = tr( "No EFI system partition configured" ); } - else if ( !(okType && okSize && okFlag ) ) + else if ( !( okType && okSize && okFlag ) ) { message = tr( "EFI system partition configured incorrectly" ); } - if ( !esp || !(okType&&okSize &&okFlag)) { - description = tr( "An EFI system partition is necessary to start %1." - "

" - "To configure an EFI system partition, go back and " - "select or create a suitable filesystem.").arg( branding->shortProductName() ); + if ( !esp || !( okType && okSize && okFlag ) ) + { + description = tr( "An EFI system partition is necessary to start %1." + "

" + "To configure an EFI system partition, go back and " + "select or create a suitable filesystem." ) + .arg( branding->shortProductName() ); } - if (!esp) { + if ( !esp ) + { cDebug() << o << "No ESP mounted"; - description.append(' '); - description.append(tr("The filesystem must be mounted on %1.").arg(espMountPoint)); + description.append( ' ' ); + description.append( + tr( "The filesystem must be mounted on %1." ).arg( espMountPoint ) ); } - if (!okType) { + if ( !okType ) + { cDebug() << o << "ESP wrong type"; - description.append(' '); - description.append(tr("The filesystem must have type FAT32.")); + description.append( ' ' ); + description.append( tr( "The filesystem must have type FAT32." ) ); } - if (!okSize) { + if ( !okSize ) + { cDebug() << o << "ESP too small"; - description.append(' '); - description.append(tr("The filesystem must be at least %1 MiB in size.").arg( PartUtils::efiFilesystemMinimumSize() )); + description.append( ' ' ); + description.append( tr( "The filesystem must be at least %1 MiB in size." ) + .arg( PartUtils::efiFilesystemMinimumSize() ) ); } - if (!okFlag) + if ( !okFlag ) { cDebug() << o << "ESP missing flag"; - description.append(' '); - description.append(tr("The filesystem must have flag %1 set.").arg(PartitionTable::flagName( espFlag ))); + description.append( ' ' ); + description.append( tr( "The filesystem must have flag %1 set." ) + .arg( PartitionTable::flagName( espFlag ) ) ); } - if (!description.isEmpty()) { + if ( !description.isEmpty() ) + { description.append( "

" ); - description.append( tr( - "You can continue without setting up an EFI system " - "partition but your system may fail to start." )); + description.append( tr( "You can continue without setting up an EFI system " + "partition but your system may fail to start." ) ); } if ( !message.isEmpty() ) { - QMessageBox::warning( m_manualPartitionPage, message, description ); + QMessageBox mb( QMessageBox::Warning, message, description, QMessageBox::Ok, m_manualPartitionPage ); + Calamares::fixButtonLabels( &mb ); + mb.exec(); } } else @@ -591,7 +603,10 @@ PartitionViewStep::onLeave() "to start %1 on a BIOS system with GPT." ) .arg( branding->shortProductName() ); - QMessageBox::information( m_manualPartitionPage, message, description ); + QMessageBox mb( + QMessageBox::Information, message, description, QMessageBox::Ok, m_manualPartitionPage ); + Calamares::fixButtonLabels( &mb ); + mb.exec(); } } @@ -621,7 +636,9 @@ PartitionViewStep::onLeave() "recreate it, selecting Encrypt " "in the partition creation window." ); - QMessageBox::warning( m_manualPartitionPage, message, description ); + QMessageBox mb( QMessageBox::Warning, message, description, QMessageBox::Ok, m_manualPartitionPage ); + Calamares::fixButtonLabels( &mb ); + mb.exec(); } } } diff --git a/src/modules/partition/gui/PartitionPage.cpp b/src/modules/partition/gui/PartitionPage.cpp index d22f6f01d..9d7a2f0d7 100644 --- a/src/modules/partition/gui/PartitionPage.cpp +++ b/src/modules/partition/gui/PartitionPage.cpp @@ -31,13 +31,13 @@ #include "ui_CreatePartitionTableDialog.h" #include "ui_PartitionPage.h" +#include "Branding.h" #include "GlobalStorage.h" #include "JobQueue.h" #include "partition/PartitionQuery.h" #include "utils/Logger.h" #include "utils/Retranslator.h" - -#include "Branding.h" +#include "widgets/TranslationFix.h" // KPMcore #include @@ -258,13 +258,16 @@ PartitionPage::checkCanCreate( Device* device ) if ( ( table->numPrimaries() >= table->maxPrimaries() ) && !table->hasExtended() ) { - QMessageBox::warning( - this, + QMessageBox mb( + QMessageBox::Warning, tr( "Can not create new partition" ), tr( "The partition table on %1 already has %2 primary partitions, and no more can be added. " "Please remove one primary partition and add an extended partition, instead." ) .arg( device->name() ) - .arg( table->numPrimaries() ) ); + .arg( table->numPrimaries() ), + QMessageBox::Ok ); + Calamares::fixButtonLabels( &mb ); + mb.exec(); return false; } return true; diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index a82d873e9..1ea3f2429 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -26,6 +26,7 @@ #include "utils/Logger.h" #include "utils/NamedEnum.h" #include "utils/Retranslator.h" +#include "widgets/TranslationFix.h" #include #include @@ -251,6 +252,7 @@ WelcomePage::showAboutBox() .arg( Calamares::Branding::instance()->versionedName() ), QMessageBox::Ok, this ); + Calamares::fixButtonLabels( &mb ); mb.setIconPixmap( CalamaresUtils::defaultPixmap( CalamaresUtils::Squid, CalamaresUtils::Original,