From ab71c67414666800f19fdd3f6515f15c90cb822e Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 23 Jul 2026 12:41:29 +0200 Subject: psalter: port psalm versification --- internal/psalter/psalter.go | 46 ++++++++++++++++++++++++++++++++++++++++ internal/psalter/psalter_test.go | 28 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 internal/psalter/psalter.go create mode 100644 internal/psalter/psalter_test.go (limited to 'internal') diff --git a/internal/psalter/psalter.go b/internal/psalter/psalter.go new file mode 100644 index 0000000..815f660 --- /dev/null +++ b/internal/psalter/psalter.go @@ -0,0 +1,46 @@ +// Package psalter bridges psalm versification between the Vulgate-family +// versions and the Douay-Rheims source. See the Go port of psalm_versify.py. +package psalter + +// DRBTitleFold maps a Hebrew psalm number to the number of title verses the DRB +// source folds into verse 1 (1, or 2 for a historical superscription). Untitled +// psalms are absent (k = 0). Copy every entry from psalm_versify.py DRB_TITLE_FOLD. +var DRBTitleFold = map[int]int{ + 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, 11: 1, 12: 1, 14: 1, 18: 1, 19: 1, + 20: 1, 21: 1, 22: 1, 30: 1, 31: 1, 34: 1, 36: 1, 38: 1, 39: 1, 40: 1, + 41: 1, 42: 1, 44: 1, 45: 1, 46: 1, 47: 1, 48: 1, 49: 1, 51: 2, 52: 2, + 53: 1, 54: 2, 55: 1, 56: 1, 57: 1, 58: 1, 59: 1, 60: 2, 61: 1, 62: 1, + 63: 1, 64: 1, 65: 1, 67: 1, 68: 1, 69: 1, 70: 1, 75: 1, 76: 1, 77: 1, + 80: 1, 81: 1, 83: 1, 84: 1, 85: 1, 88: 1, 89: 1, 92: 1, 102: 1, 108: 1, + 140: 1, 142: 1, +} + +// DrbVerse returns the DRB-source verse number for a lectionary (BT) psalm verse. +func DrbVerse(hebrewPsalm, lectionaryVerse int) int { + v := lectionaryVerse - DRBTitleFold[hebrewPsalm] + if v < 1 { + return 1 + } + return v +} + +// HebrewToVulgateChapter maps a Masoretic psalm number to its Vulgate chapter. +func HebrewToVulgateChapter(h int) int { + switch { + case h <= 8 || h >= 148: + return h + case h >= 9 && h <= 10: + return 9 + case h >= 11 && h <= 113: + return h - 1 + case h >= 114 && h <= 115: + return 113 + case h == 116: + return 114 + case h >= 117 && h <= 146: + return h - 1 + case h == 147: + return 146 + } + return h +} diff --git a/internal/psalter/psalter_test.go b/internal/psalter/psalter_test.go new file mode 100644 index 0000000..612bf1d --- /dev/null +++ b/internal/psalter/psalter_test.go @@ -0,0 +1,28 @@ +package psalter + +import "testing" + +func TestDrbVerse(t *testing.T) { + cases := []struct{ psalm, v, want int }{ + {34, 2, 1}, // Ps 34: k=1, title folded + {34, 3, 2}, + {51, 3, 1}, // Ps 51: k=2 (two-line title) + {63, 2, 1}, // Ps 63: k=1 + {1, 5, 5}, // untitled: identity + {34, 1, 1}, // clamp: never below 1 + } + for _, c := range cases { + if got := DrbVerse(c.psalm, c.v); got != c.want { + t.Errorf("DrbVerse(%d,%d)=%d want %d", c.psalm, c.v, got, c.want) + } + } +} + +func TestHebrewToVulgateChapter(t *testing.T) { + cases := []struct{ h, want int }{{8, 8}, {34, 33}, {9, 9}, {10, 9}, {116, 114}, {147, 146}, {150, 150}} + for _, c := range cases { + if got := HebrewToVulgateChapter(c.h); got != c.want { + t.Errorf("HebrewToVulgateChapter(%d)=%d want %d", c.h, got, c.want) + } + } +} -- cgit v1.3