From 73616c2f242830df33002ca3b05a86403386e424 Mon Sep 17 00:00:00 2001 From: Hannah von Reth Date: Tue, 18 Jun 2024 16:37:06 +0200 Subject: [PATCH 1/2] Modernize durationToDescriptiveString and make it plural aware --- src/common/utility.cpp | 46 ++++++++++----------------- src/common/utility.h | 6 ++-- src/gui/folderstatusmodel.cpp | 2 +- src/gui/owncloudgui.cpp | 4 +-- src/libsync/syncengine.cpp | 2 +- test/testutility.cpp | 60 +++++++++++++++++------------------ 6 files changed, 53 insertions(+), 67 deletions(-) diff --git a/src/common/utility.cpp b/src/common/utility.cpp index 7cc60940866..12027e74667 100644 --- a/src/common/utility.cpp +++ b/src/common/utility.cpp @@ -199,46 +199,36 @@ qint64 Utility::qDateTimeToTime_t(const QDateTime &t) } namespace { - struct Period + constexpr struct { - const char *name; - quint64 msec; - - QString description(quint64 value) const - { - return QCoreApplication::translate("Utility", name, nullptr, value); - } - }; -// QTBUG-3945 and issue #4855: QT_TRANSLATE_NOOP does not work with plural form because lupdate -// limitation unless we fake more arguments -// (it must be in the form ("context", "source", "comment", n) -#undef QT_TRANSLATE_NOOP -#define QT_TRANSLATE_NOOP(ctx, str, ...) str - Q_DECL_CONSTEXPR Period periods[] = { - { QT_TRANSLATE_NOOP("Utility", "%n year(s)", 0, _), 365 * 24 * 3600 * 1000LL }, - { QT_TRANSLATE_NOOP("Utility", "%n month(s)", 0, _), 30 * 24 * 3600 * 1000LL }, - { QT_TRANSLATE_NOOP("Utility", "%n day(s)", 0, _), 24 * 3600 * 1000LL }, - { QT_TRANSLATE_NOOP("Utility", "%n hour(s)", 0, _), 3600 * 1000LL }, - { QT_TRANSLATE_NOOP("Utility", "%n minute(s)", 0, _), 60 * 1000LL }, - { QT_TRANSLATE_NOOP("Utility", "%n second(s)", 0, _), 1000LL }, - { nullptr, 0 } + const char *const name; + const std::chrono::milliseconds msec; + QString description(int value) const { return QCoreApplication::translate("Utility", name, nullptr, value); } + } periods[] = { + {QT_TRANSLATE_N_NOOP("Utility", "%n year(s)"), 24h * 365}, + {QT_TRANSLATE_N_NOOP("Utility", "%n month(s)"), 24h * 30}, + {QT_TRANSLATE_N_NOOP("Utility", "%n day(s)"), 24h}, + {QT_TRANSLATE_N_NOOP("Utility", "%n hour(s)"), 1h}, + {QT_TRANSLATE_N_NOOP("Utility", "%n minute(s)"), 1min}, + {QT_TRANSLATE_N_NOOP("Utility", "%n second(s)"), 1s}, + {nullptr, {}}, }; } // anonymous namespace -QString Utility::durationToDescriptiveString2(quint64 msecs) +QString Utility::durationToDescriptiveString2(std::chrono::milliseconds msecs) { int p = 0; while (periods[p + 1].name && msecs < periods[p].msec) { p++; } - auto firstPart = periods[p].description(int(msecs / periods[p].msec)); + const QString firstPart = periods[p].description(static_cast(msecs / periods[p].msec)); if (!periods[p + 1].name) { return firstPart; } - quint64 secondPartNum = qRound(double(msecs % periods[p].msec) / periods[p + 1].msec); + const quint64 secondPartNum = qRound(static_cast(msecs.count() % periods[p].msec.count()) / periods[p + 1].msec.count()); if (secondPartNum == 0) { return firstPart; @@ -247,15 +237,13 @@ QString Utility::durationToDescriptiveString2(quint64 msecs) return QCoreApplication::translate("Utility", "%1 %2").arg(firstPart, periods[p + 1].description(secondPartNum)); } -QString Utility::durationToDescriptiveString1(quint64 msecs) +QString Utility::durationToDescriptiveString1(std::chrono::milliseconds msecs) { int p = 0; while (periods[p + 1].name && msecs < periods[p].msec) { p++; } - - quint64 amount = qRound(double(msecs) / periods[p].msec); - return periods[p].description(amount); + return periods[p].description(qRound(static_cast(msecs.count()) / periods[p].msec.count())); } QString Utility::fileNameForGuiUse(const QString &fName) diff --git a/src/common/utility.h b/src/common/utility.h index 92d68aae12c..7650eb7d86d 100644 --- a/src/common/utility.h +++ b/src/common/utility.h @@ -96,7 +96,7 @@ OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcUtility) /** * @brief Convert milliseconds duration to human readable string. - * @param quint64 msecs the milliseconds to convert to string. + * @param msecs the milliseconds to convert to string. * @return an HMS representation of the milliseconds value. * * durationToDescriptiveString1 describes the duration in a single @@ -105,8 +105,8 @@ OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcUtility) * durationToDescriptiveString2 uses two units where possible, so * "5 minutes 43 seconds" or "1 month 3 days". */ - OCSYNC_EXPORT QString durationToDescriptiveString1(quint64 msecs); - OCSYNC_EXPORT QString durationToDescriptiveString2(quint64 msecs); + OCSYNC_EXPORT QString durationToDescriptiveString1(std::chrono::milliseconds msecs); + OCSYNC_EXPORT QString durationToDescriptiveString2(std::chrono::milliseconds msecs); /** * @brief hasDarkSystray - determines whether the systray is dark or light. diff --git a/src/gui/folderstatusmodel.cpp b/src/gui/folderstatusmodel.cpp index 552fe33fc5f..16d92117d9e 100644 --- a/src/gui/folderstatusmodel.cpp +++ b/src/gui/folderstatusmodel.cpp @@ -157,7 +157,7 @@ namespace { .arg(s1, s2) .arg(currentFile) .arg(totalFileCount) - .arg(Utility::durationToDescriptiveString1(progress.totalProgress().estimatedEta)); + .arg(Utility::durationToDescriptiveString1(std::chrono::milliseconds(progress.totalProgress().estimatedEta))); } else { //: Example text: "12 MB of 345 MB, file 6 of 7" diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 32419860d6f..54e30c4a462 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -779,7 +779,7 @@ void ownCloudGui::slotUpdateProgress(Folder *folder, const ProgressInfo &progres msg = tr("Syncing %1 of %2 (%3 left)") .arg(currentFile) .arg(totalFileCount) - .arg(Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta)); + .arg(Utility::durationToDescriptiveString2(std::chrono::milliseconds(progress.totalProgress().estimatedEta))); } else { msg = tr("Syncing %1 of %2") .arg(currentFile) @@ -791,7 +791,7 @@ void ownCloudGui::slotUpdateProgress(Folder *folder, const ProgressInfo &progres QString msg; if (progress.trustEta()) { msg = tr("Syncing %1 (%2 left)") - .arg(totalSizeStr, Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta)); + .arg(totalSizeStr, Utility::durationToDescriptiveString2(std::chrono::milliseconds(progress.totalProgress().estimatedEta))); } else { msg = tr("Syncing %1") .arg(totalSizeStr); diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 2de8f99578d..e463c5ee3d1 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -152,7 +152,7 @@ bool SyncEngine::checkErrorBlacklisting(SyncFileItem &item) } else { item._status = SyncFileItem::BlacklistedError; - auto waitSecondsStr = Utility::durationToDescriptiveString1(1000 * waitSeconds); + auto waitSecondsStr = Utility::durationToDescriptiveString1(std::chrono::seconds(waitSeconds)); item._errorString = tr("%1 (skipped due to earlier error, trying again in %2)").arg(entry._errorString, waitSecondsStr); if (entry._errorCategory == SyncJournalErrorBlacklistRecord::Category::InsufficientRemoteStorage) { diff --git a/test/testutility.cpp b/test/testutility.cpp index b51a66a1dae..918b11a9272 100644 --- a/test/testutility.cpp +++ b/test/testutility.cpp @@ -13,6 +13,8 @@ #include "common/filesystembase.h" #include "common/utility.h" +using namespace std::chrono_literals; + using namespace OCC::Utility; namespace OCC { @@ -67,38 +69,34 @@ private Q_SLOTS: QLocale::setDefault(QLocale(QStringLiteral("C"))); //NOTE: in order for the plural to work we would need to load the english translation - quint64 sec = 1000; - quint64 hour = 3600 * sec; - - QDateTime current = QDateTime::currentDateTimeUtc(); - - QCOMPARE(durationToDescriptiveString2(0), QString::fromLatin1("0 second(s)")); - QCOMPARE(durationToDescriptiveString2(5), QString::fromLatin1("0 second(s)")); - QCOMPARE(durationToDescriptiveString2(1000), QString::fromLatin1("1 second(s)")); - QCOMPARE(durationToDescriptiveString2(1005), QString::fromLatin1("1 second(s)")); - QCOMPARE(durationToDescriptiveString2(56123), QString::fromLatin1("56 second(s)")); - QCOMPARE(durationToDescriptiveString2(90 * sec), QString::fromLatin1("1 minute(s) 30 second(s)")); - QCOMPARE(durationToDescriptiveString2(3 * hour), QString::fromLatin1("3 hour(s)")); - QCOMPARE(durationToDescriptiveString2(3 * hour + 20 * sec), QString::fromLatin1("3 hour(s)")); - QCOMPARE(durationToDescriptiveString2(3 * hour + 70 * sec), QString::fromLatin1("3 hour(s) 1 minute(s)")); - QCOMPARE(durationToDescriptiveString2(3 * hour + 100 * sec), QString::fromLatin1("3 hour(s) 2 minute(s)")); - QCOMPARE(durationToDescriptiveString2(current.msecsTo(current.addYears(4).addMonths(5).addDays(2).addSecs(23 * 60 * 60))), + const QDateTime current = QDateTime::currentDateTimeUtc(); + + QCOMPARE(durationToDescriptiveString2(0ms), QString::fromLatin1("0 second(s)")); + QCOMPARE(durationToDescriptiveString2(5ms), QString::fromLatin1("0 second(s)")); + QCOMPARE(durationToDescriptiveString2(1s), QString::fromLatin1("1 second(s)")); + QCOMPARE(durationToDescriptiveString2(1005ms), QString::fromLatin1("1 second(s)")); + QCOMPARE(durationToDescriptiveString2(56123ms), QString::fromLatin1("56 second(s)")); + QCOMPARE(durationToDescriptiveString2(90s), QString::fromLatin1("1 minute(s) 30 second(s)")); + QCOMPARE(durationToDescriptiveString2(3h), QString::fromLatin1("3 hour(s)")); + QCOMPARE(durationToDescriptiveString2(3h + 20s), QString::fromLatin1("3 hour(s)")); + QCOMPARE(durationToDescriptiveString2(3h + 70s), QString::fromLatin1("3 hour(s) 1 minute(s)")); + QCOMPARE(durationToDescriptiveString2(3h + 100s), QString::fromLatin1("3 hour(s) 2 minute(s)")); + QCOMPARE(durationToDescriptiveString2(current.addYears(4).addMonths(5).addDays(2).addSecs(23 * 60 * 60) - current), QString::fromLatin1("4 year(s) 5 month(s)")); - QCOMPARE(durationToDescriptiveString2(current.msecsTo(current.addDays(2).addSecs(23 * 60 * 60))), QString::fromLatin1("2 day(s) 23 hour(s)")); - - QCOMPARE(durationToDescriptiveString1(0), QString::fromLatin1("0 second(s)")); - QCOMPARE(durationToDescriptiveString1(5), QString::fromLatin1("0 second(s)")); - QCOMPARE(durationToDescriptiveString1(1000), QString::fromLatin1("1 second(s)")); - QCOMPARE(durationToDescriptiveString1(1005), QString::fromLatin1("1 second(s)")); - QCOMPARE(durationToDescriptiveString1(56123), QString::fromLatin1("56 second(s)")); - QCOMPARE(durationToDescriptiveString1(90 * sec), QString::fromLatin1("2 minute(s)")); - QCOMPARE(durationToDescriptiveString1(3 * hour), QString::fromLatin1("3 hour(s)")); - QCOMPARE(durationToDescriptiveString1(3 * hour + 20 * sec), QString::fromLatin1("3 hour(s)")); - QCOMPARE(durationToDescriptiveString1(3 * hour + 70 * sec), QString::fromLatin1("3 hour(s)")); - QCOMPARE(durationToDescriptiveString1(3 * hour + 100 * sec), QString::fromLatin1("3 hour(s)")); - QCOMPARE( - durationToDescriptiveString1(current.msecsTo(current.addYears(4).addMonths(5).addDays(2).addSecs(23 * 60 * 60))), QString::fromLatin1("4 year(s)")); - QCOMPARE(durationToDescriptiveString1(current.msecsTo(current.addDays(2).addSecs(23 * 60 * 60))), QString::fromLatin1("3 day(s)")); + QCOMPARE(durationToDescriptiveString2(current.addDays(2).addSecs(23 * 60 * 60) - current), QString::fromLatin1("2 day(s) 23 hour(s)")); + + QCOMPARE(durationToDescriptiveString1(0s), QString::fromLatin1("0 second(s)")); + QCOMPARE(durationToDescriptiveString1(5ms), QString::fromLatin1("0 second(s)")); + QCOMPARE(durationToDescriptiveString1(1s), QString::fromLatin1("1 second(s)")); + QCOMPARE(durationToDescriptiveString1(1005ms), QString::fromLatin1("1 second(s)")); + QCOMPARE(durationToDescriptiveString1(56123ms), QString::fromLatin1("56 second(s)")); + QCOMPARE(durationToDescriptiveString1(90s), QString::fromLatin1("2 minute(s)")); + QCOMPARE(durationToDescriptiveString1(3h), QString::fromLatin1("3 hour(s)")); + QCOMPARE(durationToDescriptiveString1(3h + 20s), QString::fromLatin1("3 hour(s)")); + QCOMPARE(durationToDescriptiveString1(3h + 70s), QString::fromLatin1("3 hour(s)")); + QCOMPARE(durationToDescriptiveString1(3h + 100s), QString::fromLatin1("3 hour(s)")); + QCOMPARE(durationToDescriptiveString1(current.addYears(4).addMonths(5).addDays(2).addSecs(23 * 60 * 60) - current), QString::fromLatin1("4 year(s)")); + QCOMPARE(durationToDescriptiveString1(current.addDays(2).addSecs(23 * 60 * 60) - current), QString::fromLatin1("3 day(s)")); } void testTimeAgo() From 611751df3d613fdf516c89f89194c88de7b8ff8b Mon Sep 17 00:00:00 2001 From: Hannah von Reth Date: Wed, 19 Jun 2024 13:39:50 +0200 Subject: [PATCH 2/2] Provide plural forms for durations --- translations/client_en.ts | 80 +++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/translations/client_en.ts b/translations/client_en.ts index d8d25a34e50..6d0d6807174 100644 --- a/translations/client_en.ts +++ b/translations/client_en.ts @@ -3930,42 +3930,42 @@ Are you sure you want to proceed? QObject - + in the future - + %n day(s) ago - - - + + %n day ago + %n days ago - + %n hour(s) ago - - - + + %n hour ago + %n hours ago - + now - + less than a minute ago - + %n minute(s) ago - - - + + %n minute ago + %n minutes ago @@ -4174,55 +4174,55 @@ Are you sure you want to proceed? Utility - + %n year(s) - - - + + %n year + %n years - + %n month(s) - - - + + %n month + %n months - + %n day(s) - - - + + %n day + %n days - + %n hour(s) - - - + + %n hour + %n hours - + %n minute(s) - - - + + %n minute + %n minutes - + %n second(s) - - - + + %n second + %n seconds - + %1 %2