From b163f502b8db4aeaef444102eae5ccc468d9b81b Mon Sep 17 00:00:00 2001 From: Will Estes Date: Sat, 29 Aug 2026 07:33:48 -0400 Subject: [PATCH] Scope renderCitation to the currently displayed languages renderCitation deduplicated a text's citation values across every stored language, not just the ones actually being rendered. Once a citation's La/En abbreviations genuinely differ (e.g. "Jac 1:12" vs. "Jas 1:12", or "Sap. 10:10" vs. "Wis. 10:10"), both survived the dedupe and got joined together regardless of view mode, leaking the other language's abbreviation into a single-language display. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi --- src/ui/hour-view.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ui/hour-view.ts b/src/ui/hour-view.ts index 5e6df00..e15c3b1 100644 --- a/src/ui/hour-view.ts +++ b/src/ui/hour-view.ts @@ -26,12 +26,18 @@ function renderColumns(resolved: ResolvedText | ResolvedVerse, languages: readon } // Scripture quotations always carry a full citation (book, chapter, verse) — -// shown once, deduplicated across languages when they happen to match. -function renderCitation(text: ResolvedText): string { +// shown once per currently-displayed language, deduplicated when they +// happen to match (e.g. a plain "Psalm 118" citation reused verbatim in +// both columns) — restricted to `languages` so a language-specific +// abbreviation (Latin "Jac 1:12" vs. English "Jas 1:12") never leaks into +// a single-language view. +function renderCitation(text: ResolvedText, languages: readonly string[]): string { if (!text.citation) { return ''; } - const values = [...new Set(Object.values(text.citation).filter((v): v is string => Boolean(v)))]; + const values = [ + ...new Set(languages.map((lang) => text.citation![lang]).filter((v): v is string => Boolean(v))), + ]; return values.length ? `

${escapeHtml(values.join(' / '))}

` : ''; } @@ -64,7 +70,7 @@ function renderPart(part: ResolvedPart, languages: readonly string[]): string { return `

${hourLabel(part.kind)}

- ${renderCitation(part.text)} + ${renderCitation(part.text, languages)} ${renderColumns(part.text, languages)}
`; @@ -93,7 +99,7 @@ function renderPart(part: ResolvedPart, languages: readonly string[]): string { return `
${renderLessonLabel(part.label, languages)} - ${renderCitation(part.text)} + ${renderCitation(part.text, languages)} ${renderColumns(part.text, languages)} ${part.responsory ? `
${renderColumns(part.responsory, languages)}
` : ''}
@@ -110,7 +116,7 @@ function renderPart(part: ResolvedPart, languages: readonly string[]): string { return `

Gospel

- ${renderCitation(part.text)} + ${renderCitation(part.text, languages)} ${renderColumns(part.text, languages)} ${part.source ? `

${escapeHtml(part.source)}

` : ''} ${part.responsory ? `
${renderColumns(part.responsory, languages)}
` : ''} @@ -170,7 +176,7 @@ function renderPart(part: ResolvedPart, languages: readonly string[]): string {
${part.antiphon ? renderColumns(part.antiphon, languages) : ''}

${titleCols}

- ${renderCitation(part.text)} + ${renderCitation(part.text, languages)} ${renderColumns(part.text, languages)} ${part.gloriaPatri ? `
${renderColumns(part.gloriaPatri, languages)}
` : ''}