From 161df86c285b1864684101bfd688e436062d6cfa Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 6 Sep 2026 04:59:29 +0000 Subject: [PATCH] Add Latin, and a test so the language list cannot drift again The hand-written ISO 639-1 set shipped one code short, so 'la' reached the live sign-up form as a checkbox. A hand-kept list of 184 entries will drift again, so the test holds it to the standard rather than to my eyesight, and also pins the reason the codes are excluded by name: 'ai' and 'go' are subjects and must survive. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0144uEVbZK3jdaQkwcLYTXPE --- apps/web/src/lib/partners.js | 2 +- apps/web/test/partner-niches.test.js | 36 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 apps/web/test/partner-niches.test.js diff --git a/apps/web/src/lib/partners.js b/apps/web/src/lib/partners.js index 11da275..6c8b99a 100644 --- a/apps/web/src/lib/partners.js +++ b/apps/web/src/lib/partners.js @@ -57,7 +57,7 @@ const LANGUAGE_CODES = new Set([ 'ca','ce','ch','co','cr','cs','cu','cv','cy','da','de','dv','dz','ee','el','en','eo','es','et','eu','fa','ff', 'fi','fj','fo','fr','fy','ga','gd','gl','gn','gu','gv','ha','he','hi','ho','hr','ht','hu','hy','hz','ia','id', 'ie','ig','ii','ik','io','is','it','iu','ja','jv','ka','kg','ki','kj','kk','kl','km','kn','ko','kr','ks','ku', - 'kv','kw','ky','lb','lg','li','ln','lo','lt','lu','lv','mg','mh','mi','mk','ml','mn','mr','ms','mt','my','na', + 'kv','kw','ky','la','lb','lg','li','ln','lo','lt','lu','lv','mg','mh','mi','mk','ml','mn','mr','ms','mt','my','na', 'nb','nd','ne','ng','nl','nn','no','nr','nv','ny','oc','oj','om','or','os','pa','pi','pl','ps','pt','qu','rm', 'rn','ro','ru','rw','sa','sc','sd','se','sg','si','sk','sl','sm','sn','so','sq','sr','ss','st','su','sv','sw', 'ta','te','tg','th','ti','tk','tl','tn','to','tr','ts','tt','tw','ty','ug','uk','ur','uz','ve','vi','vo','wa', diff --git a/apps/web/test/partner-niches.test.js b/apps/web/test/partner-niches.test.js new file mode 100644 index 0000000..7a0a107 --- /dev/null +++ b/apps/web/test/partner-niches.test.js @@ -0,0 +1,36 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import { test } from 'node:test'; + +/** + * The niche picker hides ISO 639-1 codes, because feeds tag themselves with + * their language and those outrank real subjects. The list was hand-written + * and shipped one short: Latin reached the live sign-up form as a checkbox + * reading "la". A hand-kept list drifts, so this holds it to the standard. + */ +const CANONICAL = `aa ab ae af ak am an ar as av ay az ba be bg bh bi bm bn bo br bs ca ce ch co cr cs cu cv cy da de +dv dz ee el en eo es et eu fa ff fi fj fo fr fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id ie ig ii ik io is +it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mr ms mt my na +nb nd ne ng nl nn no nr nv ny oc oj om or os pa pi pl ps pt qu rm rn ro ru rw sa sc sd se sg si sk sl sm sn so sq sr +ss st su sv sw ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zu` + .split(/\s+/) + .filter(Boolean); + +test('every ISO 639-1 code is excluded from the niche picker', async () => { + const src = await readFile(new URL('../src/lib/partners.js', import.meta.url), 'utf8'); + const block = src.match(/const LANGUAGE_CODES = new Set\(\[([\s\S]*?)\]\);/)?.[1]; + assert.ok(block, 'the LANGUAGE_CODES set should be findable'); + const listed = new Set([...block.matchAll(/'([a-z]{2})'/g)].map((m) => m[1])); + + const missing = CANONICAL.filter((code) => !listed.has(code)); + assert.deepEqual(missing, [], `these languages would be offered as niches: ${missing.join(', ')}`); +}); + +test('real two-letter subjects are still offered', async () => { + const src = await readFile(new URL('../src/lib/partners.js', import.meta.url), 'utf8'); + const block = src.match(/const LANGUAGE_CODES = new Set\(\[([\s\S]*?)\]\);/)?.[1]; + const listed = new Set([...block.matchAll(/'([a-z]{2})'/g)].map((m) => m[1])); + // The whole reason the codes are excluded by name rather than by length. + assert.equal(listed.has('ai'), false, 'ai is a subject, not a language'); + assert.equal(listed.has('go'), false, 'go is a subject, not a language'); +});