63 lines
3.2 KiB
JavaScript
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)`)
|