fix: corrigeer woordplaatjes in taalbibliotheek (v0.4.44-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m1s

This commit is contained in:
Ramon 2026-07-21 22:01:41 +02:00
parent ba4483d5d3
commit 6f593e05b2
4 changed files with 107 additions and 4 deletions

View file

@ -1 +1 @@
0.4.43-beta 0.4.44-beta

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
/* version shown until /api/version resolves (or if the fetch fails, e.g. offline). /* version shown until /api/version resolves (or if the fetch fails, e.g. offline).
Kept in sync by hand with the VERSION file at the repo root on every release. */ Kept in sync by hand with the VERSION file at the repo root on every release. */
const VERSION = "0.4.43-beta"; const VERSION = "0.4.44-beta";
(function(){ (function(){
const tag = document.getElementById("verTag"); const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION; tag.textContent = "v"+VERSION;

View file

@ -411,6 +411,85 @@ const LANGUAGE_CONCEPTS = [
["season","time","seizoen","season","🍁"] ["season","time","seizoen","season","🍁"]
].map(([id,theme,nl,en,pic])=>({id,theme,nl,en,pic})); ].map(([id,theme,nl,en,pic])=>({id,theme,nl,en,pic}));
/* Gecontroleerde Nederlandse beeldcorrecties. Bestaande handgekozen emoji
blijven de terugval; deze lijst corrigeert polyseme woorden en geeft veel
voorkomende concrete woorden een specifieker beeld. */
const LANGUAGE_PICTURE_EXACT=Object.freeze({
groentekraam:"🥕🏪",veehouderij:"🐄",wastafel:"🚰",woonkamermeubel:"🛋️",badkamertegel:"🚿",prullenbak:"🗑️",
tekstproductie:"✍️📄",verdrietverwerking:"😢🧠",bezorgd:"😟",ouderverzorging:"👩❤️",spierkracht:"💪",
schoolslag:"🏊",wedstrijdreglement:"🏀📋",toneelspeler:"🎭",spellingspatroon:"🔤",meetinstrument:"📐",
lentebloem:"🌼",zomerdag:"🌞",herfstblad:"🍂",winterjas:"⛄",jaargetijde:"🍁",gitaarspel:"🎸",
ruimtestation:"🛰️",boekje:"📖",muziek:"🎶",onderzoeksverslag:"🧪📋",grondrecht:"⚖️",
bol:"🥯",toast:"🍞",korst:"🍞",kruimel:"🍞",karnemelk:"🥛",room:"🥛",boter:"🧈",vla:"🍮",
brie:"🧀",plak:"🧀",friet:"🍟",puree:"🥔",schil:"🥔",knol:"🥔",prei:"🥬",kool:"🥬",boon:"🫘",erwtje:"🫛",
koek:"🍪",snoep:"🍬",wafel:"🧇",gebakje:"🧁",slagroom:"🍰",
stam:"🌳",tak:"🌿",wortel:"🌱",stengel:"🌱",knop:"🌷",boeket:"💐",druppel:"💧",plas:"💦",sloot:"🏞️",beek:"🏞️",
licht:"☀️",schaduw:"◐",bui:"🌦️",vorst:"🥶",hagel:"🌨️",vlok:"❄️",aarde:"🌍",grond:"🟫",kiem:"🌱",
bus:"🚌",taxi:"🚕",rit:"🛣️",band:"🛞",step:"🛴",pedaal:"🚲",bel:"🔔",stuur:"🚲",rail:"🛤️",spoor:"🛤️",
roeispaan:"🚣",vleugel:"✈️",piloot:"🧑‍✈️",vlucht:"✈️",pad:"🥾",bocht:"↪️",streep:"",file:"🚗🚗",route:"🗺️",
kast:"🗄️",nachtkast:"🗄️",slaapkamer:"🛏️",slaapkamerraam:"🪟",flat:"🏢",hut:"🛖",dak:"🏠",muur:"🧱",deken:"🛏️",kussen:"🛏️",kruk:"🪑",slot:"🔒",sleutel:"🔑",
pan:"🍳",pot:"🍲",kom:"🥣",lepel:"🥄",bad:"🛁",douche:"🚿",wc:"🚽",kraan:"🚰",zeep:"🧼",
stof:"🫧",vuil:"🗑️",bezem:"🧹",dweil:"🧽",spons:"🧽",
duim:"👍",vinger:"☝️",nagel:"💅",pols:"⌚",teen:"🦶",hiel:"🦶",enkel:"🦵",knie:"🦵",
wang:"🙂",kin:"🙂",nek:"🧣",keel:"🗣️",lip:"👄",kies:"🦷",tong:"👅",speeksel:"💧",gebit:"😁",
trui:"👕",broek:"👖",rok:"👗",long:"🫁",bloed:"🩸",bot:"🦴",spier:"💪",skelet:"🦴",
bewegingsapparaat:"🦴",bewegingsrichting:"🧭",lichaamsbeweging:"🤸",bewegingsreeks:"🔄",bewegingsoefening:"🤸",bewegingspatroon:"💃",gaan:"🚶",stap:"👣",staan:"🧍",zitten:"🪑",racen:"🏁",sprinten:"🏃",haasten:"⏩",vluchten:"🏃",
hupsen:"🐇",bukken:"🙇",rollen:"🤸",draaien:"🔄",blad:"📄",zin:"📝",tekst:"📄",schrift:"📓",
praten:"🗣️",zeggen:"💬",vragen:"❓",roepen:"📣",fluisteren:"🤫",delen:"🤲",geven:"🎁",halen:"📥",brengen:"📤",
leuk:"😀",fijn:"😊",glimlach:"🙂",sip:"😔",verdriet:"😢",pijn:"🤕",kwaad:"😠",ruzie:"💢",zorgen:"😟",
rust:"🧘",kalm:"🙂",stil:"🤫",zacht:"🪶",ademen:"🌬️",dapper:"🦸",durven:"💪",winnen:"🏆",raar:"🤔",wauw:"🤩",
gezin:"👨‍👩‍👧‍👦",ouders:"👪",mama:"👩",tante:"👩",dochter:"👧",papa:"👨",oom:"👨",zoon:"👦",
jongen:"👦",meisje:"👧",kleuter:"🧒",puber:"🧑",maat:"🧑‍🤝‍🧑",buur:"🏘️",gast:"🧑",juf:"👩‍🏫",meester:"👨‍🏫",
leraar:"🧑‍🏫",mentor:"🧑‍🏫",coach:"🧑‍🏫",team:"👥",klas:"🏫",paar:"👫",kring:"⭕",
kaart:"🃏",doel:"🥅",trap:"⚽",veld:"🏟️",basket:"🏀",korf:"🧺",worp:"🤾",score:"💯",punt:"🔵",stuk:"🧩",rand:"🧩",
plaat:"🖼️",beer:"🧸",blok:"🧱",pion:"♟️",plons:"💦",slag:"🏊",prijs:"🏆",beker:"🏆",medaille:"🏅",
straat:"🛣️",landingsbaan:"🛬",plattegrond:"🗺️",landbouwer:"🧑‍🌾",plein:"🏘️",les:"📚",gym:"🤸",kassa:"🧾",kar:"🛒",mand:"🧺",klant:"🧑",arts:"🧑‍⚕️",zaal:"🚪",zorg:"❤️",
boer:"🧑‍🌾",stal:"🏚️",schuur:"🏚️",land:"🌾",erf:"🏡",balie:"🛎️",lezer:"📖",buurt:"🏘️",vijver:"🏞️",
dag:"☀️",uur:"🕐",tijd:"⏰",middag:"🌤️",vroeg:"🌅",wakker:"⏰",ontbijt:"🥣",avond:"🌇",laat:"🌙",
donker:"🌑",week:"🗓️",maand:"📆",jaar:"🎆",datum:"📅",agenda:"📒",feest:"🥳",kaars:"🕯️",ballon:"🎈",
lente:"🌼",zomer:"🌞",herfst:"🍂",winter:"⛄",seconde:"⏱️",kwart:"¼",half:"½",duur:"⏳",
kleur:"🌈",verf:"🎨",kwast:"🖌️",doek:"🖼️",palet:"🎨",tekening:"🖍️",lijn:"",vorm:"🔷",vak:"◻️",
toon:"🎵",lied:"🎶",stem:"🗣️",klank:"🔊",trom:"🥁",fluit:"🪈",snaar:"🎸",toets:"🎹",
dans:"💃",sprong:"🤸",draai:"🔄",toneel:"🎭",rol:"🎭",pak:"👔",podium:"🎭",foto:"📷",film:"🎬",lens:"📷",
zoeken:"🔎",vraag:"❓",vondst:"💡",proef:"🧪",test:"✅",buis:"🧪",mengen:"🥣",
magneet:"🧲",ijzer:"🔩",pool:"🧲",kracht:"💪",wiel:"🛞",as:"⚙️",tand:"🦷",veer:"🪶",hefboom:"⚖️",
stroom:"⚡",draad:"🧵",stekker:"🔌",digitaal:"💻",internet:"🌐",programmeren:"🧑‍💻",computer:"💻",muis:"🖱️",scherm:"🖥️",bestand:"📄",ruimte:"🌌",
planeet:"🪐",raket:"🚀",satelliet:"🛰️",heelal:"🌌",astronaut:"🧑‍🚀",
letter:"🔤",woord:"🔠",naam:"🏷️",teken:"✍️",komma:",",titel:"🏷️",prent:"🖼️",taal:"🗣️",
spraak:"💬",verhaal:"📖",nul:"0⃣",een:"1⃣",twee:"2⃣",drie:"3⃣",getal:"🔢",cijfer:"🔣",reeks:"🔢",
som:"",plus:"",min:"",keer:"✖️",hoek:"📐",vlak:"◻️",lengte:"📏",
samen:"🤝",hulp:"🆘",beurt:"🔄",afspraak:"🤝",regel:"📋",wijk:"🏘️",wereld:"🌍",grens:"🚧",
noord:"⬆️",zuid:"⬇️",oost:"➡️",west:"⬅️",plek:"📍",richting:"🧭",nieuws:"📰",krant:"🗞️",bericht:"💬",
radio:"📻",media:"📺",afval:"🗑️",bak:"🗑️",glas:"♻️",papier:"📄",recht:"⚖️",plicht:"📋",keus:"🔀",
wet:"⚖️",eerlijk:"⚖️",mening:"💭",besluit:"✅"
});
/* Betekenisdragende delen voor samenstellingen. Het familiebeeld blijft
voorop staan; maximaal één tweede symbool verduidelijkt het onderscheid. */
const LANGUAGE_PICTURE_HINTS=Object.freeze([
["bescherming","🛡️"],["veiligheid","🛡️"],["verzorging","🧼"],["vaardigheid","🎯"],["onderzoek","🔬"],
["bereiding","🍳"],["productie","🏭"],["verwerking","🏭"],["organisatie","📋"],["ontwikkeling","📈"],
["geschiedenis","📜"],["industrie","🏭"],["maatschappij","🌍"],["informatie",""],["technologie","💻"],
["wedstrijd","🏆"],["training","🏋️"],["strategie","♟️"],["berekening","🧮"],["verdeling","📊"],
["winkel","🏪"],["fabriek","🏭"],["bedrijf","🏭"],["centrum","🏙️"],["gebouw","🏢"],["kamer","🚪"],
["boek","📕"],["schrift","📓"],["kaart","🗺️"],["verslag","📋"],["bericht","💬"],["programma","💻"],
["verlichting","💡"],["licht","💡"],["water","💧"],["lucht","🌬️"],["grond","🟫"],["bloem","🌷"],
["boom","🌳"],["tuin","🌱"],["weide","🌿"],["storm","🌪️"],["regen","🌧️"],["sneeuw","❄️"],
["bak","📦"],["voer","🍽️"],["hok","🏠"],["stal","🏚️"],["riem","🦮"],["kooi","🪹"],
["boot","⛵"],["reis","🧳"],["straat","🏘️"],["station","🚉"],["haven","⚓"],
["deur","🚪"],["raam","🪟"],["kast","🗄️"],["tafel","🪑"],["stoel","🪑"],["bed","🛏️"],
["zorg","❤️"],["hulp","🤝"],["school","🏫"],["leer","📚"],["taal","🔤"],["reken","🧮"],
["spel","🎲"],["sport","🏅"],["feest","🥳"],["dag","📅"],["tijd","⏰"],["jaar","🗓️"],
["kracht","💪"],["energie","⚡"],["stroom","⚡"],["machine","⚙️"],["instrument","🎵"],["muziek","🎶"],
["groep","👥"],["team","👥"],["familie","👨‍👩‍👧"],["ouder","👪"],["kind","🧒"],["mens","🧑"],
["wereld","🌍"],["milieu","♻️"],["afval","🗑️"],["bestuur","🏛️"]
]);
function languageProgressionPicture(word,fallback){
if(LANGUAGE_PICTURE_EXACT[word])return LANGUAGE_PICTURE_EXACT[word];
const match=LANGUAGE_PICTURE_HINTS.filter(([part])=>word.includes(part)).sort((a,b)=>b[0].length-a[0].length)
.find(([,emoji])=>emoji!==fallback);
return match?fallback+match[1]:fallback
}
/* Ruim duizend aanvullende Nederlandse woorden, geordend in woordfamilies. /* Ruim duizend aanvullende Nederlandse woorden, geordend in woordfamilies.
Iedere regel loopt bewust van een kort, concreet basiswoord naar langere Iedere regel loopt bewust van een kort, concreet basiswoord naar langere
afleidingen, samenstellingen en schooltaal. De positie op de regel bepaalt afleidingen, samenstellingen en schooltaal. De positie op de regel bepaalt
@ -444,7 +523,7 @@ const LANGUAGE_NL_PROGRESSION_WORDS=(()=>{
const word=raw.trim();if(!word||seen.has(word))return;seen.add(word); const word=raw.trim();if(!word||seen.has(word))return;seen.add(word);
const slug=word.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z]/g,""); const slug=word.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z]/g,"");
const yearGroup=LANGUAGE_PROGRESSION_YEARS[Math.min(familyPosition++,LANGUAGE_PROGRESSION_YEARS.length-1)]; const yearGroup=LANGUAGE_PROGRESSION_YEARS[Math.min(familyPosition++,LANGUAGE_PROGRESSION_YEARS.length-1)];
out.push({id:"nl-"+theme+"-"+slug,theme,nl:word,pic,yearGroup}); out.push({id:"nl-"+theme+"-"+slug,theme,nl:word,pic:languageProgressionPicture(word,pic),yearGroup,pictureChecked:true});
}); });
})); }));
return out return out
@ -474,7 +553,8 @@ function languageThemeList(lang=LANG){
})).filter(theme=>theme.words.length); })).filter(theme=>theme.words.length);
} }
function languageEmojiDataUrl(emoji,colors=["#f4f8ff","#dce9fa"]){ function languageEmojiDataUrl(emoji,colors=["#f4f8ff","#dce9fa"]){
const svg=`<svg xmlns="http://www.w3.org/2000/svg" width="320" height="320" viewBox="0 0 320 320"><defs><linearGradient id="g" x2="1" y2="1"><stop stop-color="${colors[0]}"/><stop offset="1" stop-color="${colors[1]}"/></linearGradient></defs><rect width="320" height="320" rx="48" fill="url(#g)"/><circle cx="160" cy="160" r="112" fill="#fff" opacity=".92"/><text x="160" y="177" text-anchor="middle" dominant-baseline="middle" font-family="Apple Color Emoji,Segoe UI Emoji,Noto Color Emoji,sans-serif" font-size="148">${emoji}</text></svg>`; const fontSize=emoji.length>4?104:emoji.length>2?122:148;
const svg=`<svg xmlns="http://www.w3.org/2000/svg" width="320" height="320" viewBox="0 0 320 320"><defs><linearGradient id="g" x2="1" y2="1"><stop stop-color="${colors[0]}"/><stop offset="1" stop-color="${colors[1]}"/></linearGradient></defs><rect width="320" height="320" rx="48" fill="url(#g)"/><circle cx="160" cy="160" r="112" fill="#fff" opacity=".92"/><text x="160" y="177" text-anchor="middle" dominant-baseline="middle" font-family="Apple Color Emoji,Segoe UI Emoji,Noto Color Emoji,sans-serif" font-size="${fontSize}">${emoji}</text></svg>`;
return "data:image/svg+xml;charset=utf-8,"+encodeURIComponent(svg); return "data:image/svg+xml;charset=utf-8,"+encodeURIComponent(svg);
} }
function languagePictureCatalog(lang=LANG){ function languagePictureCatalog(lang=LANG){

View file

@ -48,6 +48,29 @@ test('taalwidgets delen ruim duizend extra Nederlandse woorden over leerjaar en
assert.equal(data.themesEn.reduce((sum,theme)=>sum+theme.words.length,0),data.concepts.length); assert.equal(data.themesEn.reduce((sum,theme)=>sum+theme.words.length,0),data.concepts.length);
}); });
test('alle aanvullende woorden hebben een gecontroleerd en correct gekoppeld woordplaatje',async()=>{
const data=await languageData();
const builtinByName=new Map(data.catalogNl.images.filter(image=>image.builtin).map(image=>[image.name,image]));
assert.ok(new Set(data.progression.map(word=>word.pic)).size>=400,'verwacht brede beeldvariatie');
for(const word of data.progression){
assert.equal(word.pictureChecked,true,word.nl);
const image=builtinByName.get(word.nl);
assert.ok(image,word.nl);
assert.equal(image.value,word.pic,word.nl);
assert.ok(image.src.startsWith('data:image/svg+xml;charset=utf-8,'),word.nl);
}
const expected={
kattenbak:'🐈📦',kattenvoer:'🐈🍽️',groentekraam:'🥕🏪',landingsbaan:'🛬',
kast:'🗄️',slaapkamerraam:'🪟',bewegingsapparaat:'🦴',bewegingsrichting:'🧭',
digitaal:'💻',kaart:'🃏',landbouwer:'🧑‍🌾',straat:'🛣️',plattegrond:'🗺️',
veehouderij:'🐄',wastafel:'🚰',tekstproductie:'✍️📄',verdrietverwerking:'😢🧠',
bezorgd:'😟',schoolslag:'🏊',toneelspeler:'🎭',spellingspatroon:'🔤',
meetinstrument:'📐',ruimtestation:'🛰️',grondrecht:'⚖️'
};
for(const [word,picture] of Object.entries(expected))
assert.equal(data.progression.find(item=>item.nl===word)?.pic,picture,word);
});
test('alle oude startwoorden blijven staan en krijgen ook een bibliotheekplaatje',async()=>{ test('alle oude startwoorden blijven staan en krijgen ook een bibliotheekplaatje',async()=>{
const data=await languageData(); const data=await languageData();
const oldNl=['aap','vis','zon','kat','bal','ei','boom','huis','maan','boot','kip','muis','boek','ster','roos','vuur','fiets','taart','jas','bril','klok','peer','kaas','eend','hand','voet','neus','oog','oor','mond']; const oldNl=['aap','vis','zon','kat','bal','ei','boom','huis','maan','boot','kip','muis','boek','ster','roos','vuur','fiets','taart','jas','bril','klok','peer','kaas','eend','hand','voet','neus','oog','oor','mond'];