diff --git a/proto/backend.proto b/proto/backend.proto
index fd17b2f3a..4495a7fe8 100644
--- a/proto/backend.proto
+++ b/proto/backend.proto
@@ -45,6 +45,7 @@ message BackendInput {
TrashMediaFilesIn trash_media_files = 29;
TranslateStringIn translate_string = 30;
FormatTimeSpanIn format_time_span = 31;
+ StudiedTodayIn studied_today = 32;
}
}
@@ -66,6 +67,7 @@ message BackendOutput {
Empty trash_media_files = 29;
string translate_string = 30;
string format_time_span = 31;
+ string studied_today = 32;
BackendError error = 2047;
}
@@ -315,3 +317,8 @@ message FormatTimeSpanIn {
float seconds = 1;
Context context = 2;
}
+
+message StudiedTodayIn {
+ uint32 cards = 1;
+ double seconds = 2;
+}
diff --git a/pylib/anki/rsbackend.py b/pylib/anki/rsbackend.py
index 290b63e3a..a7993f8b5 100644
--- a/pylib/anki/rsbackend.py
+++ b/pylib/anki/rsbackend.py
@@ -355,3 +355,10 @@ class RustBackend:
format_time_span=pb.FormatTimeSpanIn(seconds=seconds, context=context)
)
).format_time_span
+
+ def studied_today(self, cards: int, seconds: float,) -> str:
+ return self._run_command(
+ pb.BackendInput(
+ studied_today=pb.StudiedTodayIn(cards=cards, seconds=seconds)
+ )
+ ).studied_today
diff --git a/pylib/anki/stats.py b/pylib/anki/stats.py
index 333f46360..15516dc95 100644
--- a/pylib/anki/stats.py
+++ b/pylib/anki/stats.py
@@ -1,6 +1,8 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
+from __future__ import annotations
+
import datetime
import json
import time
@@ -104,7 +106,7 @@ colSusp = "#ff0"
class CollectionStats:
- def __init__(self, col) -> None:
+ def __init__(self, col: anki.storage._Collection) -> None:
self.col = col
self._stats = None
self.type = PERIOD_MONTH
@@ -176,15 +178,8 @@ from revlog where id > ? """
def bold(s):
return "" + str(s) + ""
- msgp1 = (
- ngettext("%d card", "%d cards", cards) % cards
- )
if cards:
- b += _("Studied %(a)s %(b)s today (%(secs).1fs/card)") % dict(
- a=bold(msgp1),
- b=bold(fmtTimeSpan(thetime, unit=1, inTime=True)),
- secs=thetime / cards,
- )
+ b += self.col.backend.studied_today(cards, float(thetime))
# again/pass count
b += "
" + _("Again count: %s") % bold(failed)
if cards:
diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py
index 9c5babb43..37432993c 100644
--- a/qt/aqt/deckbrowser.py
+++ b/qt/aqt/deckbrowser.py
@@ -158,12 +158,7 @@ where id > ?""",
)
cards = cards or 0
thetime = thetime or 0
- msgp1 = (
- ngettext("%d card", "%d cards", cards) % cards
- )
- buf = _("Studied %(a)s %(b)s today.") % dict(
- a=msgp1, b=fmtTimeSpan(thetime, unit=1, inTime=True)
- )
+ buf = self.mw.col.backend.studied_today(cards, float(thetime))
return buf
def _countWarn(self):
diff --git a/rslib/src/backend.rs b/rslib/src/backend.rs
index 3aee1239e..1cc63729f 100644
--- a/rslib/src/backend.rs
+++ b/rslib/src/backend.rs
@@ -11,7 +11,7 @@ use crate::media::check::MediaChecker;
use crate::media::sync::MediaSyncProgress;
use crate::media::MediaManager;
use crate::sched::cutoff::{local_minutes_west_for_stamp, sched_timing_today};
-use crate::sched::timespan::{answer_button_time, time_span};
+use crate::sched::timespan::{answer_button_time, studied_today, time_span};
use crate::template::{
render_card, without_legacy_template_directives, FieldMap, FieldRequirements, ParsedTemplate,
RenderedNode,
@@ -202,6 +202,11 @@ impl Backend {
}
Value::TranslateString(input) => OValue::TranslateString(self.translate_string(input)),
Value::FormatTimeSpan(input) => OValue::FormatTimeSpan(self.format_time_span(input)),
+ Value::StudiedToday(input) => OValue::StudiedToday(studied_today(
+ input.cards as usize,
+ input.seconds as f32,
+ &self.i18n,
+ )),
})
}
diff --git a/rslib/src/i18n/scheduling.ftl b/rslib/src/i18n/scheduling.ftl
index 482b2cdf9..f671abffd 100644
--- a/rslib/src/i18n/scheduling.ftl
+++ b/rslib/src/i18n/scheduling.ftl
@@ -44,43 +44,3 @@ time-span-years = { $amount ->
[one] {$amount} year
*[other] {$amount} years
}
-
-## A span of time studying took place in, for example
-## "(studied 30 cards) in 3 minutes". In English the text
-## just adds "in" to the start of time-span-*, but other
-## languages may need to use different words here instead
-## of reusing the time-span-* text.
-## See the 'studied-today' context for where this is used,
-## and the Polish translation for an example of different
-## wordings used here.
-
-in-time-span-seconds = in { time-span-seconds }
-in-time-span-minutes = in { time-span-minutes }
-in-time-span-hours = in { time-span-hours }
-in-time-span-days = in { time-span-days }
-in-time-span-months = in { time-span-months }
-in-time-span-years = in { time-span-years }
-
-##
-
-cards = { $cards ->
- [one] {$cards} card
- *[other] {$cards} cards
- }
-
-# Shown at the bottom of the deck list, and in the statistics screen.
-# eg "Studied 3 cards in 13 seconds today (4.33s/card)."
-# The { in-time-span-seconds } part should be pasted in from the English
-# version unmodified.
-
-studied-today =
- Studied { cards }
- { $unit ->
- [seconds] { in-time-span-seconds }
- [minutes] { in-time-span-minutes }
- [hours] { in-time-span-hours }
- [days] { in-time-span-days }
- [months] { in-time-span-months }
- *[years] { in-time-span-years }
- } today
- ({$secs-per-card}s/card).
diff --git a/rslib/src/i18n/statistics.ftl b/rslib/src/i18n/statistics.ftl
index d9d066459..792faaf16 100644
--- a/rslib/src/i18n/statistics.ftl
+++ b/rslib/src/i18n/statistics.ftl
@@ -10,3 +10,60 @@ due-for-new-card = New #{$number}
cards-per-min = {$cards-per-minute} cards/minute
average-answer-time = {$average-seconds}s ({cards-per-min})
+
+## A span of time studying took place in, for example
+## "(studied 30 cards) in 3 minutes".
+
+in-time-span-seconds = { $amount ->
+ [one] in {$amount} second
+ *[other] in {$amount} seconds
+ }
+
+in-time-span-minutes = { $amount ->
+ [one] in {$amount} minute
+ *[other] in {$amount} minutes
+ }
+
+in-time-span-hours = { $amount ->
+ [one] in {$amount} hour
+ *[other] in {$amount} hours
+ }
+
+in-time-span-days = { $amount ->
+ [one] in {$amount} day
+ *[other] in {$amount} days
+ }
+
+in-time-span-months = { $amount ->
+ [one] in {$amount} month
+ *[other] in {$amount} months
+ }
+
+in-time-span-years = { $amount ->
+ [one] in {$amount} year
+ *[other] in {$amount} years
+ }
+
+##
+
+cards = { $cards ->
+ [one] {$cards} card
+ *[other] {$cards} cards
+ }
+
+# Shown at the bottom of the deck list, and in the statistics screen.
+# eg "Studied 3 cards in 13 seconds today (4.33s/card)."
+# The { in-time-span-seconds } part should be pasted in from the English
+# version unmodified.
+
+studied-today =
+ Studied { cards }
+ { $unit ->
+ [seconds] { in-time-span-seconds }
+ [minutes] { in-time-span-minutes }
+ [hours] { in-time-span-hours }
+ [days] { in-time-span-days }
+ [months] { in-time-span-months }
+ *[years] { in-time-span-years }
+ } today
+ ({$secs-per-card}s/card)
diff --git a/rslib/src/sched/timespan.rs b/rslib/src/sched/timespan.rs
index 6b6cbf4c5..f1b1f7530 100644
--- a/rslib/src/sched/timespan.rs
+++ b/rslib/src/sched/timespan.rs
@@ -29,8 +29,7 @@ pub fn time_span(seconds: f32, i18n: &I18n) -> String {
}
// fixme: this doesn't belong here
-#[allow(dead_code)]
-fn studied_today(cards: usize, secs: f32, i18n: &I18n) -> String {
+pub fn studied_today(cards: usize, secs: f32, i18n: &I18n) -> String {
let span = Timespan::from_secs(secs).natural_span();
let amount = span.as_unit();
let unit = span.unit().as_str();
@@ -41,7 +40,7 @@ fn studied_today(cards: usize, secs: f32, i18n: &I18n) -> String {
};
let args = tr_args!["amount" => amount, "unit" => unit,
"cards" => cards, "secs-per-card" => secs_per];
- i18n.get(StringsGroup::Scheduling)
+ i18n.get(StringsGroup::Statistics)
.trn("studied-today", args)
}