Skip to content

Add Dutch (Nederlands) primitive aliases and localization - #248

Open
laurensWoon wants to merge 22 commits into
jrincayc:masterfrom
laurensWoon:nl
Open

Add Dutch (Nederlands) primitive aliases and localization#248
laurensWoon wants to merge 22 commits into
jrincayc:masterfrom
laurensWoon:nl

Conversation

@laurensWoon

Copy link
Copy Markdown
Contributor

Summary

  • Adds Dutch (Nederlands) names as additional aliases for ~65 primitives (77 alias entries including short forms), covering turtle graphics, procedure definition, control flow, list/word operations, math and I/O.
  • Purely additive: every existing English name keeps working exactly as before, this only adds new entries to the primitive table alongside them (same pattern UCBLogo already uses internally for e.g. list?/listp or fd/forward).
  • Short forms follow UCBLogo's own abbreviation convention (fd/bk/rt/lt/pd/pu -> vt/at/re/li/pn/pp).
  • Adds logolib/Messages.nl, a full Dutch translation of the existing localization file (same format as the existing Messages.fr/Messages.sp/Messages.zh_TW) -- all ~73 error/status messages plus the ~34 reserved words the translations[]/isName()/theName() mechanism supports (to/end/if/ifelse/output/stop/true/false/etc). %p/%s/%t placeholder count and order verified to match the English original exactly on every line (required for ndprintf's positional substitution).
  • Adds two Dutch-language docs: NEDERLANDS.md (quick EN/NL lookup table) and LOGO-COMMANDOS-NL.md (each Dutch command with a plain-language Dutch explanation of what it does, not just its English equivalent).

Vocabulary source

Sourced from SuperLogo (1994, Addo Stuur / A.W. Bruna Informatica, based on Comenius Logo) -- historically the main Dutch-language Logo implementation, used in Dutch primary education. The software is freely archived at https://archive.org/details/superlogo-voor-windows; the primitive vocabulary was extracted directly from its SLOGO.EXE via strings rather than invented for this PR. A few gaps not covered by that source (e.g. laad for load, wisscherm for clearscreen) were filled in following the same naming conventions once the SuperLogo source was exhausted.

leer/end and the translations[] mechanism

to is an ordinary primitive ({"to", ..., lto}), so leer is added the same way as every other alias here. end, however, is recognized structurally while parsing a multi-line procedure body (isName(..., Name_end) in wrksp.c), not via the primitive table -- isName() always checks both the English name and the Alt (translated) name from Messages.nl regardless of any setting, so eind works as a procedure terminator once Messages.nl is installed, with no separate table entry needed. alsanders (ifelse) is a primitive like to, added the same way.

The Dutch Messages.nl file is not runtime-switchable (matching how the existing Messages.fr etc. already work -- logolib/Messages is loaded by a fixed filename, there's no language flag), so full Dutch error text requires building/installing with Messages.nl in place of Messages. The primitive aliases in init.c work either way, independent of which Messages file is installed.

Deliberately not included

doe/kom (possible extra Comenius Logo structural keywords) are not aliased -- no confirmed UCBLogo equivalent for either.

Test plan

Built and ran on macOS (both the console build and the wxWidgets GUI build). Verified:

  • Aliases produce identical output to their English counterparts, e.g. gelijk? 3 3 / equalp 3 3, telop 2 3 / sum 2 3, vermenigvuldig 4 5 / product 4 5, lijst? [1 2 3] / listp [1 2 3], maak "x 10 + ding "x / make "x 10 + thing "x, gok 100 / random 100.
  • A full recursive procedure using only Dutch syntax:
    make "usealternatenames "true
    leer teller :n
    alsanders :n > 5 [uitvoer "klaar] [print :n uitvoer teller :n + 1]
    eind
    print teller 1
    
    runs correctly end to end, including waar/onwaar display once usealternatenames is set.
  • With Messages.nl installed as Messages: an unknown-command error prints in Dutch (Ik weet niet hoe ik <naam> moet uitvoeren), and the exit banner prints in Dutch.

Built on top of #246 and #247 (portability/bugfixes unrelated to the Dutch work but needed to get a clean macOS build to test against) -- this diff will shrink to just the Dutch-related commits once those land.

laurensWoon and others added 20 commits August 29, 2026 17:03
…GETA/TCSETA ioctls

term.c used TCGETA/TCSETA ioctl request codes whenever HAVE_TERMIO_H or
HAVE_TERMIOS_H was defined. Those constants exist on Linux (compat with old
System V termio) but not on macOS/BSD, which only implement the POSIX
termios API via tcgetattr()/tcsetattr(). Split the HAVE_TERMIOS_H case out
to use the POSIX calls; the HAVE_TERMIO_H (no termios) fallback keeps using
the old ioctl approach unchanged.
Adds Dutch names as additional aliases alongside the existing English
primitives (English keeps working unchanged) for turtle graphics, basic
control flow, list/word operations, math and I/O -- about 60 primitives,
73 aliases total including short forms (vt/at/re/li/pn/pp/etc, matching
UCBLogo's own fd/bk/rt/lt/pd/pu convention).

Vocabulary sourced from SuperLogo (1994, Addo Stuur / A.W. Bruna
Informatica, based on Comenius Logo) -- extracted via 'strings' from its
SLOGO.EXE, the only real historical Dutch Logo dialect I could find (see
https://archive.org/details/superlogo-voor-windows for the source
software). Full extraction + category breakdown documented separately.

Deliberately NOT included yet: the procedure-definition keywords
(SuperLogo's possible 'leer'/'doe'/'eind'/'kom') -- Comenius Logo's syntax
model isn't confirmed identical to UCBLogo's TO/END, so guessing those
risks baking in wrong core-language semantics. Needs verification against
the actual running software before adding.
…ved words

init.c: adds the procedure-definition and remaining core aliases that were
missing from the first batch -- leer (to), alsanders (ifelse), uitvoer/uv
(output), bewerk/bw (edit), telherhaal (repcount), toets? (key?), sa
(sentence), lw/ll (readword/readlist).

logolib/Messages.nl: Dutch translation of UCBLogo's built-in localization
file (same format/mechanism as the existing Messages.fr/Messages.sp/
Messages.zh_TW), covering:
- all ~73 error/status messages (%p/%s/%t placeholders verified to match
  the English original exactly, position and count, via a small script --
  required for ndprintf's positional substitution to work)
- the ~34 reserved words UCBLogo's own translation mechanism supports
  (to/end/if/ifelse/output/stop/true/false/goto/tag/macro/toplevel/
  system/error/nothing + screen/pen/turtle-mode + operator names), which
  is what makes 'eind' work as a procedure terminator without needing a
  table entry -- END is recognized structurally via isName() against
  both the English and this Alt translation, unlike ordinary primitives.

This is intentionally NOT a runtime language switch: UCBLogo's Messages
mechanism only supports one 'Messages' file per build/distribution
(matching how Messages.fr etc. already work), so a Dutch build means
installing Messages.nl as 'Messages'. usealternatenames (a buried Logo
variable, default false) additionally controls whether generated text
(e.g. TRUE/FALSE display, welcome message) shows the Dutch or English
variant.
…overflows the 1-byte record_buffer

Root-caused with lldb: any procedure containing 2+ turtle-movement
commands (any combination including FORWARD/BACK) crashed with
EXC_BAD_ACCESS in varTrue(), called from the core evaluator with a
corrupted AllowGetSet pointer (0x0000000200000001).

nographics.h defines GR_SIZE as 1 ("a dummy graphics header file for
computers without graphics"), so graphics.c's
`char record_buffer[GR_SIZE];` is a single byte. safe_to_save() --
called unconditionally from save_line()/save_move()/etc, not gated by
any backend-specific stub -- writes a full 8-byte pointer into that
1-byte buffer on its very first call (`*(char **)(record) = 0;`),
silently corrupting whatever global follows record_buffer in memory
(AllowGetSet, in this build). The corruption doesn't crash immediately;
it surfaces later, on the next unrelated procedure lookup that happens
to consult that now-garbage pointer -- hence the confusing symptom of a
crash on the *second* movement command, or even later, rather than
the first.

FORWARD/BACK are the only two movement primitives that call
forward_helper() (which calls save_line()/save_move()); RIGHT/LEFT do
not, which is why 'right 90 right 90' alone never triggered this.

Fix: make safe_to_save() an unconditional no-op for headless builds,
mirroring the existing HAVE_WX-only early-out in draw_turtle() a few
lines up. There is no window to ever redraw in a headless build, so
recording draw operations for later replay serves no purpose there --
bumping GR_SIZE instead would only move the overflow further out, not
fix the underlying mismatch.

Verified: 'koch 150 4' (256 nested FD/LT/RT calls, previously crashed
immediately) now completes cleanly with a correct final position.
Decompiled logolib/Messages.hlp equivalent -- SLOGO.HLP -- with helpdeco
(https://github.com/rofl0r/helpdeco) and found the actual, official
'Woordenlijst van procedures Nederlands-Engels' embedded in the SuperLogo
help file. This is authoritative (straight from the product's own
documentation) rather than reverse-engineered from strings/usage patterns,
and revealed a few mistakes in the earlier batches:

Fixes:
- laatzien/lz were wrongly aliased to SHOWTURTLE -- the official table
  says LAATZIEN/LZ -> SHOW (prints a value with brackets preserved,
  unlike PRINT). Fixed.
- kom -> SHOWTURTLE/ST added (this is what laatzien was incorrectly
  standing in for).
- wisscherm/ws (my own invented words for CLEARSCREEN, not sourced) were
  removed in favor of the authentic wistekening/wt.
- welwaar/nietwaar (official terms for TRUE/FALSE) replace the invented
  waar/onwaar in Messages.nl's reserved-word section.

New (doe question from earlier this session, plus the rest of the
official table cross-referenced programmatically against this fork's
current primitive table):
- doe -> RUN (finally resolved -- was left out earlier as unconfirmed)
- 57 more primitives with a confirmed UCBLogo equivalent: aantal(count),
  achtergrond/ag(background), bb/bewerkbestand(editfile),
  definieer(define), definitie?(defined?), fout(error), graden(heading),
  gum(penerase), integer(int), kenmerklijst(plist), me/mineerste(butfirst),
  minlaatste/ml(butlast), naam?(name?), naar(towards), namen(names),
  neem(ask), neemkenmerk(gprop), opdrachtvenster/ov(textscreen),
  open(load), opslaan(save), pauze(pause), penomgekeerd(penreverse),
  pk(pencolor), plaatserachter(lput), plaatservoor(fput),
  plaatskenmerk(pprop), primitief?(primitive?), printdefinitie(po),
  printnaarov(type), printperregel(print), printtekst(text), rand(wrap),
  splitsvenster(splitscreen), teken(char), venster(window),
  verberg(bury), verbergniet(unbury), verborg(buried), vul(fill),
  wb/wisbestand(erasefile), wis(erase), wiskenmerk(remprop),
  wisopdracht/wo(cleartext), wistekening/wt(clearscreen),
  zag/zetachtergrond(setbackground), zetkleurov(settc),
  zetcursor(setcursor), zichtbaar?(shown?).

~110 further SuperLogo commands (bitmap/mouse/sound/turtle-shape-editor
related, e.g. openbitmap, maakturtle, speelgeluid) have no UCBLogo
equivalent -- SuperLogo's Windows GUI has a richer media/object API than
UCBLogo's simpler turtle graphics, so these are intentionally not
aliased.
logolib/Messages.nl existed in the repo but was never listed in
dist_logolib_DATA, so `make install` silently skipped it. On this
Dutch-localization branch, also copy it over the default Messages
file during install so error/status text is actually Dutch by
default, matching the reserved-word and command-alias localization
already done elsewhere.

Found while test-building this branch on Debian (Crostini portability
check) -- the app ran but showed English messages despite the wx GUI
and Dutch command aliases working.
EDIT/bewerk now opens in a standalone top-level window instead of
swapping panels into the main frame, similar to the separate turtle-
graphics window and matching how Atari ST Logo's editor worked. Two-
phase construction (EditorFrame(wxWindow*) + AttachEditor(TextEditor*))
since the frame and its TextEditor need each other to exist first.

Fullscreen-mode fixes (both macOS-specific):
- EditorFrame is parented to NULL, not the main LogoFrame -- parenting
  it to the main window made it a Cocoa child window, which could hang
  the main window when exiting native fullscreen.
- EditorFrame's native NSWindow gets
  NSWindowCollectionBehaviorFullScreenAuxiliary (via the plain ObjC
  runtime C API, no separate .mm file needed) so it opens alongside a
  fullscreen LogoFrame in the same Space instead of getting shunted to
  the regular desktop, which otherwise left the fullscreen window's
  focus/cursor broken afterward.

Also translated the remaining hardcoded English menu strings to Dutch
(File/Edit/Logo/Font menus, the editor's own menu, dialog titles and
the Save/Load file-picker) -- these were never covered by any
localization system (plain wxWidgets _T() text, not gettext-backed),
so this is manual translation like the rest of the Dutch work. Left
LogoFrame::SetUpEditMenu() untouched -- confirmed unreferenced dead
code from before this window-based editor existed.
Found while comparing our command set against ACSLogo's (a different,
more feature-rich macOS-native Logo dialect) at the user's request.
These four were genuine gaps, not just naming differences from
UCBLogo's existing primitives:

- abs/absolutewaarde: no absolute-value primitive existed at all.
  Implemented as a new opcode in math.c's binary() dispatcher, named
  labsx (not labs) since labs already exists in <stdlib.h> -- same
  reason lroundx avoids lround.
- tan/tangens: sin, cos and atan (arctangent) existed, but plain
  tangent did not.
- xcor/xcoordinaat, ycor/ycoordinaat: only the combined POS existed
  (outputting [x y] as a list); these output just one coordinate,
  mirroring lpos's existing turtle_x/x_scale and turtle_y/y_scale
  math in graphics.c.

Verified via a headless WASM build (today's proof-of-concept setup)
with real turtle-position tracking: fd 100 -> xcor 0 / ycor 100,
then rt 90 fd 50 -> xcor 50 / ycor 100, matching pos exactly.
openwrite/openread/openappend/openupdate/setwrite/setread/close had
no Nederlands alias yet, unlike most other primitives on this branch.
Adds openschrijf/openlees/opentoevoeg/openbijwerk/zetschrijf/zetlees/
sluit, documented in NEDERLANDS.md and LOGO-COMMANDOS-NL.md.
emgraphics.h/emgraphics.c/emterm.c implement the EM_GRAPHICS backend that
graphics.c has referenced since the WASM/browser proof-of-concept, but
which was never actually committed -- the nl branch didn't build with
-DEM_GRAPHICS for anyone who didn't already have these files locally.

wrksp.c: ledit() gets a new EM_GRAPHICS branch. fork()+execlp() of an
external editor process doesn't work for an embedded/app host (no
external editor binary, and modern Android blocks exec of anything an
app wrote itself); em_edit_file() hands the temp file to the host
instead. Android (androidjni.c, not part of this repo) implements this
with a real blocking dialog; the WASM backend gets a no-op stub so EDIT
behaves like an immediate cancel there rather than failing to link.
Windows and macOS builds were shipping the English logolib/Messages
file, so the startup welcome text and the EDIT template for a new
procedure ('to %p / end') stayed in English even on the nl branch.
Copy Messages.nl over Messages in the install/bundle step so native
builds match the WASM demo's Dutch output.
When a .lg file's final line was the closing 'end'/'eind' of a
procedure but had no trailing newline, feof() would already be true
right after reading it. The code unconditionally treated that as 'no
end line was found' and replaced the just-read line with a synthetic
theName(Name_end) placeholder -- an internal name object, not
printable text -- silently discarding the real 'eind' line from the
procedure's cached body text. Any later SAVE would then write that
procedure back out without its closing line.

Only synthesize the placeholder when the read genuinely found nothing
(car(tnode) == Null_Word), i.e. a truly truncated file missing 'end'
entirely -- not whenever feof() merely happens to be set because the
real closing line was the last bytes in the file.

Verified with a local console (--disable-wx) build: reproduced the
bug via lldb (the dropped line resolved to an empty, non-printable
node instead of the string "eind"), confirmed the fix restores it,
and confirmed both the normal (trailing-newline) case and the
genuinely-missing-end fallback still behave as before.
@jrincayc

jrincayc commented Sep 4, 2026

Copy link
Copy Markdown
Owner

If I am understanding this correctly, this will merge in alternative names for logo commands, that are always available. I am not sure I like that. Possibly this might be better if it added a configure flag like '--enable-nl' (or similar, just something that makes sense) and then if that was enabled turn on things like "achtergrond". This is not a hard no, but I would like to think about this more. Possibly an actual aliasing system (or just to achtergrond ... background ... end) instead of stuffing more things in prims might be better.

laurensWoon and others added 2 commits September 7, 2026 08:48
Addresses jrincayc's review comment on jrincayc#248: the ~65 Dutch aliases
were unconditionally compiled in, permanently reserving those words
even for users who never asked for them. Mirrors the existing
--enable-objects pattern exactly (AC_ARG_ENABLE + AC_DEFINE +
AM_CONDITIONAL in configure.ac, #ifdef ENABLE_NL around each alias
entry in prims[], same grouping convention already used for #ifdef
OBJECTS blocks throughout this file).

Verified both configurations with a plain --disable-wx build:
without the flag, Dutch aliases are unrecognized and English works
exactly as before; with the flag, a full recursive Dutch-only
procedure (leer/alsanders/uitvoer/eind, with usealternatenames and
Messages.nl installed) runs correctly end to end.

logolib/Messages.nl is untouched -- it already follows the same
opt-in-at-install-time pattern as Messages.fr/.sp/.zh_TW, so it
wasn't part of the "always available" concern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKfNE3DAacgz89XYkv5gkv
@laurensWoon

Copy link
Copy Markdown
Contributor Author

Added a --enable-nl configure flag (default off), mirroring --enable-objects exactly: AC_ARG_ENABLE/AC_DEFINE/AM_CONDITIONAL in configure.ac, and each Dutch alias entry in prims[] wrapped in #ifdef ENABLE_NL/#endif, same grouping convention as the existing #ifdef OBJECTS blocks throughout this file.

Without the flag, behavior is unchanged from stock UCBLogo -- the Dutch words aren't recognized as anything, English works exactly as before. With it, everything works as originally submitted, verified with a full recursive Dutch-only procedure (leer/alsanders/uitvoer/eind, usealternatenames + Messages.nl installed) running end to end.

logolib/Messages.nl itself is untouched -- it already follows the same opt-in-at-install-time pattern as Messages.fr/.sp/.zh_TW (you choose which Messages file to install), so it wasn't part of the "always available" concern, only the prims[] entries were.

Didn't attempt the "actual aliasing system" (Logo-level to X ... end wrappers instead of C table entries) -- looked into it, and it doesn't cleanly cover the full set: to itself can't be its own wrapper (needs the parser's multi-line-reading behavior), the MACRO_PRIORITY primitives (if/ifelse/iftrue/iffalse/repeat/run/ask/catch, plus output) have stop/output-propagation semantics tied to their priority level that an extra ordinary-procedure-call frame would risk disturbing, and the unlimited-arity primitives (and/or/list/word/sentence/print/sum/product/type/local, 10 primitives) can't be replicated by a fixed-arity Logo procedure at all. That's 20 of the ~65 primitives that would need to stay as C entries regardless, so a full rewrite would end up as a hybrid anyway -- the flag alone seemed like the higher-value fix for the concern you raised, happy to revisit the wrapper approach for the rest if that's still wanted on top of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants