diff --git a/src/hours/lauds-canticles.ts b/src/hours/lauds-canticles.ts index 7ec3e98..6c33e8e 100644 --- a/src/hours/lauds-canticles.ts +++ b/src/hours/lauds-canticles.ts @@ -34,3 +34,12 @@ export function getCanticle(id: string): Canticle { } return canticle; } + +// Non-throwing lookup for the UI's canticle title — unlike getCanticle, +// callers here may pass ids (nunc-dimittis, benedictus, magnificat, or a +// Matins nocturn-3 scripture-ref-derived id) that this store never holds, +// since only the 7 Lauds weekday OT canticles have an authored English +// `name` distinct from their Latin id. +export function tryGetCanticleName(id: string): string | undefined { + return canticles.get(id)?.name; +} diff --git a/src/ui/hour-view.ts b/src/ui/hour-view.ts index bcc0ae1..0d60979 100644 --- a/src/ui/hour-view.ts +++ b/src/ui/hour-view.ts @@ -2,6 +2,7 @@ import { getState } from '../app-state'; import { resolveOrdo } from '../hours'; import type { ResolvedPart, ResolvedText, ResolvedVerse } from '../hours/types'; import { hourLabel } from './format'; +import { tryGetCanticleName } from '../hours/lauds-canticles'; function escapeHtml(value: string): string { return value.replace(/&/g, '&').replace(//g, '>'); @@ -120,14 +121,27 @@ function renderPart(part: ResolvedPart, languages: readonly string[]): string { `; } case 'canticle': { - const title = part.canticleId + // The Latin title is always the id capitalized (it's already Latin — + // canticum-ezechiae -> "Canticum Ezechiae"). English only matches + // that pattern for names already conventional untranslated in + // English (Benedictus, Magnificat, Nunc Dimittis); the 7 Lauds + // weekday OT canticles have a real English name (e.g. "Canticle of + // Ezechias") authored separately — see lauds-canticles.ts. + const derivedTitle = part.canticleId .split('-') .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) .join(' '); + const title: Partial> = { + la: derivedTitle, + en: tryGetCanticleName(part.canticleId) ?? derivedTitle, + }; + const titleCols = languages + .map((lang) => `${escapeHtml(title[lang] ?? derivedTitle)}`) + .join(''); return `
${part.antiphon ? renderColumns(part.antiphon, languages) : ''} -

${escapeHtml(title)}

+

${titleCols}

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