Skip to content

i18n WIP#1131

Closed
Aciid wants to merge 62 commits into
TripSit:mainfrom
Aciid:i18n-wip
Closed

i18n WIP#1131
Aciid wants to merge 62 commits into
TripSit:mainfrom
Aciid:i18n-wip

Conversation

@Aciid

@Aciid Aciid commented May 22, 2026

Copy link
Copy Markdown

Summary

Introduces full internationalization (i18n) infrastructure to TripBot and localizes the
overwhelming majority of user-facing commands. Adds a fi (Finnish) locale alongside the
en-US source of truth as a working second locale, wires locale resolution into command deployment and runtime.

This is a large but mostly mechanical branch: 204 files changed, ~10.3k insertions.
The bulk is locale JSON (121 files across two locales × 59 namespaces) and the command-builder edits
that reference those keys.

What's included

Infrastructure

  • i18next-based i18n core (src/i18n/index.ts) — t() and getCommandLocalizations()
    helpers, namespace auto-discovery from en-US filenames, no code change needed to add a namespace.
  • Dot-notation key refst() and getCommandLocalizations() accept dot-namespaced refs
    (e.g. idose.commandName), replacing the older (ns, key) form. i18n-ally VSCode config and
    regex updated to match peek translations.
  • Locale resolutiongetLocale() driven by env LOCALE; runtime falls back cleanly.
  • Locale sync script (src/scripts/syncLocales.ts, npm run i18n:sync) — keeps all locales
    in structural parity with en-US, the single source of truth. Supports --dry.
  • Startup + deploy wiringinitI18n() runs before command modules load in both
    src/start.ts and commandDeploy.ts, so slash commands register with localized name/description.
  • Per server locale -- Setup per guild locale using /setup locale set <locale>, lives on guild table locale column.

Command localization

  • 58 of 69 commands localized (84.1%), or 57 of 60 user-facing commands (95.0%).
  • Both command name/description localizations (shown in the Discord client picker) and response
    body strings moved to locale files.

Housekeeping

  • Prisma generated-client paths updated to load from src/ (where they're generated).
  • CLAUDE.md, README, and i18n design/plan docs added.

What's left out (intentional)

Excluded by design — not localized (9)

Staff/admin tooling and the RPG game are not user-facing harm-reduction surfaces, so they keep
literal English strings:

  • Mod/Admin: admin, mod, botmod, purge, clearchat, botstats, bottest, say
  • RPG: rpg

Remaining user-facing, not yet localized (3)

All three are context-menu commands (not slash commands) and were deferred to a follow-up:

  • m.quote
  • m.report
  • u.report

Coverage

Scope Localized Total Coverage
All commands 58 69 84.1%
User-facing (excl. mod/admin/rpg) 57 60 95.0%

Counts exclude archived commands and templates.

Notes for reviewers

  • en-US is the source of truth. Run npm run i18n:sync -- --dry to confirm locale parity.
  • New command? Add a src/locales/en-US/<name>.json namespace — no code change needed.
  • New locale? Add a src/locales/lang folder to trigger structure auto create by running npm run i18n:sync
  • AI translations are best to check by human review before production usage on a server.

E2EE TESTED AI DRIVEN CODE.

Aciid and others added 30 commits May 18, 2026 13:47
Adds an optional locale column to the discord_guilds table so each
guild can store its preferred language for i18n lookups.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds i18next with filesystem backend, locale files for en-US and fi,
t()/getLocale()/getCommandLocalizations() helpers, a test suite, and
an npm sync script that keeps non-default locales in sync with en-US.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Initialises i18next before Discord connects, exposes LOCALE env var,
and loads translations before command modules are imported during deploy.
Updates jest config to include i18n test coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wires t()/getLocale()/getCommandLocalizations() into every command so
response strings and Discord slash command name/description registrations
are driven by locale files instead of hardcoded English strings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ignore

Alphabetise imports in timer.ts and discord.ts. Add eslint-disable
comments for dormant functions/vars in timer.ts that are intentionally
commented out. Add .devcontainer/devcontainer-lock.json and docs/ to
.gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ale dirs

- Change getLocale() parameter from ChatInputCommandInteraction to
  BaseInteraction so it works with all interaction types (context menus,
  modals, etc.) without casting at call sites
- Filter syncLocales to skip directories whose names don't match
  /^[a-zA-Z-]+$/ (e.g. macOS Finder duplicates like "en-US 2")
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Aciid and others added 29 commits May 20, 2026 11:33
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds fi locale stubs for: birthday, bountyleaderboard, busyness,
cooperative, counting, donate, dramacounter, h2flow, issue, karma,
leaderboard, levels, opioidConverter, profile, quote, reminder,
report, rss, say, search, selftimeout, sheesh, tent, timezone,
tripsitstats.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates fi translations for: ai, avatar, bridge, calc, coinflip,
combo, convert, ems, fact, feedback, help, hr, hydrate, invite, joke,
kipp, learn, lovebomb, magick8ball, privacy, reactionRole, remindme,
rockpaperscissors, setup, testkits, tictactoe, topic, translate,
tripsitmode, triptacgo, triptoys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Aligns the locale key name with the naming convention used by other body
text keys, updating both locales and the Discord command reference.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Subcommand names (help, link, unlink, profile) need their own locale
keys distinct from description keys so name localizations don't share
the description string. Updates both locales and the Discord command.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded g.about.ts static properties in d.help.ts with
t(locale, 'help', key) calls so all body text is locale-aware.
Add en-US and fi translations for all 9 body text keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace g.about.ts imports in d.setup.ts with t(locale, 'setup', key)
calls for the 4 long description fields. Add en-US and fi translations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Refactor g.learn.ts link/unlink to return typed discriminated unions
instead of raw English strings. Update d.learn.ts to resolve locale-
aware messages via t(locale, 'learn', key). Add en-US and fi translations
for all response keys including moodle help title/description/footer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
drug: add getCommandLocalizations to substance, section, and ephemeral options.
hr: replace hardcoded en-US builder strings with t('en-US', 'hr', key).
calc: replace hardcoded constants with t('en-US', 'calc', key) and add
getCommandLocalizations; add the 3 psychedelics options that had no
localizations at all. Add en-US and fi translations for new calc keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Convenience wrapper around getCommandLocalizations that accepts a single
"ns.key" string, useful when the reference is constructed programmatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set up i18n-ally extension to recognise src/locales with en-US as the
source language, flat key style, and namespace-per-file path matching.
Add custom framework YAML so ally detects getCommandLocalizations and
getCommandLocalizationsNs usage patterns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…namespaced refs

Add a second call signature to both functions so callers can pass a single
"ns.key" string instead of separate ns and key arguments. The first dot is
used as the separator, allowing keys that themselves contain dots.

This makes the call-site pattern t(locale, 'ns.key') and
getCommandLocalizations('ns.key') readable by i18n-ally, which cannot
parse the two-argument comma form. The previous getCommandLocalizationsNs
helper is removed since it is now redundant. The custom-framework regex
is updated to match both overloads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…notation refs

Replace three-argument calls like t(locale, 'ns', 'key') and
getCommandLocalizations('ns', 'key') with the dot-namespaced overloads
t(locale, 'ns.key') and getCommandLocalizations('ns.key') across all
command files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per-guild DB lookup removed — discord_guilds.locale write in
/setup locale set is now a no-op (kept for re-enablement later).
interaction and ns params retained to avoid touching ~58 call sites.

Docs updated to describe the simplified resolution chain and the
two independent locale axes (command metadata vs. reply content).
Per-guild locale resolution was never effective after getLocale() was
simplified to env LOCALE only. Remove the dead surface area entirely:
- Drop /setup locale get|set subcommands and autocomplete handler
- Remove localeGet/localeSet functions and getAvailableLocales import
- Drop discord_guilds.locale column and its migration
- Remove locale keys from en-US and fi setup.json
- Update getLocale() tests to match the simplified contract

BREAKING CHANGE: /setup locale get and /setup locale set no longer
exist. Re-deploy slash commands after merging (npm run tripbot:deployCommands).
Commit 2c2c603 accidentally committed local debug state that
commented out nearly all scheduled timers (checkReminders,
checkTickets, checkVoice, undoExpiredBans, checkBirthdays, etc.)
and the checkVoice body. Restore the file to its main version so
the timer loop runs the full schedule again.
@Aciid Aciid closed this by deleting the head repository May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant