/* * liturgy.js — the handful of words that must never be guessed at. * * Measured against the shipped NLLB, the single most frequent word in a service * translates as follows: * * "Amen." → spa "- Sí, estoy bien." ("yes, I'm fine") * fra "Je vous en prie." ("you're welcome") * deu "- Das ist doch gut." ("well, that's good") * zho "现在,我们要去." ("now, we're going to go") * rus "- Да, да." ("yes, yes") * * Of ten languages tested, four were right. This is not a translation problem * that better decoding fixes — one word carries no context for a context model * to work from. So these bypass the model completely. * * SCOPE IS DELIBERATELY TINY. Only Hebrew LOANWORDS are here — amen, hallelujah, * hosanna — words every tradition transliterated rather than translated, so * there is one right answer and no denominational choice hiding in it. * "Praise the Lord" and "Glory to God" are NOT here: they are translated * phrases, and their wording differs between Protestant and Catholic editions * of the same language. Guessing those would be the exact silent, confident * error this file exists to prevent. * * Matching is WHOLE-UTTERANCE ONLY. "Amen" is a title of Christ in Revelation * 3:14 and a deity in an Exodus sermon; "can I get an amen?" is a sentence. * None of those may be touched, and equality matching means none of them are. */ (function (root, factory) { if (typeof module === 'object' && module.exports) module.exports = factory(); else root.Liturgy = factory(); }(typeof self !== 'undefined' ? self : this, function () { 'use strict'; /* * Whisper writes these many ways: "Amen", "amen!", "A-men.", "Amen...". * * Hyphens are removed (A-men -> amen) but whitespace is COLLAPSED, not * deleted. Deleting it turned "praise god" into "praisegod", which could * never match a table key — so every multi-word entry would have been a * silent no-op. Only single words are in the table today, so this was latent; * fixing it now means a multi-word entry added later actually works. */ function key(text) { return String(text || '') .toLowerCase() .replace(/[‘’']/g, '') .replace(/[-‐-―]+/g, '') // A-men -> amen .replace(/\s+/g, ' ') // collapse, do NOT delete .replace(/[.!?,;:…。!?]+$/g, '') .trim(); } /* * Confidence is recorded per language, not assumed. HIGH = a form I can state * without hedging. REVIEW = believed correct and worth a native speaker's * glance before a service. A language absent from a table falls through to * NLLB — no entry is better than a confident wrong one. */ const REVIEW = { vie_Latn: 1, hin_Deva: 1, hat_Latn: 1, arb_Arab: 1, kor_Hang: 1, npi_Deva: 1 }; const AMEN = { spa_Latn: 'Amén.', por_Latn: 'Amém.', por_PT: 'Amém.', fra_Latn: 'Amen.', deu_Latn: 'Amen.', ita_Latn: 'Amen.', nld_Latn: 'Amen.', pol_Latn: 'Amen.', ces_Latn: 'Amen.', swe_Latn: 'Amen.', dan_Latn: 'Amen.', fin_Latn: 'Aamen.', hun_Latn: 'Ámen.', cat_Latn: 'Amén.', ron_Latn: 'Amin.', tur_Latn: 'Âmin.', ell_Grek: 'Αμήν.', rus_Cyrl: 'Аминь.', ukr_Cyrl: 'Амінь.', srp_Cyrl: 'Амин.', swh_Latn: 'Amina.', zho_Hans: '阿们。', zho_Hant: '阿們。', kor_Hang: '아멘.', vie_Latn: 'A-men.', hat_Latn: 'Amèn.', arb_Arab: 'آمين.', hin_Deva: 'आमीन।', urd_Arab: 'آمین۔', pes_Arab: 'آمین.' }; const HALLELUJAH = { spa_Latn: '¡Aleluya!', por_Latn: 'Aleluia!', por_PT: 'Aleluia!', fra_Latn: 'Alléluia !', deu_Latn: 'Halleluja!', ita_Latn: 'Alleluia!', nld_Latn: 'Halleluja!', pol_Latn: 'Alleluja!', ces_Latn: 'Aleluja!', swe_Latn: 'Halleluja!', dan_Latn: 'Halleluja!', fin_Latn: 'Halleluja!', hun_Latn: 'Halleluja!', cat_Latn: 'Al·leluia!', ron_Latn: 'Aleluia!', ell_Grek: 'Αλληλούια!', rus_Cyrl: 'Аллилуйя!', ukr_Cyrl: 'Алілуя!', srp_Cyrl: 'Алилуја!', zho_Hans: '哈利路亚!', zho_Hant: '哈利路亞!', kor_Hang: '할렐루야!', vie_Latn: 'Ha-lê-lu-gia!', hat_Latn: 'Alelouya!', arb_Arab: 'هللويا!' }; const HOSANNA = { spa_Latn: '¡Hosanna!', por_Latn: 'Hosana!', por_PT: 'Hosana!', fra_Latn: 'Hosanna !', deu_Latn: 'Hosianna!', ita_Latn: 'Osanna!', nld_Latn: 'Hosanna!', pol_Latn: 'Hosanna!', rus_Cyrl: 'Осанна!', ell_Grek: 'Ωσαννά!', zho_Hans: '和散那!', zho_Hant: '和散那!', kor_Hang: '호산나!', hat_Latn: 'Ozana!' }; const PHRASES = { amen: AMEN, hallelujah: HALLELUJAH, halleluyah: HALLELUJAH, alleluia: HALLELUJAH, hosanna: HOSANNA, hosana: HOSANNA }; /* The whole utterance, or nothing. Returns null so callers fall through to normal translation, which must stay the default path. */ /* A regional variant inherits its base language's forms. Without this a Spain or Portugal listener falls through to NLLB for the single most frequent utterance in the service. Canonical list: NLLB_ALIAS. */ const VARIANT_OF = { por_PT: 'por_Latn', spa_ES: 'spa_Latn', spa_MX: 'spa_Latn' }; function lookup(text, lang) { const table = PHRASES[key(text)]; if (!table) return null; return table[lang] || table[VARIANT_OF[lang]] || null; } function needsReview(lang) { return !!REVIEW[lang]; } function phrases() { return Object.keys(PHRASES); } return { lookup, key, needsReview, phrases, PHRASES }; }));