From e6c1b1f384fe2e3d1686c9a329e20e42c3e393c2 Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 23:21:27 +0000 Subject: [PATCH] feat(grammar): expose relative time helpers in templates Co-Authored-By: Virgil --- docs/forward-api.md | 2 +- grammar.go | 2 ++ grammar_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/forward-api.md b/docs/forward-api.md index f342c75..3bc1f11 100644 --- a/docs/forward-api.md +++ b/docs/forward-api.md @@ -338,4 +338,4 @@ All grammar functions are available as Go template functions via `TemplateFuncs( template.New("").Funcs(i18n.TemplateFuncs()) ``` -Available functions: `title`, `lower`, `upper`, `past`, `gerund`, `plural`, `pluralForm`, `article`, `quote`. +Available functions: `title`, `lower`, `upper`, `past`, `gerund`, `plural`, `pluralForm`, `article`, `quote`, `label`, `progress`, `progressSubject`, `actionResult`, `actionFailed`, `timeAgo`, `formatAgo`. diff --git a/grammar.go b/grammar.go index 324bc26..5c1da47 100644 --- a/grammar.go +++ b/grammar.go @@ -690,6 +690,8 @@ func TemplateFuncs() template.FuncMap { "progressSubject": ProgressSubject, "actionResult": ActionResult, "actionFailed": ActionFailed, + "timeAgo": TimeAgo, + "formatAgo": FormatAgo, } } diff --git a/grammar_test.go b/grammar_test.go index e1e8740..d0e693c 100644 --- a/grammar_test.go +++ b/grammar_test.go @@ -4,6 +4,7 @@ import ( "strings" "testing" "text/template" + "time" ) func TestPastTense(t *testing.T) { @@ -878,6 +879,8 @@ func TestTemplateFuncs(t *testing.T) { "progressSubject", "actionResult", "actionFailed", + "timeAgo", + "formatAgo", } for _, name := range expected { if _, ok := funcs[name]; !ok { @@ -927,6 +930,34 @@ func TestTemplateFuncs_CompositeHelpers(t *testing.T) { } } +func TestTemplateFuncs_TimeHelpers(t *testing.T) { + svc, err := New() + if err != nil { + t.Fatalf("New() failed: %v", err) + } + SetDefault(svc) + + tmpl, err := template.New("").Funcs(TemplateFuncs()).Parse( + `{{formatAgo 3 "hour"}}|{{timeAgo .}}`, + ) + if err != nil { + t.Fatalf("Parse() failed: %v", err) + } + + var buf strings.Builder + if err := tmpl.Execute(&buf, time.Now().Add(-5*time.Minute)); err != nil { + t.Fatalf("Execute() failed: %v", err) + } + + got := buf.String() + if !strings.HasPrefix(got, "3 hours ago|") { + t.Fatalf("template time helpers prefix = %q, want %q", got, "3 hours ago|") + } + if !strings.Contains(got, "minutes ago") && !strings.Contains(got, "just now") { + t.Fatalf("template time helpers suffix = %q, want relative time output", got) + } +} + func TestCompositeHelpersRespectWordMap(t *testing.T) { svc, err := New() if err != nil { -- 2.45.3