diff --git a/package.json b/package.json index a7ac26253..b877e1f88 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "check:i18n-treeshake": "node internal/check-i18n-treeshake.mjs", "check:kpi-unit": "node internal/check-kpi-unit-once.mjs", "check:label-joins": "node internal/check-label-joins.mjs", + "check:language-code-link": "node plugin-designs/doxa-research-map/scripts/check-language-code-link.mjs", "check:leaf-engine-per-provider": "node internal/check-leaf-engine-per-provider.mjs", "check:leaf-english-leaks": "node internal/check-leaf-english-leaks.mjs", "check:leaf-english-leaks:self-test": "node internal/check-leaf-english-leaks.mjs --self-test", @@ -310,6 +311,7 @@ "check:host-locale-contract": "a HOST's profile-config.locale reaches every leaf: each leaf page is loaded with ONLY \"locale\":\"ar\" added to its profile-config (no ?lang=, the page keeps lang=\"en\") and must draw at least half the Arabic text the same page draws at ?lang=ar. regions-dashboard/regions-list is the positive control (NOT MEASURED if it does not enter Arabic). Guards ProfileLoader's inject('appI18n'): a bundle that never provides appI18n silently ignores the host. --dir for a before/after, --only a/b,c/d to narrow. Through browser-slot.sh.", "check:i18n-never-translated": "a key PRESENT in all 11 catalogs but IDENTICAL in all of them is copied, not translated. check:i18n-parity asserts presence; presence and translatedness are different properties. Carries an allowlist for keys correctly identical everywhere (pure format strings, brand names, ISO designations) — each with a reason, so the list records decisions rather than silencing findings.", "check:i18n-treeshake": "each built bundle carries every translation area its code asks for: every area-prefixed key literal in .js belongs to an area the build included (the build narrows library/i18n's catalogue glob per bundle, internal/i18n-areas.mjs). Headless.", + "check:language-code-link": "the map's language selection reaches the grid as a locale-stable CODE, or narrows nothing at all. rega measured Languages > Language > \"Arabic\" taking the grid 2,107 -> 0 in BOTH locales: the emitter looked for a row whose language LABEL equalled the selected name, but a language tier's label is derived by splitting the API label at the comma, and no row reads \"Arabic\" - they read \"Arabic, Sudanese\", \"Arabic, Levantine\", 22 codes in all. Lifts the emitter's match rule and the composite's gridLanguage() from the shipping source (never re-typed) and runs them against a committed fixture of the 864 distinct language label/value pairs: the emitter's rule must agree with the legend's own three-arm filter on every (label, tier) pair, every tier must select at least one row, a tier covering one code must emit it, a tier covering several must emit NONE and leave the axis unfiltered. No network, no browser; --refresh-fixture re-takes the fixture.", "check:leaf-engine-per-provider": "every leaf in the manifest at ?provider=maplibre makes ZERO requests to any *.mapbox.com host and a map leaf still draws; at its default every map leaf draws with the engine it drew with before (read from the canvas that drew). --baseline compares against another tree (e.g. main). Browser gate, @browser-slot-max-hold 2700.", "check:leaves-mount": "DID THE ELEMENT ACTUALLY MOUNT, on all five gospel leaves. Exists because a ReferenceError thrown during setup dies INSIDE the custom-element boundary: the page loads, every asset returns 200, pageerror fires zero times, and the element sits there with an empty shadow root. A healthy-looking dead page. This asks the cheap unambiguous question the rich gates are too slow to ask on every leaf — is anything there — in five steps that each name their own failure: tag defined, host present, shadowRoot attached, shadow root non-empty, visible text rendered. It does NOT trust the absence of console errors; zero errors is not the same as working. --poison for the negative test.", "check:legend-export-reachable": "the Export affordance must be reachable at BOTH widths. Selects a leaf row first (the control is gated on selectedNode) and opens the mobile sheet first (it starts closed). Asserts a REAL BOX, not CSS visibility — on mobile the elements report visibility:visible at 0x0. PASSES at both widths since the mobile sheet was given :export-enabled and :tabs. SKIPs when nothing is served.", diff --git a/plugin-designs/doxa-research-map/research-map.vue b/plugin-designs/doxa-research-map/research-map.vue index 647c85ffd..330dc6c89 100644 --- a/plugin-designs/doxa-research-map/research-map.vue +++ b/plugin-designs/doxa-research-map/research-map.vue @@ -2182,29 +2182,74 @@ function emitFilterState() { // // The NAME still goes out because this map's own legend selects by name; the CODE goes out for // anyone matching rows. Both halves get the form they can actually use. + // ★ THE LOOKUP HAS TO MATCH THE WAY THE LEGEND BUILT THE LABEL (rega, 2026-09-26, main 49992a5d: + // MapLibre, BOTH locales, Languages > Language > "Arabic" -> languageCode:"" -> grid 2,107 -> 0). + // + // WHAT I GOT WRONG. This found a row whose language LABEL equals the selected name with `===`. + // A language node's label is NOT a label any row carries: useLanguageFamilyLegendData builds the + // tree family > language > dialect, and the LANGUAGE tier's label is a BASE NAME derived by + // splitting the API label at the comma. MEASURED against the live source (2,107 rows, all 2,107 + // carrying primary_language as {value,label}): there is NO row whose label is "Arabic". What + // exists is "Arabic, Sudanese", "Arabic, Levantine", "Arabic, Gulf", ... So the exact match could + // never hit, in any locale — which is why rega saw it fail identically in en and ar, and why the + // locale fix that prompted this code was right about the DISEASE and wrong about this line. + // + // This is the derived-value trap, one tier down from where I last wrote it up: a value that + // crosses a component boundary must exist on a row, or the two ends are comparing different + // things. "Arabic" is a GROUPING the legend invented; `primary_language.label` is a FIELD. + // + // So the rows are matched the way the legend's own node matches pins — base, comma-prefix, + // space-suffix — rather than by a fourth hand-typed rule that can drift from the other three. const langName = mapStore?.selectedLanguage || '' + // A dialect is a language selection too, and it was emitting nothing at all: the watcher below + // did not observe selectedDialect, so drilling to the deepest tier left the grid on the previous + // state. Its originalLabels ARE exact API labels, so it is the one unambiguous case. + const dialect = mapStore?.selectedDialect || null + const dialectLabels = Array.isArray(dialect?.originalLabels) ? dialect.originalLabels.map((s) => String(s).trim()).filter(Boolean) : [] // Read the records here rather than assuming a `rows` in scope — check:no-free-identifiers caught // exactly that on its first outing against this very edit, which is the class of bug it is for. const langRows = mapData?.normalizedPeopleGroups?.value || [] - const langCode = langName - ? String( - (langRows.find((r) => { - const l = r && (r.language ?? r.primary_language) - const lab = l && typeof l === 'object' ? l.label : l - return String(lab || '').trim() === String(langName).trim() - }) || {})._raw?.primary_language?.value || '' - ).trim() - : '' + const rowLangLabel = (r) => { + const l = r && (r.language ?? r.primary_language) + return String((l && typeof l === 'object' ? l.label : l) || '').trim() + } + // The legend node's own predicate, in JS. Keep these three arms in step with the `filter` + // expression in useLanguageFamilyLegendData.js — they are the same rule, and a fourth spelling + // of it is how this broke in the first place. + const matchesLanguage = (lab, base) => + lab === base || lab.startsWith(base + ',') || lab.includes(' ' + base) + const selectedRows = dialectLabels.length + ? langRows.filter((r) => dialectLabels.includes(rowLangLabel(r))) + : (langName ? langRows.filter((r) => matchesLanguage(rowLangLabel(r), langName.trim())) : []) + // ★ ONE CODE ONLY WHEN THERE IS ONE. "Arabic" covers many ISO 639-3 codes (apd, acm, ayl, ...), + // so there is no single value that means it, and inventing one would filter the grid to a + // fraction of the selection while looking like it worked. Emitting '' is the honest answer, and + // the composite's job is then to NOT narrow on an axis it cannot express (fail OPEN) rather than + // to narrow to nothing. The full set travels alongside for any consumer that can use a set. + const langCodes = [...new Set(selectedRows + .map((r) => String(r?._raw?.primary_language?.value || (r?.language && typeof r.language === 'object' ? r.language.value : '') || '').trim()) + .filter(Boolean))] + const langCode = langCodes.length === 1 ? langCodes[0] : '' const detail = { region: mapStore?.selectedRegion || '', religion: religionName, - language: langName, + // A dialect selection reports the dialect's own display name, so a host that shows the value + // shows what the user clicked rather than its parent. + language: dialectLabels.length ? (dialect?.key ? `${langName}, ${dialect.key}` : langName) : langName, languageCode: langCode, + // ADDITIVE: every code the selection covers, so a consumer with multi-value filtering can + // narrow correctly where a single code cannot express the selection. Existing listeners that + // only read `languageCode` are unaffected. + languageCodes: langCodes, } host.dispatchEvent(new CustomEvent('map-filtered', { detail, bubbles: true, composed: true })) } -watch(() => [mapStore?.selectedRegion, mapStore?.selectedLanguage, uiStore?.religionFilter], +// selectedDialect joins the sources: it is the deepest tier of the Language tree and a genuine +// language selection, but it was not observed here, so drilling from "Arabic" to "Arabic, Sudanese" +// changed the map and left the grid reporting the tier above. `.key` rather than the object, +// because the store replaces it wholesale and a deep watch here would re-emit on every re-render. +watch(() => [mapStore?.selectedRegion, mapStore?.selectedLanguage, mapStore?.selectedDialect?.key, uiStore?.religionFilter], () => emitFilterState()) // ─── Universal-legend (LegendRows) → applyDimFilter bridge ─────────────────── diff --git a/plugin-designs/doxa-research-map/scripts/check-language-code-link.mjs b/plugin-designs/doxa-research-map/scripts/check-language-code-link.mjs new file mode 100644 index 000000000..9afa2d055 --- /dev/null +++ b/plugin-designs/doxa-research-map/scripts/check-language-code-link.mjs @@ -0,0 +1,205 @@ +#!/usr/bin/env node +/** + * check-language-code-link.mjs — the map's language selection must reach the grid, or narrow nothing. + * + * THE BUG (rega, 2026-09-26, main 49992a5d, MapLibre, BOTH locales). Languages > Language > + * "Arabic": the map emitted `map-filtered` with {language:"Arabic", languageCode:""}, the composite + * handed the grid an empty code, and the grid went 2,107 -> 0. An empty grid reads as "no results", + * which is the worst shape a wiring bug can take — the reader believes the data. + * + * THE CAUSE, and it is one line. The emitter looked for a row whose language LABEL === the selected + * name. A LANGUAGE NODE'S LABEL IS NOT A LABEL ANY ROW CARRIES: useLanguageFamilyLegendData builds + * family > language > dialect and derives the language tier by splitting the API label at the comma. + * MEASURED on the live source: 2,107 rows, all carrying primary_language as {value,label}, and NO + * row whose label is "Arabic" — what exists is "Arabic, Sudanese", "Arabic, Levantine", "Arabic, + * Gulf", 22 codes in all. The exact match could never hit, in any locale, which is why it failed + * identically in en and ar. + * + * ★ THE NUMBERS THIS GATE PINS, measured on the committed fixture (864 distinct label/value pairs, + * 805 base language tiers): + * OLD exact-label rule: 61 tiers resolved "" -> the grid went to zero. "Arabic" was one. + * NEW rule: 764 tiers resolve ONE code (the grid filters), 41 cover several and + * abstain honestly. + * The 41 are real ambiguity, not a bug: "Arabic" alone means 22 ISO codes, so no single value can + * express it. Sending one of them would show a fraction of the selection while looking correct; + * sending the tier NAME shows zero. Abstaining is the only option that does not lie, until + * filterSet goes multi-value (SPEC-DASHBOARD-KIT D1). + * + * ★ ONE APPROXIMATION, STATED RATHER THAN HIDDEN. The gate derives the tier set by splitting each + * label at the first comma. The legend derives `langKey` by a longer route (family lookup, suffix + * patterns), so the two sets are close but not provably identical — a tier the legend shows and + * this split does not would go unchecked. What IS exact is the part that broke: check B proves the + * emitter's predicate and the legend's filter agree on every (label, tier) pair, so the two ends + * cannot drift apart again whatever the tier set turns out to be. + * + * WHAT IT CHECKS — all of it against the SHIPPING SOURCE, lifted, never re-typed: + * A. the emitter's match rule exists and is the legend's three-arm rule (base / "base," prefix / + * " base" suffix), evaluated against the fixture. + * B. the legend's own filter expression still has those same three arms — because the ONE thing + * that caused this bug was two spellings of one rule drifting apart. A fourth spelling is the + * next bug, so the gate compares the two that exist. + * C. for every base tier: exactly one code -> a NON-EMPTY languageCode; several -> an EMPTY + * languageCode AND a populated languageCodes. + * D. the composite fails OPEN: gridLanguage() must return '' when the selection covers several + * codes. Returning the label there is what produced the empty grid. + * E. no tier may produce a value that selects zero rows. That is the user-visible invariant and + * it is asserted directly, not inferred. + * + * NO NETWORK, NO BROWSER (Playwright is rega's alone). The fixture is committed and was taken from + * the live source; refresh it with --refresh-fixture when the source's language set changes. + * + * NEGATIVE-TESTED 2026-09-26, each FAILS: + * the emitter's rule reverted to `lab === base` -> A, then C/E naming "Arabic" + * the comma-prefix arm dropped from the emitter -> A (disagrees with the legend) + * the legend's filter arms changed without the emitter -> B + * gridLanguage() reverted to `value || label` -> D + */ +import { readFileSync, writeFileSync, existsSync } from 'node:fs' +import { resolve, dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const TAG = 'LANGUAGE-CODE-LINK' +const HERE = dirname(fileURLToPath(import.meta.url)) +const ROOT = resolve(HERE, '..', '..', '..') +const EMITTER = join(ROOT, 'plugin-designs/doxa-research-map/research-map.vue') +const COMPOSITE = join(ROOT, 'plugin-designs/research-map-plus-grid/research-map-plus-grid.vue') +const LEGEND = join(ROOT, 'library/composables/legends/useLanguageFamilyLegendData.js') +const FIXTURE = join(HERE, 'fixtures', 'language-codes.json') + +const fails = [] +const notes = [] + +// ── --refresh-fixture: the only thing here that touches the network ────────────────────────── +if (process.argv.includes('--refresh-fixture')) { + const sources = JSON.parse(readFileSync(join(ROOT, 'library/api/sources.json'), 'utf8')) + const cfg = sources.sources[sources.activeSource] + const url = `https://pray.doxa.life${cfg.endpoints.bulk}?fields=${cfg.defaultFields.join(',')}&lang=en` + const j = await (await fetch(url, { signal: AbortSignal.timeout(60000) })).json() + const rows = j.posts || j.data || [] + // Deduplicate by the (label,value) PAIR — never sample. Both questions this fixture answers + // (does the exact label exist; how many codes does this tier cover) must be asked of the + // complete language set, or the counts above are about a sample and mean nothing. + const seen = new Set(); const keep = [] + for (const r of rows) { + const l = r.primary_language + if (!l || !l.label || !l.value) continue + const k = l.label + '\u0000' + l.value + if (seen.has(k)) continue + seen.add(k) + keep.push({ primary_language: { value: l.value, label: l.label } }) + } + writeFileSync(FIXTURE, JSON.stringify(keep) + '\n') + console.log(`${TAG}: fixture refreshed — ${rows.length} api rows -> ${keep.length} distinct (label,value) pairs.`) + process.exit(0) +} + +if (!existsSync(FIXTURE)) { console.log(`${TAG}: SKIP — no fixture (run with --refresh-fixture).`); process.exit(0) } +const rows = JSON.parse(readFileSync(FIXTURE, 'utf8')) +const emitterSrc = readFileSync(EMITTER, 'utf8') +const compositeSrc = readFileSync(COMPOSITE, 'utf8') +const legendSrc = readFileSync(LEGEND, 'utf8') + +// ── A. lift the emitter's match rule and run it ────────────────────────────────────────────── +// Lifted, not re-typed: a gate that carries its own copy of the rule passes while the product is +// broken, which is precisely how the bug above survived a green check:linked-vocabulary. +const mRule = /const matchesLanguage = \(lab, base\) =>\s*([\s\S]*?)\n\s*const selectedRows/.exec(emitterSrc) +let matchesLanguage = null +if (!mRule) { + fails.push('A research-map.vue: no `const matchesLanguage = (lab, base) =>` — the emitter\'s match rule moved or was renamed, so this gate is blind to the line that broke.') +} else { + try { matchesLanguage = new Function('lab', 'base', `return (${mRule[1].trim()})`) } catch (e) { + fails.push(`A research-map.vue: the lifted match rule does not evaluate (${e.message}).`) + } +} + +// ── B. the legend's own filter must still be the same three arms ───────────────────────────── +// This is the drift guard. The bug was two spellings of one rule disagreeing; the fix mirrors the +// legend's expression in JS, so the gate's job is to notice when the original moves. +{ + const node = /id:\s*`lang:\$\{fam\.key\}__\$\{langKey\}`[\s\S]*?filter: \[([\s\S]*?)\],\n\s*children: \[\],/.exec(legendSrc) + if (!node) { + fails.push('B useLanguageFamilyLegendData.js: could not find the `lang:` node\'s filter expression — the legend\'s own rule moved, and the emitter mirrors it.') + } else { + const f = node[1] + const arms = [ + [/\['==', \['get', 'language'\], langKey\]/, 'exact match on the base name'], + [/\['==', \['slice', \['get', 'language'\], 0, langKey\.length \+ 1\], langKey \+ ','\]/, 'the "base," comma-prefix arm'], + [/\['in', ' ' \+ langKey, \['get', 'language'\]\]/, 'the " base" suffix-contains arm'], + ] + for (const [re, what] of arms) { + if (!re.test(f)) fails.push(`B useLanguageFamilyLegendData.js: the language node's filter no longer has ${what}. research-map.vue's matchesLanguage() mirrors these three arms — change both together, or the map and the grid select different rows again.`) + } + if (matchesLanguage) { + // And prove the mirror on real data rather than on the text: the JS rule must agree with the + // expression's semantics for every label in the fixture. + const expr = (lab, base) => lab === base || lab.slice(0, base.length + 1) === base + ',' || lab.includes(' ' + base) + let disagreements = 0 + const bases = new Set(rows.map((r) => String(r.primary_language.label).split(',')[0].trim())) + for (const base of bases) for (const r of rows) { + const lab = String(r.primary_language.label).trim() + if (expr(lab, base) !== !!matchesLanguage(lab, base)) disagreements++ + } + if (disagreements) fails.push(`B the emitter's matchesLanguage() disagrees with the legend's filter on ${disagreements} (label, tier) pair(s).`) + else notes.push(`match rule: agrees with the legend's three-arm filter on every one of ${bases.size} tiers x ${rows.length} labels`) + } + } +} + +// ── C/E. every tier resolves to a code, or abstains — and never to an empty grid ────────────── +if (matchesLanguage) { + const byBase = new Map() + for (const r of rows) { + const b = String(r.primary_language.label).split(',')[0].trim() + if (!byBase.has(b)) byBase.set(b, []) + byBase.get(b).push(r) + } + let single = 0, many = 0 + const zeroSelecting = [] + for (const [base, tierRows] of byBase) { + const selected = rows.filter((r) => matchesLanguage(String(r.primary_language.label).trim(), base)) + // E: the tier the user clicked must select SOMETHING. A tier that selects nothing is the + // 2,107 -> 0 screen by another route. + if (!selected.length) { zeroSelecting.push(base); continue } + const codes = [...new Set(selected.map((r) => r.primary_language.value).filter(Boolean))] + const languageCode = codes.length === 1 ? codes[0] : '' + if (codes.length === 1) { + single++ + if (!languageCode) fails.push(`C "${base}" covers exactly one code but resolved an empty languageCode.`) + } else { + many++ + if (languageCode) fails.push(`C "${base}" covers ${codes.length} codes but still emitted a single languageCode — one of them would show a fraction of the selection while looking correct.`) + if (!codes.length) fails.push(`C "${base}" resolved no codes at all.`) + } + } + if (zeroSelecting.length) { + fails.push(`E ${zeroSelecting.length} language tier(s) select ZERO rows, so clicking them empties the grid: ${zeroSelecting.slice(0, 6).join(', ')}`) + } + notes.push(`tiers: ${byBase.size} — ${single} resolve one code (the grid filters), ${many} cover several (the axis is left open)`) + if (many === 0) fails.push('C no tier in the fixture covers several codes, so the ambiguous path is untested — the fixture was sampled rather than deduplicated.') +} + +// ── D. the composite fails OPEN ────────────────────────────────────────────────────────────── +{ + const g = /function gridLanguage\(\) \{([\s\S]*?)\n\}/.exec(compositeSrc) + if (!g) { + fails.push('D research-map-plus-grid.vue: no gridLanguage() — the composite is back to sending `value || label`, which hands the grid a tier NAME no row carries and empties it.') + } else { + let fn = null + try { fn = new Function('linked', `${g[1]}`) } catch (e) { fails.push(`D gridLanguage() does not evaluate (${e.message}).`) } + if (fn) { + const many = { language: { value: '', label: 'Arabic', codes: ['apd', 'acm', 'ayl'] } } + const one = { language: { value: 'ben', label: 'Bengali', codes: ['ben'] } } + if (fn(many) !== '') fails.push(`D gridLanguage() returned ${JSON.stringify(fn(many))} for a selection covering 3 codes — it must return '' and leave the axis unfiltered. Returning the label is what took the grid to 0.`) + if (fn(one) !== 'ben') fails.push(`D gridLanguage() returned ${JSON.stringify(fn(one))} for an unambiguous selection — it must send the single code.`) + if (!fails.some((f) => f.startsWith('D'))) notes.push('composite: gridLanguage() sends the code when there is one and abstains when there is not') + } + } +} + +for (const n of notes) console.log(' · ' + n) +if (fails.length) { + console.error(`\n${TAG}: FAIL`) + for (const f of fails) console.error(' ' + f) + process.exit(1) +} +console.log(`${TAG}: PASS — every language tier reaches the grid as a code, or honestly narrows nothing.`) diff --git a/plugin-designs/doxa-research-map/scripts/fixtures/language-codes.json b/plugin-designs/doxa-research-map/scripts/fixtures/language-codes.json new file mode 100644 index 000000000..0b8935204 --- /dev/null +++ b/plugin-designs/doxa-research-map/scripts/fixtures/language-codes.json @@ -0,0 +1 @@ +[{"primary_language":{"value":"abf","label":"Abai Sungai"}},{"primary_language":{"value":"apd","label":"Arabic, Sudanese"}},{"primary_language":{"value":"tel","label":"Telugu"}},{"primary_language":{"value":"mcd","label":"Sharanahua"}},{"primary_language":{"value":"adi","label":"Adi"}},{"primary_language":{"value":"yea","label":"Ravula"}},{"primary_language":{"value":"aar","label":"Afar"}},{"primary_language":{"value":"aft","label":"Afitti"}},{"primary_language":{"value":"azb","label":"Azerbaijani, South"}},{"primary_language":{"value":"kfr","label":"Kacchi"}},{"primary_language":{"value":"tcy","label":"Tulu"}},{"primary_language":{"value":"mar","label":"Marathi"}},{"primary_language":{"value":"agx","label":"Aghul"}},{"primary_language":{"value":"thm","label":"Aheu"}},{"primary_language":{"value":"urd","label":"Urdu"}},{"primary_language":{"value":"aih","label":"Ai-Cham"}},{"primary_language":{"value":"jpn","label":"Japanese"}},{"primary_language":{"value":"aib","label":"Ainu (China)"}},{"primary_language":{"value":"aio","label":"Aiton"}},{"primary_language":{"value":"krs","label":"Gbaya"}},{"primary_language":{"value":"aks","label":"Akaselem"}},{"primary_language":{"value":"byo","label":"Biyo"}},{"primary_language":{"value":"ahk","label":"Akha"}},{"primary_language":{"value":"acq","label":"Arabic, Ta’izzi-Adeni"}},{"primary_language":{"value":"akv","label":"Akhvakh"}},{"primary_language":{"value":"che","label":"Chechen"}},{"primary_language":{"value":"alk","label":"Alak"}},{"primary_language":{"value":"btz","label":"Batak Alas-Kluet"}},{"primary_language":{"value":"tam","label":"Tamil"}},{"primary_language":{"value":"apc","label":"Arabic, Levantine"}},{"primary_language":{"value":"gwd","label":"Ale"}},{"primary_language":{"value":"yig","label":"Nasu, Wusa"}},{"primary_language":{"value":"mal","label":"Malayalam"}},{"primary_language":{"value":"nos","label":"Nisu, Eastern"}},{"primary_language":{"value":"xal","label":"Kalmyk-Oirat"}},{"primary_language":{"value":"amc","label":"Amahuaca"}},{"primary_language":{"value":"por","label":"Portuguese"}},{"primary_language":{"value":"amr","label":"Amarakaeri"}},{"primary_language":{"value":"cui","label":"Cuiba"}},{"primary_language":{"value":"aeb","label":"Arabic, Tunisian"}},{"primary_language":{"value":"grr","label":"Taznatit"}},{"primary_language":{"value":"jbn","label":"Nafusi"}},{"primary_language":{"value":"bwi","label":"Baniwa"}},{"primary_language":{"value":"rwm","label":"Amba (Uganda)"}},{"primary_language":{"value":"amv","label":"Ambelau"}},{"primary_language":{"value":"adw","label":"Amundava"}},{"primary_language":{"value":"hca","label":"Andaman Hindi Creole"}},{"primary_language":{"value":"ani","label":"Andi"}},{"primary_language":{"value":"cat","label":"Catalan"}},{"primary_language":{"value":"gaz","label":"Oromo, West Central"}},{"primary_language":{"value":"ben","label":"Bengali"}},{"primary_language":{"value":"kkn","label":"Kon Keu"}},{"primary_language":{"value":"spa","label":"Spanish"}},{"primary_language":{"value":"yix","label":"Axi"}},{"primary_language":{"value":"waw","label":"Waiwai"}},{"primary_language":{"value":"mup","label":"Malvi"}},{"primary_language":{"value":"guj","label":"Gujarati"}},{"primary_language":{"value":"kan","label":"Kannada"}},{"primary_language":{"value":"gbm","label":"Garhwali"}},{"primary_language":{"value":"hsn","label":"Chinese, Xiang"}},{"primary_language":{"value":"cmn","label":"Chinese, Mandarin"}},{"primary_language":{"value":"iii","label":"Nuosu"}},{"primary_language":{"value":"ssh","label":"Arabic, Shihhi"}},{"primary_language":{"value":"afb","label":"Arabic, Gulf"}},{"primary_language":{"value":"dgo","label":"Dogri"}},{"primary_language":{"value":"bjj","label":"Kanauji"}},{"primary_language":{"value":"pan","label":"Punjabi"}},{"primary_language":{"value":"tuo","label":"Tucano"}},{"primary_language":{"value":"nld","label":"Dutch"}},{"primary_language":{"value":"awt","label":"Araweté"}},{"primary_language":{"value":"arv","label":"Arbore"}},{"primary_language":{"value":"vie","label":"Vietnamese"}},{"primary_language":{"value":"lao","label":"Lao"}},{"primary_language":{"value":"jle","label":"Ngile"}},{"primary_language":{"value":"prq","label":"Ashéninka, Perené"}},{"primary_language":{"value":"cpu","label":"Ashéninka, Pichis"}},{"primary_language":{"value":"ask","label":"Ashkun"}},{"primary_language":{"value":"asl","label":"Asilulu"}},{"primary_language":{"value":"asn","label":"Asurini of Xingú"}},{"primary_language":{"value":"avv","label":"Avá-Canoeiro"}},{"primary_language":{"value":"ava","label":"Avaric"}},{"primary_language":{"value":"awe","label":"Awetí"}},{"primary_language":{"value":"kfa","label":"Kodava"}},{"primary_language":{"value":"bqx","label":"Baangi"}},{"primary_language":{"value":"shu","label":"Arabic, Chadian"}},{"primary_language":{"value":"hne","label":"Chhattisgarhi"}},{"primary_language":{"value":"hin","label":"Hindi"}},{"primary_language":{"value":"rwr","label":"Marwari (India)"}},{"primary_language":{"value":"pbp","label":"Badyara"}},{"primary_language":{"value":"mbv","label":"Mbulungish"}},{"primary_language":{"value":"sus","label":"Susu"}},{"primary_language":{"value":"bmd","label":"Baga Manduri"}},{"primary_language":{"value":"bsp","label":"Baga Sitemu"}},{"primary_language":{"value":"bqg","label":"Bago-Kusuntu"}},{"primary_language":{"value":"kva","label":"Bagvalal"}},{"primary_language":{"value":"eng","label":"English"}},{"primary_language":{"value":"bcz","label":"Bainouk-Gunyaamolo"}},{"primary_language":{"value":"ory","label":"Odia"}},{"primary_language":{"value":"bls","label":"Balaesang"}},{"primary_language":{"value":"bra","label":"Braj Bhasha"}},{"primary_language":{"value":"asm","label":"Assamese"}},{"primary_language":{"value":"bqk","label":"Banda-Mbrès"}},{"primary_language":{"value":"bqj","label":"Bandial"}},{"primary_language":{"value":"dba","label":"Bangime"}},{"primary_language":{"value":"kas","label":"Kashmiri"}},{"primary_language":{"value":"knn","label":"Konkani"}},{"primary_language":{"value":"npi","label":"Nepali"}},{"primary_language":{"value":"bxw","label":"Bankagooma"}},{"primary_language":{"value":"anp","label":"Angika"}},{"primary_language":{"value":"swh","label":"Swahili"}},{"primary_language":{"value":"bwx","label":"Bunu, Bu-Nao"}},{"primary_language":{"value":"ind","label":"Indonesian"}},{"primary_language":{"value":"bns","label":"Bundeli"}},{"primary_language":{"value":"bva","label":"Barein"}},{"primary_language":{"value":"hoj","label":"Haroti"}},{"primary_language":{"value":"mtr","label":"Mewari"}},{"primary_language":{"value":"bdj","label":"Bai"}},{"primary_language":{"value":"bbt","label":"Burku"}},{"primary_language":{"value":"bsh","label":"Kateviri"}},{"primary_language":{"value":"bsg","label":"Bashkardi"}},{"primary_language":{"value":"gwc","label":"Gawri"}},{"primary_language":{"value":"blo","label":"Anii"}},{"primary_language":{"value":"acx","label":"Arabic, Omani"}},{"primary_language":{"value":"btv","label":"Bateri"}},{"primary_language":{"value":"bvt","label":"Bati (Indonesia)"}},{"primary_language":{"value":"ars","label":"Arabic, Najdi"}},{"primary_language":{"value":"hoz","label":"Hozo"}},{"primary_language":{"value":"hea","label":"Miao, Northern Qiandong"}},{"primary_language":{"value":"bej","label":"Bedawiyet"}},{"primary_language":{"value":"kcy","label":"Korandje"}},{"primary_language":{"value":"blm","label":"Beli (South Sudan)"}},{"primary_language":{"value":"wti","label":"Berta"}},{"primary_language":{"value":"btf","label":"Birgit"}},{"primary_language":{"value":"bdo","label":"Morom"}},{"primary_language":{"value":"bgw","label":"Bhatri"}},{"primary_language":{"value":"kfs","label":"Bilaspuri"}},{"primary_language":{"value":"swv","label":"Shekhawati"}},{"primary_language":{"value":"bhu","label":"Bhunjia"}},{"primary_language":{"value":"bid","label":"Bidiyo"}},{"primary_language":{"value":"soy","label":"Miyobe"}},{"primary_language":{"value":"mne","label":"Naba"}},{"primary_language":{"value":"byn","label":"Bilen"}},{"primary_language":{"value":"yul","label":"Yulu"}},{"primary_language":{"value":"bsy","label":"Bisaya, Sabah"}},{"primary_language":{"value":"bsb","label":"Bisaya, Brunei"}},{"primary_language":{"value":"bgk","label":"Bit"}},{"primary_language":{"value":"blt","label":"Tai Dam"}},{"primary_language":{"value":"bgl","label":"Bo (Laos)"}},{"primary_language":{"value":"brx","label":"Boro (India)"}},{"primary_language":{"value":"dta","label":"Daur"}},{"primary_language":{"value":"dau","label":"Daju, Dar Sila"}},{"primary_language":{"value":"bvo","label":"Bolgo"}},{"primary_language":{"value":"bfw","label":"Bondo"}},{"primary_language":{"value":"bna","label":"Bonerate"}},{"primary_language":{"value":"bdg","label":"Bonggi"}},{"primary_language":{"value":"glc","label":"Bon Gula"}},{"primary_language":{"value":"bvf","label":"Boor"}},{"primary_language":{"value":"knc","label":"Kanuri, Yerwa"}},{"primary_language":{"value":"bor","label":"Borôro"}},{"primary_language":{"value":"bos","label":"Bosnian"}},{"primary_language":{"value":"bph","label":"Botlikh"}},{"primary_language":{"value":"bod","label":"Tibetan"}},{"primary_language":{"value":"bze","label":"Bozo, Jenaama"}},{"primary_language":{"value":"brb","label":"Brao"}},{"primary_language":{"value":"bro","label":"Brokkat"}},{"primary_language":{"value":"bkk","label":"Brokskat"}},{"primary_language":{"value":"dtp","label":"Kadazan Dusun"}},{"primary_language":{"value":"bub","label":"Bua"}},{"primary_language":{"value":"bdm","label":"Buduma"}},{"primary_language":{"value":"bbh","label":"Bugan"}},{"primary_language":{"value":"bly","label":"Notre"}},{"primary_language":{"value":"dzg","label":"Dazaga"}},{"primary_language":{"value":"bfu","label":"Gahri"}},{"primary_language":{"value":"blf","label":"Buol"}},{"primary_language":{"value":"bxu","label":"Buriat, China"}},{"primary_language":{"value":"buc","label":"Bushi"}},{"primary_language":{"value":"zgn","label":"Zhuang, Guibian"}},{"primary_language":{"value":"bee","label":"Byangsi"}},{"primary_language":{"value":"cbb","label":"Cabiyarí"}},{"primary_language":{"value":"giq","label":"Gelao, Green"}},{"primary_language":{"value":"sss","label":"So (Laos)"}},{"primary_language":{"value":"lbj","label":"Ladakhi"}},{"primary_language":{"value":"afr","label":"Afrikaans"}},{"primary_language":{"value":"cby","label":"Carabayo"}},{"primary_language":{"value":"cbc","label":"Carapana"}},{"primary_language":{"value":"xom","label":"Komo (Sudan)"}},{"primary_language":{"value":"sml","label":"Sama, Central"}},{"primary_language":{"value":"shm","label":"Shahrudi"}},{"primary_language":{"value":"cbi","label":"Chachi"}},{"primary_language":{"value":"fra","label":"French"}},{"primary_language":{"value":"sck","label":"Sadri"}},{"primary_language":{"value":"ckh","label":"Chak"}},{"primary_language":{"value":"tgf","label":"Chalikha"}},{"primary_language":{"value":"ceg","label":"Chamacoco"}},{"primary_language":{"value":"cji","label":"Chamalal"}},{"primary_language":{"value":"tzm","label":"Tamazight, Central Atlas"}},{"primary_language":{"value":"cdn","label":"Chaudangsi"}},{"primary_language":{"value":"cnu","label":"Chenoua"}},{"primary_language":{"value":"kdn","label":"Kunda"}},{"primary_language":{"value":"cog","label":"Chong"}},{"primary_language":{"value":"scb","label":"Chut"}},{"primary_language":{"value":"cib","label":"Gbe, Ci"}},{"primary_language":{"value":"bem","label":"Bemba"}},{"primary_language":{"value":"asf","label":"Auslan"}},{"primary_language":{"value":"coa","label":"Malay, Cocos Islands"}},{"primary_language":{"value":"wlc","label":"Comorian, Mwali"}},{"primary_language":{"value":"wni","label":"Comorian, Ndzwani"}},{"primary_language":{"value":"twm","label":"Monpa, Tawang"}},{"primary_language":{"value":"cnq","label":"Chung (Cameroon)"}},{"primary_language":{"value":"dsh","label":"Daasanach"}},{"primary_language":{"value":"dbr","label":"Dabarre"}},{"primary_language":{"value":"kie","label":"Kibet"}},{"primary_language":{"value":"daj","label":"Daju, Dar Fur"}},{"primary_language":{"value":"dil","label":"Dilling"}},{"primary_language":{"value":"dln","label":"Darlong"}},{"primary_language":{"value":"dml","label":"Dameli"}},{"primary_language":{"value":"dms","label":"Dampelas"}},{"primary_language":{"value":"dnu","label":"Danau"}},{"primary_language":{"value":"mhu","label":"Digaro-Mishmi"}},{"primary_language":{"value":"phr","label":"Pahari-Potwari"}},{"primary_language":{"value":"afg","label":"Afghan Sign Language"}},{"primary_language":{"value":"asp","label":"Algerian Sign Language"}},{"primary_language":{"value":"ase","label":"American Sign Language"}},{"primary_language":{"value":"qao","label":"Angolan Sign Language"}},{"primary_language":{"value":"aen","label":"Armenian Sign Language"}},{"primary_language":{"value":"dse","label":"Sign Language of the Netherlands"}},{"primary_language":{"value":"tsm","label":"Turkish Sign Language"}},{"primary_language":{"value":"qbh","label":"Bahraini Sign Language"}},{"primary_language":{"value":"rsl","label":"Russian Sign Language"}},{"primary_language":{"value":"qbj","label":"Benin Sign Language"}},{"primary_language":{"value":"qbt","label":"Bhutanese Sign Language"}},{"primary_language":{"value":"lgs","label":"Guinea-Bissau Sign Language"}},{"primary_language":{"value":"ysl","label":"Slovenian Sign Language"}},{"primary_language":{"value":"bfi","label":"British Sign Language"}},{"primary_language":{"value":"qbn","label":"Brunei Sign Language"}},{"primary_language":{"value":"bqn","label":"Bulgarian Sign Language"}},{"primary_language":{"value":"ysm","label":"Myanmar Sign Language"}},{"primary_language":{"value":"csx","label":"Cambodian Sign Language"}},{"primary_language":{"value":"qcm","label":"Cameroon Sign Language"}},{"primary_language":{"value":"qfa","label":"Francophone African Sign Language"}},{"primary_language":{"value":"qkm","label":"Comorian Sign Language"}},{"primary_language":{"value":"fsl","label":"French Sign Language"}},{"primary_language":{"value":"qcd","label":"Congolese Sign Language"}},{"primary_language":{"value":"nzs","label":"New Zealand Sign Language"}},{"primary_language":{"value":"csf","label":"Cuban Sign Language"}},{"primary_language":{"value":"qcy","label":"Cypriot Sign Language"}},{"primary_language":{"value":"qso","label":"Somali Sign Language"}},{"primary_language":{"value":"qae","label":"Emirati Sign Language"}},{"primary_language":{"value":"qer","label":"Eritrean Sign Language"}},{"primary_language":{"value":"dsl","label":"Danish Sign Language"}},{"primary_language":{"value":"qfj","label":"Fiji Sign Language"}},{"primary_language":{"value":"qga","label":"Gabonese Sign Language"}},{"primary_language":{"value":"qgm","label":"Gambian Sign Language"}},{"primary_language":{"value":"qge","label":"Georgian Sign Language"}},{"primary_language":{"value":"gss","label":"Greek Sign Language"}},{"primary_language":{"value":"gus","label":"Guinean Sign Language"}},{"primary_language":{"value":"icl","label":"Icelandic Sign Language"}},{"primary_language":{"value":"qki","label":"Kiribati Sign Language"}},{"primary_language":{"value":"psc","label":"Iranian Sign Language"}},{"primary_language":{"value":"qiq","label":"Iraqi Sign Language"}},{"primary_language":{"value":"isr","label":"Israeli Sign Language"}},{"primary_language":{"value":"jls","label":"Jamaican Sign Language"}},{"primary_language":{"value":"jos","label":"Jordanian Sign Language"}},{"primary_language":{"value":"qkp","label":"North Korean Sign Language"}},{"primary_language":{"value":"sqk","label":"Albanian Sign Language"}},{"primary_language":{"value":"qkw","label":"Kuwaiti Sign Language"}},{"primary_language":{"value":"lso","label":"Laos Sign Language"}},{"primary_language":{"value":"lbs","label":"Libyan Sign Language"}},{"primary_language":{"value":"gsg","label":"German Sign Language"}},{"primary_language":{"value":"qmv","label":"Maldivian Sign Language"}},{"primary_language":{"value":"mdl","label":"Maltese Sign Language"}},{"primary_language":{"value":"qns","label":"Natural Sign Language"}},{"primary_language":{"value":"lsy","label":"Mauritian Sign Language"}},{"primary_language":{"value":"xms","label":"Moroccan Sign Language"}},{"primary_language":{"value":"mzy","label":"Mozambican Sign Language"}},{"primary_language":{"value":"qnh","label":"Vanuatu Sign Language"}},{"primary_language":{"value":"hks","label":"Hong Kong Sign Language"}},{"primary_language":{"value":"qom","label":"Omani Sign Language"}},{"primary_language":{"value":"pks","label":"Pakistan Sign Language"}},{"primary_language":{"value":"esl","label":"Egyptian Sign Language"}},{"primary_language":{"value":"pgz","label":"Papua New Guinean Sign Language"}},{"primary_language":{"value":"qqa","label":"Qatari Unified Sign Language"}},{"primary_language":{"value":"ise","label":"Italian Sign Language"}},{"primary_language":{"value":"qsm","label":"Samoan Sign Language"}},{"primary_language":{"value":"qtp","label":"Sao Tome and Principe Sign Language"}},{"primary_language":{"value":"sdl","label":"Saudi Arabian Sign Language"}},{"primary_language":{"value":"szs","label":"Solomon Islands Sign Language"}},{"primary_language":{"value":"sqs","label":"Sri Lankan Sign Language"}},{"primary_language":{"value":"qsr","label":"Surinamese Sign Language"}},{"primary_language":{"value":"nsl","label":"Norwegian Sign Language"}},{"primary_language":{"value":"qsz","label":"Swazi Sign Language"}},{"primary_language":{"value":"swl","label":"Swedish Sign Language"}},{"primary_language":{"value":"qry","label":"Yemeni Sign Language"}},{"primary_language":{"value":"deg","label":"Degema"}},{"primary_language":{"value":"deh","label":"Dehwari"}},{"primary_language":{"value":"dek","label":"Dek"}},{"primary_language":{"value":"ddn","label":"Dendi (Benin)"}},{"primary_language":{"value":"kwv","label":"Kaba Naa, Sara"}},{"primary_language":{"value":"dbb","label":"Deno"}},{"primary_language":{"value":"des","label":"Desano"}},{"primary_language":{"value":"hlb","label":"Halbi"}},{"primary_language":{"value":"mai","label":"Maithili"}},{"primary_language":{"value":"dhi","label":"Dhimal"}},{"primary_language":{"value":"dhm","label":"Dhimba"}},{"primary_language":{"value":"pah","label":"Tenharim"}},{"primary_language":{"value":"zyg","label":"Zhuang, Yang"}},{"primary_language":{"value":"ymm","label":"Maay"}},{"primary_language":{"value":"dwa","label":"Dirya"}},{"primary_language":{"value":"dox","label":"Mositacha"}},{"primary_language":{"value":"dgs","label":"Dogoso"}},{"primary_language":{"value":"rus","label":"Russian"}},{"primary_language":{"value":"kbp","label":"Kabiyè"}},{"primary_language":{"value":"rmt","label":"Domari"}},{"primary_language":{"value":"pes","label":"Persian, Iranian"}},{"primary_language":{"value":"dok","label":"Dondo"}},{"primary_language":{"value":"nnj","label":"Nyangatom"}},{"primary_language":{"value":"lhp","label":"Lhokpu"}},{"primary_language":{"value":"hau","label":"Hausa"}},{"primary_language":{"value":"bsk","label":"Burushaski"}},{"primary_language":{"value":"dbp","label":"Duwai"}},{"primary_language":{"value":"dzl","label":"Dzalakha"}},{"primary_language":{"value":"bgp","label":"Balochi, Eastern"}},{"primary_language":{"value":"tbn","label":"Tunebo, Barro Negro"}},{"primary_language":{"value":"muq","label":"Miao, Eastern Xiangxi"}},{"primary_language":{"value":"lma","label":"Limba, East"}},{"primary_language":{"value":"arb","label":"Arabic, Standard"}},{"primary_language":{"value":"unk","label":"Enawené-Nawé"}},{"primary_language":{"value":"enn","label":"Engenni"}},{"primary_language":{"value":"epi","label":"Epie"}},{"primary_language":{"value":"sjg","label":"Assangori"}},{"primary_language":{"value":"ers","label":"Ersu"}},{"primary_language":{"value":"amh","label":"Amharic"}},{"primary_language":{"value":"evn","label":"Evenki"}},{"primary_language":{"value":"ewe","label":"Ewe"}},{"primary_language":{"value":"fni","label":"Fania"}},{"primary_language":{"value":"ayl","label":"Arabic, Libyan"}},{"primary_language":{"value":"fin","label":"Finnish"}},{"primary_language":{"value":"fvr","label":"Fur"}},{"primary_language":{"value":"fod","label":"Foodo"}},{"primary_language":{"value":"fuf","label":"Pular"}},{"primary_language":{"value":"fuc","label":"Pulaar"}},{"primary_language":{"value":"bam","label":"Bambara"}},{"primary_language":{"value":"fuj","label":"Ko"}},{"primary_language":{"value":"fwe","label":"Fwe"}},{"primary_language":{"value":"mvy","label":"Kohistani, Indus"}},{"primary_language":{"value":"cqd","label":"Miao, Chuanqiandian Cluster"}},{"primary_language":{"value":"gzn","label":"Gane"}},{"primary_language":{"value":"gqu","label":"Qau"}},{"primary_language":{"value":"gex","label":"Garre"}},{"primary_language":{"value":"gwt","label":"Gawar-Bati"}},{"primary_language":{"value":"ajp","label":"South Levantine Arabic"}},{"primary_language":{"value":"gya","label":"Gbaya, Northwest"}},{"primary_language":{"value":"gbn","label":"Mo’da"}},{"primary_language":{"value":"diu","label":"Gciriku"}},{"primary_language":{"value":"giw","label":"Duoluo"}},{"primary_language":{"value":"mxj","label":"Miju-Mishmi"}},{"primary_language":{"value":"gea","label":"Geruma"}},{"primary_language":{"value":"ges","label":"Geser-Gorom"}},{"primary_language":{"value":"ary","label":"Arabic, Moroccan"}},{"primary_language":{"value":"pll","label":"Palaung, Shwe"}},{"primary_language":{"value":"goe","label":"Gongduk"}},{"primary_language":{"value":"srp","label":"Serbian"}},{"primary_language":{"value":"goq","label":"Gorap"}},{"primary_language":{"value":"gow","label":"Gorowa"}},{"primary_language":{"value":"xnr","label":"Kangri"}},{"primary_language":{"value":"kvf","label":"Kabalai"}},{"primary_language":{"value":"gwf","label":"Gowro"}},{"primary_language":{"value":"nli","label":"Grangali"}},{"primary_language":{"value":"und","label":"Undetermined"}},{"primary_language":{"value":"gju","label":"Gujari"}},{"primary_language":{"value":"zna","label":"Zan Gula"}},{"primary_language":{"value":"ghl","label":"Ghulfan"}},{"primary_language":{"value":"abv","label":"Arabic, Baharna"}},{"primary_language":{"value":"gwb","label":"Gwa"}},{"primary_language":{"value":"gyo","label":"Gyalsumdo"}},{"primary_language":{"value":"ayh","label":"Arabic, Hadrami"}},{"primary_language":{"value":"bgc","label":"Haryanvi"}},{"primary_language":{"value":"hld","label":"Halang Doan"}},{"primary_language":{"value":"lic","label":"Hlai"}},{"primary_language":{"value":"hae","label":"Oromo, Eastern"}},{"primary_language":{"value":"hss","label":"Harsusi"}},{"primary_language":{"value":"hac","label":"Gurani"}},{"primary_language":{"value":"adx","label":"Tibetan, Amdo"}},{"primary_language":{"value":"her","label":"Herero"}},{"primary_language":{"value":"nyn","label":"Nyankore"}},{"primary_language":{"value":"htu","label":"Hitu"}},{"primary_language":{"value":"gdq","label":"Mehri"}},{"primary_language":{"value":"hoh","label":"Hobyót"}},{"primary_language":{"value":"tiz","label":"Tai Hongjin"}},{"primary_language":{"value":"huo","label":"Hu"}},{"primary_language":{"value":"hug","label":"Huachipaeri"}},{"primary_language":{"value":"hmh","label":"Miao, Southwestern Huishui"}},{"primary_language":{"value":"hnu","label":"Hung"}},{"primary_language":{"value":"jup","label":"Hupdë"}},{"primary_language":{"value":"iba","label":"Iban"}},{"primary_language":{"value":"ibr","label":"Ibuoro"}},{"primary_language":{"value":"dsq","label":"Tadaksahak"}},{"primary_language":{"value":"thv","label":"Tamahaq, Tahaggart"}},{"primary_language":{"value":"irr","label":"Ir"}},{"primary_language":{"value":"yhd","label":"Arabic, Judeo-Iraqi"}},{"primary_language":{"value":"shp","label":"Shipibo-Conibo"}},{"primary_language":{"value":"isk","label":"Ishkashimi"}},{"primary_language":{"value":"arr","label":"Karo (Brazil)"}},{"primary_language":{"value":"kyw","label":"Kudmali"}},{"primary_language":{"value":"mey","label":"Hassaniyya"}},{"primary_language":{"value":"anq","label":"Jarawa"}},{"primary_language":{"value":"snd","label":"Sindhi"}},{"primary_language":{"value":"kpj","label":"Karajá"}},{"primary_language":{"value":"jeu","label":"Jonkor Bourmataguil"}},{"primary_language":{"value":"oyb","label":"Oy"}},{"primary_language":{"value":"lsd","label":"Lishana Deni"}},{"primary_language":{"value":"heb","label":"Hebrew (modern)"}},{"primary_language":{"value":"ydd","label":"Yiddish, Eastern"}},{"primary_language":{"value":"jio","label":"Jiamao"}},{"primary_language":{"value":"ysn","label":"Sani"}},{"primary_language":{"value":"shv","label":"Shehri"}},{"primary_language":{"value":"jii","label":"Jiiddu"}},{"primary_language":{"value":"jmb","label":"Zibinju"}},{"primary_language":{"value":"jmi","label":"Jimi"}},{"primary_language":{"value":"jia","label":"Jina"}},{"primary_language":{"value":"jiu","label":"Jinuo, Youle"}},{"primary_language":{"value":"jit","label":"Jita"}},{"primary_language":{"value":"toq","label":"Toposa"}},{"primary_language":{"value":"mmy","label":"Migaama"}},{"primary_language":{"value":"dyu","label":"Jula"}},{"primary_language":{"value":"kia","label":"Kim"}},{"primary_language":{"value":"kxj","label":"Kulfa"}},{"primary_language":{"value":"bfy","label":"Bagheli"}},{"primary_language":{"value":"kdu","label":"Kadaru"}},{"primary_language":{"value":"mgd","label":"Moru"}},{"primary_language":{"value":"dkg","label":"Kadung"}},{"primary_language":{"value":"kzq","label":"Kaike"}},{"primary_language":{"value":"xdq","label":"Kaitag"}},{"primary_language":{"value":"ras","label":"Tegali"}},{"primary_language":{"value":"ckq","label":"Kajakse"}},{"primary_language":{"value":"kui","label":"Kuikúro-Kalapálo"}},{"primary_language":{"value":"kbo","label":"Keliko"}},{"primary_language":{"value":"xka","label":"Kalkoti"}},{"primary_language":{"value":"kcu","label":"Kami (Tanzania)"}},{"primary_language":{"value":"xvi","label":"Komviri"}},{"primary_language":{"value":"dhd","label":"Dhundari"}},{"primary_language":{"value":"kcp","label":"Kanga"}},{"primary_language":{"value":"kty","label":"Kango (DRC, , Bas-Uélé district)"}},{"primary_language":{"value":"kth","label":"Karanga"}},{"primary_language":{"value":"kpt","label":"Karata"}},{"primary_language":{"value":"daa","label":"Dangaléat"}},{"primary_language":{"value":"kil","label":"Kariya"}},{"primary_language":{"value":"kko","label":"Karko"}},{"primary_language":{"value":"kxh","label":"Karo (Ethiopia)"}},{"primary_language":{"value":"mnk","label":"Mandinka"}},{"primary_language":{"value":"xsm","label":"Kasem"}},{"primary_language":{"value":"tdf","label":"Talieng"}},{"primary_language":{"value":"bru","label":"Bru, Eastern"}},{"primary_language":{"value":"kuf","label":"Katu, Western"}},{"primary_language":{"value":"knm","label":"Kanamarí"}},{"primary_language":{"value":"tri","label":"Trió"}},{"primary_language":{"value":"kaz","label":"Kazakh"}},{"primary_language":{"value":"alw","label":"Alaba-K’abeena"}},{"primary_language":{"value":"ndp","label":"Kebu"}},{"primary_language":{"value":"kxd","label":"Brunei"}},{"primary_language":{"value":"kec","label":"Keiga"}},{"primary_language":{"value":"bzx","label":"Bozo, Kelengaxo"}},{"primary_language":{"value":"klf","label":"Kendeje"}},{"primary_language":{"value":"kns","label":"Kensiu"}},{"primary_language":{"value":"gax","label":"Oromo, Borana-Arsi-Guji"}},{"primary_language":{"value":"kbg","label":"Khamba"}},{"primary_language":{"value":"cdh","label":"Chambeali"}},{"primary_language":{"value":"kqg","label":"Khe"}},{"primary_language":{"value":"ngt","label":"Kriang"}},{"primary_language":{"value":"kjg","label":"Khmu"}},{"primary_language":{"value":"khw","label":"Khowar"}},{"primary_language":{"value":"kmz","label":"Khorasani Turkish"}},{"primary_language":{"value":"bgg","label":"Bugun"}},{"primary_language":{"value":"xhv","label":"Khua"}},{"primary_language":{"value":"khf","label":"Khuen"}},{"primary_language":{"value":"kfm","label":"Khunsari"}},{"primary_language":{"value":"khv","label":"Khvarshi"}},{"primary_language":{"value":"kyi","label":"Kiput"}},{"primary_language":{"value":"kks","label":"Giiwo"}},{"primary_language":{"value":"cdz","label":"Koda"}},{"primary_language":{"value":"nkd","label":"Koireng"}},{"primary_language":{"value":"kou","label":"Koke"}},{"primary_language":{"value":"kvp","label":"Kompane"}},{"primary_language":{"value":"kvh","label":"Komodo"}},{"primary_language":{"value":"kqm","label":"Khisa"}},{"primary_language":{"value":"kjk","label":"Konjo, Highland"}},{"primary_language":{"value":"kjc","label":"Konjo, Coastal"}},{"primary_language":{"value":"kke","label":"Kakabe"}},{"primary_language":{"value":"knu","label":"Kono (Guinea)"}},{"primary_language":{"value":"kcz","label":"Konongo"}},{"primary_language":{"value":"kfd","label":"Koraga, Korra"}},{"primary_language":{"value":"vkn","label":"Koro Nulu"}},{"primary_language":{"value":"vkz","label":"Koro Zuba"}},{"primary_language":{"value":"xor","label":"Korubo"}},{"primary_language":{"value":"kfe","label":"Kota (India)"}},{"primary_language":{"value":"kdh","label":"Tem"}},{"primary_language":{"value":"hal","label":"Halang"}},{"primary_language":{"value":"men","label":"Mende (Sierra Leone)"}},{"primary_language":{"value":"uan","label":"Kuan"}},{"primary_language":{"value":"cub","label":"Cubeo"}},{"primary_language":{"value":"lkc","label":"Kucong"}},{"primary_language":{"value":"kfg","label":"Kudiya"}},{"primary_language":{"value":"kdt","label":"Kuay"}},{"primary_language":{"value":"vkj","label":"Kujarge"}},{"primary_language":{"value":"zum","label":"Kumzari"}},{"primary_language":{"value":"kpa","label":"Kutto"}},{"primary_language":{"value":"knk","label":"Kuranko"}},{"primary_language":{"value":"kuj","label":"Kuria"}},{"primary_language":{"value":"kmr","label":"Kurdish, Northern"}},{"primary_language":{"value":"xkz","label":"Kurtokha"}},{"primary_language":{"value":"kfy","label":"Kumaoni"}},{"primary_language":{"value":"kwn","label":"Kwangali"}},{"primary_language":{"value":"kir","label":"Kyrgyz"}},{"primary_language":{"value":"div","label":"Maldivian"}},{"primary_language":{"value":"lha","label":"Laha (Viet Nam)"}},{"primary_language":{"value":"lhn","label":"Lahanan"}},{"primary_language":{"value":"lkh","label":"Lakha"}},{"primary_language":{"value":"lki","label":"Laki"}},{"primary_language":{"value":"lbn","label":"Rmeet"}},{"primary_language":{"value":"abl","label":"Lampung Nyo"}},{"primary_language":{"value":"bdi","label":"Burun"}},{"primary_language":{"value":"tgr","label":"Tareng"}},{"primary_language":{"value":"alo","label":"Larike-Wakasihu"}},{"primary_language":{"value":"lan","label":"Laru"}},{"primary_language":{"value":"lss","label":"Lasi"}},{"primary_language":{"value":"lbt","label":"Lachi"}},{"primary_language":{"value":"ltu","label":"Latu"}},{"primary_language":{"value":"lbo","label":"Laven"}},{"primary_language":{"value":"ywt","label":"Lalo, Central"}},{"primary_language":{"value":"zlm","label":"Malay"}},{"primary_language":{"value":"avl","label":"Arabic, Eastern Egyptian Bedawi"}},{"primary_language":{"value":"toi","label":"Tonga (Zambia)"}},{"primary_language":{"value":"yne","label":"Lang’e"}},{"primary_language":{"value":"pse","label":"Malay, Central"}},{"primary_language":{"value":"pha","label":"Pa-Hng"}},{"primary_language":{"value":"liu","label":"Logorik"}},{"primary_language":{"value":"mni","label":"Meitei"}},{"primary_language":{"value":"lcd","label":"Lola"}},{"primary_language":{"value":"lop","label":"Lopa"}},{"primary_language":{"value":"lcq","label":"Luhu"}},{"primary_language":{"value":"luk","label":"Lunanakha"}},{"primary_language":{"value":"rob","label":"Tae’"}},{"primary_language":{"value":"snn","label":"Siona"}},{"primary_language":{"value":"mbn","label":"Macaguán"}},{"primary_language":{"value":"mew","label":"Maaka"}},{"primary_language":{"value":"wmd","label":"Mamaindê"}},{"primary_language":{"value":"mqi","label":"Mariri"}},{"primary_language":{"value":"xmj","label":"Majera"}},{"primary_language":{"value":"xsr","label":"Sherpa"}},{"primary_language":{"value":"vmk","label":"Makhuwa-Shirima"}},{"primary_language":{"value":"bcc","label":"Balochi, Southern"}},{"primary_language":{"value":"mgh","label":"Makhuwa-Meetto"}},{"primary_language":{"value":"myy","label":"Macuna"}},{"primary_language":{"value":"mjp","label":"Malapandaram"}},{"primary_language":{"value":"xns","label":"Kanashi"}},{"primary_language":{"value":"mdy","label":"Male"}},{"primary_language":{"value":"pkt","label":"Maleng"}},{"primary_language":{"value":"acm","label":"Arabic, Mesopotamian"}},{"primary_language":{"value":"zng","label":"Mang"}},{"primary_language":{"value":"kby","label":"Kanuri, Manga"}},{"primary_language":{"value":"mge","label":"Mango"}},{"primary_language":{"value":"mbd","label":"Manobo, Dibabawon"}},{"primary_language":{"value":"knf","label":"Mankanya"}},{"primary_language":{"value":"mml","label":"Man Met"}},{"primary_language":{"value":"mns","label":"Mansi (Russian Federation)"}},{"primary_language":{"value":"wmg","label":"Minyag, Western"}},{"primary_language":{"value":"mgb","label":"Mararit"}},{"primary_language":{"value":"liq","label":"Libido"}},{"primary_language":{"value":"mvu","label":"Marfa"}},{"primary_language":{"value":"hmm","label":"Miao, Central Mashan"}},{"primary_language":{"value":"msv","label":"Maslam"}},{"primary_language":{"value":"msw","label":"Mansoanka"}},{"primary_language":{"value":"cgk","label":"Chocangacakha"}},{"primary_language":{"value":"mhw","label":"Mbukushu"}},{"primary_language":{"value":"mhr","label":"Mari, Meadow"}},{"primary_language":{"value":"tsj","label":"Tshangla"}},{"primary_language":{"value":"mmh","label":"Mehináku"}},{"primary_language":{"value":"mnq","label":"Minriq"}},{"primary_language":{"value":"tig","label":"Tigré"}},{"primary_language":{"value":"mpe","label":"Majang"}},{"primary_language":{"value":"mes","label":"Masmaje"}},{"primary_language":{"value":"mei","label":"Midob"}},{"primary_language":{"value":"nmd","label":"Ndumu"}},{"primary_language":{"value":"mra","label":"Mlabri"}},{"primary_language":{"value":"mkg","label":"Mak (China)"}},{"primary_language":{"value":"moy","label":"Shekkacho"}},{"primary_language":{"value":"prs","label":"Dari"}},{"primary_language":{"value":"mou","label":"Mogum"}},{"primary_language":{"value":"moz","label":"Mukulu"}},{"primary_language":{"value":"tou","label":"Tho"}},{"primary_language":{"value":"pga","label":"Arabic, Juba"}},{"primary_language":{"value":"xmo","label":"Morerebi"}},{"primary_language":{"value":"aju","label":"Arabic, Judeo-Moroccan"}},{"primary_language":{"value":"mqn","label":"Moronene"}},{"primary_language":{"value":"nru","label":"Narua"}},{"primary_language":{"value":"mot","label":"Barí"}},{"primary_language":{"value":"mrj","label":"Mari, Hill"}},{"primary_language":{"value":"mpz","label":"Mpi"}},{"primary_language":{"value":"mub","label":"Mubi"}},{"primary_language":{"value":"hni","label":"Hani"}},{"primary_language":{"value":"muv","label":"Muthuvan"}},{"primary_language":{"value":"tgk","label":"Tajik"}},{"primary_language":{"value":"bmr","label":"Muinane"}},{"primary_language":{"value":"dar","label":"Dargwa"}},{"primary_language":{"value":"mnj","label":"Munji"}},{"primary_language":{"value":"xma","label":"Mushungulu"}},{"primary_language":{"value":"mwe","label":"Mwera (Tanzania, Lindi Region)"}},{"primary_language":{"value":"mzb","label":"Tumzabt"}},{"primary_language":{"value":"nbt","label":"Na"}},{"primary_language":{"value":"wbr","label":"Wagdi"}},{"primary_language":{"value":"noe","label":"Nimadi"}},{"primary_language":{"value":"nxq","label":"Naxi"}},{"primary_language":{"value":"vgr","label":"Vaghri"}},{"primary_language":{"value":"naq","label":"Khoekhoe"}},{"primary_language":{"value":"nmy","label":"Namuyi"}},{"primary_language":{"value":"nrb","label":"Nara"}},{"primary_language":{"value":"loh","label":"Laarim"}},{"primary_language":{"value":"nml","label":"Ndemli"}},{"primary_language":{"value":"ndg","label":"Ndengereko"}},{"primary_language":{"value":"ndt","label":"Ndunga"}},{"primary_language":{"value":"yue","label":"Chinese, Yue"}},{"primary_language":{"value":"njl","label":"Njalgulgule"}},{"primary_language":{"value":"nya","label":"Nyanja"}},{"primary_language":{"value":"nuo","label":"Nguôn"}},{"primary_language":{"value":"aee","label":"Pashai, Northeast"}},{"primary_language":{"value":"bao","label":"Waimaha"}},{"primary_language":{"value":"qxn","label":"Quechua, Northern Conchucos"}},{"primary_language":{"value":"doc","label":"Dong, Northern"}},{"primary_language":{"value":"ymx","label":"Muji, Northern"}},{"primary_language":{"value":"sme","label":"Northern Sami"}},{"primary_language":{"value":"kgn","label":"Karingani"}},{"primary_language":{"value":"nod","label":"Thai, Northern"}},{"primary_language":{"value":"ayn","label":"Arabic, Sanaani"}},{"primary_language":{"value":"kmq","label":"Gwama"}},{"primary_language":{"value":"kcn","label":"Nubi"}},{"primary_language":{"value":"nus","label":"Nuer"}},{"primary_language":{"value":"npb","label":"Nupbikha"}},{"primary_language":{"value":"cbn","label":"Nyahkur"}},{"primary_language":{"value":"nev","label":"Nyaheun"}},{"primary_language":{"value":"nmi","label":"Nyam"}},{"primary_language":{"value":"nwm","label":"Nyamusa-Molo"}},{"primary_language":{"value":"nye","label":"Nyengo"}},{"primary_language":{"value":"neh","label":"Nyenkha"}},{"primary_language":{"value":"yno","label":"Yong"}},{"primary_language":{"value":"tyh","label":"O’du"}},{"primary_language":{"value":"okn","label":"Oki-No-Erabu"}},{"primary_language":{"value":"opa","label":"Okpamheri"}},{"primary_language":{"value":"ole","label":"Olekha"}},{"primary_language":{"value":"lul","label":"Olu’bo"}},{"primary_language":{"value":"oon","label":"Öñge"}},{"primary_language":{"value":"lgn","label":"Opo"}},{"primary_language":{"value":"ost","label":"Osatu"}},{"primary_language":{"value":"pqa","label":"Pa’anci"}},{"primary_language":{"value":"pac","label":"Pacoh"}},{"primary_language":{"value":"adh","label":"Jopadhola"}},{"primary_language":{"value":"phj","label":"Pahari"}},{"primary_language":{"value":"btd","label":"Batak Dairi"}},{"primary_language":{"value":"phl","label":"Palula"}},{"primary_language":{"value":"fub","label":"Fulfulde, Adamawa"}},{"primary_language":{"value":"pnq","label":"Pana (Burkina Faso)"}},{"primary_language":{"value":"phq","label":"Phana’"}},{"primary_language":{"value":"pgg","label":"Pangwali"}},{"primary_language":{"value":"prc","label":"Parachi"}},{"primary_language":{"value":"gvp","label":"Gavião, Pará"}},{"primary_language":{"value":"ort","label":"Oriya, Adivasi"}},{"primary_language":{"value":"lkr","label":"Päri"}},{"primary_language":{"value":"aoc","label":"Pemon"}},{"primary_language":{"value":"prt","label":"Prai"}},{"primary_language":{"value":"pho","label":"Phunoi"}},{"primary_language":{"value":"phh","label":"Phula"}},{"primary_language":{"value":"pht","label":"Phu Thai"}},{"primary_language":{"value":"pil","label":"Yom"}},{"primary_language":{"value":"myp","label":"Pirahã"}},{"primary_language":{"value":"pir","label":"Piratapuyo"}},{"primary_language":{"value":"tur","label":"Turkish"}},{"primary_language":{"value":"pnx","label":"Phong-Kniang"}},{"primary_language":{"value":"ycl","label":"Lolopo"}},{"primary_language":{"value":"prn","label":"Prasuni"}},{"primary_language":{"value":"pum","label":"Puma"}},{"primary_language":{"value":"uuu","label":"U"}},{"primary_language":{"value":"laq","label":"Qabiao"}},{"primary_language":{"value":"tdb","label":"Panchpargania"}},{"primary_language":{"value":"suv","label":"Puroik"}},{"primary_language":{"value":"zqe","label":"Zhuang, Qiubei"}},{"primary_language":{"value":"rji","label":"Raji"}},{"primary_language":{"value":"jnl","label":"Rawat"}},{"primary_language":{"value":"tct","label":"T’en"}},{"primary_language":{"value":"tyr","label":"Tai Daeng"}},{"primary_language":{"value":"gbk","label":"Gaddi"}},{"primary_language":{"value":"ren","label":"Rengao"}},{"primary_language":{"value":"sgh","label":"Shughni"}},{"primary_language":{"value":"rui","label":"Rufiji"}},{"primary_language":{"value":"bma","label":"Lame"}},{"primary_language":{"value":"rbb","label":"Palaung, Rumai"}},{"primary_language":{"value":"djc","label":"Daju, Dar Daju"}},{"primary_language":{"value":"saa","label":"Saba"}},{"primary_language":{"value":"tts","label":"Thai, Northeastern"}},{"primary_language":{"value":"sbm","label":"Sagala"}},{"primary_language":{"value":"ssy","label":"Saho"}},{"primary_language":{"value":"knz","label":"Kalamsé"}},{"primary_language":{"value":"sgy","label":"Sanglechi"}},{"primary_language":{"value":"msc","label":"Maninka, Sankaran"}},{"primary_language":{"value":"kmc","label":"Dong, Southern"}},{"primary_language":{"value":"ssn","label":"Waata"}},{"primary_language":{"value":"krn","label":"Sapo"}},{"primary_language":{"value":"spu","label":"Sapuan"}},{"primary_language":{"value":"srh","label":"Sarikoli"}},{"primary_language":{"value":"sdg","label":"Savi"}},{"primary_language":{"value":"hik","label":"Seit-Kaitetu"}},{"primary_language":{"value":"smy","label":"Semnani"}},{"primary_language":{"value":"seq","label":"Sénoufo, Senara"}},{"primary_language":{"value":"tum","label":"Tumbuka"}},{"primary_language":{"value":"std","label":"Sentinel"}},{"primary_language":{"value":"sdp","label":"Sherdukpen"}},{"primary_language":{"value":"zne","label":"Zande"}},{"primary_language":{"value":"sze","label":"Seze"}},{"primary_language":{"value":"sdb","label":"Shabak"}},{"primary_language":{"value":"sbf","label":"Shabo"}},{"primary_language":{"value":"bho","label":"Bhojpuri"}},{"primary_language":{"value":"sho","label":"Shanga"}},{"primary_language":{"value":"she","label":"Sheko"}},{"primary_language":{"value":"scl","label":"Shina"}},{"primary_language":{"value":"sxg","label":"Shuhi"}},{"primary_language":{"value":"sts","label":"Shumashti"}},{"primary_language":{"value":"mvf","label":"Mongolian, Peripheral"}},{"primary_language":{"value":"slt","label":"Sila"}},{"primary_language":{"value":"btx","label":"Batak Karo"}},{"primary_language":{"value":"puo","label":"Puoc"}},{"primary_language":{"value":"skq","label":"Sininkere"}},{"primary_language":{"value":"sri","label":"Siriano"}},{"primary_language":{"value":"siy","label":"Sivandi"}},{"primary_language":{"value":"siz","label":"Siwi"}},{"primary_language":{"value":"sqt","label":"Soqotri"}},{"primary_language":{"value":"soj","label":"Soi"}},{"primary_language":{"value":"sok","label":"Sokoro"}},{"primary_language":{"value":"sle","label":"Sholaga"}},{"primary_language":{"value":"hmb","label":"Songhay, Humburi Senni"}},{"primary_language":{"value":"sqq","label":"Sou"}},{"primary_language":{"value":"psi","label":"Pashai, Southeast"}},{"primary_language":{"value":"nbw","label":"Ngbandi, Southern"}},{"primary_language":{"value":"avd","label":"Alviri-Vidari"}},{"primary_language":{"value":"psh","label":"Pashai, Southwest"}},{"primary_language":{"value":"bxr","label":"Buriat, Russia"}},{"primary_language":{"value":"sbs","label":"Kuhane"}},{"primary_language":{"value":"mag","label":"Magahi"}},{"primary_language":{"value":"szn","label":"Sula"}},{"primary_language":{"value":"suz","label":"Sunwar"}},{"primary_language":{"value":"sbj","label":"Surbakhal"}},{"primary_language":{"value":"suq","label":"Suri, Tirmaga-Chai"}},{"primary_language":{"value":"swx","label":"Suruahá"}},{"primary_language":{"value":"suy","label":"Suyá"}},{"primary_language":{"value":"lae","label":"Pattani"}},{"primary_language":{"value":"shz","label":"Sénoufo, Syenara"}},{"primary_language":{"value":"taz","label":"Tocho"}},{"primary_language":{"value":"tbm","label":"Tagbu"}},{"primary_language":{"value":"tda","label":"Tagdal"}},{"primary_language":{"value":"tag","label":"Tagoi"}},{"primary_language":{"value":"kyp","label":"Kang"}},{"primary_language":{"value":"kkh","label":"Khün"}},{"primary_language":{"value":"shn","label":"Shan"}},{"primary_language":{"value":"tlq","label":"Tai Loi"}},{"primary_language":{"value":"khb","label":"Lü"}},{"primary_language":{"value":"tyj","label":"Tai Yo"}},{"primary_language":{"value":"tdd","label":"Tai Nüa"}},{"primary_language":{"value":"nyw","label":"Nyaw"}},{"primary_language":{"value":"phk","label":"Phake"}},{"primary_language":{"value":"tdj","label":"Tajio"}},{"primary_language":{"value":"tbr","label":"Tumtum"}},{"primary_language":{"value":"tly","label":"Talysh"}},{"primary_language":{"value":"tma","label":"Tama (Chad)"}},{"primary_language":{"value":"mwn","label":"Nyamwanga"}},{"primary_language":{"value":"tth","label":"Ta’oih, Upper"}},{"primary_language":{"value":"kpc","label":"Curripaco"}},{"primary_language":{"value":"teq","label":"Temein"}},{"primary_language":{"value":"thk","label":"Kitharaka"}},{"primary_language":{"value":"thu","label":"Thuri"}},{"primary_language":{"value":"arq","label":"Arabic, Algerian"}},{"primary_language":{"value":"boz","label":"Bozo, Tieyaxo"}},{"primary_language":{"value":"qvz","label":"Quichua, Northern Pastaza"}},{"primary_language":{"value":"acw","label":"Arabic, Hijazi"}},{"primary_language":{"value":"tin","label":"Tindi"}},{"primary_language":{"value":"tkn","label":"Toku-No-Shima"}},{"primary_language":{"value":"txm","label":"Tomini"}},{"primary_language":{"value":"oog","label":"Ong"}},{"primary_language":{"value":"peh","label":"Bonan"}},{"primary_language":{"value":"trj","label":"Toram"}},{"primary_language":{"value":"ttl","label":"Totela"}},{"primary_language":{"value":"tyv","label":"Tuvan"}},{"primary_language":{"value":"tgd","label":"Choogen"}},{"primary_language":{"value":"tsb","label":"Tsamai"}},{"primary_language":{"value":"tsk","label":"Tseku"}},{"primary_language":{"value":"tsl","label":"Ts’ün-Lao"}},{"primary_language":{"value":"tsc","label":"Tswa"}},{"primary_language":{"value":"dru","label":"Rukai"}},{"primary_language":{"value":"tqq","label":"Tunni"}},{"primary_language":{"value":"neb","label":"Toura (Côte d’Ivoire)"}},{"primary_language":{"value":"ttg","label":"Tutong"}},{"primary_language":{"value":"tyy","label":"Tiyaa"}},{"primary_language":{"value":"tue","label":"Tuyuca"}},{"primary_language":{"value":"txi","label":"Ikpeng"}},{"primary_language":{"value":"udj","label":"Ujir"}},{"primary_language":{"value":"kcf","label":"Ukaan"}},{"primary_language":{"value":"kib","label":"Koalib"}},{"primary_language":{"value":"une","label":"Uneme"}},{"primary_language":{"value":"pkb","label":"Kipfokomu"}},{"primary_language":{"value":"urz","label":"Uru-Eu-Wau-Wau"}},{"primary_language":{"value":"urp","label":"Uru-Pa-In"}},{"primary_language":{"value":"usi","label":"Usoi"}},{"primary_language":{"value":"ush","label":"Ushojo"}},{"primary_language":{"value":"uzn","label":"Uzbek, Northern"}},{"primary_language":{"value":"vai","label":"Vai"}},{"primary_language":{"value":"gbl","label":"Gamit"}},{"primary_language":{"value":"bgq","label":"Bagri"}},{"primary_language":{"value":"bvi","label":"Belanda Viri"}},{"primary_language":{"value":"rmy","label":"Romani, Vlax"}},{"primary_language":{"value":"vut","label":"Vute"}},{"primary_language":{"value":"wwa","label":"Waama"}},{"primary_language":{"value":"wbk","label":"Waigali"}},{"primary_language":{"value":"atr","label":"Waimiri-Atroarí"}},{"primary_language":{"value":"wbl","label":"Wakhi"}},{"primary_language":{"value":"wll","label":"Wali (Sudan)"}},{"primary_language":{"value":"nyr","label":"Nyiha, Malawi"}},{"primary_language":{"value":"wne","label":"Waneci"}},{"primary_language":{"value":"orc","label":"Orma"}},{"primary_language":{"value":"wrn","label":"Warnang"}},{"primary_language":{"value":"wbj","label":"Alagwa"}},{"primary_language":{"value":"wau","label":"Waurá"}},{"primary_language":{"value":"oym","label":"Wayampi"}},{"primary_language":{"value":"zhd","label":"Zhuang, Dai"}},{"primary_language":{"value":"bgn","label":"Balochi, Western"}},{"primary_language":{"value":"tnb","label":"Tunebo, Western"}},{"primary_language":{"value":"sjo","label":"Xibe"}},{"primary_language":{"value":"wol","label":"Wolof"}},{"primary_language":{"value":"bwn","label":"Bunu, Wunai"}},{"primary_language":{"value":"wuh","label":"Wutunhua"}},{"primary_language":{"value":"xan","label":"Xamtanga"}},{"primary_language":{"value":"hml","label":"Miao, Luopohe"}},{"primary_language":{"value":"cuu","label":"Tai Ya"}},{"primary_language":{"value":"rys","label":"Yaeyama"}},{"primary_language":{"value":"yad","label":"Yagua"}},{"primary_language":{"value":"ybh","label":"Yakkha"}},{"primary_language":{"value":"yaa","label":"Yaminahua"}},{"primary_language":{"value":"pcc","label":"Bouyei"}},{"primary_language":{"value":"yao","label":"Yao"}},{"primary_language":{"value":"yax","label":"Yauma"}},{"primary_language":{"value":"kay","label":"Kamayurá"}},{"primary_language":{"value":"ywn","label":"Yawanawa"}},{"primary_language":{"value":"yrn","label":"Yerong"}},{"primary_language":{"value":"ydg","label":"Yadgha"}},{"primary_language":{"value":"xwg","label":"Kwegu"}},{"primary_language":{"value":"clk","label":"Idu-Mishmi"}},{"primary_language":{"value":"yom","label":"Kiyombe"}},{"primary_language":{"value":"yoi","label":"Yonaguni"}},{"primary_language":{"value":"yox","label":"Yoron"}},{"primary_language":{"value":"ium","label":"Iu Mien"}},{"primary_language":{"value":"buh","label":"Bunu, Younuo"}},{"primary_language":{"value":"yoy","label":"Yoy"}},{"primary_language":{"value":"yup","label":"Yukpa"}},{"primary_language":{"value":"kaf","label":"Katso"}},{"primary_language":{"value":"swi","label":"Sui"}},{"primary_language":{"value":"zag","label":"Zaghawa"}},{"primary_language":{"value":"zkr","label":"Zakhring"}},{"primary_language":{"value":"ziw","label":"Zigula"}},{"primary_language":{"value":"pto","label":"Zo’é"}}] diff --git a/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue b/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue index c8ab9b21c..daf7c7faa 100644 --- a/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue +++ b/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue @@ -236,7 +236,10 @@ const bundleSrc = (bundle, file) => // legend selects by NAME; the grid matches rows by VALUE. Carrying one form would have meant the // link matching nothing the moment the grid's data followed the URL's language — and an empty // intersection reads as "no results", not as a broken wire. -const linked = reactive({ region: { value: '', label: '' }, religion: '', language: { value: '', label: '' } }) +// `language.codes` is every ISO code the current language selection covers — one for a real +// language, many for a legend TIER like "Arabic". It is what lets gridLanguage() tell "I can +// express this" from "I cannot", instead of guessing from an empty code. +const linked = reactive({ region: { value: '', label: '' }, religion: '', language: { value: '', label: '', codes: [] } }) // ★ WHAT THE LIST IS SHOWING, so the map can go there (BUILD-GRID-SELECTION-FLIES-THE-MAP). // The link ran one way: the map narrowed the grid, and the grid moved nothing. The grid already @@ -254,7 +257,7 @@ const gridSlugs = ref([]) function clearExcept(keep) { if (keep !== 'region' && (linked.region.value || linked.region.label)) { linked.region.value = ''; linked.region.label = '' } if (keep !== 'religion' && linked.religion) linked.religion = '' - if (keep !== 'language' && (linked.language.value || linked.language.label)) { linked.language.value = ''; linked.language.label = '' } + if (keep !== 'language' && (linked.language.value || linked.language.label)) { linked.language.value = ''; linked.language.label = ''; linked.language.codes = [] } } const slugify = (label) => String(label || '').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '') @@ -291,6 +294,9 @@ function adopt(next) { if (v !== linked.language.value || l !== linked.language.label) { linked.language.value = v linked.language.label = l + // Every code the selection covers. The grid direction reports ONE real language, so this is + // that one code; the map direction may report a grouping (see the note on the push below). + linked.language.codes = Array.isArray(next.language.codes) ? next.language.codes : (v ? [v] : []) clearExcept('language') } return @@ -331,11 +337,43 @@ function onMapFiltered(ev) { adopt({ region: { value: label ? slugify(label) : '', label }, religion: ev?.detail?.religion || '', - // The map sends both: the name its legend selected by, and the locale-stable ISO code. - language: { value: ev?.detail?.languageCode || '', label: ev?.detail?.language || '' }, + // The map sends three things: the name its legend selected by, the locale-stable ISO code when + // there IS a single one, and every code the selection covers. + language: { + value: ev?.detail?.languageCode || '', + label: ev?.detail?.language || '', + codes: Array.isArray(ev?.detail?.languageCodes) ? ev.detail.languageCodes : [], + }, }) } +// ★ AN AXIS THIS GRID CANNOT EXPRESS MUST NOT NARROW IT TO NOTHING (rega, 2026-09-26: Languages > +// Language > "Arabic" took the grid 2,107 -> 0 in BOTH locales, reading as "no results"). +// +// This line used to be `linked.language.value || linked.language.label`, and the fallback was the +// trap rather than the safety net. When the map reports a language TIER — "Arabic" — there is no +// single ISO code that means it (MEASURED on the live source: "Arabic" covers "Arabic, Sudanese", +// "Arabic, Levantine", "Arabic, Gulf" ... under many different codes), so the code arrives empty +// and the NAME was sent instead. The grid's valueMatches() normalises and compares whole values, so +// "Arabic" matches no row that reads "Arabic, Sudanese" — an empty grid, indistinguishable from a +// genuinely empty result. +// +// The three cases, and none of them may lie: +// one code -> send it. Locale-stable, and the grid filters exactly the selection. +// many codes -> send NOTHING and leave the axis unfiltered. The map is narrowed, the grid is not, +// and the reader can see both — which is honest. Sending the tier NAME would show +// zero rows; sending one of the codes would show a fraction while looking correct. +// Both are worse than not narrowing on an axis we cannot yet express. +// no codes -> nothing is selected; send the label if there is one (the grid->map direction +// always carries a real, single language, so its label is a value the grid owns). +// The `many` case closes properly when filterSet goes multi-value (SPEC-DASHBOARD-KIT D1): the grid +// then takes the whole set and this becomes a real narrowing instead of an honest abstention. +function gridLanguage() { + const codes = Array.isArray(linked.language.codes) ? linked.language.codes : [] + if (codes.length > 1) return '' + return linked.language.value || linked.language.label +} + let rootEl = null // ★ PUSH THE STATE ONTO THE MOUNTED CHILDREN, DON'T JUST RE-COMPUTE THE SECTIONS. @@ -363,7 +401,7 @@ function pushToChildren() { // ★ THE CODE, NOT THE NAME. valueMatches compares the normalized value as well as the label, // so a stable ISO code matches in every locale while a display name only matches in the one it // was fetched in. - grid.setAttribute('primary-language', linked.language.value || linked.language.label) + grid.setAttribute('primary-language', gridLanguage()) } } watch(linked, pushToChildren, { deep: true }) @@ -469,7 +507,7 @@ const sections = computed(() => [ // reason); driving them from the composite is the same channel, not a new one. 'wagf-region': linked.region.value, 'religion-family': linked.religion, - 'primary-language': linked.language.value || linked.language.label, + 'primary-language': gridLanguage(), } } ])