aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/bible/booktable.go32
-rw-r--r--internal/bible/booktable_test.go31
-rw-r--r--internal/cli/cli.go48
-rw-r--r--internal/cli/cli_test.go9
-rw-r--r--internal/config/config.go2
5 files changed, 106 insertions, 16 deletions
diff --git a/internal/bible/booktable.go b/internal/bible/booktable.go
index eb3b4e4..007e75e 100644
--- a/internal/bible/booktable.go
+++ b/internal/bible/booktable.go
@@ -141,6 +141,38 @@ func (t *BookTable) ParseRef(dialect, input string) (string, bool) {
return "", false
}
+// shortcut returns the dialect's primary abbreviation (the first form) for a
+// canonical book, or "" when the dialect has no entry for it.
+func (t *BookTable) shortcut(dialect, canonical string) string {
+ if forms := t.forms[dialect][canonical]; len(forms) > 0 {
+ return forms[0]
+ }
+ return ""
+}
+
+// FormatRef renders a canonical English reference ("John 20:1,11-18") in the
+// dialect's sigla: the dialect's book shortcut plus its number style -- English
+// "Jn 20:1,11-18" (colon chapter:verse, comma groups); Polish "J 20, 1. 11-18"
+// (comma chapter, verse; period groups). It is the inverse of ParseRef's
+// normalizeSigla. If canonicalRef can't be parsed or the book is not in the
+// dialect, it is returned unchanged (a safe, still-readable fallback).
+func (t *BookTable) FormatRef(dialect, canonicalRef string) string {
+ m := refRe.FindStringSubmatch(strings.TrimSpace(canonicalRef))
+ if m == nil {
+ return canonicalRef
+ }
+ canon, chap, verses := m[1], m[2], m[3]
+ abbrev := t.shortcut(dialect, canon)
+ if abbrev == "" {
+ return canonicalRef
+ }
+ if dialect == "pl" {
+ verses = strings.ReplaceAll(verses, ",", ". ") // disjoint groups
+ return abbrev + " " + chap + ", " + verses
+ }
+ return abbrev + " " + chap + ":" + verses
+}
+
// normalizeSigla rewrites a dialect's verse-reference tail into the colon/comma
// form bible.Lookup expects: "<chap>:<groups>", groups comma-separated, ranges
// with "-". Polish uses a comma (with or without a space) as the chapter/verse
diff --git a/internal/bible/booktable_test.go b/internal/bible/booktable_test.go
index ededad3..2a57d80 100644
--- a/internal/bible/booktable_test.go
+++ b/internal/bible/booktable_test.go
@@ -64,6 +64,37 @@ func TestParseRefDialects(t *testing.T) {
}
}
+func TestFormatRef(t *testing.T) {
+ tbl, _ := LoadBookTable(nil)
+ cases := []struct {
+ dialect, canonical, want string
+ }{
+ {"en", "John 20:1,11-18", "Jn 20:1,11-18"},
+ {"pl", "John 20:1,11-18", "J 20, 1. 11-18"},
+ {"en", "Matthew 13:18-23", "Matt 13:18-23"},
+ {"pl", "Matthew 13:18-23", "Mt 13, 18-23"},
+ {"en", "Luke 16:1-9", "Lk 16:1-9"},
+ // Round-trip: ParseRef then FormatRef in the same dialect is stable.
+ }
+ for _, c := range cases {
+ if got := tbl.FormatRef(c.dialect, c.canonical); got != c.want {
+ t.Errorf("FormatRef(%q,%q)=%q want %q", c.dialect, c.canonical, got, c.want)
+ }
+ }
+ // Unparseable / unknown book -> unchanged (safe fallback).
+ if got := tbl.FormatRef("en", "not a ref"); got != "not a ref" {
+ t.Errorf("unparseable ref should be unchanged, got %q", got)
+ }
+ // Round-trip through both dialects.
+ canon, ok := tbl.ParseRef("pl", "J 20, 1. 11-18")
+ if !ok || canon != "John 20:1,11-18" {
+ t.Fatalf("ParseRef round-trip canon=%q ok=%v", canon, ok)
+ }
+ if got := tbl.FormatRef("pl", canon); got != "J 20, 1. 11-18" {
+ t.Errorf("pl round-trip = %q", got)
+ }
+}
+
func TestBookTableMergeAndMalformed(t *testing.T) {
// User adds an alias "Jhn" to English John; other books stay default.
user := []byte("[en]\nJohn = [\"Jn\", \"Jhn\", \"John\"]\n")
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index 611ce52..31a00ec 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -181,11 +181,12 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
cfg.TraditionalLang = lang
}
- if citation {
- return runCitation(cfg, date, refresh, stdout, stderr)
- }
- if week {
- return runWeek(cfg, date, refresh, stdout, stderr)
+ if citation || week {
+ tbl, _ := bible.LoadBookTable(userBooksTOML())
+ if citation {
+ return runCitation(cfg, tbl, date, refresh, stdout, stderr)
+ }
+ return runWeek(cfg, tbl, date, refresh, stdout, stderr)
}
effAll := all || cfg.All
@@ -291,11 +292,34 @@ func gospelCitation(sec liturgy.Section) string {
return ""
}
+// dialectCitation renders a gospel section's reference in the configured sigla
+// dialect (cfg.SiglaLang(): sigla_style, or -- "auto" -- ui_language). The
+// source citation's language is the lectionary's: Polish for the modern
+// (niedziela) lectionary, cfg.TraditionalLang for the traditional one. The ref
+// is parsed to canonical and re-rendered in the target dialect; a citation
+// whose book can't be parsed comes back in its source form unchanged.
+func dialectCitation(cfg config.Config, tbl *bible.BookTable, sec liturgy.Section) string {
+ raw := gospelCitation(sec)
+ if raw == "" || tbl == nil {
+ return raw
+ }
+ sourceLang := "pl"
+ if cfg.Lectionary == "traditional" {
+ sourceLang = cfg.TraditionalLang
+ }
+ canonical, ok := tbl.ParseRef(sourceLang, raw)
+ if !ok {
+ return raw
+ }
+ return tbl.FormatRef(cfg.SiglaLang(), canonical)
+}
+
// runCitation handles --citation: fetch the day's gospel (gospel-only) and
-// print just its scripture reference, for scripts/cron/prompt use. Honors the
-// resolved cfg (lectionary/lang/offline) and date. Exit 1 if the day has no
-// gospel reference (unpublished date, no network while offline, ...).
-func runCitation(cfg config.Config, date string, refresh bool, stdout, stderr io.Writer) int {
+// print just its scripture reference in the configured sigla dialect (see
+// dialectCitation), for scripts/cron/prompt use. Honors the resolved cfg
+// (lectionary/lang/offline) and date. Exit 1 if the day has no gospel
+// reference (unpublished date, no network while offline, ...).
+func runCitation(cfg config.Config, tbl *bible.BookTable, date string, refresh bool, stdout, stderr io.Writer) int {
secs, _, err := readings.Load(cfg, readings.Options{Date: date, Refresh: refresh, Offline: cfg.Offline, All: false})
if err != nil {
fmt.Fprintln(stderr, "lectio:", err)
@@ -306,7 +330,7 @@ func runCitation(cfg config.Config, date string, refresh bool, stdout, stderr io
fmt.Fprintln(stderr, "lectio: no gospel for", date)
return 1
}
- cit := gospelCitation(sec)
+ cit := dialectCitation(cfg, tbl, sec)
if cit == "" {
fmt.Fprintln(stderr, "lectio: no gospel reference for", date)
return 1
@@ -320,7 +344,7 @@ func runCitation(cfg config.Config, date string, refresh bool, stdout, stderr io
// can't be loaded (unpublished, offline gap, no gospel) shows "—" rather than
// aborting the run, so the list is always seven lines. Honors cfg
// (lectionary/lang/offline).
-func runWeek(cfg config.Config, date string, refresh bool, stdout, stderr io.Writer) int {
+func runWeek(cfg config.Config, tbl *bible.BookTable, date string, refresh bool, stdout, stderr io.Writer) int {
start, err := time.Parse("2006-01-02", date)
if err != nil {
fmt.Fprintln(stderr, "lectio:", err)
@@ -332,7 +356,7 @@ func runWeek(cfg config.Config, date string, refresh bool, stdout, stderr io.Wri
secs, _, err := readings.Load(cfg, readings.Options{Date: d, Refresh: refresh, Offline: cfg.Offline, All: false})
if err == nil {
if sec, ok := gospelSection(secs); ok {
- if c := gospelCitation(sec); c != "" {
+ if c := dialectCitation(cfg, tbl, sec); c != "" {
cit = c
}
}
diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go
index 47d8f55..374d723 100644
--- a/internal/cli/cli_test.go
+++ b/internal/cli/cli_test.go
@@ -391,8 +391,11 @@ func TestCitation(t *testing.T) {
if code := Run([]string{"--citation", "2026-07-22"}, nil, &out, &errb); code != 0 {
t.Fatalf("citation code=%d stderr=%q", code, errb.String())
}
- if s := strings.TrimSpace(out.String()); !strings.Contains(s, "J 20") {
- t.Errorf("citation = %q, want a gospel ref containing 'J 20'", s)
+ // Default config resolves to the English dialect (sigla_style auto +
+ // ui_language en), so the Polish source "J 20, 1. 11-18" is rendered as the
+ // English sigla "Jn 20:1,11-18".
+ if s := strings.TrimSpace(out.String()); !strings.Contains(s, "Jn 20:") {
+ t.Errorf("citation = %q, want English-dialect gospel ref 'Jn 20:...'", s)
}
}
@@ -415,7 +418,7 @@ func TestWeek(t *testing.T) {
if len(lines) != 7 {
t.Fatalf("week printed %d lines, want 7:\n%s", len(lines), out.String())
}
- if !strings.HasPrefix(lines[0], "2026-07-22") || !strings.Contains(lines[0], "J 20") {
+ if !strings.HasPrefix(lines[0], "2026-07-22") || !strings.Contains(lines[0], "Jn 20:") {
t.Errorf("week[0] = %q", lines[0])
}
}
diff --git a/internal/config/config.go b/internal/config/config.go
index 59ab378..3c5e60d 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -24,7 +24,7 @@ var seedTOML []byte
// Version is lectio's release version, shared by every binary's
// -v/--version output (lectio, lectio-ui, lectio-web).
-const Version = "0.10.0"
+const Version = "0.11.0"
// validVersions are the five scripture versions lectio understands.
var validVersions = map[string]bool{