Merge lang/i18nhandlers 56762050: the key check walks @On listeners, hooks, tests, computed fields and scenes; reseeded

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-30 03:19:33 +03:00
commit 69adbddb46
8 changed files with 64333 additions and 63946 deletions

View file

@ -0,0 +1,6 @@
bump: patch
type: fix
**A key used only in a listener counts as used.** The key check walked the program's declarations but
not the bodies kept beside them - `@On` listeners, the lifecycle hooks, tests, computed fields and
scenes - so a key used only there was never checked against en.po and `ludic schema` listed it
unused. They are walked now, as every other pass walks them.

View file

@ -0,0 +1,14 @@
# i18n_listen.ludic - a key used only inside an @On listener is a used key: the check walks the
# bodies kept beside the program's declarations (listeners, hooks, tests, scenes), so listen.put is
# checked against en.po and `ludic schema` does not report it unused.
#
# Running it prints: listen.put
program I18nListen {
event Put { n: int = 0 }
function tr(key: Key) -> string {
let s = string(key)
return s[1..len(s)]
}
@On(Put) handler Said { print(tr(k"listen.put")) }
entry { emit Put(n: 1) }
}

View file

@ -0,0 +1,8 @@
# The source language of the listener keys example.
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
#. What is said when something is put down.
msgid "listen.put"
msgstr "Put down"

View file

@ -0,0 +1,2 @@
# the listener keys example (i18n_listen.ludic): lang/en.po is the source every key is checked against
lang "lang" en

View file

@ -341,10 +341,29 @@ function i18n_check() -> void {
if not is_runtime_file(prog[i].file) { i18n_walk(prog[i]) }
i += 1
}
# the bodies kept beside prog, as privates.ludic walks them: an @On listener's keys are used too
i18n_walk_all(g_tests)
i18n_walk_all(g_onlisten)
i18n_walk_all(g_onspawn)
i18n_walk_all(g_ondespawn)
i18n_walk_all(g_onattach)
i18n_walk_all(g_ondetach)
i18n_walk_all(g_onenable)
i18n_walk_all(g_ondisable)
i18n_walk_all(g_computed)
i18n_walk_all(g_scenes)
if not g_i18n_on { return }
i18n_walk_templates() # i18n_xml.ludic
i18n_split_check()
}
function i18n_walk_all(ns: []Node) -> void {
if ns == null { return }
var i = 0
while i < len(ns) {
if ns[i] != null and (ns[i].file == null or not is_runtime_file(ns[i].file)) { i18n_walk(ns[i]) }
i += 1
}
}
function i18n_is_data_file(f: pointer) -> bool {
if f == null { return false }
let n = len(f)

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1352,6 +1352,7 @@ function cmd_dev_test() -> int {
# phase 26: text keys - k"..." / kn"..." of type Key, checked against package.ludic's lang en.po
feat_case("lang/i18n/i18n", "", "pause.resume yes no 13 12 hud.day(3) catch.count[2](trout) items.rope.name items.lamp.name steps.gather_wood.hint", "i18n.ludic (phase 26: k\"...\" and kn\"...\" of type Key, their marker byte, == on keys, a @Text Key field filled with its derived key, @TextKey's prefix)")
i18n_check_case()
schema_case("lang/i18n_listen/i18n_listen", "\"unused\": []", "--emit-schema: lang.unused - a key used only inside an @On listener is used")
feat_case("lang/i18n_nested/i18n_nested", "", "raids.camp.arrive.steps.0.text raids.camp.arrive.steps.1.text 2 raids.camp.said.1 0 raids.quiet.arrive.steps.0.text hud.day(3)", "i18n_nested.ludic (phase 26: derived keys below a row - a nested record's, a list item's, a @Text []Key filled from en.po; null is no text; trf's trailing \"\" not counted)")
schema_case("lang/i18n/i18n", "{\"key\": \"items.rope.name\", \"kind\": \"data\", \"kinds\": [\"data\"], \"sites\": [\"examples/lang/i18n/data/i18n_items.lres:2:1\"], \"in_source\": true, \"english\": \"Rope\"", "--emit-schema: lang.keys - a derived key, its kind, its site and en.po's English")
schema_case("lang/i18n/i18n", "\"unused\": [\"map.close\", \"ui.left_click\", \"ui.middle_click\", \"ui.press_key\", \"ui.right_click\"]", "--emit-schema: lang.unused - en.po's keys the program uses nowhere")