feat: slot op liniaal/geodriehoek en richtingsbewust langs de lat tekenen (v0.3.76-beta)
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 34s

- Slot-knop (🔓/🔒) op liniaal én geodriehoek: vastgezet gereedschap kan niet meer verschuiven of draaien (draaiknop verdwijnt), er kan alleen nog langs getekend worden; tweede klik ontgrendelt
- Naast de lat beslist nu de richting i.p.v. één vaste afstand: binnen 22px van een rand wacht de haal de eerste ~7px beweging af - loopt die grofweg evenwijdig aan de rand (≤30°), dan kleeft hij, anders blijft hij vrij; een tik zet gewoon een stip
- Daarmee is langs de lat tekenen betrouwbaar (ook met dikke digibord-vingers) zónder dat de lat vrije halen in de buurt grijpt
- Op de lat zelf blijft de intentie ondubbelzinnig: direct kleven binnen 24px van de rand
- Geverifieerd in headless Chromium: 12 nieuwe checks (richtingsregel, stip-tik, slot aan/uit, vastgezet = onverplaatsbaar maar betekenbaar) + de drie bestaande suites (35 checks) blijven groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
This commit is contained in:
Ramon 2026-07-16 14:04:15 +02:00
parent 5d12d2f8ec
commit 85268050fd
4 changed files with 81 additions and 30 deletions

View file

@ -1 +1 @@
0.3.75-beta 0.3.76-beta

View file

@ -373,6 +373,8 @@
.dtool-opts button:hover{background:var(--accent-soft);} .dtool-opts button:hover{background:var(--accent-soft);}
/* lengteknop toont de maat ("10 cm") en is dus breder dan een rond knopje */ /* lengteknop toont de maat ("10 cm") en is dus breder dan een rond knopje */
.dtool-opts .do-wide{width:auto; min-width:48px; padding:0 9px; border-radius:12px;} .dtool-opts .do-wide{width:auto; min-width:48px; padding:0 9px; border-radius:12px;}
/* slot-knop kleurt mee zodra het gereedschap vaststaat */
.dtool-opts .do-lock.on{background:var(--accent-soft);}
/* live hoek-uitlezing tijdens het draaien van liniaal/geodriehoek */ /* live hoek-uitlezing tijdens het draaien van liniaal/geodriehoek */
.dtool-deg{ .dtool-deg{
display:none; position:absolute; left:50%; top:50%; margin:-16px 0 0 -24px; display:none; position:absolute; left:50%; top:50%; margin:-16px 0 0 -24px;

View file

@ -58,6 +58,7 @@ const REGISTRY = [
{ id:"names", cat:"tools", icon:"🎯", w:420, h:430, minW:320, minH:330, mount:mountNames }, { id:"names", cat:"tools", icon:"🎯", w:420, h:430, minW:320, minH:330, mount:mountNames },
{ id:"birthday",cat:"class", icon:"🎂", w:620, h:560, minW:400, minH:400, mount:mountBirthday }, { id:"birthday",cat:"class", icon:"🎂", w:620, h:560, minW:400, minH:400, mount:mountBirthday },
{ id:"schedule", cat:"class", icon:"📅", w:500, h:520, minW:340, minH:340, mount:mountSchedule }, { id:"schedule", cat:"class", icon:"📅", w:500, h:520, minW:340, minH:340, mount:mountSchedule },
{ id:"light", cat:"class", icon:"🚦", w:480, h:440, minW:320, minH:320, mount:mountLight },
{ id:"mood", cat:"class", icon:"🌡️", w:530, h:360, minW:350, minH:260, mount:mountMood }, { id:"mood", cat:"class", icon:"🌡️", w:530, h:360, minW:350, minH:260, mount:mountMood },
{ id:"poll", cat:"class", icon:"📊", w:540, h:500, minW:360, minH:330, mount:mountPoll }, { id:"poll", cat:"class", icon:"📊", w:540, h:500, minW:360, minH:330, mount:mountPoll },
{ id:"media", cat:"media", icon:"🎬", w:560, h:420, minW:320, minH:240, mount:mountMedia } { id:"media", cat:"media", icon:"🎬", w:560, h:420, minW:320, minH:240, mount:mountMedia }
@ -577,8 +578,10 @@ function makeMovable(t){
const px = (e.clientX - r.left) * (board.clientWidth / r.width); const px = (e.clientX - r.left) * (board.clientWidth / r.width);
const py = (e.clientY - r.top) * (board.clientHeight / r.height); const py = (e.clientY - r.top) * (board.clientHeight / r.height);
const hit = nearestEdge(px, py); const hit = nearestEdge(px, py);
if(hit && hit.d <= 24){ startInkStroke(e, 24); return; } if(hit && hit.d <= 24){ startInkStroke(e, true); return; }
} }
/* vastgezet gereedschap verschuift en draait niet meer (slot-knop) */
if(t._locked) return;
if(e.target.classList.contains("dtool-rot")){ if(e.target.classList.contains("dtool-rot")){
const r = t.getBoundingClientRect(); const r = t.getBoundingClientRect();
const cx = r.left+r.width/2, cy = r.top+r.height/2; const cx = r.left+r.width/2, cy = r.top+r.height/2;
@ -661,6 +664,7 @@ function toggleDTool(kind){
<div class="dtool-opts"> <div class="dtool-opts">
<button class="do-len do-wide"></button> <button class="do-len do-wide"></button>
<button class="do-hc"></button> <button class="do-hc"></button>
<button class="do-lock">🔓</button>
</div>`; </div>`;
t.querySelector(".do-len").addEventListener("click", ()=>{ t.querySelector(".do-len").addEventListener("click", ()=>{
t._cm = RULER_CMS[(RULER_CMS.indexOf(t._cm)+1) % RULER_CMS.length]; drawRuler(); t._cm = RULER_CMS[(RULER_CMS.indexOf(t._cm)+1) % RULER_CMS.length]; drawRuler();
@ -764,6 +768,7 @@ function toggleDTool(kind){
<button class="do-len do-wide"></button> <button class="do-len do-wide"></button>
<button class="do-mode do-wide"></button> <button class="do-mode do-wide"></button>
<button class="do-hc"></button> <button class="do-hc"></button>
<button class="do-lock">🔓</button>
</div>`; </div>`;
t.querySelector(".do-len").addEventListener("click", ()=>{ t.querySelector(".do-len").addEventListener("click", ()=>{
t._cm = GEO_CMS[(GEO_CMS.indexOf(t._cm)+1) % GEO_CMS.length]; drawGeo(); t._cm = GEO_CMS[(GEO_CMS.indexOf(t._cm)+1) % GEO_CMS.length]; drawGeo();
@ -852,6 +857,18 @@ function toggleDTool(kind){
const rot = document.createElement("button"); const rot = document.createElement("button");
rot.className = "dtool-rot"; rot.textContent = "↻"; rot.className = "dtool-rot"; rot.textContent = "↻";
t.appendChild(rot); t.appendChild(rot);
/* slot: zet het gereedschap vast op zijn plek - niets kan hem meer
verschuiven of draaien, zodat er rustig langs getekend kan worden */
const lockBtn = t.querySelector(".do-lock");
const syncLock = ()=>{
lockBtn.textContent = t._locked ? "🔒" : "🔓";
lockBtn.title = T("dtLock");
lockBtn.setAttribute("aria-pressed", String(!!t._locked));
lockBtn.classList.toggle("on", !!t._locked);
rot.style.display = t._locked ? "none" : "";
};
lockBtn.addEventListener("click", ()=>{ t._locked = !t._locked; syncLock(); });
syncLock();
} }
makeMovable(t); makeMovable(t);
board.appendChild(t); board.appendChild(t);
@ -952,22 +969,31 @@ function snapPoint(x, y){
/* start van een haal; ook aanroepbaar vanaf de liniaal/geodriehoek zelf /* start van een haal; ook aanroepbaar vanaf de liniaal/geodriehoek zelf
(pen op de randzone van de lat = tekenen, niet verslepen) - de pointer (pen op de randzone van de lat = tekenen, niet verslepen) - de pointer
capture op bInk stuurt de vervolg-events vanzelf hierheen. capture op bInk stuurt de vervolg-events vanzelf hierheen.
snapDist: naast de lat een kleine zone (10px, anders "grijpt" de lat Naast de lat beslist de RICHTING: binnen 22px van een rand wachten we de
halen die vrij bedoeld zijn), óp de lat zelf ruimer (24px, zie makeMovable). */ eerste ~7px beweging af; loopt die grofweg evenwijdig aan de rand (30°),
function startInkStroke(e, snapDist = 10){ dan kleeft de haal - anders blijft hij vrij. Zo grijpt de lat geen vrije
halen en werkt langs de rand tekenen toch betrouwbaar. Op de lat zelf
(fromTool) is de intentie ondubbelzinnig en kleeft de haal direct. */
let bPend = null;
function startInkStroke(e, fromTool = false){
if(PEN.tool==="text"){ startBoardText(e); return; } if(PEN.tool==="text"){ startBoardText(e); return; }
bInk.setPointerCapture(e.pointerId); bInk.setPointerCapture(e.pointerId);
bDraw = true; bDraw = true;
PEN.nib = PEN.size*0.8; PEN.nib = PEN.size*0.8;
[bx,by] = bPos(e); [bx,by] = bPos(e);
bSnap = null; bSnap = null; bPend = null;
bMidX = bMidY = null;
if(PEN.tool!=="erase" && PEN.tool!=="hand"){ if(PEN.tool!=="erase" && PEN.tool!=="hand"){
const k = bInk.width / board.clientWidth; const k = bInk.width / board.clientWidth;
const hit = nearestEdge(bx/k, by/k); const hit = nearestEdge(bx/k, by/k);
if(hit && hit.d <= snapDist) bSnap = hit; if(fromTool){
if(hit && hit.d <= 24) bSnap = hit;
}else if(hit && hit.d <= 22){
bPend = { x0:bx, y0:by, hit };
return; /* nog niets tekenen; de eerste beweging beslist (flush hieronder) */
}
} }
[bx,by] = snapPoint(bx, by); [bx,by] = snapPoint(bx, by);
bMidX = bMidY = null;
bStroke(bx+0.01, by+0.01, e.pressure, e.pointerType); bStroke(bx+0.01, by+0.01, e.pressure, e.pointerType);
} }
bInk.addEventListener("pointerdown", e=>{ bInk.addEventListener("pointerdown", e=>{
@ -979,11 +1005,30 @@ bInk.addEventListener("pointermove", e=>{
if(!bDraw) return; if(!bDraw) return;
(e.getCoalescedEvents ? e.getCoalescedEvents() : [e]).forEach(ev=>{ (e.getCoalescedEvents ? e.getCoalescedEvents() : [e]).forEach(ev=>{
const [rx,ry] = bPos(ev); const [rx,ry] = bPos(ev);
if(bPend){
const k = bInk.width / board.clientWidth;
const dx = rx - bPend.x0, dy = ry - bPend.y0;
if(Math.hypot(dx, dy)/k < 7) return; /* nog te weinig beweging om te beslissen */
const move = Math.atan2(dy, dx), edge = Math.atan2(bPend.hit.uy, bPend.hit.ux);
let diff = Math.abs(move - edge) % Math.PI;
diff = Math.min(diff, Math.PI - diff);
if(diff <= Math.PI/6) bSnap = bPend.hit;
const [sx, sy] = snapPoint(bPend.x0, bPend.y0);
bx = sx; by = sy; bMidX = bMidY = null;
bStroke(sx+0.01, sy+0.01, ev.pressure, ev.pointerType);
bPend = null;
}
const [x,y] = snapPoint(rx, ry); const [x,y] = snapPoint(rx, ry);
bStroke(x, y, ev.pressure, ev.pointerType); bStroke(x, y, ev.pressure, ev.pointerType);
}); });
}); });
const bStop = ()=>{ const bStop = ()=>{
if(bDraw && bPend){
/* tik zonder beweging vlak naast de lat: gewoon een vrije stip zetten */
bx = bPend.x0; by = bPend.y0; bMidX = bMidY = null;
bStroke(bx+0.01, by+0.01, 0, "mouse");
bPend = null;
}
if(bDraw){ if(bDraw){
/* markeerstift: de haal staat dekkend op de overlay - nu in één keer /* markeerstift: de haal staat dekkend op de overlay - nu in één keer
met vaste transparantie op de inktlaag zetten (egale kleur, geen met vaste transparantie op de inktlaag zetten (egale kleur, geen

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.3.75-beta"; const VERSION = "0.3.76-beta";
(function(){ (function(){
const tag = document.getElementById("verTag"); const tag = document.getElementById("verTag");
tag.textContent = "v"+VERSION; tag.textContent = "v"+VERSION;
@ -96,15 +96,16 @@ const I18N = {
wFull:"Maximaliseren", wUnfull:"Terugzetten", wFull:"Maximaliseren", wUnfull:"Terugzetten",
wZoom:"Inhoud groter of kleiner (voor slechtzienden)", wZoom:"Inhoud groter of kleiner (voor slechtzienden)",
wg_flits:"Flitswoorden", wg_flits_d:"Een woord flitst kort in beeld lezen voordat het verdwijnt!", wg_flits:"Flitswoorden", wg_flits_d:"Een woord flitst kort in beeld lezen voordat het verdwijnt!",
flFlash:"⚡ Flits", flShow:"👁 Toon", flNext:"Volgende ▸", flSec:"sec", flFlash:"⚡ Flits", flShow:"👁 Toon", flNext:"Volgende ▸", flSec:"sec", flMission:"Lees het woord voordat het verdwijnt.", flQuestion:"Kon je het woord zelf lezen?", flGotIt:"🌟 Gelukt!", flAgain:"Nog oefenen", flScore:"{score} sterren",
wg_dice:"Dobbelstenen", wg_dice_d:"Gooi 1, 2 of 3 grote dobbelstenen.", wg_dice:"Dobbelstenen", wg_dice_d:"Gooi 1, 2 of 3 grote dobbelstenen.",
diceRoll:"🎲 Gooi!", diceSum:"Samen", diceRoll:"🎲 Gooi!", diceSum:"Samen", diceMission:"Gooi, tel de ogen en controleer de uitkomst.", diceHistory:"Vorige worpen",
wg_light:"Stoplicht", wg_light_d:"Rood, oranje of groen bijvoorbeeld voor het werkrumoer.", wg_light:"Klassenstoplicht", wg_light_d:"Maak in één oogopslag duidelijk of kinderen luisteren, fluisteren of rustig mogen werken.",
lightRed:"Rood", lightRedHint:"Stop en luister", lightOrange:"Oranje", lightOrangeHint:"Fluister en rond af", lightGreen:"Groen", lightGreenHint:"Je mag rustig werken", lightStatus:"{color}: {hint}",
wg_names:"Namenkiezer", wg_names_d:"Kies willekeurig een naam uit de klas.", wg_names:"Namenkiezer", wg_names_d:"Kies willekeurig een naam uit de klas.",
namesPh:"Eén naam per regel…", namesPick:"🎯 Kies!", namesNoRep:"Zonder herhaling", namesPh:"Eén naam per regel…", namesPick:"🎯 Kies!", namesNoRep:"Zonder herhaling",
namesDone:"Iedereen is geweest! 🎉", namesDone:"Iedereen is geweest! 🎉", namesReset:"Opnieuw", namesProgress:"{used} van {total} geweest",
wg_hak:"Hakken & plakken", wg_hak_d:"Woorden in klanken hakken en weer plakken, met voorlezen.", wg_hak:"Hakken & plakken", wg_hak_d:"Woorden in klanken hakken en weer plakken, met voorlezen.",
hakChop:"✂️ Hak", hakGlue:"🔗 Plak", hakSay:"🔊 Lees voor", hakChop:"✂️ Hak", hakGlue:"🔗 Plak", hakSay:"🔊 Lees voor", hakHint:"Bekijk en hoor de klankgroepen in het woord.",
wg_ball:"Ballonnenwoord", wg_ball_d:"Raad het woord letter voor letter voordat de ballonnen knappen.", wg_ball:"Ballonnenwoord", wg_ball_d:"Raad het woord letter voor letter voordat de ballonnen knappen.",
wg_anchor:"Ankerwoorden", wg_anchor_d:"Woordweb voor woordenschatonderwijs: leer woorden in samenhang rond een themawoord (het anker), met plaatjes. Elk woord verankert aan de woorden eromheen.", wg_anchor:"Ankerwoorden", wg_anchor_d:"Woordweb voor woordenschatonderwijs: leer woorden in samenhang rond een themawoord (het anker), met plaatjes. Elk woord verankert aan de woorden eromheen.",
fabAnchor:"Ankerdiagram (woordweb)", fabAnchor:"Ankerdiagram (woordweb)",
@ -114,15 +115,15 @@ const I18N = {
birthdaySprinkles:"Spikkels", birthdayFruit:"Fruit", birthdayStars:"Sterren", birthdayNone:"Geen versiering", birthdaySprinkles:"Spikkels", birthdayFruit:"Fruit", birthdayStars:"Sterren", birthdayNone:"Geen versiering",
wg_numberline:"Getallenlijn", wg_numberline_d:"Oefen getalbegrip met een instelbare, interactieve getallenlijn.", wg_numberline:"Getallenlijn", wg_numberline_d:"Oefen getalbegrip met een instelbare, interactieve getallenlijn.",
numberlineFrom:"Van", numberlineTo:"Tot", numberlineStep:"Stap", numberlineNew:"Nieuwe opdracht", numberlineTask:"Zet de stip op {number}", numberlineFrom:"Van", numberlineTo:"Tot", numberlineStep:"Stap", numberlineNew:"Nieuwe opdracht", numberlineTask:"Zet de stip op {number}",
numberlineCheck:"Controleren", numberlineGood:"Goed gevonden! 🌟", numberlineTry:"Kijk nog eens naar de getallenlijn.", numberlineCheck:"Controleren", numberlineGood:"Goed gevonden! 🌟", numberlineTry:"Kijk nog eens naar de getallenlijn.", numberlineScore:"{score} sterren · reeks {streak}",
wg_fractions:"Breukenmuur", wg_fractions_d:"Vergelijk breuken visueel en markeer gelijke delen.", wg_fractions:"Breukenmuur", wg_fractions_d:"Bouw breuken, vergelijk de gekleurde delen en ontdek gelijkwaardige breuken.",
wg_clock:"Oefenklok", wg_clock_d:"Leer kloktijden op vier niveaus met meerdere leerwijzen en spellen.", wg_clock:"Oefenklok", wg_clock_d:"Leer kloktijden op vier niveaus met meerdere leerwijzen en spellen.",
wg_placevalue:"Plaatswaardetabel", wg_placevalue_d:"Ontdek de waarde van cijfers tot honderdduizend.", wg_placevalue:"Plaatswaardetabel", wg_placevalue_d:"Ontdek de waarde van cijfers tot honderdduizend.",
wg_money:"Geldrekenen", wg_money_d:"Oefen bedragen maken, geld tellen en wisselgeld op drie niveaus.", wg_money:"Geldrekenen", wg_money_d:"Oefen bedragen maken, geld tellen en wisselgeld op drie niveaus.",
wg_trees:"Bomen & bladeren", wg_trees_d:"Leer achttien Nederlandse boomsoorten met vijf foto-, kenmerk- en koppeloefeningen.", wg_trees:"Bomen & bladeren", wg_trees_d:"Leer achttien Nederlandse boomsoorten met vijf foto-, kenmerk- en koppeloefeningen.",
wg_birds:"Vogels herkennen", wg_birds_d:"Leer achttien Nederlandse vogels met vier foto-, kenmerk- en naamoefeningen.", wg_birds:"Vogels herkennen", wg_birds_d:"Leer achttien Nederlandse vogels met vier foto-, kenmerk- en naamoefeningen.",
wg_plants:"Wilde planten", wg_plants_d:"Herken twaalf algemene wilde planten aan echte foto's en duidelijke veldkenmerken.", wg_plants:"Wilde planten", wg_plants_d:"Herken twaalf algemene wilde planten aan echte foto's en duidelijke veldkenmerken.",
wg_topography:"Topografie Nederland", wg_topography_d:"Oefen provincies, plaatsen, landsdelen, rivieren en werelddelen op nauwkeurige kaarten.", wg_topography:"Topografie", wg_topography_d:"Oefen Nederland én de wereld: provincies, plaatsen, landsdelen, rivieren en werelddelen op nauwkeurige kaarten.",
worldActivity:"Werkvorm", worldLearn:"Leren", worldQuiz:"Quiz", worldExercise:"Oefening", worldLevel:"Niveau", worldTreeView:"Wat zie je?", worldTreeWhole:"Hele boom", worldTreeLeaf:"Blad", worldTreeMixed:"Boom en blad", worldActivity:"Werkvorm", worldLearn:"Leren", worldQuiz:"Quiz", worldExercise:"Oefening", worldLevel:"Niveau", worldTreeView:"Wat zie je?", worldTreeWhole:"Hele boom", worldTreeLeaf:"Blad", worldTreeMixed:"Boom en blad",
worldExerciseRecognize:"Herken de soort", worldExercisePair:"Koppel boom en blad", worldExerciseClue:"Raad met kenmerken", worldExercisePhoto:"Kies de juiste foto", worldExerciseLatin:"Wetenschappelijke naam", worldExerciseRecognize:"Herken de soort", worldExercisePair:"Koppel boom en blad", worldExerciseClue:"Raad met kenmerken", worldExercisePhoto:"Kies de juiste foto", worldExerciseLatin:"Wetenschappelijke naam",
worldScore:"Score: {score} · reeks: {streak}", worldExploreHint:"Bekijk de kenmerken en vergelijk de soorten.", worldQuestionTree:"Welke boom zie je?", worldQuestionLeaf:"Bij welke boom hoort dit blad?", worldQuestionBird:"Welke vogel zie je?", worldQuestionPlant:"Welke wilde plant zie je?", worldScore:"Score: {score} · reeks: {streak}", worldExploreHint:"Bekijk de kenmerken en vergelijk de soorten.", worldQuestionTree:"Welke boom zie je?", worldQuestionLeaf:"Bij welke boom hoort dit blad?", worldQuestionBird:"Welke vogel zie je?", worldQuestionPlant:"Welke wilde plant zie je?",
@ -146,10 +147,10 @@ const I18N = {
wg_mood:"Gevoelsmeter", wg_mood_d:"Doe een snelle, anonieme check-in met de klas.", wg_mood:"Gevoelsmeter", wg_mood_d:"Doe een snelle, anonieme check-in met de klas.",
wg_poll:"Klaspoll", wg_poll_d:"Stem samen op maximaal zes antwoorden.", wg_poll:"Klaspoll", wg_poll_d:"Stem samen op maximaal zes antwoorden.",
clock24Hour:"24-uursklok", clock24Hour:"24-uursklok",
widgetSettings:"Instellingen", clockWelcome:"Oefenen met de klok", clockWelcomeHint:"Kies bovenaan niveau 1, 2 of 3. Kies bij Instellingen hoe de opdracht wordt getoond en start daarna.", clockSetTitle:"Zet de wijzers op de goede tijd", clockReadTitle:"Bekijk de opdracht en maak de tijd", clockChooseTitle:"Kies het juiste tijdblok", clockYourTask:"Jouw opdracht", clockLinkHands:"Grote wijzer draait mee", clockTypeHint:"Voer de tijd in als UU:MM.", clockLevel1Hint:"Niveau 1: hele en halve uren", clockLevel2Hint:"Niveau 2: stappen van vijf minuten", clockLevel3Hint:"Niveau 3: alle minuten, met optioneel 24 uur en dagdelen", clockBuildHint:"Sleep vier cijfers naar de vakken en maak UU:MM.", clockDigitGhost:"?", clockDigit:"Cijfer {digit}", clockIncomplete:"Maak eerst de volledige tijd af.", clockCorrect:"Goed gedaan! Kies de volgende opdracht. 🌟", clockTryAgain:"Bijna! Probeer het nog een keer.", clockStartTask:"Start opdracht", clockNextTask:"Volgende opdracht", clockLevel:"Niveau", clockLevelHour:"Hele uren", clockLevelQuarter:"Kwartieren", clockLevelFive:"Vijf minuten", clockLevelMinute:"Iedere minuut", clockLearningStyle:"Opdracht tonen", clockStyleAnalogue:"Analoge klok", clockStyleDigital:"Grote digitale tijd", clockStyleWords:"In woorden", clockStyleBoth:"Klok, cijfers en woorden", clockDragHint:"Sleep de wijzers om de tijd te veranderen.", clockGame:"Spel", clockGameSet:"Klok zetten", clockGameRead:"Tijd aflezen", clockGameChoose:"Kies de tijd", clockStart:"Kies Nieuwe opdracht om te beginnen", clockRead:"Welke tijd zie je? Stel je antwoord hieronder in.", clockChoose:"Welke digitale tijd hoort bij deze klok?", clockTry:"Nog niet. Het goede antwoord is {time}.", clockScore:"Score: {score} · reeks: {streak}", clockWordsHour:"{hour} uur", clockWordsQuarterPast:"kwart over {hour}", clockWordsHalf:"half {hour}", clockWordsQuarterTo:"kwart voor {hour}", clockWordsPast:"{minutes} over {hour}", clockWordsTo:"{minutes} voor {hour}", clockMorning:"in de ochtend", clockAfternoon:"in de middag", clockEvening:"in de avond", clockNight:"in de nacht", fractionRows:"Rijen", fractionLabels:"Breuken tonen", clockTask:"Oefenopdracht", clockSet:"Zet de klok op {time}", clockHour:"Uur", clockMinute:"Minuten", placeNumber:"Getal", moneyMake:"Maak € {amount}", wordtypeSentence:"Zin", wordtypeHint:"Tik: blauw zelfstandig naamwoord · groen werkwoord · geel bijvoeglijk naamwoord", scheduleActivity:"activiteit…", scheduleEmpty:"Voeg de eerste activiteit toe.", pollReset:"Opnieuw", pollQuestion:"Vraag", pollOptions:"Antwoorden (één per regel)", galleryFavorites:"Favorieten", galleryFavorite:"Favoriet maken", galleryEmpty:"Geen widgets gevonden.", gallerySearch:"Zoek widgets…", templateMath:"Rekenles", templateLanguage:"Taalles", templateDay:"Dagstart", exportBoard:"Exporteren", importBoard:"Importeren", importError:"Dit is geen geldig Teach-bordbestand.", widgetDuplicate:"Dupliceren", widgetLock:"Vastzetten", widgetUnlock:"Losmaken", widgetPreview:"Voorbeeld zonder bediening", undo:"Ongedaan maken", redo:"Opnieuw", widgetSettings:"Instellingen", clockWelcome:"Oefenen met de klok", clockWelcomeHint:"Kies bovenaan niveau 1, 2 of 3. Kies bij Instellingen hoe de opdracht wordt getoond en start daarna.", clockSetTitle:"Zet de wijzers op de goede tijd", clockReadTitle:"Bekijk de opdracht en maak de tijd", clockChooseTitle:"Kies het juiste tijdblok", clockYourTask:"Jouw opdracht", clockLinkHands:"Grote wijzer draait mee", clockTypeHint:"Voer de tijd in als UU:MM.", clockLevel1Hint:"Niveau 1: hele en halve uren", clockLevel2Hint:"Niveau 2: stappen van vijf minuten", clockLevel3Hint:"Niveau 3: alle minuten, met optioneel 24 uur en dagdelen", clockBuildHint:"Sleep vier cijfers naar de vakken en maak UU:MM.", clockDigitGhost:"?", clockDigit:"Cijfer {digit}", clockIncomplete:"Maak eerst de volledige tijd af.", clockCorrect:"Goed gedaan! Kies de volgende opdracht. 🌟", clockTryAgain:"Bijna! Probeer het nog een keer.", clockStartTask:"Start opdracht", clockNextTask:"Volgende opdracht", clockLevel:"Niveau", clockLevelHour:"Hele uren", clockLevelQuarter:"Kwartieren", clockLevelFive:"Vijf minuten", clockLevelMinute:"Iedere minuut", clockLearningStyle:"Opdracht tonen", clockStyleAnalogue:"Analoge klok", clockStyleDigital:"Grote digitale tijd", clockStyleWords:"In woorden", clockStyleBoth:"Klok, cijfers en woorden", clockDragHint:"Sleep de wijzers om de tijd te veranderen.", clockGame:"Spel", clockGameSet:"Klok zetten", clockGameRead:"Tijd aflezen", clockGameChoose:"Kies de tijd", clockStart:"Kies Nieuwe opdracht om te beginnen", clockRead:"Welke tijd zie je? Stel je antwoord hieronder in.", clockChoose:"Welke digitale tijd hoort bij deze klok?", clockTry:"Nog niet. Het goede antwoord is {time}.", clockScore:"Score: {score} · reeks: {streak}", clockWordsHour:"{hour} uur", clockWordsQuarterPast:"kwart over {hour}", clockWordsHalf:"half {hour}", clockWordsQuarterTo:"kwart voor {hour}", clockWordsPast:"{minutes} over {hour}", clockWordsTo:"{minutes} voor {hour}", clockMorning:"in de ochtend", clockAfternoon:"in de middag", clockEvening:"in de avond", clockNight:"in de nacht", fractionRows:"Rijen", fractionLabels:"Breuken tonen", fractionHint:"Tik in een rij tot waar je de breuk wilt kleuren.", fractionSelected:"Gekozen breuk: {fraction}", fractionClear:"Leegmaken", clockTask:"Oefenopdracht", clockSet:"Zet de klok op {time}", clockHour:"Uur", clockMinute:"Minuten", placeNumber:"Getal", moneyMake:"Maak € {amount}", wordtypeSentence:"Zin", wordtypeHint:"Tik: blauw zelfstandig naamwoord · groen werkwoord · geel bijvoeglijk naamwoord", scheduleActivity:"activiteit…", scheduleEmpty:"Voeg de eerste activiteit toe.", scheduleCount:"{count} momenten op de planning", pollReset:"Opnieuw", pollQuestion:"Vraag", pollOptions:"Antwoorden (één per regel)", pollTotal:"{count} stemmen", moodTotal:"{count} kinderen hebben gekozen", moodVote:"Kies {face}", galleryFavorites:"Favorieten", galleryFavorite:"Favoriet maken", galleryEmpty:"Geen widgets gevonden.", gallerySearch:"Zoek widgets…", templateMath:"Rekenles", templateLanguage:"Taalles", templateDay:"Dagstart", exportBoard:"Exporteren", importBoard:"Importeren", importError:"Dit is geen geldig Teach-bordbestand.", widgetDuplicate:"Dupliceren", widgetLock:"Vastzetten", widgetUnlock:"Losmaken", widgetPreview:"Voorbeeld zonder bediening", undo:"Ongedaan maken", redo:"Opnieuw",
wg_sentence:"Zinsbouwer", wg_sentence_d:"Bouw zinnen met kleurgecodeerde zinsdelen en voeg eigen woorden toe.", wg_sentence:"Zinsbouwer", wg_sentence_d:"Bouw zinnen met kleurgecodeerde zinsdelen en voeg eigen woorden toe.",
sentence_who:"Wie?", sentence_does:"Doet wat?", sentence_what:"Wat of waar?", sentenceHint:"Kies woorden om een zin te maken…", sentence_who:"Wie?", sentence_does:"Doet wat?", sentence_what:"Wat of waar?", sentenceHint:"Kies woorden om een zin te maken…",
sentenceAdd:"eigen woord of zinsdeel…", sentenceClear:"Wissen", sentenceSpeak:"🔊 Lees voor", sentenceRemove:"Verwijder woord", sentenceAdd:"eigen woord of zinsdeel…", sentenceClear:"Wissen", sentenceSpeak:"🔊 Lees voor", sentenceRemove:"Verwijder woord", sentenceSurprise:"✨ Verrassingszin",
anchorPh:"thema…", anchorHint:"Woordweb: zet het themawoord in het midden en bouw eromheen · tik op een vak en typ · sleep om te schuiven", anchorPh:"thema…", anchorHint:"Woordweb: zet het themawoord in het midden en bouw eromheen · tik op een vak en typ · sleep om te schuiven",
anchorHintReadonly:"Sleep de achtergrond om te schuiven", anchorHintReadonly:"Sleep de achtergrond om te schuiven",
anchorColor:"Kleur: klik om te wisselen (verbind woorden met dezelfde kleur)", anchorColor:"Kleur: klik om te wisselen (verbind woorden met dezelfde kleur)",
@ -245,6 +246,7 @@ const I18N = {
parentUnlinkWarn:"Verwijdert alleen de koppeling; het account van je kind blijft bestaan.", parentUnlinkWarn:"Verwijdert alleen de koppeling; het account van je kind blijft bestaan.",
parentProgress:"📈 Voortgang", parentProgressEmpty:"Nog geen voortgang.", parentProgress:"📈 Voortgang", parentProgressEmpty:"Nog geen voortgang.",
dtLen:"Lengte", dtContrast:"Hoog contrast", dtLen:"Lengte", dtContrast:"Hoog contrast",
dtLock:"Vastzetten: kan niet meer verschuiven of draaien, alleen nog langs tekenen",
dtMode:"Basis: grote hoofdhoeken en hele centimeters. Volledig: graden per 2° met dubbele schaal, millimeters en evenwijdige hulplijnen.", dtMode:"Basis: grote hoofdhoeken en hele centimeters. Volledig: graden per 2° met dubbele schaal, millimeters en evenwijdige hulplijnen.",
dtModeBasic:"basis", dtModeFull:"volledig", dtModeBasic:"basis", dtModeFull:"volledig",
pupilEmpty:"Je leerkracht heeft nog niets voor je klaargezet.", pupilEmpty:"Je leerkracht heeft nog niets voor je klaargezet.",
@ -370,15 +372,16 @@ const I18N = {
wFull:"Maximize", wUnfull:"Restore", wFull:"Maximize", wUnfull:"Restore",
wZoom:"Content bigger or smaller (low vision)", wZoom:"Content bigger or smaller (low vision)",
wg_flits:"Flash words", wg_flits_d:"A word flashes briefly read it before it disappears!", wg_flits:"Flash words", wg_flits_d:"A word flashes briefly read it before it disappears!",
flFlash:"⚡ Flash", flShow:"👁 Show", flNext:"Next ▸", flSec:"sec", flFlash:"⚡ Flash", flShow:"👁 Show", flNext:"Next ▸", flSec:"sec", flMission:"Read the word before it disappears.", flQuestion:"Could you read the word by yourself?", flGotIt:"🌟 Got it!", flAgain:"Practise again", flScore:"{score} stars",
wg_dice:"Dice", wg_dice_d:"Roll 1, 2 or 3 big dice.", wg_dice:"Dice", wg_dice_d:"Roll 1, 2 or 3 big dice.",
diceRoll:"🎲 Roll!", diceSum:"Total", diceRoll:"🎲 Roll!", diceSum:"Total", diceMission:"Roll, count the dots and check the total.", diceHistory:"Previous rolls",
wg_light:"Traffic light", wg_light_d:"Red, orange or green e.g. for classroom noise.", wg_light:"Class traffic light", wg_light_d:"Show at a glance whether children listen, whisper or work quietly.",
lightRed:"Red", lightRedHint:"Stop and listen", lightOrange:"Amber", lightOrangeHint:"Whisper and finish", lightGreen:"Green", lightGreenHint:"You may work quietly", lightStatus:"{color}: {hint}",
wg_names:"Name picker", wg_names_d:"Pick a random name from the class.", wg_names:"Name picker", wg_names_d:"Pick a random name from the class.",
namesPh:"One name per line…", namesPick:"🎯 Pick!", namesNoRep:"No repeats", namesPh:"One name per line…", namesPick:"🎯 Pick!", namesNoRep:"No repeats",
namesDone:"Everyone has had a turn! 🎉", namesDone:"Everyone has had a turn! 🎉", namesReset:"Start over", namesProgress:"{used} of {total} picked",
wg_hak:"Chop & blend", wg_hak_d:"Chop words into sounds and blend them back, with read-aloud.", wg_hak:"Chop & blend", wg_hak_d:"Chop words into sounds and blend them back, with read-aloud.",
hakChop:"✂️ Chop", hakGlue:"🔗 Blend", hakSay:"🔊 Read aloud", hakChop:"✂️ Chop", hakGlue:"🔗 Blend", hakSay:"🔊 Read aloud", hakHint:"See and hear the sound groups in the word.",
wg_ball:"Balloon word", wg_ball_d:"Guess the word letter by letter before the balloons pop.", wg_ball:"Balloon word", wg_ball_d:"Guess the word letter by letter before the balloons pop.",
wg_anchor:"Anchor words", wg_anchor_d:"Word web for vocabulary teaching: learn words in meaningful clusters around a theme word (the anchor), with pictures. Every word anchors to its neighbours.", wg_anchor:"Anchor words", wg_anchor_d:"Word web for vocabulary teaching: learn words in meaningful clusters around a theme word (the anchor), with pictures. Every word anchors to its neighbours.",
fabAnchor:"Anchor diagram (word web)", fabAnchor:"Anchor diagram (word web)",
@ -388,15 +391,15 @@ const I18N = {
birthdaySprinkles:"Sprinkles", birthdayFruit:"Fruit", birthdayStars:"Stars", birthdayNone:"No decoration", birthdaySprinkles:"Sprinkles", birthdayFruit:"Fruit", birthdayStars:"Stars", birthdayNone:"No decoration",
wg_numberline:"Number line", wg_numberline_d:"Practise number sense with an adjustable, interactive number line.", wg_numberline:"Number line", wg_numberline_d:"Practise number sense with an adjustable, interactive number line.",
numberlineFrom:"From", numberlineTo:"To", numberlineStep:"Step", numberlineNew:"New task", numberlineTask:"Move the marker to {number}", numberlineFrom:"From", numberlineTo:"To", numberlineStep:"Step", numberlineNew:"New task", numberlineTask:"Move the marker to {number}",
numberlineCheck:"Check", numberlineGood:"Well done! 🌟", numberlineTry:"Take another look at the number line.", numberlineCheck:"Check", numberlineGood:"Well done! 🌟", numberlineTry:"Take another look at the number line.", numberlineScore:"{score} stars · streak {streak}",
wg_fractions:"Fraction wall", wg_fractions_d:"Compare fractions visually and mark equal parts.", wg_fractions:"Fraction wall", wg_fractions_d:"Build fractions, compare coloured parts and discover equivalent fractions.",
wg_clock:"Practice clock", wg_clock_d:"Learn time at four levels with multiple learning styles and games.", wg_clock:"Practice clock", wg_clock_d:"Learn time at four levels with multiple learning styles and games.",
wg_placevalue:"Place value", wg_placevalue_d:"Explore digit values up to hundred thousands.", wg_placevalue:"Place value", wg_placevalue_d:"Explore digit values up to hundred thousands.",
wg_money:"Money", wg_money_d:"Practise making amounts, counting money and change at three levels.", wg_money:"Money", wg_money_d:"Practise making amounts, counting money and change at three levels.",
wg_trees:"Trees & leaves", wg_trees_d:"Learn eighteen Dutch tree species with five photo, feature and matching exercises.", wg_trees:"Trees & leaves", wg_trees_d:"Learn eighteen Dutch tree species with five photo, feature and matching exercises.",
wg_birds:"Bird identification", wg_birds_d:"Learn eighteen Dutch birds with four photo, feature and naming exercises.", wg_birds:"Bird identification", wg_birds_d:"Learn eighteen Dutch birds with four photo, feature and naming exercises.",
wg_plants:"Wild plants", wg_plants_d:"Recognise twelve common wild plants from real photographs and clear field marks.", wg_plants:"Wild plants", wg_plants_d:"Recognise twelve common wild plants from real photographs and clear field marks.",
wg_topography:"Map of the Netherlands", wg_topography_d:"Practise provinces, places, regions, rivers and continents on accurate maps.", wg_topography:"Topography", wg_topography_d:"Practise the Netherlands and the world: provinces, places, regions, rivers and continents on accurate maps.",
worldActivity:"Activity", worldLearn:"Learn", worldQuiz:"Quiz", worldExercise:"Exercise", worldLevel:"Level", worldTreeView:"What do you see?", worldTreeWhole:"Whole tree", worldTreeLeaf:"Leaf", worldTreeMixed:"Tree and leaf", worldActivity:"Activity", worldLearn:"Learn", worldQuiz:"Quiz", worldExercise:"Exercise", worldLevel:"Level", worldTreeView:"What do you see?", worldTreeWhole:"Whole tree", worldTreeLeaf:"Leaf", worldTreeMixed:"Tree and leaf",
worldExerciseRecognize:"Recognise the species", worldExercisePair:"Match tree and leaf", worldExerciseClue:"Guess from features", worldExercisePhoto:"Choose the correct photo", worldExerciseLatin:"Scientific name", worldExerciseRecognize:"Recognise the species", worldExercisePair:"Match tree and leaf", worldExerciseClue:"Guess from features", worldExercisePhoto:"Choose the correct photo", worldExerciseLatin:"Scientific name",
worldScore:"Score: {score} · streak: {streak}", worldExploreHint:"Study the features and compare the species.", worldQuestionTree:"Which tree do you see?", worldQuestionLeaf:"Which tree does this leaf belong to?", worldQuestionBird:"Which bird do you see?", worldQuestionPlant:"Which wild plant do you see?", worldScore:"Score: {score} · streak: {streak}", worldExploreHint:"Study the features and compare the species.", worldQuestionTree:"Which tree do you see?", worldQuestionLeaf:"Which tree does this leaf belong to?", worldQuestionBird:"Which bird do you see?", worldQuestionPlant:"Which wild plant do you see?",
@ -420,10 +423,10 @@ const I18N = {
wg_mood:"Mood check-in", wg_mood_d:"Run a quick anonymous class check-in.", wg_mood:"Mood check-in", wg_mood_d:"Run a quick anonymous class check-in.",
wg_poll:"Class poll", wg_poll_d:"Vote together on up to six answers.", wg_poll:"Class poll", wg_poll_d:"Vote together on up to six answers.",
clock24Hour:"24-hour clock", clock24Hour:"24-hour clock",
widgetSettings:"Settings", clockWelcome:"Practise telling time", clockWelcomeHint:"Choose level 1, 2 or 3 at the top. In Settings, choose how the task is shown, then start.", clockSetTitle:"Move the hands to the correct time", clockReadTitle:"View the task and make the time", clockChooseTitle:"Choose the correct time block", clockYourTask:"Your task", clockLinkHands:"Move the minute hand along", clockTypeHint:"Enter the time as HH:MM.", clockLevel1Hint:"Level 1: whole and half hours", clockLevel2Hint:"Level 2: five-minute steps", clockLevel3Hint:"Level 3: every minute, with optional 24-hour time and day parts", clockBuildHint:"Drag four digits into the slots to make HH:MM.", clockDigitGhost:"?", clockDigit:"Digit {digit}", clockIncomplete:"Complete the full time first.", clockCorrect:"Well done! Choose the next task. 🌟", clockTryAgain:"Almost! Try again.", clockStartTask:"Start task", clockNextTask:"Next task", clockLevel:"Level", clockLevelHour:"Whole hours", clockLevelQuarter:"Quarter hours", clockLevelFive:"Five minutes", clockLevelMinute:"Every minute", clockLearningStyle:"Show task as", clockStyleAnalogue:"Analogue clock", clockStyleDigital:"Large digital time", clockStyleWords:"In words", clockStyleBoth:"Clock, digits and words", clockDragHint:"Drag the hands to change the time.", clockGame:"Game", clockGameSet:"Set the clock", clockGameRead:"Read the time", clockGameChoose:"Choose the time", clockStart:"Choose New task to begin", clockRead:"What time is it? Set your answer below.", clockChoose:"Which digital time matches this clock?", clockTry:"Not yet. The correct answer is {time}.", clockScore:"Score: {score} · streak: {streak}", clockWordsHour:"{hour} o'clock", clockWordsQuarterPast:"quarter past {hour}", clockWordsHalf:"half past {hour}", clockWordsQuarterTo:"quarter to {hour}", clockWordsPast:"{minutes} past {hour}", clockWordsTo:"{minutes} to {hour}", clockMorning:"in the morning", clockAfternoon:"in the afternoon", clockEvening:"in the evening", clockNight:"at night", fractionRows:"Rows", fractionLabels:"Show fractions", clockTask:"Practice task", clockSet:"Set the clock to {time}", clockHour:"Hour", clockMinute:"Minutes", placeNumber:"Number", moneyMake:"Make € {amount}", wordtypeSentence:"Sentence", wordtypeHint:"Tap: blue noun · green verb · yellow adjective", scheduleActivity:"activity…", scheduleEmpty:"Add the first activity.", pollReset:"Reset", pollQuestion:"Question", pollOptions:"Answers (one per line)", galleryFavorites:"Favourites", galleryFavorite:"Add favourite", galleryEmpty:"No widgets found.", gallerySearch:"Search widgets…", templateMath:"Maths lesson", templateLanguage:"Language lesson", templateDay:"Day start", exportBoard:"Export", importBoard:"Import", importError:"This is not a valid Teach board file.", widgetDuplicate:"Duplicate", widgetLock:"Lock", widgetUnlock:"Unlock", widgetPreview:"Preview without controls", undo:"Undo", redo:"Redo", widgetSettings:"Settings", clockWelcome:"Practise telling time", clockWelcomeHint:"Choose level 1, 2 or 3 at the top. In Settings, choose how the task is shown, then start.", clockSetTitle:"Move the hands to the correct time", clockReadTitle:"View the task and make the time", clockChooseTitle:"Choose the correct time block", clockYourTask:"Your task", clockLinkHands:"Move the minute hand along", clockTypeHint:"Enter the time as HH:MM.", clockLevel1Hint:"Level 1: whole and half hours", clockLevel2Hint:"Level 2: five-minute steps", clockLevel3Hint:"Level 3: every minute, with optional 24-hour time and day parts", clockBuildHint:"Drag four digits into the slots to make HH:MM.", clockDigitGhost:"?", clockDigit:"Digit {digit}", clockIncomplete:"Complete the full time first.", clockCorrect:"Well done! Choose the next task. 🌟", clockTryAgain:"Almost! Try again.", clockStartTask:"Start task", clockNextTask:"Next task", clockLevel:"Level", clockLevelHour:"Whole hours", clockLevelQuarter:"Quarter hours", clockLevelFive:"Five minutes", clockLevelMinute:"Every minute", clockLearningStyle:"Show task as", clockStyleAnalogue:"Analogue clock", clockStyleDigital:"Large digital time", clockStyleWords:"In words", clockStyleBoth:"Clock, digits and words", clockDragHint:"Drag the hands to change the time.", clockGame:"Game", clockGameSet:"Set the clock", clockGameRead:"Read the time", clockGameChoose:"Choose the time", clockStart:"Choose New task to begin", clockRead:"What time is it? Set your answer below.", clockChoose:"Which digital time matches this clock?", clockTry:"Not yet. The correct answer is {time}.", clockScore:"Score: {score} · streak: {streak}", clockWordsHour:"{hour} o'clock", clockWordsQuarterPast:"quarter past {hour}", clockWordsHalf:"half past {hour}", clockWordsQuarterTo:"quarter to {hour}", clockWordsPast:"{minutes} past {hour}", clockWordsTo:"{minutes} to {hour}", clockMorning:"in the morning", clockAfternoon:"in the afternoon", clockEvening:"in the evening", clockNight:"at night", fractionRows:"Rows", fractionLabels:"Show fractions", fractionHint:"Tap a row up to the part you want to colour.", fractionSelected:"Selected fraction: {fraction}", fractionClear:"Clear", clockTask:"Practice task", clockSet:"Set the clock to {time}", clockHour:"Hour", clockMinute:"Minutes", placeNumber:"Number", moneyMake:"Make € {amount}", wordtypeSentence:"Sentence", wordtypeHint:"Tap: blue noun · green verb · yellow adjective", scheduleActivity:"activity…", scheduleEmpty:"Add the first activity.", scheduleCount:"{count} moments in the schedule", pollReset:"Reset", pollQuestion:"Question", pollOptions:"Answers (one per line)", pollTotal:"{count} votes", moodTotal:"{count} children have chosen", moodVote:"Choose {face}", galleryFavorites:"Favourites", galleryFavorite:"Add favourite", galleryEmpty:"No widgets found.", gallerySearch:"Search widgets…", templateMath:"Maths lesson", templateLanguage:"Language lesson", templateDay:"Day start", exportBoard:"Export", importBoard:"Import", importError:"This is not a valid Teach board file.", widgetDuplicate:"Duplicate", widgetLock:"Lock", widgetUnlock:"Unlock", widgetPreview:"Preview without controls", undo:"Undo", redo:"Redo",
wg_sentence:"Sentence builder", wg_sentence_d:"Build sentences with colour-coded parts and add your own words.", wg_sentence:"Sentence builder", wg_sentence_d:"Build sentences with colour-coded parts and add your own words.",
sentence_who:"Who?", sentence_does:"Does what?", sentence_what:"What or where?", sentenceHint:"Choose words to build a sentence…", sentence_who:"Who?", sentence_does:"Does what?", sentence_what:"What or where?", sentenceHint:"Choose words to build a sentence…",
sentenceAdd:"your own word or phrase…", sentenceClear:"Clear", sentenceSpeak:"🔊 Read aloud", sentenceRemove:"Remove word", sentenceAdd:"your own word or phrase…", sentenceClear:"Clear", sentenceSpeak:"🔊 Read aloud", sentenceRemove:"Remove word", sentenceSurprise:"✨ Surprise sentence",
anchorPh:"theme…", anchorHint:"Word web: put the theme word in the middle and build around it · tap a cell and type · drag to pan", anchorPh:"theme…", anchorHint:"Word web: put the theme word in the middle and build around it · tap a cell and type · drag to pan",
anchorHintReadonly:"Drag the background to pan", anchorHintReadonly:"Drag the background to pan",
anchorColor:"Colour: click to cycle (connect words with the same colour)", anchorColor:"Colour: click to cycle (connect words with the same colour)",
@ -464,7 +467,7 @@ const I18N = {
imgQuotaMb:"limit in MB", imgQuotaInvalid:"Enter a valid limit.", imgSchools:"Schools", imgQuotaMb:"limit in MB", imgQuotaInvalid:"Enter a valid limit.", imgSchools:"Schools",
imgUsers:"Users", imgSearchUsers:"Search user…", imgUsers:"Users", imgSearchUsers:"Search user…",
cats:["Animals","Food","Nature","Transport","Things","Body"], cats:["Animals","Food","Nature","Transport","Things","Body"],
notesPh:"Write here…", notesPh:"Write here…", notesColor:"Note colour", notesLarge:"Large letters", notesCount:"{count} characters",
start:"Start", pause:"Pause", reset:"Reset", min:"min", start:"Start", pause:"Pause", reset:"Reset", min:"min",
tmDigits:"Digits", tmVisual:"Visual clock", tmBoth:"Both", tmSound:"Sound on/off", tmDigits:"Digits", tmVisual:"Visual clock", tmBoth:"Both", tmSound:"Sound on/off",
tmHint:"Drag the red disc to set the time.", tmHint:"Drag the red disc to set the time.",
@ -519,6 +522,7 @@ const I18N = {
parentUnlinkWarn:"Removes only the link; your child's account remains.", parentUnlinkWarn:"Removes only the link; your child's account remains.",
parentProgress:"📈 Progress", parentProgressEmpty:"No progress yet.", parentProgress:"📈 Progress", parentProgressEmpty:"No progress yet.",
dtLen:"Length", dtContrast:"High contrast", dtLen:"Length", dtContrast:"High contrast",
dtLock:"Lock in place: can no longer move or rotate, only draw along it",
dtMode:"Basic: big main angles and whole centimetres. Full: degrees every 2° with a double scale, millimetres and parallel guide lines.", dtMode:"Basic: big main angles and whole centimetres. Full: degrees every 2° with a double scale, millimetres and parallel guide lines.",
dtModeBasic:"basic", dtModeFull:"full", dtModeBasic:"basic", dtModeFull:"full",
pupilEmpty:"Your teacher hasn't set up anything for you yet.", pupilEmpty:"Your teacher hasn't set up anything for you yet.",