feat(faith): rename rite URL slugs to vetus/novus

Replace /1962 and /1969 with /vetus and /novus — matches how Catholics
actually refer to the missals (Vetus Ordo / Novus Ordo), reads the same
across de/en/la, and sidesteps the value-laden old-vs-new framing.
Rite pill labels flip to "Vetus" / "Novus"; the year stays visible in
the subtitle. Legacy year-slug URLs 307-redirect to keep bookmarks alive.
This commit is contained in:
2026-04-21 16:09:52 +02:00
parent 693db06128
commit 2f2fcc2f51
7 changed files with 56 additions and 33 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.41.4",
"version": "1.42.0",
"private": true,
"type": "module",
"scripts": {
+3 -1
View File
@@ -1,5 +1,7 @@
import type { ParamMatcher } from '@sveltejs/kit';
// Accepts the new Latin slugs (`vetus` / `novus`) plus the legacy year slugs
// so old bookmarks land on a load handler that 307s them to the new shape.
export const match: ParamMatcher = (param) => {
return param === '1962' || param === '1969';
return param === 'vetus' || param === 'novus' || param === '1962' || param === '1969';
};
@@ -10,5 +10,5 @@ export const load: PageServerLoad = async ({ params, url, fetch }) => {
throw redirect(307, `/${params.faithLang}/${slug}`);
}
const search = url.search ?? '';
throw redirect(307, `/${params.faithLang}/${params.calendar}/1962${search}`);
throw redirect(307, `/${params.faithLang}/${params.calendar}/vetus${search}`);
};
@@ -40,7 +40,18 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
const lang: CalendarLang =
params.faithLang === 'faith' ? 'en' : params.faithLang === 'fides' ? 'la' : 'de';
const rite: Rite = params.rite === '1969' ? '1969' : '1962';
// Legacy year-slug links (/.../1962/... or /.../1969/...) forward to the new
// Latin slugs so old bookmarks stay alive.
if (params.rite === '1962' || params.rite === '1969') {
const tail = url.pathname.split('/').slice(4).join('/');
const suffix = tail ? `/${tail}` : '';
throw redirect(
307,
`/${params.faithLang}/${params.calendar}/${params.rite === '1962' ? 'vetus' : 'novus'}${suffix}${url.search}`
);
}
const rite: Rite = params.rite === 'novus' ? 'novus' : 'vetus';
const dioceseParam = url.searchParams.get('diocese');
const diocese1962: Diocese1962 = isDiocese1962(dioceseParam)
@@ -57,7 +68,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
}
const today = new Date();
const minYear = rite === '1962' ? 1900 : 1969;
const minYear = rite === 'vetus' ? 1900 : 1969;
const yParam = params.yyyy ? Number(params.yyyy) : NaN;
const mParam = params.mm ? Number(params.mm) - 1 : NaN;
@@ -65,7 +76,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
const month = Number.isFinite(mParam) && mParam >= 0 && mParam <= 11 ? mParam : today.getMonth();
const fetchLy = async (y: number) =>
rite === '1962'
rite === 'vetus'
? await getYear1962(lang, diocese1962, y)
: await getYear(lang, diocese1969, y);
@@ -135,7 +146,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
const todayIso = today.toISOString().slice(0, 10);
const todayYearMap =
rite === '1962'
rite === 'vetus'
? await getYear1962(lang, diocese1962, today.getFullYear())
: await getYear(lang, diocese1969, today.getFullYear());
const todayEntry = todayYearMap.get(todayIso) ?? null;
@@ -154,7 +165,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
? yearMap
: selectedYear === today.getFullYear()
? todayYearMap
: rite === '1962'
: rite === 'vetus'
? await getYear1962(lang, diocese1962, selectedYear)
: await getYear(lang, diocese1969, selectedYear);
const selectedEntry = selectedYearMap.get(selectedIso) ?? monthDays[0];
@@ -241,7 +252,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
// are unresolved i18n paths like 'lent.season', so always go through
// `season1962Label`. 1969: prefer the engine-resolved localized name.
const name =
rite === '1962'
rite === 'vetus'
? (key ? season1962Label(key, lang) : '')
: key && key !== d.seasonKey
? key
@@ -264,7 +275,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
return {
rite,
diocese: rite === '1962' ? diocese1962 : diocese1969,
diocese: rite === 'vetus' ? diocese1962 : diocese1969,
wip: false,
year,
liturgicalYear,
@@ -65,7 +65,7 @@
const rite = $derived(data.rite);
const wip = $derived(data.wip);
const riteSubtitle = $derived(t(rite === '1962' ? 'rite1962Long' : 'rite1969Long', lang));
const riteSubtitle = $derived(t(rite === 'vetus' ? 'rite1962Long' : 'rite1969Long', lang));
function pad(n: number) {
return String(n).padStart(2, '0');
@@ -94,11 +94,11 @@
// Only append ?diocese= when non-default, keeps default URLs clean.
const dioceseQuery = $derived.by(() => {
const def = rite === '1962' ? DEFAULT_DIOCESE_1962 : DEFAULT_DIOCESE_1969;
const def = rite === 'vetus' ? DEFAULT_DIOCESE_1962 : DEFAULT_DIOCESE_1969;
return diocese && diocese !== def ? `?diocese=${diocese}` : '';
});
const dioceseOptions = $derived(rite === '1962' ? DIOCESES_1962 : DIOCESES_1969);
const dioceseOptions = $derived(rite === 'vetus' ? DIOCESES_1962 : DIOCESES_1969);
// URL: /{faithLang}/{calendar}/{rite}/{yyyy}/{mm}/{dd} — rite is a required
// path segment so day/month nav stays inside the active rite.
@@ -133,14 +133,14 @@
// When switching rites we drop ?diocese because the ID spaces differ (1962 has
// diocesan calendars, 1969 only "general" or "switzerland"). The server
// re-applies each rite's default if none is given.
function riteHref(r: '1969' | '1962') {
function riteHref(r: 'novus' | 'vetus') {
const dd = selectedIso.slice(8, 10);
return `${calendarBase}/${r}/${year}/${pad(month + 1)}/${dd}`;
}
function onDioceseChange(e: Event) {
const next = (e.currentTarget as HTMLSelectElement).value;
const def = rite === '1962' ? DEFAULT_DIOCESE_1962 : DEFAULT_DIOCESE_1969;
const def = rite === 'vetus' ? DEFAULT_DIOCESE_1962 : DEFAULT_DIOCESE_1969;
const dd = selectedIso.slice(8, 10);
const path = `${riteBase}/${year}/${pad(month + 1)}/${dd}`;
goto(next === def ? path : `${path}?diocese=${next}`, { noScroll: true });
@@ -159,21 +159,21 @@
<div class="rite-toggle" role="tablist" aria-label="Rite">
<a
role="tab"
aria-selected={rite === '1969'}
aria-selected={rite === 'novus'}
class="rite-pill"
class:active={rite === '1969'}
href={riteHref('1969')}
class:active={rite === 'novus'}
href={riteHref('novus')}
>
1969
Novus
</a>
<a
role="tab"
aria-selected={rite === '1962'}
aria-selected={rite === 'vetus'}
class="rite-pill"
class:active={rite === '1962'}
href={riteHref('1962')}
class:active={rite === 'vetus'}
href={riteHref('vetus')}
>
1962
Vetus
</a>
</div>
<label class="diocese-picker">
@@ -184,7 +184,7 @@
{/each}
</select>
</label>
{#if rite === '1969'}
{#if rite === 'novus'}
<p class="diocese-note">{t('rite1969SwissNote', lang)}</p>
{/if}
</header>
@@ -196,7 +196,7 @@
<p>{t('wipBody', lang)}</p>
</section>
{:else}
{#if rite === '1962'}
{#if rite === 'vetus'}
<aside class="disclaimer" role="note">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
<div>
@@ -210,7 +210,7 @@
day={hero}
{lang}
{todayIso}
href={rite === '1962' ? detailHref(hero.iso) : undefined}
href={rite === 'vetus' ? detailHref(hero.iso) : undefined}
/>
{/if}
@@ -24,8 +24,18 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
const lang: CalendarLang =
params.faithLang === 'faith' ? 'en' : params.faithLang === 'fides' ? 'la' : 'de';
const rite: Rite = params.rite === '1969' ? '1969' : '1962';
if (rite !== '1962') await errorWithVerse(fetch, url.pathname, 404, 'Not found');
// Legacy year-slug links forward to the Latin slugs.
if (params.rite === '1962' || params.rite === '1969') {
const tail = url.pathname.split('/').slice(4).join('/');
const suffix = tail ? `/${tail}` : '';
throw redirect(
307,
`/${params.faithLang}/${params.calendar}/${params.rite === '1962' ? 'vetus' : 'novus'}${suffix}${url.search}`
);
}
const rite: Rite = params.rite === 'novus' ? 'novus' : 'vetus';
if (rite !== 'vetus') await errorWithVerse(fetch, url.pathname, 404, 'Not found');
const dioceseParam = url.searchParams.get('diocese');
const diocese1962: Diocese1962 = isDiocese1962(dioceseParam)
@@ -35,7 +45,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
? dioceseParam
: DEFAULT_DIOCESE_1969;
const minYear = rite === '1962' ? 1900 : 1969;
const minYear = rite === 'vetus' ? 1900 : 1969;
const year = Number(params.yyyy);
const month = Number(params.mm) - 1;
const day = Number(params.dd);
@@ -53,7 +63,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
// belong to LY N+1, so fetch both and pick the correct one — mirrors the
// rollover logic in the month page.
const fetchLy = async (y: number) =>
rite === '1962'
rite === 'vetus'
? await getYear1962(lang, diocese1962, y)
: await getYear(lang, diocese1969, y);
const yearMapN = await fetchLy(year);
@@ -76,7 +86,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
return {
lang,
rite,
diocese: rite === '1962' ? diocese1962 : diocese1969,
diocese: rite === 'vetus' ? diocese1962 : diocese1969,
year,
month,
day,
@@ -145,9 +145,9 @@ export function t(key: keyof typeof ui, lang: CalendarLang): string {
return ui[key][lang] ?? ui[key].en;
}
export type Rite = '1969' | '1962';
export type Rite = 'novus' | 'vetus';
export function isValidRite(v: string | null): v is Rite {
return v === '1969' || v === '1962';
return v === 'novus' || v === 'vetus';
}
// --- Diocese selection ---