mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
add non-abbreviated timespan translation; update existing short=True calls
- drop the '5m3s' special casing done in the card stats screen, and just use decimals - change alignment of the review log so that the non-abbreviated spans are easier to read
This commit is contained in:
parent
99c07cfdcb
commit
2fc15d0d3a
8 changed files with 69 additions and 51 deletions
|
@ -308,7 +308,8 @@ message TranslateArgValue {
|
|||
|
||||
message FormatTimeSpanIn {
|
||||
enum Context {
|
||||
ANSWER_BUTTONS = 0;
|
||||
NORMAL = 0;
|
||||
ANSWER_BUTTONS = 1;
|
||||
}
|
||||
|
||||
float seconds = 1;
|
||||
|
|
|
@ -345,7 +345,11 @@ class RustBackend:
|
|||
)
|
||||
).translate_string
|
||||
|
||||
def format_time_span(self, seconds: float, context: FormatTimeSpanContext) -> str:
|
||||
def format_time_span(
|
||||
self,
|
||||
seconds: float,
|
||||
context: FormatTimeSpanContext = FormatTimeSpanContext.NORMAL,
|
||||
) -> str:
|
||||
return self._run_command(
|
||||
pb.BackendInput(
|
||||
format_time_span=pb.FormatTimeSpanIn(seconds=seconds, context=context)
|
||||
|
|
|
@ -28,8 +28,6 @@ class CardStats:
|
|||
|
||||
def report(self) -> str:
|
||||
c = self.card
|
||||
# pylint: disable=unnecessary-lambda
|
||||
fmt = lambda x, **kwargs: fmtTimeSpan(x, short=True, **kwargs)
|
||||
self.txt = "<table width=100%>"
|
||||
self.addLine(_("Added"), self.date(c.id / 1000))
|
||||
first = self.col.db.scalar("select min(id) from revlog where cid = ?", c.id)
|
||||
|
@ -52,7 +50,9 @@ class CardStats:
|
|||
next,
|
||||
)
|
||||
if c.queue == QUEUE_TYPE_REV:
|
||||
self.addLine(_("Interval"), fmt(c.ivl * 86400))
|
||||
self.addLine(
|
||||
_("Interval"), self.col.backend.format_time_span(c.ivl * 86400)
|
||||
)
|
||||
self.addLine(_("Ease"), "%d%%" % (c.factor / 10.0))
|
||||
self.addLine(_("Reviews"), "%d" % c.reps)
|
||||
self.addLine(_("Lapses"), "%d" % c.lapses)
|
||||
|
@ -83,13 +83,8 @@ class CardStats:
|
|||
def date(self, tm) -> str:
|
||||
return time.strftime("%Y-%m-%d", time.localtime(tm))
|
||||
|
||||
def time(self, tm) -> str:
|
||||
s = ""
|
||||
if tm >= 60:
|
||||
s = fmtTimeSpan((tm / 60) * 60, short=True, point=-1, unit=1)
|
||||
if tm % 60 != 0 or not s:
|
||||
s += fmtTimeSpan(tm % 60, point=2 if not s else -1, short=True)
|
||||
return s
|
||||
def time(self, tm: float) -> str:
|
||||
return self.col.backend.format_time_span(tm)
|
||||
|
||||
|
||||
# Collection stats
|
||||
|
|
|
@ -24,7 +24,7 @@ from html.entities import name2codepoint
|
|||
from typing import Iterable, Iterator, List, Optional, Tuple, Union
|
||||
|
||||
from anki.db import DB
|
||||
from anki.lang import _, ngettext
|
||||
from anki.lang import ngettext
|
||||
|
||||
_tmpdir: Optional[str]
|
||||
|
||||
|
@ -56,28 +56,10 @@ inTimeTable = {
|
|||
}
|
||||
|
||||
|
||||
def shortTimeFmt(type: str) -> str:
|
||||
return {
|
||||
# T: year is an abbreviation for year. %s is a number of years
|
||||
"years": _("%sy"),
|
||||
# T: m is an abbreviation for month. %s is a number of months
|
||||
"months": _("%smo"),
|
||||
# T: d is an abbreviation for day. %s is a number of days
|
||||
"days": _("%sd"),
|
||||
# T: h is an abbreviation for hour. %s is a number of hours
|
||||
"hours": _("%sh"),
|
||||
# T: m is an abbreviation for minute. %s is a number of minutes
|
||||
"minutes": _("%sm"),
|
||||
# T: s is an abbreviation for second. %s is a number of seconds
|
||||
"seconds": _("%ss"),
|
||||
}[type]
|
||||
|
||||
|
||||
def fmtTimeSpan(
|
||||
time: Union[int, float],
|
||||
pad: int = 0,
|
||||
point: int = 0,
|
||||
short: bool = False,
|
||||
inTime: bool = False,
|
||||
unit: int = 99,
|
||||
) -> str:
|
||||
|
@ -86,13 +68,10 @@ def fmtTimeSpan(
|
|||
time = convertSecondsTo(time, type)
|
||||
if not point:
|
||||
time = int(round(time))
|
||||
if short:
|
||||
fmt = shortTimeFmt(type)
|
||||
if inTime:
|
||||
fmt = inTimeTable[type](_pluralCount(time, point))
|
||||
else:
|
||||
if inTime:
|
||||
fmt = inTimeTable[type](_pluralCount(time, point))
|
||||
else:
|
||||
fmt = timeTable[type](_pluralCount(time, point))
|
||||
fmt = timeTable[type](_pluralCount(time, point))
|
||||
timestr = "%%%(a)d.%(b)df" % {"a": pad, "b": point}
|
||||
return locale.format_string(fmt % timestr, time)
|
||||
|
||||
|
|
|
@ -1451,13 +1451,10 @@ border: 1px solid #000; padding: 3px; '>%s</div>"""
|
|||
if not entries:
|
||||
return ""
|
||||
s = "<table width=100%%><tr><th align=left>%s</th>" % _("Date")
|
||||
s += ("<th align=right>%s</th>" * 5) % (
|
||||
_("Type"),
|
||||
_("Rating"),
|
||||
_("Interval"),
|
||||
_("Ease"),
|
||||
_("Time"),
|
||||
)
|
||||
s += "<th align=right>%s</th>" % _("Type")
|
||||
s += "<th align=center>%s</th>" % _("Rating")
|
||||
s += "<th align=left>%s</th>" % _("Interval")
|
||||
s += ("<th align=right>%s</th>" * 2) % (_("Ease"), _("Time"),)
|
||||
cnt = 0
|
||||
for (date, ease, ivl, factor, taken, type) in reversed(entries):
|
||||
cnt += 1
|
||||
|
@ -1485,13 +1482,14 @@ border: 1px solid #000; padding: 3px; '>%s</div>"""
|
|||
if ivl == 0:
|
||||
ivl = _("0d")
|
||||
elif ivl > 0:
|
||||
ivl = fmtTimeSpan(ivl * 86400, short=True)
|
||||
ivl = fmtTimeSpan(ivl * 86400)
|
||||
else:
|
||||
ivl = cs.time(-ivl)
|
||||
s += ("<td align=right>%s</td>" * 5) % (
|
||||
tstr,
|
||||
ease,
|
||||
ivl,
|
||||
s += "<td align=right>%s</td>" % tstr
|
||||
s += "<td align=center>%s</td>" % ease
|
||||
s += "<td align=left>%s</td>" % ivl
|
||||
|
||||
s += ("<td align=right>%s</td>" * 2) % (
|
||||
"%d%%" % (factor / 10) if factor else "",
|
||||
cs.time(taken),
|
||||
) + "</tr>"
|
||||
|
|
|
@ -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;
|
||||
use crate::sched::timespan::{answer_button_time, time_span};
|
||||
use crate::template::{
|
||||
render_card, without_legacy_template_directives, FieldMap, FieldRequirements, ParsedTemplate,
|
||||
RenderedNode,
|
||||
|
@ -406,6 +406,7 @@ impl Backend {
|
|||
None => return "".to_string(),
|
||||
};
|
||||
match context {
|
||||
pb::format_time_span_in::Context::Normal => time_span(input.seconds, &self.i18n),
|
||||
pb::format_time_span_in::Context::AnswerButtons => {
|
||||
answer_button_time(input.seconds, &self.i18n)
|
||||
}
|
||||
|
|
|
@ -9,3 +9,31 @@ answer-button-time-hours = {$amount}h
|
|||
answer-button-time-days = {$amount}d
|
||||
answer-button-time-months = {$amount}mo
|
||||
answer-button-time-years = {$amount}y
|
||||
|
||||
## A span of time, such as the delay until a card is shown again, the
|
||||
## amount of time taken to answer a card, and so on.
|
||||
|
||||
time-span-seconds = { $amount ->
|
||||
[one] {$amount} second
|
||||
*[other] {$amount} seconds
|
||||
}
|
||||
time-span-minutes = { $amount ->
|
||||
[one] {$amount} minute
|
||||
*[other] {$amount} minutes
|
||||
}
|
||||
time-span-hours = { $amount ->
|
||||
[one] {$amount} hour
|
||||
*[other] {$amount} hours
|
||||
}
|
||||
time-span-days = { $amount ->
|
||||
[one] {$amount} day
|
||||
*[other] {$amount} days
|
||||
}
|
||||
time-span-months = { $amount ->
|
||||
[one] {$amount} month
|
||||
*[other] {$amount} months
|
||||
}
|
||||
time-span-years = { $amount ->
|
||||
[one] {$amount} year
|
||||
*[other] {$amount} years
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
|
||||
use crate::i18n::{tr_args, I18n, StringsGroup};
|
||||
|
||||
/// Short string like '4d' to place above answer buttons.
|
||||
pub fn answer_button_time(seconds: f32, i18n: &I18n) -> String {
|
||||
let span = Timespan::from_secs(seconds).natural_span();
|
||||
let amount = match span.unit() {
|
||||
TimespanUnit::Months | TimespanUnit::Years => span.as_unit(),
|
||||
// we don't show fractional value except for months/years
|
||||
// we don't show fractional values except for months/years
|
||||
_ => span.as_unit().round(),
|
||||
};
|
||||
let unit = span.unit().as_str();
|
||||
|
@ -16,6 +17,17 @@ pub fn answer_button_time(seconds: f32, i18n: &I18n) -> String {
|
|||
.trn(&format!("answer-button-time-{}", unit), args)
|
||||
}
|
||||
|
||||
/// Describe the given seconds using the largest appropriate unit
|
||||
/// eg 70 seconds -> "1.17 minutes"
|
||||
pub fn time_span(seconds: f32, i18n: &I18n) -> String {
|
||||
let span = Timespan::from_secs(seconds).natural_span();
|
||||
let amount = span.as_unit();
|
||||
let unit = span.unit().as_str();
|
||||
let args = tr_args!["amount" => amount];
|
||||
i18n.get(StringsGroup::Scheduling)
|
||||
.trn(&format!("time-span-{}", unit), args)
|
||||
}
|
||||
|
||||
const SECOND: f32 = 1.0;
|
||||
const MINUTE: f32 = 60.0 * SECOND;
|
||||
const HOUR: f32 = 60.0 * MINUTE;
|
||||
|
|
Loading…
Reference in a new issue