Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
build: ${{ steps.filter.outputs.build }}
target: ${{ steps.filter.outputs.target }}
docs: ${{ steps.filter.outputs.docs }}
catalog: ${{ steps.filter.outputs.catalog }}
steps:
- uses: actions/checkout@v7
with:
Expand All @@ -43,6 +44,7 @@ jobs:
echo "build=$(match "$always|^src/")"
echo "target=$(match "$always|^(src/|tests/copperline/)")"
echo "docs=$(match "$always|^(userdocs/|mkdocs\.yml|tools/docs2guide\.py|tools/docs-requirements\.txt)")"
echo "catalog=$(match "$always|^(locale/|tools/check_catalog\.py)")"
} >> "$GITHUB_OUTPUT"

docs-build:
Expand Down Expand Up @@ -76,6 +78,16 @@ jobs:
- name: CLI smoke test
run: make smoke

catalog-lint:
name: Catalog structural checks
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.catalog == 'true'
steps:
- uses: actions/checkout@v7
- name: Check placeholders, mnemonics, re-key prompt markers
run: make check-catalog

differential:
name: Differential fuzz (vs OpenSSL)
runs-on: ubuntu-latest
Expand Down
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ QUIRC_M68K_OBJS := $(patsubst src/qr/%.c,$(BUILD)/qr-m68k/%.o,$(QUIRC_SRCS))
QRCODEGEN_HOST_OBJ := $(BUILD)/qr-host/qrcodegen.o
QRCODEGEN_M68K_OBJ := $(BUILD)/qr-m68k/qrcodegen.o

.PHONY: all test cli smoke diff m68k m68k-docker gui gui-docker gui-smoke qr-onhw qr-onhw-docker qr-onhw-smoke arexx-onhw arexx-onhw-docker arexx-onhw-smoke serialtest-m68k serialtest-m68k-docker copperline-smoke pbkdf2-bench asm-bench amissl-bench flexcat flexcat-docker catalog-strings catalog-strings-docker catalog-onhw-smoke catalog-nolib-onhw catalog-nolib-onhw-docker clean
.PHONY: all test cli smoke diff m68k m68k-docker gui gui-docker gui-smoke qr-onhw qr-onhw-docker qr-onhw-smoke arexx-onhw arexx-onhw-docker arexx-onhw-smoke serialtest-m68k serialtest-m68k-docker copperline-smoke pbkdf2-bench asm-bench amissl-bench flexcat flexcat-docker catalog-strings catalog-strings-docker check-catalog catalog-onhw-smoke catalog-nolib-onhw catalog-nolib-onhw-docker clean

all: test cli

Expand Down Expand Up @@ -204,6 +204,15 @@ catalog-strings-docker:
$(DOCKER) run --rm --platform linux/amd64 $(DOCKER_USER) -v "$(CURDIR)":/work -w /work \
$(AMIGA_GCC_IMAGE) sh -lc 'make catalog-strings'

# Structural sanity checks on locale/AmiAuth.cd and any .ct translation -
# placeholder consistency, button-mnemonic uniqueness, CLI re-key prompt
# markers (tools/check_catalog.py). Pure Python, no FlexCat/Docker needed.
# Runs against every .ct this repo has, including unreviewed locale/drafts/
# ones - these are purely structural checks, not a translation-quality
# review, so there's no reason to exempt a draft from them.
check-catalog:
python3 tools/check_catalog.py locale/AmiAuth.cd $(wildcard locale/*.ct) $(wildcard locale/drafts/*.ct)

# --- Headless GUI smoke test: boot WB 3.2 under Copperline, render AmiAuthGUI --
# Boots an A1200/OS 3.2 under native Copperline, auto-launches AmiAuthGUI, and
# asserts the ReAction window rendered (screenshot in build/gui-smoke/). No VNC
Expand Down
38 changes: 33 additions & 5 deletions locale/AmiAuth.cd
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,38 @@
; reused by the GUI for its own "%s: %s\n" library-load failure).
;
; A leading underscore in a button label (MSG_GUI_BTN_*, e.g. "_Add") marks
; the keyboard mnemonic letter - window.class reads it back out of the
; string at runtime (see the LBL_* comment in src/gui/main.c), so a
; translation MUST keep exactly one '_' immediately before an ASCII letter,
; ideally one that doesn't collide with another button's mnemonic.
; the keyboard mnemonic letter - the WMHI_VANILLAKEY handler reads it back
; out of the string at runtime via a HARDCODED index (LBL_ADD[1], see
; src/gui/main.c), not by searching for '_' wherever it happens to be. This
; means the '_' MUST be the very FIRST character of the string (index 0),
; immediately followed by an ASCII letter (index 1) - a translation can
; choose whichever word it likes for the button (the mnemonic is always
; that word's first letter, not a letter of your choosing mid-word), and
; the six mnemonics used together in the toolbar must be pairwise distinct.
; Get this wrong (underscore not at the very start) and the code silently
; reads whatever character actually sits at index 1 instead - not an error,
; just a dead or wrong shortcut. `tools/check_catalog.py` enforces this.
;
; Same idea for the CLI's three re-key confirmation prompts
; (MSG_CLI_REKEY_STRENGTHEN_PROMPT/MSG_CLI_REKEY_LOWER_PROMPT): the letter
; typed to accept/decline is parsed out of the string itself at runtime -
; the *first* "(x)" in the string is the accept letter, and for
; MSG_CLI_REKEY_STRENGTHEN_PROMPT the *third* "(x)" is the "never ask
; again" letter (the second, "no", is never checked - typing anything else
; falls through to "no"). A translation is free to pick its own letters
; (they need not be the English y/N/v, and need not be the first letter of
; the translated word) - just keep exactly one "(x)" per choice, in the
; same left-to-right order, and make the accept/never-ask letters distinct
; from each other. If they DO collide (both "(x)" use the same letter), the
; code degrades safely rather than misfiring: "never ask again" - which
; writes a persisted opt-out pref - simply becomes unreachable that run, so
; a mistranslation can only under-deliver (lose the never-ask shortcut),
; never silently write a preference the user didn't ask for. Still worth
; getting right, though - distinct letters give the user the full choice.
; MSG_CLI_CONFIRM_YES_PROMPT works the same way but with a whole word
; instead of a letter: the text between the first pair of ' quotes is what
; the user must type back - translate that word freely, the check follows
; whatever is inside the quotes.
;
#language english
#version 0
Expand Down Expand Up @@ -140,7 +168,7 @@ MSG_CLI_REKEY_SLOW_NOTICE (30//)
%s: unlock took ~%lus; this vault was tuned for faster hardware.\n
;
MSG_CLI_REKEY_LOWER_PROMPT (31//)
Re-key LOWER for quicker unlocks here? This REDUCES security. [y/N]
Re-key LOWER for quicker unlocks here? This REDUCES security. [(y)es/(N)o]
;
MSG_CLI_CONFIRM_YES_PROMPT (32//)
Type 'yes' to confirm:
Expand Down
48 changes: 48 additions & 0 deletions locale/drafts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Draft translations - NOT reviewed, NOT installed by anything

Everything in this directory is a **machine-generated first pass** at a
translation of `locale/AmiAuth.cd`, produced by an AI coding assistant with
no native-speaker review. Nothing here is built, tested, or referenced by
any `make` target - that's deliberate, so a draft can never end up in a
release or get picked up by AmigaOS's catalog search just by existing in
the tree.

**Do not install a `.ct` file from here as-is.** Treat it the same as any
other unreviewed contribution: it needs a native (or at least fluent)
speaker to check it, especially the security-relevant prompts (unencrypted
storage, no-RNG, re-key strengthen/weaken) where a subtly wrong translation
could mislead someone about what they're agreeing to.

## Promoting a draft to a real translation

1. A fluent speaker reviews the `.ct` file line by line against
`locale/AmiAuth.cd` (the English source of truth) - fixing wording,
register/tone, and any button-mnemonic collisions (see the underscore
note in `AmiAuth.cd`'s header).
2. Build and smoke-test it locally:
```
FlexCat ../AmiAuth.cd yourlanguage.ct CATALOG AmiAuth.catalog
```
then drop the result at `LOCALE:Catalogs/<language>/AmiAuth.catalog` and
exercise the CLI/GUI to see it in practice (see
[Localization](../../userdocs/Localization.md#installing-a-translation)).
3. Move the reviewed `.ct` out of `drafts/` and open a pull request per the
normal [translator workflow](../../userdocs/Localization.md#contributing-a-translation).

## The three CLI re-key prompts are now fully localizable

`maybe_rekey()`'s three re-key confirmation prompts in `src/cli/main.c`
originally parsed the user's typed answer against hardcoded English
letters/words in C, found and fixed while drafting this translation:
`prompt_letter()`/`prompt_quoted_word()` (`src/cli/main.c`) now extract the
accepted letter(s)/word straight out of the *translated* prompt at runtime
- the same self-describing-string technique `src/gui/main.c`'s `LBL_*`
already uses for button mnemonics. See the convention documented in
`locale/AmiAuth.cd`'s header (search for "MSG_CLI_REKEY_STRENGTHEN_PROMPT"):
a translation is free to pick its own letters/word (they need not be
English `y`/`N`/`v`/`yes`, and a letter need not be the first letter of the
translated word) - just keep exactly one `"(x)"` per choice, in the same
left-to-right order, with the accept and never-ask letters distinct from
each other, and the confirm word inside `'...'` quotes. `deutsch.ct` below
already uses real German letters/word (`j`/`N`/`i`, `'ja'`) as a worked
example.
Loading