From feede51697be870ae183a95b513ef64f031dbd0f Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Tue, 28 Jul 2026 11:57:45 +0200 Subject: feat(readings): compute the daily view offline (OF + EF) Route readings.Load through the embedded calendar engine and lectionary data instead of the niedziela/missalemeum scrapers. The daily view now computes each day (calendar.Compute + caldata.Readings) and renders text from the public-domain corpora, with citations resolved per corpus. - bible.OFRef: normalise an English-canonical OF citation (drop sub-verse letters, ";" -> ",") and renumber Psalms for the target Psalter (Hebrew->Vulgate chapter for vul/grb/wuj; DRB title-fold verses for drb). - liturgy.Section gains Ref (English-canonical lookup ref) alongside Citation (sigla-dialect display); the loader fills both, resolveRef uses Ref, headings/citation command show Citation. - EffectiveVersions always drops "bt" (no offline corpus); the single daily version defaults to vernacularVersion (reading corpus else Latin). Scraper packages remain in the tree, unreferenced, pending removal. --- internal/bible/ofref.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 internal/bible/ofref.go (limited to 'internal/bible/ofref.go') diff --git a/internal/bible/ofref.go b/internal/bible/ofref.go new file mode 100644 index 0000000..8a72342 --- /dev/null +++ b/internal/bible/ofref.go @@ -0,0 +1,71 @@ +package bible + +import ( + "regexp" + "strconv" + "strings" + + "github.com/lukaszkasprzak/lectio/internal/psalter" +) + +var ( + // ofCiteRe splits an English-canonical citation into book, chapter and the + // verse tail: "2 Samuel 6:12b-15,17-19" -> ("2 Samuel", "6", "12b-15,17-19"). + // The book is non-greedy so a leading ordinal ("2 Samuel") stays with it. + ofCiteRe = regexp.MustCompile(`^(.*?)\s+(\d+):(.+)$`) + // ofVerseLetterRe drops sub-verse part letters so lookups resolve at whole + // verses: "12b" -> "12", "3ab" -> "3", "3cd" -> "3". + ofVerseLetterRe = regexp.MustCompile(`(\d)[a-z]+`) +) + +// normalizeOFVerses rewrites a citation's verse tail into the shape +// bible.Lookup parses: cross-chapter semicolons become commas, ranges use a +// plain hyphen, sub-verse letters are dropped, and spaces are removed. +func normalizeOFVerses(tail string) string { + tail = strings.ReplaceAll(tail, ";", ",") + tail = dashRe.ReplaceAllString(tail, "-") + tail = ofVerseLetterRe.ReplaceAllString(tail, "$1") + tail = strings.ReplaceAll(tail, " ", "") + return tail +} + +// OFRef turns an English-canonical Ordinary Form citation (lectio's authored +// form) into a bible.Lookup-ready reference for the target corpus's Psalter. +// +// Every citation's verse tail is normalized (see normalizeOFVerses). Only the +// Psalms differ between Psalters, so their chapter/verse is additionally +// renumbered: +// +// - "vulgate" (vul/grb/wuj): shift the Hebrew chapter to its Vulgate +// equivalent (Ps 27 -> 26, Ps 147 -> 146). Verse numbers are kept, so the +// rare intra-psalm verse-boundary shifts are not corrected here. +// - "drb": the Douay-Rheims corpus keeps modern (Hebrew) chapter numbers, so +// the chapter is kept; only the DRB title-fold verse shift applies (see +// psalter.DrbVerse). +// - "hebrew" / anything else: already in the corpus's numbering. +// +// A citation OFRef cannot parse (no "chapter:verse") is returned unchanged for +// bible.Lookup to accept or reject. +func OFRef(citation, system string) string { + m := ofCiteRe.FindStringSubmatch(citation) + if m == nil { + return citation + } + book, chap, verses := m[1], m[2], normalizeOFVerses(m[3]) + + if book == "Psalms" { + heb, err := strconv.Atoi(chap) + if err == nil { + switch system { + case "vulgate": + chap = strconv.Itoa(psalter.HebrewToVulgateChapter(heb)) + case "drb": + verses = digitsRe.ReplaceAllStringFunc(verses, func(s string) string { + n, _ := strconv.Atoi(s) + return strconv.Itoa(psalter.DrbVerse(heb, n)) + }) + } + } + } + return book + " " + chap + ":" + verses +} -- cgit v1.3