doxa-maps/plugin-designs/gospel-resources/scripts/fetch-iso-macrolanguages.mjs
Doxa Maps e19697673d
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Doxa Maps — the map bundler, 7 production plugins and the Experimental shelf
2026-09-25 20:07:59 +00:00

63 lines
3.2 KiB
JavaScript

#!/usr/bin/env node
/**
* fetch-iso-macrolanguages.mjs — snapshot SIL's ISO 639-3 macrolanguage mappings.
*
* WHAT IT IS FOR. The single largest entry in this map's gap list is "Chinese, Jinyu —
* 60.3 million people — nothing found", followed by Gan at 41.3M. Both are true statements
* about those ISO codes and both are misleading as priorities: ISO 639-3 files them as
* members of the macrolanguage `zho`, alongside `cmn` (Mandarin), which has Scripture, film,
* audio and training here. A worker reading the gap list top-down would be sent to the two
* places least likely to need them.
*
* Measured: 84 people-group pins covering 140M people sit at "nothing found" while a sibling
* variety of their own ISO macrolanguage carries resources.
*
* WHAT THIS IS NOT. Macrolanguage membership is NOT a claim of mutual intelligibility, and
* the map must never present it as one. Spoken Jinyu and spoken Mandarin are not mutually
* intelligible; what they share is a written standard. ISO's own relation is the only thing
* asserted here — "the standard files these as varieties of one language" — and the reader
* is told exactly that, so they can judge it. It changes no tier and closes no gap.
*
* The table is fetched rather than transcribed so it cannot silently go stale, and it is
* written through the snapshot guard like every other catalogue here.
*/
import { writeSnapshot } from './_snapshot-guard.mjs'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const HERE = dirname(fileURLToPath(import.meta.url))
const OUT = resolve(HERE, '../../..', 'data/tables/iso-macrolanguages.json')
const SRC = 'https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3-macrolanguages.tab'
const UA = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
const res = await fetch(SRC, { headers: { 'user-agent': UA }, signal: AbortSignal.timeout(60000) })
if (!res.ok) throw new Error(`macrolanguages.tab: HTTP ${res.status}`)
const text = await res.text()
const lines = text.trim().split('\n').slice(1)
if (lines.length < 300) throw new Error(`macrolanguages.tab gave only ${lines.length} rows — refusing to run on a truncated table`)
// I_Status 'A' is active; 'R' is retired. A retired membership is not a current fact.
const macroOf = {}
const members = {}
let retired = 0
for (const line of lines) {
const [m, i, st] = line.split('\t')
if ((st || '').trim() !== 'A') { retired++; continue }
macroOf[i] = m
;(members[m] = members[m] || []).push(i)
}
writeSnapshot(
OUT,
`${JSON.stringify({
_note: 'ISO 639-3 macrolanguage membership from SIL. Active memberships only. NOT a claim of mutual intelligibility — it is only what the standard files together.',
source: SRC,
generated: new Date().toISOString().slice(0, 10),
counts: { rows: lines.length, active: Object.keys(macroOf).length, retired, macrolanguages: Object.keys(members).length },
macroOf,
members,
}, null, 1)}\n`,
(j) => Object.keys(j.macroOf || {}).length,
'active ISO 639-3 macrolanguage memberships',
)
console.log(`ISO-MACRO: ${Object.keys(macroOf).length} active memberships across ${Object.keys(members).length} macrolanguages (${retired} retired rows skipped)`)