account-state
Account, LocalCache, User/Note and feeds in commons/model + commons/feeds: per-user XState objects (.flow),…
Translation audits of `strings.xml` locales in `commonsUI/.../composeResources` and `amethyst/src/main/res`: missing or untranslated keys, CLDR plural categories, Crowdin sync rules, lint gates. Use before translating or seeding locale files.
Claude Code
$ npx -y skills add vitorpamplona/amethyst --skill find-missing-translations --agent claude-code
Codex
$ npx skills add vitorpamplona/amethyst --skill find-missing-translations -a codex -y
Cursor
$ npx skills add vitorpamplona/amethyst --skill find-missing-translations -a cursor -y
Gemini CLI
$ npx skills add vitorpamplona/amethyst --skill find-missing-translations -a gemini-cli -y
GitHub Copilot
$ npx skills add vitorpamplona/amethyst --skill find-missing-translations -a github-copilot -y
OpenCode
$ npx skills add vitorpamplona/amethyst --skill find-missing-translations -a opencode -y
Windsurf
$ npx skills add vitorpamplona/amethyst --skill find-missing-translations -a windsurf -y
name: find-missing-translations description: Translation audits of `strings.xml` locales in `commonsUI/.../composeResources` and `amethyst/src/main/res`: missing or untranslated keys, CLDR plural categories, Crowdin sync rules, lint gates. Use before translating or seeding locale files.
How to author a new string (where it goes, `Res.string`, positional args, Compose escaping) is in AGENTS.md "Strings" — not repeated here. This skill is the audit: diff locales against their default, fill the gaps, and pass the gates.
Each is its own Crowdin source in `crowdin.yml`, so each count reconciles against its own Crowdin UI number.
| Catalog | Default file | Size | |--|--|--| | **commonsUI** (Compose resources, Android + Desktop) | `commonsUI/src/commonMain/composeResources/values/strings.xml` | ~6,155 `<string>` + ~198 `<plurals>` | | **amethyst** (Android `res/`) | `amethyst/src/main/res/values/strings.xml` | ~191 `<string>` + ~13 `<plurals>` — the synchronous-platform tier only |
`values-cs`, `values-de-rDE`, `values-sv-rSE`, `values-pt-rBR` (unless the user names others). Czech is on the base qualifier because `crowdin.yml` maps `cs: cs` (in both sources); there is no `values-cs-rCZ`.
Diff `<string>` **and** `<plurals>` separately (a missing `<plurals>` never shows in a `<string>` diff), and diff **every** target locale — files are asymmetric, so `cs` is not an upper bound.
keys() { grep "<$2 name=" "$1" | grep -v 'translatable="false"' | sed 's/.*name="\([^"]*\)".*/\1/' | sort -u; }
for base in commonsUI/src/commonMain/composeResources amethyst/src/main/res; do
echo "## $base"
for l in cs de-rDE sv-rSE pt-rBR; do
for t in string plurals; do
m=$(comm -23 <(keys $base/values/strings.xml $t) <(keys $base/values-$l/strings.xml $t))
echo "$l $t: $(printf '%s' "$m" | grep -c .)"; printf '%s\n' "$m" | sed '/^$/d;s/^/ /'
done
done
doneThe `strings + plurals` total per locale should match Crowdin's "N untranslated". Pull English values with `grep "name=\"$key\""` for strings; a `<plurals>` is a multi-line block (opening tag through `</plurals>`).
Stop and ask the user about any missing English string that looks plural-shaped: a hardcoded `1` next to a noun (`"1 reply"`), or a count placeholder whose noun changes with the count (`"%1$d follower"`, thresholds like "more than %1$d hashtags"). It should become a `<plurals>` first; translating the wrong shape means fixing it in every locale. The pattern is noisy (`"Limits for kind %1$d"` isn't plural) — review by hand.
Also scan the trees you touch for:
Account, LocalCache, User/Note and feeds in commons/model + commons/feeds: per-user XState objects (.flow),…
amy CLI in cli/: adding an `amy <verb>` command, Main.kt dispatch, Output.emit/--json contract, exit codes 0/1/2/124, ~/.amy…
Android shim in `amethyst/`: MainActivity, AndroidManifest/intent filters, :napplet process, play/fdroid flavors, R8 +…
NostrSigner in Amethyst: NostrSignerInternal (local key), NostrSignerRemote (NIP-46 bunker), NostrSignerExternal (NIP-55 Android…
Shared Compose UI in `commonsUI/`: screens, components, the nav shell (`ScreenLayoutSpec`, `AppShellLayout`, Navigation 3 back…
Desktop JVM shim in desktopApp/: AmethystDesktop window, DesktopMenuBar, platform ports, OS keyring; :desktopApp:run, packaging.…
Decompile Android APK, XAPK, JAR, and AAR files using jadx or Fernflower/Vineflower. Reverse engineer Android apps, extract HTTP…