mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-24 18:36:58 -06:00
* 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>
71 lines
5.7 KiB
Markdown
71 lines
5.7 KiB
Markdown
# 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](#keys)); each gets one reply line:
|
||
|
||
```json
|
||
{"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.
|
||
|
||
```sh
|
||
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 leave `key` out. Only `auth` reads `params.key`; for other methods `params.key`
|
||
is 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"|"en"|"zh-hans"|"zh-hant"|"ja"|"pt-br"|"es"|"uk"|"sr"|"sr-latn"|"et"|"tr"|"ru"|"pl"|"de"|"it"|"cs"|"hu"|"fr"}`), `ui.theme` (`{"value": "system"|"light"|"dark"}`; `system` follows the OS appearance, light when it reports none), `ui.interfaceSize` (`{"percent": 80–200}`, clamped; no value reads it; scales the interface on top of the system display scale, document zoom stays `view.zoom`), `ui.animations` (`{"value": "system"|"on"|"off"}`; no value reads it; `system` follows the system's animation setting, which the desktop app reads on Windows, macOS, Linux and the BSDs and the web app from `prefers-reduced-motion`, and means on where the system doesn't say; the result's `enabled` is what the setting comes to and `system` what the system reports, `null` when it doesn't say), `ui.fileBrowser` (desktop: `{"purpose": "document"|"picture"|"recipients"|"save"}` opens WordCraft's own file browser, for when the system file dialog doesn't show up, #576), `ui.caretAnimation` (`{"value": true|false}`; no value reads it; off, the caret jumps and blinks on and off instead of gliding and fading)…) |
|
||
| `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}`.
|