diff --git a/src/controller/application.cpp b/src/controller/application.cpp index 7263afb3..a912b2a3 100644 --- a/src/controller/application.cpp +++ b/src/controller/application.cpp @@ -103,9 +103,12 @@ bool Application::isDarkTheme() const void Application::loadTranslations(const QString& lang) { QLocale locale; - static const QStringList SUPPORTED_LANGS {"en", "et", "fi", "ru"}; - if (SUPPORTED_LANGS.contains(lang)) { - locale = QLocale(lang); + static const QStringList SUPPORTED_LANGS {QStringLiteral("en"), QStringLiteral("et"), + QStringLiteral("fi"), QStringLiteral("hr"), + QStringLiteral("ru")}; + QString langSetting = QSettings().value(QStringLiteral("lang"), lang).toString(); + if (SUPPORTED_LANGS.contains(langSetting)) { + locale = QLocale(langSetting); } void(translator->load(locale, QStringLiteral(":/translations/"))); } diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 028dc09b..67971af8 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -12,6 +12,7 @@ qt_add_translation(SOURCES translations/en.ts translations/et.ts translations/fi.ts + translations/hr.ts translations/ru.ts ) add_library(ui STATIC diff --git a/src/ui/certificatewidget.cpp b/src/ui/certificatewidget.cpp index e9fcd78a..fb3b4842 100644 --- a/src/ui/certificatewidget.cpp +++ b/src/ui/certificatewidget.cpp @@ -89,6 +89,7 @@ void CertificateWidgetInfo::drawWarnIcon() void CertificateWidgetInfo::setCertificateInfo(const CardCertificateAndPinInfo& cardCertPinInfo) { + warn->setText(CertificateWidget::tr("Pin locked")); certAndPinInfo = cardCertPinInfo; const auto certInfo = cardCertPinInfo.certInfo; QString warning, effectiveDate = certInfo.effectiveDate, expiryDate = certInfo.expiryDate; @@ -110,6 +111,11 @@ void CertificateWidgetInfo::setCertificateInfo(const CardCertificateAndPinInfo& } } +void CertificateWidgetInfo::languageChange() +{ + setCertificateInfo(certAndPinInfo); +} + CertificateWidget::CertificateWidget(QWidget* parent) : QWidget(parent), CertificateWidgetInfo(this) { info->setFocusPolicy(Qt::TabFocus); @@ -143,10 +149,6 @@ CertificateButton::CertificateButton(const CardCertificateAndPinInfo& cardCertPi CertificateWidgetInfo::icon->setAttribute(Qt::WA_TransparentForMouseEvents); info->setAttribute(Qt::WA_TransparentForMouseEvents); setCertificateInfo(cardCertPinInfo); - const auto certInfo = cardCertPinInfo.certInfo; - setText( - tr("%1 Issuer: %2 Valid: %3 to %4") - .arg(certInfo.subject, certInfo.issuer, certInfo.effectiveDate, certInfo.expiryDate)); } bool CertificateButton::eventFilter(QObject* object, QEvent* event) @@ -158,6 +160,15 @@ bool CertificateButton::eventFilter(QObject* object, QEvent* event) return QAbstractButton::eventFilter(object, event); } +void CertificateButton::setCertificateInfo(const CardCertificateAndPinInfo& cardCertPinInfo) +{ + CertificateWidgetInfo::setCertificateInfo(cardCertPinInfo); + const auto certInfo = cardCertPinInfo.certInfo; + setText( + tr("%1 Issuer: %2 Valid: %3 to %4") + .arg(certInfo.subject, certInfo.issuer, certInfo.effectiveDate, certInfo.expiryDate)); +} + void CertificateButton::paintEvent(QPaintEvent* /*event*/) { QPainter p(this); diff --git a/src/ui/certificatewidget.hpp b/src/ui/certificatewidget.hpp index a0d6ba3b..4c9bfce9 100644 --- a/src/ui/certificatewidget.hpp +++ b/src/ui/certificatewidget.hpp @@ -32,7 +32,8 @@ class CertificateWidgetInfo { public: CardCertificateAndPinInfo certificateInfo() const; - void setCertificateInfo(const CardCertificateAndPinInfo& cardCertPinInfo); + virtual void setCertificateInfo(const CardCertificateAndPinInfo& cardCertPinInfo); + void languageChange(); protected: CertificateWidgetInfo(QWidget* self); @@ -68,5 +69,6 @@ class CertificateButton final : public QAbstractButton, public CertificateWidget private: bool eventFilter(QObject* object, QEvent* event) final; + void setCertificateInfo(const CardCertificateAndPinInfo& cardCertPinInfo) final; void paintEvent(QPaintEvent* event) final; }; diff --git a/src/ui/dark.qss b/src/ui/dark.qss index 17c91bae..f981bacf 100644 --- a/src/ui/dark.qss +++ b/src/ui/dark.qss @@ -2,19 +2,19 @@ QWidget { background-color: #232325; color: white; } -QPushButton { +QPushButton, #langButton { border-color: #4E4E53; background-color: #4E4E53; } -QPushButton::disabled { +QPushButton::disabled, #langButton::disabled { border-color: #27272A; background-color: #27272A; } -QPushButton::hover { +QPushButton::hover, #langButton::hover { background-color: #76767B; border-color: #76767B; } -QPushButton::focus { +QPushButton::focus, #langButton::focus { background-color: #76767B; border-color: #DEDEDE; } @@ -34,6 +34,13 @@ QPushButton:default::focus { background-color: #008EEA; border-color: #DEDEDE; } +#langButton::menu-indicator { +image: url(:images/down_dark.svg); +} +#langButton > QMenu { +border-color: #4E4E53; +background-color: #4E4E53; +} CertificateButton, CertificateWidget { border-color: #4E4E53; } @@ -85,3 +92,6 @@ color: white; #aboutVersion { color: white; } +#selectAnotherCertificate { +color: white; +} diff --git a/src/ui/dialog.ui b/src/ui/dialog.ui index 95f75228..e66a9972 100644 --- a/src/ui/dialog.ui +++ b/src/ui/dialog.ui @@ -7,7 +7,7 @@ 0 0 500 - 464 + 495 @@ -26,25 +26,25 @@ font-size: 14px; font-family: "Roboto"; color: black; } -QPushButton { +QPushButton, #langButton { font-size: 17px; border: 3px solid #EFEFEF; border-radius: 3px; height: 39px; -padding-left: 19px; -padding-right: 19px; +padding-left: 17px; +padding-right: 17px; min-width: 30px; background-color: #EFEFEF; } -QPushButton::disabled { +QPushButton::disabled, #langButton::disabled { background-color: #FAFAFA; border-color: #FAFAFA; } -QPushButton::hover { +QPushButton::hover, #langButton::hover { background-color: #DEDEDE; border-color: #DEDEDE; } -QPushButton::focus { +QPushButton::focus, #langButton::focus { background-color: #DEDEDE; border-color: #76767B; } @@ -65,6 +65,23 @@ QPushButton:default::focus { background-color: #003168; border-color: #008EEA; } +#langButton { +padding-left: 15px; +padding-right: 30px; +height: 36px; +} +#langButton::menu-indicator { +image: url(:images/down.svg); +subcontrol-origin: padding; +subcontrol-position: right center; +left: -8px; +} +#langButton > QMenu { +font-size: 17px; +border: 3px solid #EFEFEF; +border-radius: 3px; +background-color: #EFEFEF; +} CertificateButton, CertificateWidget { border: 1px solid rgba(0,49,104,0.1); border-radius: 4px; @@ -805,6 +822,9 @@ height: 24px; + + 6 + @@ -818,6 +838,16 @@ height: 24px; + + + + EN + + + QToolButton::InstantPopup + + + @@ -825,7 +855,7 @@ height: 24px; - 40 + 0 20 diff --git a/src/ui/images/down.svg b/src/ui/images/down.svg new file mode 100644 index 00000000..b7d64ba7 --- /dev/null +++ b/src/ui/images/down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/images/down_dark.svg b/src/ui/images/down_dark.svg new file mode 100644 index 00000000..a7b51e7e --- /dev/null +++ b/src/ui/images/down_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/translations/fi.ts b/src/ui/translations/fi.ts index 355c5a18..4a4aa219 100644 --- a/src/ui/translations/fi.ts +++ b/src/ui/translations/fi.ts @@ -249,15 +249,15 @@ Select another certificate - Valitse toinen varmenne + Valitse toinen varmenne Operation failed. Make sure that the driver of the corresponding card reader is used. Read more <a href="https://www.id.ee/en/article/using-pinpad-card-reader-drivers/">here</a>. - Toimenpide epäonnistui. Varmista, että käytetään vastaavan kortinlukijan ajuria. Lue lisää <a href="https://www.id.ee/en/article/using-pinpad-card-reader-drivers/">täältä</a>. + Toimenpide epäonnistui. Varmista, että käytetään vastaavan kortinlukijan ajuria. Lue lisää <a href="https://www.id.ee/en/article/using-pinpad-card-reader-drivers/">täältä</a>. The certificate of the ID card in the reader does not match the originally submitted certificate. Please insert the original ID card. - Lukijassa oleva henkilökortin varmenne ei vastaa alun perin lähetettyä varmennetta. Aseta alkuperäinen henkilökortti kortinlukijaan. + Lukijassa oleva henkilökortin varmenne ei vastaa alun perin lähetettyä varmennetta. Aseta alkuperäinen henkilökortti kortinlukijaan. diff --git a/src/ui/translations/hr.ts b/src/ui/translations/hr.ts index 642f81a6..eb7a65d4 100644 --- a/src/ui/translations/hr.ts +++ b/src/ui/translations/hr.ts @@ -1,17 +1,6 @@ - - Application - - &File - &Datoteka - - - &About - &O programu - - CertificateButton @@ -110,7 +99,7 @@ https://www.id.ee/en/article/how-to-check-that-your-id-card-reader-is-working/ - https://www.id.ee/en/article/how-to-check-that-your-id-card-reader-is-working/ + https://www.id.ee/en/article/how-to-check-that-your-id-card-reader-is-working/ Time remaining: <b>%1</b> diff --git a/src/ui/translations/ru.ts b/src/ui/translations/ru.ts index c3cd6b2f..4c794da6 100644 --- a/src/ui/translations/ru.ts +++ b/src/ui/translations/ru.ts @@ -259,7 +259,7 @@ The certificate of the ID card in the reader does not match the originally submitted certificate. Please insert the original ID card. - Сертификат ID-карты в считывателе не соответствует указанному сертификату. Пожалуйста, вставьте оригинальную ID-карту. + Сертификат ID-карты в считывателе не соответствует указанному сертификату. Пожалуйста, вставьте оригинальную ID-карту. diff --git a/src/ui/translations/translations.qrc b/src/ui/translations/translations.qrc index 20b2eeb2..41f97319 100644 --- a/src/ui/translations/translations.qrc +++ b/src/ui/translations/translations.qrc @@ -3,6 +3,7 @@ en.qm et.qm fi.qm + hr.qm ru.qm diff --git a/src/ui/web-eid-resources.qrc b/src/ui/web-eid-resources.qrc index 4c127589..f3e72615 100644 --- a/src/ui/web-eid-resources.qrc +++ b/src/ui/web-eid-resources.qrc @@ -4,6 +4,8 @@ images/arrow.svg images/cardreader.svg images/cardreader_dark.svg + images/down.svg + images/down_dark.svg images/fatal.svg images/fatal_dark.svg images/help.svg diff --git a/src/ui/webeiddialog.cpp b/src/ui/webeiddialog.cpp index da55ced2..54d9dd0e 100644 --- a/src/ui/webeiddialog.cpp +++ b/src/ui/webeiddialog.cpp @@ -29,9 +29,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -42,6 +44,15 @@ #include #endif +#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) +constexpr inline QLatin1String operator"" _L1(const char* str, size_t size) noexcept +{ + return QLatin1String(str, int(size)); +} +#else +using namespace Qt::Literals::StringLiterals; +#endif + using namespace electronic_id; class WebEidDialog::Private : public Ui::WebEidDialog @@ -60,18 +71,32 @@ WebEidDialog::WebEidDialog(QWidget* parent) : WebEidUI(parent), ui(new Private) QFile f(QStringLiteral(":dark.qss")); if (f.open(QFile::ReadOnly | QFile::Text)) { setStyleSheet(styleSheet() + QTextStream(&f).readAll()); - ui->selectCertificateOriginLabelIcon->setPixmap(pixmap(QLatin1String("origin"))); - ui->pinInputOriginLabelIcon->setPixmap(pixmap(QLatin1String("origin"))); - ui->cardChipIcon->setPixmap(pixmap(QLatin1String("no-id-card"))); - ui->fatalErrorIcon->setPixmap(pixmap(QLatin1String("fatal"))); - ui->aboutIcon->setPixmap(pixmap(QLatin1String("fatal"))); - ui->helpButton->setIcon(QIcon(QLatin1String(":/images/help_dark.svg"))); + ui->selectCertificateOriginLabelIcon->setPixmap(pixmap("origin"_L1)); + ui->pinInputOriginLabelIcon->setPixmap(pixmap("origin"_L1)); + ui->cardChipIcon->setPixmap(pixmap("no-id-card"_L1)); + ui->fatalErrorIcon->setPixmap(pixmap("fatal"_L1)); + ui->aboutIcon->setPixmap(pixmap("fatal"_L1)); + ui->helpButton->setIcon(QIcon(QStringLiteral(":/images/help_dark.svg"))); } } setWindowFlag(Qt::CustomizeWindowHint); setWindowFlag(Qt::WindowTitleHint); setWindowTitle(qApp->applicationDisplayName()); - ui->aboutVersion->setText(tr("Version: %1").arg(qApp->applicationVersion())); + setTrText(ui->aboutVersion, [] { return tr("Version: %1").arg(qApp->applicationVersion()); }); + QMenu* langMenu = new QMenu(ui->langButton); + langMenu->addAction(QStringLiteral("EN")); + langMenu->addAction(QStringLiteral("ET")); + langMenu->addAction(QStringLiteral("FI")); + langMenu->addAction(QStringLiteral("HR")); + langMenu->addAction(QStringLiteral("RU")); + connect(langMenu, &QMenu::triggered, qApp, [this](QAction* action) { + QSettings().setValue(QStringLiteral("lang"), action->text().toLower()); + ui->langButton->setText(action->text()); + qApp->loadTranslations(); + }); + ui->langButton->setMenu(langMenu); + ui->langButton->setText( + QSettings().value(QStringLiteral("lang"), ui->langButton->text()).toString().toUpper()); ui->pinInput->setAttribute(Qt::WA_MacShowFocusRect, false); auto pinInputFont = ui->pinInput->font(); @@ -144,6 +169,10 @@ WebEidDialog::WebEidDialog(QWidget* parent) : WebEidUI(parent), ui(new Private) ui->pinTimeRemaining->setText( tr("Time remaining: %1").arg(ui->pinEntryTimeoutProgressBar->maximum() - value)); }); + + connect(this, &WebEidDialog::languageChange, this, [this]{ + ui->pinInputCertificateInfo->languageChange(); + }); } WebEidDialog::~WebEidDialog() @@ -159,7 +188,8 @@ void WebEidDialog::showAboutPage() d->ui->aboutAlert->hide(); auto app = static_cast(QCoreApplication::instance()); if (app->isSafariExtensionContainingApp()) { - d->setupOK([app] { app->showSafariSettings(); }, tr("Open Safari settings..."), true); + d->setupOK([app] { app->showSafariSettings(); }, + [] { return tr("Open Safari settings..."); }, true); connect(app, &Application::safariExtensionEnabled, d, [d](bool value) { d->ui->aboutAlert->setHidden(value); d->resizeHeight(); @@ -178,7 +208,7 @@ void WebEidDialog::showFatalErrorPage() { WebEidDialog* d = new WebEidDialog(); d->setAttribute(Qt::WA_DeleteOnClose); - d->ui->messagePageTitleLabel->setText(tr("Operation failed")); + d->setTrText(d->ui->messagePageTitleLabel, [] { return tr("Operation failed"); }); d->ui->fatalError->show(); d->ui->fatalHelp->show(); d->ui->connectCardLabel->hide(); @@ -212,11 +242,11 @@ void WebEidDialog::onSmartCardStatusUpdate(const RetriableError status) { currentCommand = CommandType::INSERT_CARD; - const auto [errorText, title, icon] = retriableErrorToTextTitleAndIcon(status); - - ui->connectCardLabel->setText(errorText); - ui->messagePageTitleLabel->setText(title); - ui->cardChipIcon->setPixmap(icon); + setTrText(ui->connectCardLabel, + [this, status] { return std::get<0>(retriableErrorToTextTitleAndIcon(status)); }); + setTrText(ui->messagePageTitleLabel, + [this, status] { return std::get<1>(retriableErrorToTextTitleAndIcon(status)); }); + ui->cardChipIcon->setPixmap(std::get<2>(retriableErrorToTextTitleAndIcon(status))); // In case the insert card page is not shown, switch back to it. ui->helpButton->show(); @@ -294,23 +324,25 @@ void WebEidDialog::onSingleCertificateReady(const QUrl& origin, setupCertificateAndPinInfo({certAndPin}); setupOK([this, certAndPin] { emit accepted(certAndPin); }); ui->selectionGroup->buttons().at(0)->click(); - ui->pageStack->setCurrentIndex(int(WebEidDialog::Page::SELECT_CERTIFICATE)); + ui->pageStack->setCurrentIndex(int(Page::SELECT_CERTIFICATE)); return; case CommandType::AUTHENTICATE: ui->pinInputCertificateInfo->setCertificateInfo(certAndPin); - ui->pinInputPageTitleLabel->setText(tr("Authenticate")); - ui->pinInputDescriptionLabel->setText( - tr("By authenticating, I agree to the transfer of my name and personal " - "identification code to the service provider.")); - ui->pinTitleLabel->setText(tr("Enter PIN1 for authentication")); + setTrText(ui->pinInputPageTitleLabel, [] { return tr("Authenticate"); }); + setTrText(ui->pinInputDescriptionLabel, [] { + return tr("By authenticating, I agree to the transfer of my name and personal " + "identification code to the service provider."); + }); + setTrText(ui->pinTitleLabel, [] { return tr("Enter PIN1 for authentication"); }); break; case CommandType::SIGN: ui->pinInputCertificateInfo->setCertificateInfo(certAndPin); - ui->pinInputPageTitleLabel->setText(tr("Signing")); - ui->pinInputDescriptionLabel->setText( - tr("By signing, I agree to the transfer of my name and personal identification " - "code to the service provider.")); - ui->pinTitleLabel->setText(tr("Enter PIN2 for signing")); + setTrText(ui->pinInputPageTitleLabel, [] { return tr("Signing"); }); + setTrText(ui->pinInputDescriptionLabel, [] { + return tr("By signing, I agree to the transfer of my name and personal identification " + "code to the service provider."); + }); + setTrText(ui->pinTitleLabel, [] { return tr("Enter PIN2 for signing"); }); break; default: emit failure(QStringLiteral("Only SELECT_CERTIFICATE, AUTHENTICATE or SIGN allowed")); @@ -327,31 +359,35 @@ void WebEidDialog::onSingleCertificateReady(const QUrl& origin, setupPinInput(certAndPin); } - ui->pageStack->setCurrentIndex(int(WebEidDialog::Page::PIN_INPUT)); + ui->pageStack->setCurrentIndex(int(Page::PIN_INPUT)); } void WebEidDialog::onRetry(const RetriableError error) { - onRetryImpl(std::get<0>(retriableErrorToTextTitleAndIcon(error))); + onRetryImpl([this, error] { return std::get<0>(retriableErrorToTextTitleAndIcon(error)); }); } void WebEidDialog::onSigningCertificateMismatch() { - onRetryImpl(tr("The certificate of the ID card in the reader does not match the originally " - "submitted certificate. Please insert the original ID card.")); + onRetryImpl([] { + return tr("The certificate of the ID card in the reader does not match the originally " + "submitted certificate. Please insert the original ID card."); + }); } void WebEidDialog::onVerifyPinFailed(const VerifyPinFailed::Status status, const qint8 retriesLeft) { using Status = VerifyPinFailed::Status; - QString message; + std::function message; // FIXME: don't allow retry in case of UNKNOWN_ERROR switch (status) { case Status::RETRY_ALLOWED: - message = retriesLeft == -1 ? tr("Incorrect PIN.") - : tr("Incorrect PIN, %n attempts left.", nullptr, retriesLeft); + message = [retriesLeft] { + return retriesLeft == -1 ? tr("Incorrect PIN.") + : tr("Incorrect PIN, %n attempts left.", nullptr, retriesLeft); + }; showPinInputWarning(true); break; case Status::PIN_BLOCKED: @@ -359,22 +395,22 @@ void WebEidDialog::onVerifyPinFailed(const VerifyPinFailed::Status status, const resizeHeight(); return; case Status::INVALID_PIN_LENGTH: - message = tr("Invalid PIN length"); + message = [] { return tr("Invalid PIN length"); }; break; case Status::PIN_ENTRY_TIMEOUT: - message = tr("PinPad timed out waiting for customer interaction."); + message = [] { return tr("PinPad timed out waiting for customer interaction."); }; break; case Status::PIN_ENTRY_CANCEL: - message = tr("PIN entry cancelled."); + message = [] { return tr("PIN entry cancelled."); }; break; case Status::PIN_ENTRY_DISABLED: case Status::UNKNOWN_ERROR: - message = tr("Technical error"); + message = [] { return tr("Technical error"); }; break; } - ui->pinErrorLabel->setHidden(message.isEmpty()); - ui->pinErrorLabel->setText(message); + ui->pinErrorLabel->setVisible(bool(message)); + setTrText(ui->pinErrorLabel, message); if (ui->pinEntryTimeoutProgressBar->isVisible()) { onRetryImpl(message); @@ -399,20 +435,29 @@ bool WebEidDialog::event(QEvent* event) { if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); - ui->aboutVersion->setText(tr("Version: %1").arg(qApp->applicationVersion())); + emit languageChange(); + resizeHeight(); } return WebEidUI::event(event); } -void WebEidDialog::onRetryImpl(const QString& error) +void WebEidDialog::onRetryImpl(const std::function& text) { - ui->connectCardLabel->setText(error); - ui->messagePageTitleLabel->setText(tr("Operation failed")); - ui->cardChipIcon->setPixmap(pixmap(QLatin1String("no-id-card"))); - setupOK([this] { emit retry(); }, tr("Try again"), true); + setTrText(ui->connectCardLabel, text); + setTrText(ui->messagePageTitleLabel, [] { return tr("Operation failed"); }); + ui->cardChipIcon->setPixmap(pixmap("no-id-card"_L1)); + setupOK([this] { emit retry(); }, [] { return tr("Try again"); }, true); ui->pageStack->setCurrentIndex(int(Page::ALERT)); } +void WebEidDialog::setTrText(QWidget* label, const std::function& text) +{ + disconnect(this, &WebEidDialog::languageChange, label, nullptr); + label->setProperty("text", text()); + connect(this, &WebEidDialog::languageChange, label, + [label, text] { label->setProperty("text", text()); }); +} + void WebEidDialog::setupCertificateAndPinInfo( const std::vector& cardCertAndPinInfos) { @@ -425,6 +470,7 @@ void WebEidDialog::setupCertificateAndPinInfo( CertificateButton* button = new CertificateButton(certAndPin, ui->selectCertificatePage); ui->selectCertificateInfo->addWidget(button); ui->selectionGroup->addButton(button); + connect(this, &WebEidDialog::languageChange, button, [button] { button->languageChange(); }); setTabOrder(previous, button); } } @@ -441,9 +487,10 @@ void WebEidDialog::setupPinPrompt(const PinInfo& pinInfo) ui->pinErrorLabel->setVisible(showPinError); showPinInputWarning(showPinError); if (showPinError) { - ui->pinErrorLabel->setText( - tr("The PIN has been entered incorrectly at least once. %n attempts left.", nullptr, - int(pinInfo.pinRetriesCount.first))); + setTrText(ui->pinErrorLabel, [pinInfo] { + return tr("The PIN has been entered incorrectly at least once. %n attempts left.", + nullptr, int(pinInfo.pinRetriesCount.first)); + }); } } @@ -457,10 +504,11 @@ void WebEidDialog::setupPinPadProgressBarAndEmitWait(const CardCertificateAndPin ui->selectAnotherCertificate->hide(); ui->pinTimeRemaining->setText( tr("Time remaining: %1").arg(ui->pinEntryTimeoutProgressBar->maximum())); - ui->pinTitleLabel->setText(tr("Please enter %1 in PinPad reader") - .arg(currentCommand == CommandType::AUTHENTICATE - ? tr("PIN1 for authentication") - : tr("PIN2 for signing"))); + setTrText(ui->pinTitleLabel, [this] { + return tr("Please enter %1 in PinPad reader") + .arg(currentCommand == CommandType::AUTHENTICATE ? tr("PIN1 for authentication") + : tr("PIN2 for signing")); + }); ui->pinEntryTimeoutProgressBar->reset(); // To be strictly correct, the timeout timer should be started after the handler thread @@ -506,13 +554,15 @@ void WebEidDialog::setupPinInput(const CardCertificateAndPinInfo& certAndPin) }); } -void WebEidDialog::setupOK(const std::function& func, const QString& label, bool enabled) +void WebEidDialog::setupOK(const std::function& func, const std::function& text, + bool enabled) { ui->okButton->disconnect(); connect(ui->okButton, &QPushButton::clicked, this, func); ui->okButton->show(); ui->okButton->setEnabled(enabled); - ui->okButton->setText(label.isEmpty() ? tr("Confirm") : label); + setTrText( + ui->okButton, text ? text : [] { return tr("Confirm"); }); ui->cancelButton->show(); ui->cancelButton->setEnabled(true); ui->helpButton->hide(); @@ -525,7 +575,7 @@ void WebEidDialog::displayPinBlockedError() ui->pinTimeoutTimer->stop(); ui->pinTimeRemaining->hide(); ui->pinEntryTimeoutProgressBar->hide(); - ui->pinErrorLabel->setText(tr("PIN is locked. Unblock and try again.")); + setTrText(ui->pinErrorLabel, [] { return tr("PIN is locked. Unblock and try again."); }); ui->pinErrorLabel->show(); ui->okButton->hide(); ui->cancelButton->setEnabled(true); @@ -549,7 +599,7 @@ void WebEidDialog::resizeHeight() QPixmap WebEidDialog::pixmap(QLatin1String name) const { return {QStringLiteral(":/images/%1%2.svg") - .arg(name, qApp->isDarkTheme() ? QLatin1String("_dark") : QLatin1String())}; + .arg(name, qApp->isDarkTheme() ? "_dark"_L1 : QLatin1String())}; } std::tuple @@ -559,71 +609,70 @@ WebEidDialog::retriableErrorToTextTitleAndIcon(const RetriableError error) case RetriableError::SMART_CARD_SERVICE_IS_NOT_RUNNING: return {tr("The smart card service required to use the ID-card is not running. Please " "start the smart card service and try again."), - tr("Launch the Smart Card service"), pixmap(QLatin1String("cardreader"))}; + tr("Launch the Smart Card service"), pixmap("cardreader"_L1)}; case RetriableError::NO_SMART_CARD_READERS_FOUND: - return { - tr("Card reader not connected. Please connect the card reader to the computer."), - tr("Connect the card reader"), pixmap(QLatin1String("cardreader"))}; + return {tr("Card reader not connected. Please connect the card reader to " + "the computer."), + tr("Connect the card reader"), pixmap("cardreader"_L1)}; case RetriableError::NO_SMART_CARDS_FOUND: case RetriableError::PKCS11_TOKEN_NOT_PRESENT: return {tr("ID-card not found. Please insert the ID-card into the reader."), - tr("Insert the ID-card"), pixmap(QLatin1String("no-id-card"))}; + tr("Insert the ID-card"), pixmap("no-id-card"_L1)}; case RetriableError::SMART_CARD_WAS_REMOVED: case RetriableError::PKCS11_TOKEN_REMOVED: return {tr("The ID-card was removed from the reader. Please insert the ID-card into the " "reader."), - tr("Insert the ID-card"), pixmap(QLatin1String("no-id-card"))}; + tr("Insert the ID-card"), pixmap("no-id-card"_L1)}; case RetriableError::SMART_CARD_TRANSACTION_FAILED: return {tr("Operation failed. Make sure that the ID-card and the card reader are connected " "correctly."), - tr("Check the ID-card and the reader connection"), - pixmap(QLatin1String("no-id-card"))}; + tr("Check the ID-card and the reader connection"), pixmap("no-id-card"_L1)}; case RetriableError::FAILED_TO_COMMUNICATE_WITH_CARD_OR_READER: return {tr("Connection to the ID-card or reader failed. Make sure that the ID-card and the " "card reader are connected correctly."), - tr("Check the ID-card and the reader connection"), - pixmap(QLatin1String("no-id-card"))}; + tr("Check the ID-card and the reader connection"), pixmap("no-id-card"_L1)}; case RetriableError::SMART_CARD_CHANGE_REQUIRED: return {tr("The desired operation cannot be performed with the inserted ID-card. Make sure " "that the ID-card is supported by the Web eID application."), - tr("Operation not supported"), pixmap(QLatin1String("no-id-card"))}; + tr("Operation not supported"), pixmap("no-id-card"_L1)}; case RetriableError::SMART_CARD_COMMAND_ERROR: return {tr("Error communicating with the card."), tr("Operation failed"), - pixmap(QLatin1String("no-id-card"))}; + pixmap("no-id-card"_L1)}; // TODO: what action should the user take? Should this be fatal? case RetriableError::PKCS11_ERROR: return {tr("Card driver error. Please try again."), tr("Card driver error"), - pixmap(QLatin1String("no-id-card"))}; + pixmap("no-id-card"_L1)}; // TODO: what action should the user take? Should this be fatal? case RetriableError::SCARD_ERROR: return {tr("An error occurred in the Smart Card service required to use the ID-card. Make " "sure that the ID-card and the card reader are connected correctly or relaunch " "the Smart Card service."), - tr("Operation failed"), pixmap(QLatin1String("no-id-card"))}; + tr("Operation failed"), pixmap("no-id-card"_L1)}; case RetriableError::UNSUPPORTED_CARD: return {tr("The card in the reader is not supported. Make sure that the entered ID-card is " "supported by the Web eID application."), - tr("Operation not supported"), pixmap(QLatin1String("no-id-card"))}; + tr("Operation not supported"), pixmap("no-id-card"_L1)}; case RetriableError::NO_VALID_CERTIFICATE_AVAILABLE: return {tr("The certificates of the ID-card have expired. Valid certificates are required " "for the electronic use of the ID-card."), - tr("Operation not supported"), pixmap(QLatin1String("no-id-card"))}; + tr("Operation not supported"), pixmap("no-id-card"_L1)}; case RetriableError::PIN_VERIFY_DISABLED: return { tr("Operation failed. Make sure that the driver of the corresponding card reader is " "used. Read more here."), + "href=\"https://www.id.ee/en/article/using-pinpad-card-reader-drivers/\">here."), tr("Card driver error"), QStringLiteral(":/images/cardreader.svg")}; case RetriableError::UNKNOWN_ERROR: - return {tr("Unknown error"), tr("Unknown error"), pixmap(QLatin1String("no-id-card"))}; + return {tr("Unknown error"), tr("Unknown error"), pixmap("no-id-card"_L1)}; } - return {tr("Unknown error"), tr("Unknown error"), pixmap(QLatin1String("no-id-card"))}; + return {tr("Unknown error"), tr("Unknown error"), pixmap("no-id-card"_L1)}; } diff --git a/src/ui/webeiddialog.hpp b/src/ui/webeiddialog.hpp index 2a51ea95..d84d7766 100644 --- a/src/ui/webeiddialog.hpp +++ b/src/ui/webeiddialog.hpp @@ -53,7 +53,7 @@ class WebEidDialog final : public WebEidUI static void showAboutPage(); static void showFatalErrorPage(); -public: // slots + // slots void onSmartCardStatusUpdate(const RetriableError status) final; void onMultipleCertificatesReady( const QUrl& origin, @@ -72,6 +72,9 @@ class WebEidDialog final : public WebEidUI close(); } +signals: + void languageChange(); + private: bool event(QEvent* event) final; void reject() final; @@ -85,23 +88,27 @@ class WebEidDialog final : public WebEidUI } } - void onRetryImpl(const QString& error); + void onRetryImpl(const std::function& text); + void setTrText(QWidget* label, const std::function& text); void setupCertificateAndPinInfo(const std::vector& cardCertAndPinInfos); void setupPinPrompt(const PinInfo& pinInfo); void setupPinPadProgressBarAndEmitWait(const CardCertificateAndPinInfo& certAndPin); void setupPinInput(const CardCertificateAndPinInfo& certAndPin); - void setupOK(const std::function& func, const QString& label = {}, + void setupOK(const std::function& func, const std::function& text = {}, bool enabled = false); void displayPinBlockedError(); void showPinInputWarning(bool show); void resizeHeight(); + Q_DISABLE_COPY(WebEidDialog) + WebEidDialog(WebEidDialog&&) = delete; + WebEidDialog& operator=(WebEidDialog&&) = delete; + QPixmap pixmap(QLatin1String name) const; - std::tuple - retriableErrorToTextTitleAndIcon(const RetriableError error); + std::tuple retriableErrorToTextTitleAndIcon(RetriableError error); class Private; Private* ui;