feat(strings): the app's words for every game (M20) #58
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/app-vocabulary"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements M20 from
docs/android/PLAN.md(planned in docs#372). It has to land inedgebefore theedge→mainrelease, so the first build with Rust screens doesn't greet a Rust community with UO's words.Commits, in the plan's order
refactor(strings): split by owner.strings.xmlholds the core strings.strings_uo.xml(189 strings) andstrings_rust.xml(136) hold the strings only that game's screens use. Android merges the three into oneR.string, so no key or Kotlin changes. Each string was classified by the screens that reference it, traced in code. All 578 elements moved byte for byte, which I checked by comparing name → element before and after. Two traces from the plan:error_shard_offlineanderror_feature_unavailableare the sharedStateViewstexts, so they are core.push_stream_server_statusis UO: all seven legacy streams,server.statusincluded, are declared only by module-uo (LEGACY_STREAM_IDS.uo).feat(strings): core rewording. 14 strings:connect_*,login_subtitle,error_shard_offline("The game server is offline right now."),error_feature_unavailable,notifications_*,push_channel_*,push_service_text.test(strings): the guard.StringVocabularyTestchecks everyvalues*directory, so translations are checked too. It fails, naming the key and the word, when the core file holds either game's word or a game's file holds the other game's word. The word list ischeckTerms.mjs's, word for word. Three more tests:strings*file with no owner is refused;Run against the old core file, it names exactly the 14 strings.
build.gradle.ktsnow declaressrc/main/resas a Test input. Without it, a text-only edit lefttestDebugUnitTestUP-TO-DATE and the guard did not run again.fix(nav): gate Moderation and Support queue onCapability.SHARD(org lead's decision during this work). Both call/admin/shard/*, which is module-uo's mount. Before this, a moderator on a Rust-only site saw a UO form ("Serial (0x…)") where every action failed. Covered by a newMenuCapabilityGatingTestcase.feat(rust): weapon names.weaponName()(RustFormat.kt) printsframe.weaponNamefrom Module-Rust#60. Against an older module it drops the.entity/.weapon/.deployedending beforeprefabName(), the same way the website'sformat.js weapon()does. So "with ak47u entity" becomes "with Assault Rifle", or "with ak47u" from an older module.Verified
./gradlew testDebugUnitTest lintDebug assembleDebug(the CI gate) passes locally: 758 unit tests, 0 failures.https://your-community.example.com.Found, not fixed (needs a decision)
The app maps every 503 to
ErrorKind.SHARD_OFFLINE. Core'ssiteModemiddleware also answers 503 in maintenance mode. So a signed-out reader of News during maintenance is told "The game server is offline right now". Before this PR it said "The shard is offline right now", so it was wrong before too. The fix is a separate maintenance error kind, read from the 503 body'smode: "maintenance". That is outside M20's scope.Not in this PR
Code identifiers and comments that say "shard" (
ui/shard,Shard*), by the plan's decision.website#221's leftovers, which belong to
website/.AI-assisted: written with Claude Code (Claude Opus 5.5). Commits carry the Co-Authored-By trailer.
🤖 Generated with Claude Code
https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
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