i18n(faith): migrate prayers index + prayer detail

Adds prayer-name keys (sign_of_cross, pater_noster, fatima_prayer, …),
search/filter UI labels (search_prayers, clear_search, filter_by_category,
all_categories), the eastertide_badge, and the prayer-detail-only
nicene_creed / hail_mary aliases (German + Latin keep the Latin form,
English uses the English name).

Prayers index labels object collapses each name ternary into a t.foo
lookup; the language-invariant ones (Glória Patri, Credo, Ave Maria,
Salve Regina, Glória, Ánima Christi, Tantum Ergo, Angelus, Regína Cæli)
stay hardcoded as single strings since they're identical across all
three locales. The baseUrl building now uses faithSlugFromLang/prayersSlug
helpers instead of inline ternaries.

Prayer detail's prayerDefs routing table — every name field that was
isEnglish ? a : b now points at a t.* lookup. Painting captions for
the Velázquez/Murillo Angelus/Regina Cæli backgrounds become
t.painting_coronation_virgin / t.painting_annunciation. The
AngelusStreakCounter call site drops its three-way ternary in favor of
the typed `lang` derived value.

Slug-table ternaries (URL slug per locale) and the long gloriaIntro
paragraph are intentionally left inline — slugs are URL data, not UI
text, and gloriaIntro is page-unique marketing copy that doesn't
benefit from being in a shared dict.
This commit is contained in:
2026-05-01 13:16:47 +02:00
parent 3dcb5c7f2b
commit d7f96f35c2
6 changed files with 153 additions and 62 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.55.1",
"version": "1.55.2",
"private": true,
"type": "module",
"scripts": {
+29 -1
View File
@@ -41,5 +41,33 @@ export const de = {
// Language-availability notice (catechesis is German-only)
only_german_pre: 'Diese Katechese ist nur auf ',
only_german_link: 'Deutsch',
only_german_post: ' verfügbar.'
only_german_post: ' verfügbar.',
// Prayers index
prayers_description: 'Katholische Gebete auf Deutsch und Latein.',
sign_of_cross: 'Das heilige Kreuzzeichen',
pater_noster: 'Paternoster',
fatima_prayer: 'Das Fatimagebet',
st_michael_prayer: 'Gebet zum hl. Erzengel Michael',
bruder_klaus_prayer: 'Bruder Klaus Gebet',
st_joseph_prayer: 'Josephgebet des hl. Papst Pius X',
the_confiteor: 'Das Confiteor',
postcommunio_prayers: 'Nachkommuniongebete',
prayer_before_crucifix: 'Gebet vor einem Kruzifix',
guardian_angel_prayer: 'Schutzengel-Gebet',
apostles_creed: 'Apostolisches Glaubensbekenntnis',
search_prayers: 'Gebete suchen…',
clear_search: 'Suche löschen',
text_match: 'Treffer im Gebetstext',
filter_by_category: 'Nach Kategorie filtern',
all_categories: 'Alle',
eastertide_badge: 'Osterzeit',
// Prayer detail page — alternate names for credo/aveMaria (English differs)
nicene_creed: 'Credo',
hail_mary: 'Ave Maria',
// Painting titles on the prayer detail page
painting_coronation_virgin: 'Die Krönung der Jungfrau',
painting_annunciation: 'Die Verkündigung'
} as const;
+29 -1
View File
@@ -41,5 +41,33 @@ export const en = {
// Language-availability notice (catechesis is German-only)
only_german_pre: 'This catechesis is only available in ',
only_german_link: 'German',
only_german_post: '.'
only_german_post: '.',
// Prayers index
prayers_description: 'Catholic prayers in Latin and English.',
sign_of_cross: 'The Sign of the Cross',
pater_noster: 'Our Father',
fatima_prayer: 'Fatima Prayer',
st_michael_prayer: 'Prayer to St. Michael the Archangel',
bruder_klaus_prayer: 'Prayer of St. Nicholas of Flüe',
st_joseph_prayer: 'Prayer to St. Joseph by Pope St. Pius X',
the_confiteor: 'The Confiteor',
postcommunio_prayers: 'Postcommunio Prayers',
prayer_before_crucifix: 'Prayer Before a Crucifix',
guardian_angel_prayer: 'Guardian Angel Prayer',
apostles_creed: "Apostles' Creed",
search_prayers: 'Search prayers…',
clear_search: 'Clear search',
text_match: 'Match in prayer text',
filter_by_category: 'Filter by category',
all_categories: 'All',
eastertide_badge: 'Eastertide',
// Prayer detail page
nicene_creed: 'Nicene Creed',
hail_mary: 'Hail Mary',
// Painting titles
painting_coronation_virgin: 'Coronation of the Virgin',
painting_annunciation: 'The Annunciation'
} as const satisfies Record<keyof typeof de, string>;
+29 -1
View File
@@ -41,5 +41,33 @@ export const la = {
// Language-availability notice (catechesis is German-only)
only_german_pre: 'Haec catechesis tantum in ',
only_german_link: 'lingua Germanica',
only_german_post: ' praesto est.'
only_german_post: ' praesto est.',
// Prayers index
prayers_description: 'Orationes catholicae in lingua Latina.',
sign_of_cross: 'Signum Crucis',
pater_noster: 'Pater Noster',
fatima_prayer: 'Oratio Fatimensis',
st_michael_prayer: 'Oratio ad S. Michaëlem Archangelum',
bruder_klaus_prayer: 'Oratio S. Nicolai de Flüe',
st_joseph_prayer: 'Oratio S. Iosephi a S. Papa Pio X',
the_confiteor: 'Confiteor',
postcommunio_prayers: 'Orationes post Communionem',
prayer_before_crucifix: 'Oratio ante Crucifixum',
guardian_angel_prayer: 'Angele Dei',
apostles_creed: 'Symbolum Apostolorum',
search_prayers: 'Orationes quaerere…',
clear_search: 'Quaestionem delere',
text_match: 'In textu orationis',
filter_by_category: 'Filtrare per categoriam',
all_categories: 'Omnia',
eastertide_badge: 'Tempus Paschale',
// Prayer detail page — Latin uses the Latin form invariantly
nicene_creed: 'Credo',
hail_mary: 'Ave Maria',
// Painting titles — Latin reuses German fallback
painting_coronation_virgin: 'Die Krönung der Jungfrau',
painting_annunciation: 'Die Verkündigung'
} as const satisfies Record<keyof typeof de, string>;
@@ -2,6 +2,7 @@
import { resolve } from '$app/paths';
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { m, faithSlugFromLang, prayersSlug } from '$lib/js/faithI18n';
import { createLanguageContext } from "$lib/contexts/languageContext.js";
import Gebet from "./Gebet.svelte";
import LanguageToggle from "$lib/components/faith/LanguageToggle.svelte";
@@ -44,37 +45,38 @@
}
});
const lang = $derived(/** @type {import('$lib/js/faithI18n').FaithLang} */ (data.lang));
const t = $derived(m[lang]);
// Reactive isEnglish based on data.lang
const isEnglish = $derived(data.lang === 'en');
const isLatin = $derived(data.lang === 'la');
const isEnglish = $derived(lang === 'en');
const isLatin = $derived(lang === 'la');
// Prayer-name labels — the language-invariant ones (Glória Patri, Credo,
// Ave Maria, Salve Regina, Glória, Ánima Christi, Tantum Ergo, Angelus,
// Regína Cæli) stay hardcoded; the rest pull from the dictionary.
const labels = $derived({
title: isLatin ? 'Orationes' : isEnglish ? 'Prayers' : 'Gebete',
description: isLatin
? 'Orationes catholicae in lingua Latina.'
: isEnglish
? 'Catholic prayers in Latin and English.'
: 'Katholische Gebete auf Deutsch und Latein.',
signOfCross: isLatin ? 'Signum Crucis' : isEnglish ? 'The Sign of the Cross' : 'Das heilige Kreuzzeichen',
title: t.prayers,
description: t.prayers_description,
signOfCross: t.sign_of_cross,
gloriaPatri: 'Glória Patri',
paternoster: isLatin ? 'Pater Noster' : isEnglish ? 'Our Father' : 'Paternoster',
paternoster: t.pater_noster,
credo: 'Credo',
aveMaria: 'Ave Maria',
salveRegina: 'Salve Regina',
fatima: isLatin ? 'Oratio Fatimensis' : isEnglish ? 'Fatima Prayer' : 'Das Fatimagebet',
fatima: t.fatima_prayer,
gloria: 'Glória',
michael: isLatin ? 'Oratio ad S. Michaëlem Archangelum' : isEnglish ? 'Prayer to St. Michael the Archangel' : 'Gebet zum hl. Erzengel Michael',
bruderKlaus: isEnglish ? 'Prayer of St. Nicholas of Flüe' : 'Bruder Klaus Gebet',
joseph: isEnglish ? 'Prayer to St. Joseph by Pope St. Pius X' : 'Josephgebet des hl. Papst Pius X',
confiteor: isLatin ? 'Confiteor' : isEnglish ? 'The Confiteor' : 'Das Confiteor',
searchPlaceholder: isLatin ? 'Orationes quaerere...' : isEnglish ? 'Search prayers...' : 'Gebete suchen...',
clearSearch: isLatin ? 'Quaestionem delere' : isEnglish ? 'Clear search' : 'Suche löschen',
textMatch: isLatin ? 'In textu orationis' : isEnglish ? 'Match in prayer text' : 'Treffer im Gebetstext',
postcommunio: isLatin ? 'Orationes post Communionem' : isEnglish ? 'Postcommunio Prayers' : 'Nachkommuniongebete',
michael: t.st_michael_prayer,
bruderKlaus: t.bruder_klaus_prayer,
joseph: t.st_joseph_prayer,
confiteor: t.the_confiteor,
searchPlaceholder: t.search_prayers,
clearSearch: t.clear_search,
textMatch: t.text_match,
postcommunio: t.postcommunio_prayers,
animachristi: 'Ánima Christi',
prayerbeforeacrucifix: isLatin ? 'Oratio ante Crucifixum' : isEnglish ? 'Prayer Before a Crucifix' : 'Gebet vor einem Kruzifix',
guardianAngel: isLatin ? 'Angele Dei' : isEnglish ? 'Guardian Angel Prayer' : 'Schutzengel-Gebet',
apostlesCreed: isLatin ? 'Symbolum Apostolorum' : isEnglish ? "Apostles' Creed" : 'Apostolisches Glaubensbekenntnis',
prayerbeforeacrucifix: t.prayer_before_crucifix,
guardianAngel: t.guardian_angel_prayer,
apostlesCreed: t.apostles_creed,
tantumErgo: 'Tantum Ergo',
angelus: 'Angelus',
reginaCaeli: 'Regína Cæli'
@@ -173,8 +175,8 @@
// Base URL for prayer links
const baseUrl = $derived(resolve('/[faithLang=faithLang]/[prayers=prayersLang]', {
faithLang: isLatin ? 'fides' : isEnglish ? 'faith' : 'glaube',
prayers: isLatin ? 'orationes' : isEnglish ? 'prayers' : 'gebete'
faithLang: faithSlugFromLang(lang),
prayers: prayersSlug(lang)
}));
// Get prayer name by ID (reactive based on language)
@@ -501,14 +503,14 @@ h1{
</div>
{/if}
<nav class="category-filters" aria-label={isLatin ? 'Filtrare per categoriam' : isEnglish ? 'Filter by category' : 'Nach Kategorie filtern'}>
<nav class="category-filters" aria-label={t.filter_by_category}>
<a
href={buildFilterHref(null)}
class="category-pill"
class:selected={!selectedCategory}
onclick={(e) => { e.preventDefault(); selectedCategory = null; }
}
>{isLatin ? 'Omnia' : isEnglish ? 'All' : 'Alle'}</a>
>{t.all_categories}</a>
{#each categories as cat (cat.id)}
<a
href={buildFilterHref(cat.id)}
@@ -575,7 +577,7 @@ h1{
<Postcommunio onlyIntro={true} />
{/if}
{#if prayer.id === 'reginaCaeli' && isEastertide}
<span class="seasonal-badge">{isLatin ? 'Tempus Paschale' : isEnglish ? 'Eastertide' : 'Osterzeit'}</span>
<span class="seasonal-badge">{t.eastertide_badge}</span>
{/if}
</Gebet>
</div>
@@ -24,6 +24,8 @@
import ReginaCaeli from "$lib/components/faith/prayers/ReginaCaeli.svelte";
import StickyImage from "$lib/components/faith/StickyImage.svelte";
import AngelusStreakCounter from "$lib/components/faith/AngelusStreakCounter.svelte";
import { m } from '$lib/js/faithI18n';
/** @typedef {import('$lib/js/faithI18n').FaithLang} FaithLang */
let { data } = $props();
@@ -37,40 +39,43 @@
}
});
const isEnglish = $derived(data.lang === 'en');
const isLatin = $derived(data.lang === 'la');
const lang = $derived(/** @type {FaithLang} */ (data.lang));
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const isLatin = $derived(lang === 'la');
// Prayer definitions with slugs
// Prayer definitions with slugs. Names come from the dictionary; slugs and
// bilingue flags stay inline since they're prayer-route metadata.
const prayerDefs = $derived({
'das-heilige-kreuzzeichen': { id: 'signOfCross', name: isEnglish ? 'The Sign of the Cross' : 'Das heilige Kreuzzeichen', bilingue: true },
'the-sign-of-the-cross': { id: 'signOfCross', name: isEnglish ? 'The Sign of the Cross' : 'Das heilige Kreuzzeichen', bilingue: true },
'das-heilige-kreuzzeichen': { id: 'signOfCross', name: t.sign_of_cross, bilingue: true },
'the-sign-of-the-cross': { id: 'signOfCross', name: t.sign_of_cross, bilingue: true },
'gloria-patri': { id: 'gloriaPatri', name: 'Glória Patri', bilingue: true },
'paternoster': { id: 'paternoster', name: isEnglish ? 'Our Father' : 'Paternoster', bilingue: true },
'our-father': { id: 'paternoster', name: isEnglish ? 'Our Father' : 'Paternoster', bilingue: true },
'credo': { id: 'credo', name: isEnglish ? 'Nicene Creed' : 'Credo', bilingue: true },
'nicene-creed': { id: 'credo', name: isEnglish ? 'Nicene Creed' : 'Credo', bilingue: true },
'ave-maria': { id: 'aveMaria', name: isEnglish ? 'Hail Mary' : 'Ave Maria', bilingue: true },
'hail-mary': { id: 'aveMaria', name: isEnglish ? 'Hail Mary' : 'Ave Maria', bilingue: true },
'paternoster': { id: 'paternoster', name: t.pater_noster, bilingue: true },
'our-father': { id: 'paternoster', name: t.pater_noster, bilingue: true },
'credo': { id: 'credo', name: t.nicene_creed, bilingue: true },
'nicene-creed': { id: 'credo', name: t.nicene_creed, bilingue: true },
'ave-maria': { id: 'aveMaria', name: t.hail_mary, bilingue: true },
'hail-mary': { id: 'aveMaria', name: t.hail_mary, bilingue: true },
'salve-regina': { id: 'salveRegina', name: 'Salve Regina', bilingue: true },
'das-fatimagebet': { id: 'fatima', name: isEnglish ? 'Fatima Prayer' : 'Das Fatimagebet', bilingue: true },
'fatima-prayer': { id: 'fatima', name: isEnglish ? 'Fatima Prayer' : 'Das Fatimagebet', bilingue: true },
'das-fatimagebet': { id: 'fatima', name: t.fatima_prayer, bilingue: true },
'fatima-prayer': { id: 'fatima', name: t.fatima_prayer, bilingue: true },
'gloria': { id: 'gloria', name: 'Glória', bilingue: true },
'gebet-zum-hl-erzengel-michael': { id: 'michael', name: isEnglish ? 'Prayer to St. Michael the Archangel' : 'Gebet zum hl. Erzengel Michael', bilingue: true },
'prayer-to-st-michael-the-archangel': { id: 'michael', name: isEnglish ? 'Prayer to St. Michael the Archangel' : 'Gebet zum hl. Erzengel Michael', bilingue: true },
'bruder-klaus-gebet': { id: 'bruderKlaus', name: isEnglish ? 'Prayer of St. Nicholas of Flüe' : 'Bruder Klaus Gebet', bilingue: false },
'prayer-of-st-nicholas-of-flue': { id: 'bruderKlaus', name: isEnglish ? 'Prayer of St. Nicholas of Flüe' : 'Bruder Klaus Gebet', bilingue: false },
'josephgebet-des-hl-papst-pius-x': { id: 'joseph', name: isEnglish ? 'Prayer to St. Joseph by Pope St. Pius X' : 'Josephgebet des hl. Papst Pius X', bilingue: false },
'prayer-to-st-joseph-by-pope-st-pius-x': { id: 'joseph', name: isEnglish ? 'Prayer to St. Joseph by Pope St. Pius X' : 'Josephgebet des hl. Papst Pius X', bilingue: false },
'das-confiteor': { id: 'confiteor', name: isEnglish ? 'The Confiteor' : 'Das Confiteor', bilingue: true },
'the-confiteor': { id: 'confiteor', name: isEnglish ? 'The Confiteor' : 'Das Confiteor', bilingue: true },
'postcommunio': { id: 'postcommunio', name: isEnglish ? 'Postcommunio Prayers' : 'Nachkommuniongebete', bilingue: true },
'gebet-zum-hl-erzengel-michael': { id: 'michael', name: t.st_michael_prayer, bilingue: true },
'prayer-to-st-michael-the-archangel': { id: 'michael', name: t.st_michael_prayer, bilingue: true },
'bruder-klaus-gebet': { id: 'bruderKlaus', name: t.bruder_klaus_prayer, bilingue: false },
'prayer-of-st-nicholas-of-flue': { id: 'bruderKlaus', name: t.bruder_klaus_prayer, bilingue: false },
'josephgebet-des-hl-papst-pius-x': { id: 'joseph', name: t.st_joseph_prayer, bilingue: false },
'prayer-to-st-joseph-by-pope-st-pius-x': { id: 'joseph', name: t.st_joseph_prayer, bilingue: false },
'das-confiteor': { id: 'confiteor', name: t.the_confiteor, bilingue: true },
'the-confiteor': { id: 'confiteor', name: t.the_confiteor, bilingue: true },
'postcommunio': { id: 'postcommunio', name: t.postcommunio_prayers, bilingue: true },
'anima-christi': { id: 'animachristi', name: 'Ánima Christi', bilingue: true },
'prayer-before-a-crucifix': { id: 'prayerbeforeacrucifix', name: isEnglish ? 'Prayer Before a Crucifix' : 'Gebet vor einem Kruzifix', bilingue: true },
'gebet-vor-einem-kruzifix': { id: 'prayerbeforeacrucifix', name: isEnglish ? 'Prayer Before a Crucifix' : 'Gebet vor einem Kruzifix', bilingue: true },
'schutzengel-gebet': { id: 'guardianAngel', name: isEnglish ? 'Guardian Angel Prayer' : 'Schutzengel-Gebet', bilingue: true },
'guardian-angel-prayer': { id: 'guardianAngel', name: isEnglish ? 'Guardian Angel Prayer' : 'Schutzengel-Gebet', bilingue: true },
'apostolisches-glaubensbekenntnis': { id: 'apostlesCreed', name: isEnglish ? "Apostles' Creed" : 'Apostolisches Glaubensbekenntnis', bilingue: true },
'apostles-creed': { id: 'apostlesCreed', name: isEnglish ? "Apostles' Creed" : 'Apostolisches Glaubensbekenntnis', bilingue: true },
'prayer-before-a-crucifix': { id: 'prayerbeforeacrucifix', name: t.prayer_before_crucifix, bilingue: true },
'gebet-vor-einem-kruzifix': { id: 'prayerbeforeacrucifix', name: t.prayer_before_crucifix, bilingue: true },
'schutzengel-gebet': { id: 'guardianAngel', name: t.guardian_angel_prayer, bilingue: true },
'guardian-angel-prayer': { id: 'guardianAngel', name: t.guardian_angel_prayer, bilingue: true },
'apostolisches-glaubensbekenntnis': { id: 'apostlesCreed', name: t.apostles_creed, bilingue: true },
'apostles-creed': { id: 'apostlesCreed', name: t.apostles_creed, bilingue: true },
'tantum-ergo': { id: 'tantumErgo', name: 'Tantum Ergo', bilingue: true },
'angelus': { id: 'angelus', name: 'Angelus', bilingue: true },
'regina-caeli': { id: 'reginaCaeli', name: 'Regína Cæli', bilingue: true }
@@ -83,8 +88,8 @@
const isAngelusPage = $derived(prayerId === 'angelus' || prayerId === 'reginaCaeli');
const angelusImageCaption = $derived(prayerId === 'reginaCaeli'
? { artist: 'Diego Velázquez', title: isEnglish ? 'Coronation of the Virgin' : 'Die Krönung der Jungfrau', year: 1641 }
: { artist: 'Bartolomé Esteban Murillo', title: isEnglish ? 'The Annunciation' : 'Die Verkündigung', year: /** @type {number | null} */(null) }
? { artist: 'Diego Velázquez', title: t.painting_coronation_virgin, year: 1641 }
: { artist: 'Bartolomé Esteban Murillo', title: t.painting_annunciation, year: /** @type {number | null} */(null) }
);
const gloriaIntro = $derived(isEnglish
@@ -183,7 +188,7 @@ h1 {
{#if isAngelusPage}
<AngelusStreakCounter
streakData={data.angelusStreak}
lang={isLatin ? 'la' : isEnglish ? 'en' : 'de'}
{lang}
isLoggedIn={!!data.session?.user}
/>
{/if}