Fourteen English strings in a .js module reached readers in every locale
gospel-resource-rows.js builds each resource row's display text, and its fallbacks were English literals: a record with no name of its own showed "Scripture in this language", "Audio Scripture", "Listen in a browser" to an Arabic or Chinese reader — precisely the rows whose source data was least complete. check:hardcoded-english does not read .js files, which is why the bundle's sweep never saw them. Thirteen keys in eleven locales, and the translator is PASSED IN rather than imported: the module is a pure function with no component context, and it stays optional, so a caller without one degrades to the English written at the call site instead of throwing. Three publisher names stay verbatim — JESUS Film, Scripture Earth, Zume — but where a name sits inside an ordinary phrase the phrase is keyed and the name is INTERPOLATED, so "Zume discipleship training" translates around a brand a translator never retypes. SE_KIND's values are displayed and take keys; its keys are the upstream feed's codes and must not be touched. Verified by running the module both ways: without a translator every row reads as it does today; with an Arabic one the labels and scopes are Arabic while "Scripture Earth" and "Zume" are unchanged. ROUTED TO STUDIO, not self-landed: the eleven locale files make this a library change. The route test says 11, and the last time I judged a landing by which plugin the work was for rather than which directories it touched, the scan ran against most of the fleet and timed out twice.
This commit is contained in:
parent
47937dea3b
commit
404b2c866e
13 changed files with 209 additions and 12 deletions
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "لا شيء موجود، ولا أحد يصلّي",
|
||||
"concentrates": "أين تتركّز الفجوة",
|
||||
"linkUnchecked": "لم يتم فحص هذا الرابط."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "الكتاب المقدس بهذه اللغة",
|
||||
"audio": "الكتاب المقدس",
|
||||
"bibleVideo": "فيديو كتابي",
|
||||
"gospelPresentation": "عرض الإنجيل",
|
||||
"studyNotes": "ملاحظات دراسية",
|
||||
"readOnline": "القراءة عبر الإنترنت",
|
||||
"audioScripture": "كتاب مقدس مسموع",
|
||||
"listenBrowser": "استمع في المتصفح",
|
||||
"inBrowser": "في المتصفح — {media}",
|
||||
"readHere": "اقرأ بهذه اللغة",
|
||||
"listenHere": "استمع بهذه اللغة",
|
||||
"wordsOfLife": "كلمات الحياة — {name}",
|
||||
"gospelAudio": "تسجيلات الإنجيل",
|
||||
"discipleship": "تدريب {brand} على صناعة التلاميذ"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Nichts gefunden, und niemand betet",
|
||||
"concentrates": "Wo sich die Lücke ballt",
|
||||
"linkUnchecked": "Dieser Link wurde nicht geprüft."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Bibel in dieser Sprache",
|
||||
"audio": "Bibel",
|
||||
"bibleVideo": "Bibelvideo",
|
||||
"gospelPresentation": "Evangeliumsdarstellung",
|
||||
"studyNotes": "Studiennotizen",
|
||||
"readOnline": "online lesen",
|
||||
"audioScripture": "Bibel als Audio",
|
||||
"listenBrowser": "Im Browser anhören",
|
||||
"inBrowser": "Im Browser — {media}",
|
||||
"readHere": "In dieser Sprache lesen",
|
||||
"listenHere": "In dieser Sprache hören",
|
||||
"wordsOfLife": "Worte des Lebens — {name}",
|
||||
"gospelAudio": "Evangeliums-Audio",
|
||||
"discipleship": "{brand} Jüngerschafts-Schulung"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Nothing found, and nobody praying",
|
||||
"concentrates": "Where the gap concentrates",
|
||||
"linkUnchecked": "This link has not been checked."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Scripture in this language",
|
||||
"audio": "Scripture",
|
||||
"bibleVideo": "Bible video",
|
||||
"gospelPresentation": "Gospel presentation",
|
||||
"studyNotes": "study notes",
|
||||
"readOnline": "read online",
|
||||
"audioScripture": "Audio Scripture",
|
||||
"listenBrowser": "Listen in a browser",
|
||||
"inBrowser": "In a browser — {media}",
|
||||
"readHere": "Read in this language",
|
||||
"listenHere": "Listen in this language",
|
||||
"wordsOfLife": "Words of Life — {name}",
|
||||
"gospelAudio": "Gospel audio",
|
||||
"discipleship": "{brand} discipleship training"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Nada encontrado, y nadie orando",
|
||||
"concentrates": "Dónde se concentra la brecha",
|
||||
"linkUnchecked": "Este enlace no ha sido verificado."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Escritura en esta lengua",
|
||||
"audio": "Escritura",
|
||||
"bibleVideo": "Video bíblico",
|
||||
"gospelPresentation": "Presentación del evangelio",
|
||||
"studyNotes": "notas de estudio",
|
||||
"readOnline": "leer en línea",
|
||||
"audioScripture": "Escritura en audio",
|
||||
"listenBrowser": "Escuchar en el navegador",
|
||||
"inBrowser": "En el navegador — {media}",
|
||||
"readHere": "Leer en esta lengua",
|
||||
"listenHere": "Escuchar en esta lengua",
|
||||
"wordsOfLife": "Palabras de Vida — {name}",
|
||||
"gospelAudio": "Audio del evangelio",
|
||||
"discipleship": "formación de discipulado {brand}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Rien trouvé, et personne ne prie",
|
||||
"concentrates": "Où l’écart se concentre",
|
||||
"linkUnchecked": "Ce lien n’a pas été vérifié."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Écriture dans cette langue",
|
||||
"audio": "Écriture",
|
||||
"bibleVideo": "Vidéo biblique",
|
||||
"gospelPresentation": "Présentation de l’Évangile",
|
||||
"studyNotes": "notes d’étude",
|
||||
"readOnline": "lire en ligne",
|
||||
"audioScripture": "Écriture audio",
|
||||
"listenBrowser": "Écouter dans le navigateur",
|
||||
"inBrowser": "Dans le navigateur — {media}",
|
||||
"readHere": "Lire dans cette langue",
|
||||
"listenHere": "Écouter dans cette langue",
|
||||
"wordsOfLife": "Paroles de Vie — {name}",
|
||||
"gospelAudio": "Audio de l’Évangile",
|
||||
"discipleship": "formation au discipulat {brand}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "कुछ नहीं मिला, और कोई प्रार्थना नहीं कर रहा",
|
||||
"concentrates": "अंतर कहाँ केंद्रित है",
|
||||
"linkUnchecked": "यह लिंक जाँचा नहीं गया है।"
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "इस भाषा में पवित्रशास्त्र",
|
||||
"audio": "पवित्रशास्त्र",
|
||||
"bibleVideo": "बाइबल वीडियो",
|
||||
"gospelPresentation": "सुसमाचार प्रस्तुति",
|
||||
"studyNotes": "अध्ययन टिप्पणियाँ",
|
||||
"readOnline": "ऑनलाइन पढ़ें",
|
||||
"audioScripture": "ऑडियो पवित्रशास्त्र",
|
||||
"listenBrowser": "ब्राउज़र में सुनें",
|
||||
"inBrowser": "ब्राउज़र में — {media}",
|
||||
"readHere": "इस भाषा में पढ़ें",
|
||||
"listenHere": "इस भाषा में सुनें",
|
||||
"wordsOfLife": "जीवन के वचन — {name}",
|
||||
"gospelAudio": "सुसमाचार ऑडियो",
|
||||
"discipleship": "{brand} शिष्यत्व प्रशिक्षण"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Nulla trovato, e nessuno in preghiera",
|
||||
"concentrates": "Dove si concentra il divario",
|
||||
"linkUnchecked": "Questo collegamento non è stato verificato."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Scrittura in questa lingua",
|
||||
"audio": "Scrittura",
|
||||
"bibleVideo": "Video biblico",
|
||||
"gospelPresentation": "Presentazione del vangelo",
|
||||
"studyNotes": "note di studio",
|
||||
"readOnline": "leggi online",
|
||||
"audioScripture": "Scrittura audio",
|
||||
"listenBrowser": "Ascolta nel browser",
|
||||
"inBrowser": "Nel browser — {media}",
|
||||
"readHere": "Leggi in questa lingua",
|
||||
"listenHere": "Ascolta in questa lingua",
|
||||
"wordsOfLife": "Parole di Vita — {name}",
|
||||
"gospelAudio": "Audio del vangelo",
|
||||
"discipleship": "formazione al discepolato {brand}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Nada encontrado, e ninguém orando",
|
||||
"concentrates": "Onde a lacuna se concentra",
|
||||
"linkUnchecked": "Este link não foi verificado."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Escritura nesta língua",
|
||||
"audio": "Escritura",
|
||||
"bibleVideo": "Vídeo bíblico",
|
||||
"gospelPresentation": "Apresentação do evangelho",
|
||||
"studyNotes": "notas de estudo",
|
||||
"readOnline": "ler online",
|
||||
"audioScripture": "Escritura em áudio",
|
||||
"listenBrowser": "Ouvir no navegador",
|
||||
"inBrowser": "No navegador — {media}",
|
||||
"readHere": "Ler nesta língua",
|
||||
"listenHere": "Ouvir nesta língua",
|
||||
"wordsOfLife": "Palavras de Vida — {name}",
|
||||
"gospelAudio": "Áudio do evangelho",
|
||||
"discipleship": "treinamento de discipulado {brand}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Nimic găsit și nimeni nu se roagă",
|
||||
"concentrates": "Unde se concentrează golul",
|
||||
"linkUnchecked": "Acest link nu a fost verificat."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Scriptura în această limbă",
|
||||
"audio": "Scriptură",
|
||||
"bibleVideo": "Video biblic",
|
||||
"gospelPresentation": "Prezentarea Evangheliei",
|
||||
"studyNotes": "note de studiu",
|
||||
"readOnline": "citește online",
|
||||
"audioScripture": "Scriptură audio",
|
||||
"listenBrowser": "Ascultă în browser",
|
||||
"inBrowser": "În browser — {media}",
|
||||
"readHere": "Citește în această limbă",
|
||||
"listenHere": "Ascultă în această limbă",
|
||||
"wordsOfLife": "Cuvintele Vieții — {name}",
|
||||
"gospelAudio": "Audio al Evangheliei",
|
||||
"discipleship": "instruire de ucenicizare {brand}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "Ничего не найдено, и никто не молится",
|
||||
"concentrates": "Где сосредоточен разрыв",
|
||||
"linkUnchecked": "Эта ссылка не проверялась."
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "Писание на этом языке",
|
||||
"audio": "Писание",
|
||||
"bibleVideo": "Библейское видео",
|
||||
"gospelPresentation": "Изложение Евангелия",
|
||||
"studyNotes": "учебные заметки",
|
||||
"readOnline": "читать онлайн",
|
||||
"audioScripture": "Аудио-Писание",
|
||||
"listenBrowser": "Слушать в браузере",
|
||||
"inBrowser": "В браузере — {media}",
|
||||
"readHere": "Читать на этом языке",
|
||||
"listenHere": "Слушать на этом языке",
|
||||
"wordsOfLife": "Слова жизни — {name}",
|
||||
"gospelAudio": "Аудио Евангелия",
|
||||
"discipleship": "обучение ученичеству {brand}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,5 +420,21 @@
|
|||
"nobodyPraying": "一无所获,也无人祷告",
|
||||
"concentrates": "差距集中在哪里",
|
||||
"linkUnchecked": "此链接尚未核查。"
|
||||
},
|
||||
"rows": {
|
||||
"scriptureHere": "这种语言的圣经",
|
||||
"audio": "圣经",
|
||||
"bibleVideo": "圣经视频",
|
||||
"gospelPresentation": "福音陈述",
|
||||
"studyNotes": "研读注释",
|
||||
"readOnline": "在线阅读",
|
||||
"audioScripture": "有声圣经",
|
||||
"listenBrowser": "在浏览器中收听",
|
||||
"inBrowser": "在浏览器中 — {media}",
|
||||
"readHere": "用这种语言阅读",
|
||||
"listenHere": "用这种语言收听",
|
||||
"wordsOfLife": "生命之道 — {name}",
|
||||
"gospelAudio": "福音录音",
|
||||
"discipleship": "{brand} 门徒训练"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,21 +41,36 @@ export const hasReadableScripture = (c) =>
|
|||
*/
|
||||
|
||||
/** Scripture Earth directory names, as a reader would say them. */
|
||||
const SE_KIND = { PDF: 'PDF', audio: 'audio', sab: 'app', study: 'study notes', viewer: 'read online' }
|
||||
// The VALUES here are displayed (joined into a row's scope), so they are labels and take keys; the
|
||||
// KEYS are the upstream feed's own codes and must never be translated. PDF/audio/app stay as they
|
||||
// are: an abbreviation and two words that are the same token in the locales we ship.
|
||||
const SE_KIND = (tx) => ({ PDF: 'PDF', audio: 'audio', sab: 'app',
|
||||
study: tx('gospel.rows.studyNotes', 'study notes'), viewer: tx('gospel.rows.readOnline', 'read online') })
|
||||
|
||||
/**
|
||||
* Every resource a language offers, flattened for a list or a table.
|
||||
* @param {object} c one entry of the pin index's codes[]
|
||||
* @returns {{url:string,title:string,type:string,scope:string}[]}
|
||||
*/
|
||||
export function resourceRows(c) {
|
||||
// ★ THE FALLBACKS BELOW ARE UI TEXT, NOT DATA. Each `c.x || 'English'` is shown when a record
|
||||
// carries no name of its own, so an Arabic or Chinese reader saw English for exactly the rows whose
|
||||
// source was least complete. check:hardcoded-english does not read .js files yet, which is why these
|
||||
// survived the bundle's sweep.
|
||||
//
|
||||
// `t` is PASSED IN rather than imported: this module is a pure function with no component context,
|
||||
// and the plugin already threads its translator the same way. It is optional and falls back to the
|
||||
// English written here, so a caller without a translator degrades to today's behaviour.
|
||||
//
|
||||
// 'JESUS Film' below is deliberately NOT keyed: it is the project's name, not a label.
|
||||
export function resourceRows(c, t = null) {
|
||||
const tx = (key, en) => { try { const v = t && t(key); return v && v !== key ? v : en } catch (_) { return en } }
|
||||
if (!c) return []
|
||||
const out = []
|
||||
const add = (title, type, url, scope = '') => {
|
||||
if (url) out.push({ url, title, type, scope })
|
||||
}
|
||||
|
||||
add(c.sv || 'Scripture in this language', 'Scripture', c.s, c.ss || '')
|
||||
add(c.sv || tx('gospel.rows.scriptureHere', 'Scripture in this language'), 'Scripture', c.s, c.ss || '')
|
||||
/* c.fT is set only where the JESUS Film component does NOT carry this language and a
|
||||
different JESUS Film Project feature does — The Savior, Magdalena. Calling that "JESUS
|
||||
Film" would be the same class of lie as calling Open Bible Stories Scripture. */
|
||||
|
|
@ -66,26 +81,32 @@ export function resourceRows(c) {
|
|||
if (c.au) {
|
||||
const media = String(c.au.m || 'audio')
|
||||
add(
|
||||
c.au.n || 'Scripture',
|
||||
c.au.n || tx('gospel.rows.audio', 'Scripture'),
|
||||
/* ⚠ ONE RECORD, TWO CAPABILITIES, AND THE TYPE ONLY SAID ONE. Faith Comes By Hearing's media
|
||||
list is often "audio, text, video": this typed every such row 'Audio Scripture', so the
|
||||
access table's byType.Scripture never saw it and 2,001 people groups were published as
|
||||
"watch or hear, cannot read" while their own readable text sat behind that link. TEXT
|
||||
decides the type; the media list stays in the scope so nothing is hidden, and the access
|
||||
builder counts a Scripture row whose scope names audio as hearable too. */
|
||||
/text/.test(media) ? 'Scripture' : 'Audio Scripture',
|
||||
/text/.test(media) ? tx('gospel.rows.audio', 'Scripture') : tx('gospel.rows.audioScripture', 'Audio Scripture'),
|
||||
c.au.u,
|
||||
media === 'audio' ? 'Listen in a browser' : `In a browser — ${media}`,
|
||||
media === 'audio' ? tx('gospel.rows.listenBrowser', 'Listen in a browser')
|
||||
: tx('gospel.rows.inBrowser', 'In a browser — {media}').replace('{media}', media),
|
||||
)
|
||||
}
|
||||
if (c.bv) add(c.bv.n || 'Bible video', 'Bible video', c.bv.u, c.bv.sc || '')
|
||||
if (c.gp) add(c.gp.n || 'Gospel presentation', 'Gospel presentation', c.gp.u, 'Read in this language')
|
||||
if (c.bv) add(c.bv.n || tx('gospel.rows.bibleVideo', 'Bible video'), 'Bible video', c.bv.u, c.bv.sc || '')
|
||||
if (c.gp) add(c.gp.n || tx('gospel.rows.gospelPresentation', 'Gospel presentation'), 'Gospel presentation', c.gp.u, tx('gospel.rows.readHere', 'Read in this language'))
|
||||
if (c.se) {
|
||||
add('Scripture Earth', 'Scripture', c.se.u, (c.se.k || []).map((k) => SE_KIND[k] || k).join(', '))
|
||||
add('Scripture Earth', 'Scripture', c.se.u, (c.se.k || []).map((k) => SE_KIND(tx)[k] || k).join(', '))
|
||||
}
|
||||
if (c.ga) {
|
||||
add(c.ga.n ? `Words of Life — ${c.ga.n}` : 'Gospel audio', 'Gospel audio', c.ga.u, 'Listen in this language')
|
||||
add(c.ga.n ? tx('gospel.rows.wordsOfLife', 'Words of Life — {name}').replace('{name}', c.ga.n)
|
||||
: tx('gospel.rows.gospelAudio', 'Gospel audio'), 'Gospel audio', c.ga.u,
|
||||
tx('gospel.rows.listenHere', 'Listen in this language'))
|
||||
}
|
||||
add('Zume discipleship training', 'Discipleship training', c.z)
|
||||
// The brand is INTERPOLATED, not retyped by a translator: "Zume" is the publisher's name and must
|
||||
// survive every locale unchanged, while "discipleship training" is an ordinary noun phrase.
|
||||
add(tx('gospel.rows.discipleship', '{brand} discipleship training').replace('{brand}', 'Zume'),
|
||||
'Discipleship training', c.z)
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ const languages = computed(() => {
|
|||
// listed only c.s and c.d, so film, audio, Bible video, tracts, Scripture Earth and
|
||||
// GRN never appeared here — a language whose only resource was a Words of Life
|
||||
// recording rendered with no links while the map offered a working one.
|
||||
const res = resourceRows(c)
|
||||
const res = resourceRows(c, tr)
|
||||
e = {
|
||||
iso: code,
|
||||
language: c.l || 'unknown',
|
||||
|
|
|
|||
Loading…
Reference in a new issue