feat(strings): the app's words for every game (M20) #58

Merged
whitlocktech merged 5 commits from feat/app-vocabulary into edge 2026-10-23 01:50:51 -05:00

5 Commits

Author SHA1 Message Date
c41aff9b2e feat(rust): print the weapon name the module sends in the feed
All checks were successful
PR Checks / android-build (pull_request) Successful in 14m33s
PLAN.md M20 step 4. Module-Rust#60 gives every event frame a weaponName: the
game's own name for a ranged weapon, or the prefab name as words. The feed
printed the prefab name as words itself, which read "with ak47u entity".

weaponName() in RustFormat.kt is the Kotlin half of module-rust's format.js
weapon(). It prints frame.weaponName. Against a module too old to send it,
it drops the .entity / .weapon / .deployed ending before prefabName(), as
the website does, so an older module's kill reads "with ak47u".

Tests: a kill with weaponName, the same kill from an older module, and the
fallback's edges (blank name, each ending, an ending only at the end, no
weapon).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-23 01:38:01 -05:00
bb9cd9008d fix(nav): gate Moderation and Support queue on the shard module
Found by the M20 trace, and fixed in this PR by the org lead's decision.
Both rows call /admin/shard/*, module-uo's admin mount, but they carried no
capability. So a moderator on a Rust-only site saw "Moderation" in the drawer
and opened a UO form ("Serial (0x…)", kick or ban by UO account) where every
action failed.

Both rows now declare Capability.SHARD, as the player rows do, so they are UO
screens and their strings belong in strings_uo.xml, where step 1 put them. A
new MenuCapabilityGatingTest case covers it: a moderator on a Rust-only
backend sees neither row but keeps the Dashboard, and on a UO backend sees
both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-23 01:36:53 -05:00
3048582ce0 test(strings): guard each strings file against another game's words
PLAN.md M20 step 3. StringVocabularyTest reads strings.xml, strings_uo.xml
and strings_rust.xml in every values* directory, so translations are checked
too. It fails, naming the key and the word, when the core file holds either
game's word, the UO file holds a Rust word, or the Rust file holds a UO word.
The word list is runicgateway.com's checkTerms.mjs list, word for word. The
app never shows Discord's "guild ID", so that allowlist entry isn't carried
over.

Three more tests keep the guard honest:
- a fourth strings file with no owner is refused, because Android would read
  it and the guard would skip it;
- the three default files must exist and hold strings, so a wrong path can't
  pass on nothing;
- the matcher is checked against known hits and misses.

Run against the core file as it was before the rewording, it names exactly
the 14 strings that commit changed.

build.gradle.kts declares src/main/res as an input of the Test tasks. A
reworded string changes no class, so without that input Gradle left the test
task UP-TO-DATE and the guard did not run again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-23 01:35:59 -05:00
5e28989adc feat(strings): use core's words on the screens every deployment shows
PLAN.md M20 step 2. The first screen a Rust community's player sees said
"Connect to your shard", and the next said "Sign in with your shard account".
The core strings now use core's words, as the website and runicgateway.com do:

- connect_*: "your community", "a Runic Gateway site"
- login_subtitle: "Sign in with your account on this site."
- error_shard_offline: "The game server is offline right now." It is the
  shared 503 text that both games' screens show.
- error_feature_unavailable and notifications_*: "This site …"
- push_channel_* and push_service_text: "Notifications from your community"

Two comments in the file said "shard" too, and now say "site". Keys are
unchanged. The UO screens keep their words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-23 01:33:10 -05:00
ff8b66ace1 refactor(strings): split strings by owner into core, UO and Rust files
PLAN.md M20 step 1. strings.xml keeps the core strings; strings_uo.xml and
strings_rust.xml take the strings only that game's screens use. Android merges
the three into one R.string, so no key changes and no Kotlin changes.

Each string was classified by the screens that reference it, traced in code,
not by its key: a string any deployment's screen can show stays core.
error_shard_offline and error_feature_unavailable are the shared error-view
texts, so they stay core. All seven legacy push streams, server.status
included, are declared only by module-uo, so their titles are UO.

No text changes: all 578 elements are moved byte for byte (checked by
comparing name → element before and after).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-23 01:32:37 -05:00