* i18n: add Hungarian (hu) interface translation
- crates/ui-egui/src/i18n/hu.tsv: complete catalog, all 1,572 keys of
es.tsv in the same order, written clean-room from the plain meaning
of the English labels; placeholders, escapes and trailing ellipses
kept. Commands are nouns, messages use the informal second person,
and only the first word of a label is capitalised. A noun after a
number stays singular in Hungarian, so the context-free format needs
no plural forms.
- LANGUAGES gains `hu` (Magyar); `hu`, `hu-HU` and `hu_HU.UTF-8`
resolve to it.
- The Font dialog's preview sample is "AaBbYyZz ŐőŰű", so All Caps
shows the double acute capitals.
- Tests: locale resolution and saved preference, key parity with the
Spanish catalog, sample translations, count wording, the sample's
capitals and Hungarian letters in the bundled interface fonts.
- Docs: new localization-hu.md (conventions, terminology, scope);
README, ROADMAP, localization-parity and control-protocol list the
new language; ATTRIBUTION row for hu.tsv.
* i18n(hu): built-in style names, equation gallery and citation styles
- hu.tsv now carries every key of the Russian catalog: built-in style
names (Normal, No Spacing, Subtitle, TOC {n}…), the equation gallery
and structure labels, paper sizes, watermarks and the Backstage
greetings, plus the citation style names (1,946 entries).
- The interface audit (untranslated_interface_text) checks Hungarian
alongside Russian and reports every language's gaps in one run.
- Tests: Hungarian keys cover the Russian catalog; built-in style
names and numbered style templates show in Hungarian.
- Docs: entry counts and scope in localization-hu, localization-parity
and ROADMAP.
* Review fixes for #731: Hungarian stays a partial catalog
- The i18n audit requires completeness from Russian only again: hu.tsv lacks ~280 strings of the
dialogs that landed since (Compare Documents, Math AutoCorrect, …), so it can't claim to be
complete. The catalog test no longer asserts it holds every Russian/Spanish key.
- 43 Hungarian rows for tab and command labels that reached main since (charts, content controls,
Developer tab, templates and the styles organizer, WordArt), which every_tab_and_command_is_translated
requires.
- Docs say partial, with the entry count (1,989); localization-parity's header keeps its quote
marker and the #505 note.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Review fixes for #731: Hungarian rows for the Outlining tab
24 rows for Outline view's tab and commands, which landed on main meanwhile; 2,013 entries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Review fixes for #731: ROADMAP header keeps main's SmartArt note
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n(hu): complete the Hungarian catalog again
- hu.tsv: 374 new rows for the strings that reached main while #731 was
in review (Compare Documents, Restrict Editing, Math AutoCorrect,
charts, SmartArt, the Options sections, the print page and more).
The catalog now holds every key of ru.tsv again: 2,397 entries.
- The completeness checks are back: the interface audit requires
Hungarian alongside Russian, and the catalog test asserts hu.tsv holds
every key of ru.tsv and es.tsv. The docs describe a complete catalog.
- Seven review rows follow the catalog's existing patterns: Text Pane
(Szöveg panel, like the other panes), Design Mode (Tervezőmód, one
compound), Picture and Date Picker Content Control (clearer compounds),
Promote to Heading 1 / Demote to Body Text (style name after a colon,
no case ending) and Reset Graphic (Ábra visszaállítása, shorter).
* Hungarian: translate interface strings added on main since this PR
Adds the 10 strings main gained with Polish proofing (spelling and grammar
messages, Do Not Check Spelling or Grammar, comment/browse buttons), so
hu.tsv again covers every key of the other catalogs (2,419 entries), and
drops the stale "Wildcards (regex)" row; updates the documented counts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
5.7 KiB
Control protocol
Start the app with a control port: wordcraft --control 7981 (or WORDCRAFT_CONTROL_PORT=7981).
It listens on 127.0.0.1 only. Send one JSON object per line, with the window's key (see
Keys); each gets one reply line:
{"id": 1, "key": "…", "method": "engine.execute", "params": {"command": "text.insert", "params": {"text": "Hello"}}}
{"id": 1, "ok": true, "result": {"anchor": {...}, "focus": {...}}}
Errors come back as {"id": …, "ok": false, "error": "message"}. A failed command leaves the
document unchanged. A line that isn't valid JSON gets one error reply, then the server closes the
connection (so an HTTP request sent to the port can't run a command); reconnect to continue.
Keys
Any local program (and possibly a web page) can reach a loopback port, so every request needs the
window's key. Once the port is bound, the app writes a random key (256 bits, as hex) to
<settings>/control-key.<instance> and removes the file when the window closes; a new start
writes a new key. <settings> is the folder that holds the preferences: on Linux
$XDG_CONFIG_HOME/wordcraft (by default ~/.config/wordcraft), on macOS
~/Library/Application Support/WordCraft, on Windows %APPDATA%\WordCraft. <instance> is the
Flatpak instance id inside Flatpak, and local-<port> otherwise. On Unix the file has mode 0600.
cat ~/.config/wordcraft/control-key.local-7981 # Linux, outside Flatpak, port 7981
- Send the key as top-level
"key"with every request, or once per connection with{"method": "auth", "key": "…"}(reply{"ok": true, "result": {}}); later requests on that connection may leavekeyout. Onlyauthreadsparams.key; for other methodsparams.keyis an ordinary parameter (ui.key {"key": "Enter"}presses Enter). - The key is checked on every request. A missing or wrong key gets
{"ok": false, "error": "unauthorized"}, and the app closes the connection. - A line over 1 MiB gets
{"ok": false, "error": "line too long"}, and the app closes the connection. - A connection that sends no authorised request within 30 s of being accepted is closed. That is one limit: blank lines and bad JSON do not extend it. After an authorised request the connection may stay idle.
wordcraft-cli mcp --connect takes the key from WORDCRAFT_CONTROL_KEY, or else from the key
file for the port it connects to, and reads it again on every new connection (the app may have
restarted). It sends the key only to loopback addresses (127.0.0.0/8, ::1, localhost). For
any other host it sends no key, says so, and the app refuses its requests: to drive an app on
another machine, forward its port to 127.0.0.1 (for example ssh -L 7981:127.0.0.1:7981 host)
and set WORDCRAFT_CONTROL_KEY to that app's key.
Methods
| Method | Params | Result |
|---|---|---|
engine.execute |
command, params |
the command's result (any id from engine.commands, including UI commands ui.tab, ui.dialog, ui.backstage, ui.zotero.* (see docs/zotero.md), ui.language (`{"value": "auto" |
engine.commands |
— | every command: id, label, location, shortcut, params, enabled |
document.inspect |
text? |
blocks (text, style, runs, lists, tables), parts, sections, selection, pages |
ui.inspect |
— | UI state, view, dialog, window size, page rects on screen, caret, comment balloons (balloons: id + screen rect; balloon: the selected one), perf |
ui.click |
x, y, button?, count?, shift?, cmd?, alt? |
real pointer input at window coordinates |
ui.clickText |
page (0-based), x, y (points from the page's top-left), count? |
click inside a page |
ui.move / ui.drag |
x,y / x,y,toX,toY,steps? |
pointer move / drag |
ui.press / ui.release |
x,y, modifiers |
primary button down / up there (with ui.move between: a drag you can screenshot halfway) |
ui.key |
key (B, Enter, Left…), shift?, alt?, cmd? |
key press through egui (shortcuts apply) |
ui.text |
text |
typed text through egui |
ui.screenshot |
path? |
PNG of the window: written to path, or without one returned as base64 png in the reply |
ui.render |
path?, page? (1-based), scale? |
PNG of a page, rendered by the engine: written to path, or without one returned as base64 png in the reply (never a fixed name in the shared temporary folder) |
ui.parity |
— | feature-catalog parity |
ui.resize / ui.focus / app.quit |
window control |
Any other method name is treated as a command id: {"method": "format.bold"} works.
Positions are {"story": "body" | {"part": n}, "path": [block, row, cell, block, …], "off": byteOffset}.