Repository navigation
feat(i18n): spec 019 language packs: catalog, checker, backend, module translations and designs - #668
ValgulNecron wants to merge 65 commits into
Conversation
… and i18n-check Spec 019 T001-T004, T007-T019: new Go module i18n/ (go.work, GO_MODULES, CI matrices, dependabot, coverage gate 90), ICU MessageFormat subset parser/formatter with CLDR plurals, pack load/validate/completeness, embedded catalog with regional -> base -> en fallback, the i18n-check CLI and one seeded defective fixture per finding code. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Spec 019 T005, T006 (web), T024-T033: react-intl provider with language resolution, storage and no-flash boot snippet; locale-aware formatting helpers replacing hard-coded en-US; problem+json parsing in APIError with err.body kept as the English detail; extract/compile/manifest scripts; formatjs ESLint rules on migrated paths. No visible UI change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Spec 019 T006 (api/operator), T020-T023: api/internal/messages registry (server.* ids with translator notes), httperr.Message and WriteMessage, RFC 9457 problem details only when Accept lists application/problem+json with q > 0 (plain-text bodies stay byte-identical), 5xx never echo error text or args, messages-export command and make i18n-sync writing the server.* entries into i18n/locales/en/app.json. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Spec 019 T034, T048: the web job builds the language manifest, runs i18n-check (extraction drift, server-message drift, before/after completeness in the job summary) and self-tests the checker on the seeded defective packs; make check-i18n joins make lint. i18n-check now creates the manifest's directory. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 445 files, which is 345 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configuration
⛔ Files ignored due to path filters: 30
📒 Files selected for processing: 445
You can disable this status message by setting the
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…tions golangci-lint (gosec G703, staticcheck QF1001) on the new i18n module. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
eslint formatjs/enforce-description on src/lib/i18n/serverMessage.ts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
CI Report - a009569run 38831683575 - attempt 1 0 failed - 32 passed - 0 skipped - 36m3s elapsed Coverage
Changed
Slowest jobs
e2e buckets run
|
|
Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
…guage Spec 019 T036, T038-T041, T093: migration 016 adds user_preferences.language; PUT /users/me/language (listed languages only, server.i18n.unknown_language); language in GET /users/me/preferences; unauthenticated GET /auth/locale exposing only defaultLanguage; admin config section i18n validated against the listed languages (server.i18n.unlisted_language). E2E for /auth/locale in the api-auth bucket. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
…ider Spec 019 T042, T046, T047: Users.setLanguage and Auth.locale endpoints, AppI18nProvider reading the cached /users/me language and /auth/locale default, and the 0% fixture language behind VITE_I18N_FIXTURES=1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> GameServerStatus gains conditionArgs (map of condition type to the values interpolated into its English message), set after each status pass and cleared when the reason carries no values. The condition-ids generator writes condition.<type>.<reason> English entries into the reference pack and has a -check mode for drift. Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Sinks take an optional language (validated against the listed languages). Titles, details and test text come from notify.* catalog entries in the sink language, then the instance default, then English. Webhook payloads add language, title and text and keep every existing field. English output is unchanged. Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Every 4xx http.Error in handlers, auth, ws and rbac now goes through httperr.WriteMessage (registry id) or httperr.WriteCode (generic id). Plain-text bodies stay byte-identical; 5xx stays http.Error. Unauthenticated login and OIDC paths only use server.auth.invalid_credentials or generic ids. make i18n-sync also syncs notify.* and condition.* ids, and i18n-check covers notify.* drift. Adds the problem+json E2E and ticks the 019 US5 backend tasks. Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> i18n-check gains --valid-out, which writes each pack's usable entries. The compile script and the web image use it, so a broken translation shows the English text instead (FR-018). Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
valgul approved this expectation change on the spec 019 decision card. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> New i18n/modlocale derives module ids from module.yaml and template.yaml with reversible ~0/~1 escaping. gp-module gains i18n extract and i18n stamp, validate checks locales/*.json, and package adds one OCI layer per language and includes locales/ in --output tarballs. i18n-check --module checks en.json drift and validates translations. Signed-off-by: Claude <noreply@anthropic.com>
Brings in PRs #630, #690, #691 and #696. Conflicts resolved: - api/internal/notify/format.go: master's remote-cluster headline is kept through a new notify.title.cluster message, so "[prod] server unhealthy: remote-1/games/mc" is unchanged in English; app.json regenerated with make i18n-sync. - web/src/lib/endpoints.ts: master's cluster parameter on Modules, and Modules.locales takes the same parameter. - web/src/components/ui/NotificationsPanel.tsx: both the formatter ref effect and master's enabled guard. - docs/architecture.md: master's standalone-panel paragraph, then the Internationalization section. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Master added 016_standalone_management.sql and 017_standalone_key_state.sql, so 016_user_language.sql collided on version 016 and Migrate refused to run. The language column moves to the next free version; spec 019 docs and api/specs.md follow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Brings in PRs #618, #621, #648, #693, #697-#700 and #702. PR #702 regrouped design.pen. valgul chose to take master's design.pen and design exports, so the branch's spec 019 picker designs and their exports are dropped and T043, T072 and T094 are reopened, to be redrawn on the regrouped canvas in Pencil. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
|
This failure comes from master, not this PR:
I couldn't find an open PR that fixes it, so I haven't ported anything into this PR. The fix belongs on master: either re-export Generated by Claude Code |
Adds web/scripts/i18n-migrate.ts (npm run i18n:migrate), run with Node's type stripping and the installed TypeScript compiler API only. It moves JSX text and display props (aria-label, title, placeholder, alt, and label/hint/subtitle/message-like props on components) to intl.formatMessage with ids web.<path>.<slug> and a description stub, inserts useOptionalIntl() at the top of the enclosing component or hook, keeps sentences with simple computed values as one ICU message, checks every message parses and renders the same English, is idempotent, and reports what needs a human (ternaries, rich text, JSX outside components). i18n-reference.mjs now writes the merged reference to i18n/locales/en/app.json, as `npm run i18n:extract` is documented to do; it used to overwrite src/generated/i18n/extracted.json instead, so the reference CI compares against never received web.* entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Redraws the spec 019 designs (T043, T072, T094) on the regrouped design.pen, after the 2026-10-12 pass was dropped when master's canvas regroup (PR #702) was taken in the merge. - Personal settings: a Language card (component Gameplane/Language Card) is the first card of Theme & Appearance and its Warnings variant, plus a mobile screen. Native names with completeness, an "Automatic (browser language)" option and a note that missing text shows in English (OD-016). - Login and share pages: a compact picker (component Gameplane/Language Picker Compact) in the top-right corner of every card, and a login screen with its menu open. It shows language names only (OD-017). - Notifications: a Language select on each sink row (component Gameplane/Sink Language Row) and a new Add sink screen whose Language select defaults to Instance default (OD-015). - Admin settings: a Language card under General with the Default language field and its own Save changes button (config section i18n). Exports: JSON and 2x PNG for every new or changed node, each JSON checked against the canvas by length and FNV-1a hash; root x/y patched for the screens the row shifts moved. Details in assets/design-export/MANIFEST.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Adds a --check mode that reproduces formatjs/no-literal-string-in-jsx
locally (JSX text, string and template literals in child expressions
including ternary, logical and + branches, and the aria-*/title/
placeholder/alt props), since ESLint is not run locally. The codemod
now joins {" "} children into plain same-line spaces instead of
emitting them, because the lint rule flags {" "}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApTxEGsCt52QvsiF39nPiR
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…ec 019) UI (T044, T045, T073, T095, per the 83c958d design): - LanguagePicker in ThemeSettings; CompactLanguagePicker on Login and Share (browser-local gameplane-language.choice). - Admin settings: Language card under General (config section i18n) and a per-sink language field in Notifications (Instance default). - AdminSettings.test.tsx and AdminSettings_sections.test.tsx: 13 Save button queries scoped to the General region, approved by valgul because the Language card adds a second "Save changes" button. String migration (T053-T056 waves, not ticked yet): components, routes and lib move to useOptionalIntl().formatMessage with web.* ids; i18n/locales/en/app.json regenerated (2611 messages); src/components/settings/** added to MIGRATED_I18N_PATHS. Local checks: tsc --noEmit clean, i18n-migrate --check src 0 findings. Not done: T057, T059 (used ids must include API and operator ids), T060, T089 descriptions pass, T100 en-XA run, raw err.message sites, and recording the event-id and Local-accounts decisions in OPEN-DECISIONS.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApTxEGsCt52QvsiF39nPiR Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Brings in master up to 4b11c41. Makefile conflicted on the lint target: master added check-features-sync and this branch added check-i18n; the target now runs both. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
endpoints.ts now builds its legacy clients from @/lib/api at import time (master). I18nProvider imported it statically, so every module that only needs useLanguage pulled that in, and the Share page suites, which mock @/lib/api without api, failed to load. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
…c 019)
The string migration swapped the row's raw kind ("webhook") for the
translated picker label ("Webhook"), which the live admin-notifications
e2e spec and master's behaviour do not expect. The kind picker keeps the
translated labels.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
… valgul) LanguagePicker: the completeness label sits in the radio's label, so assert the radio's accessible name instead of searching inside the input element (drops the now unused within import). Share language: wait for the resolved card before opening the menu, so the loading card's picker is not the one clicked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
Translator descriptions replace the codemod stubs for every message in web/src/components/**, so Weblate shows what each text is and where it appears. The empty select options and the password removal note in ConfigFields render through intl (the exported English constants stay for the tests). src/components/** joins MIGRATED_I18N_PATHS and i18n/locales/en/app.json is regenerated. The English is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
… 019 T054) Translator descriptions replace the codemod stubs in Login, Share, NotFound, Dashboard, Servers, Clusters and Cluster; the routes join MIGRATED_I18N_PATHS and i18n/locales/en/app.json is regenerated. The English is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…19 T055) Translator descriptions replace the codemod stubs in CreateServer, ServerDetail and every server tab. The Backup now hints, the console connect and disconnect lines and the mod provider subtitle render through intl. The files join MIGRATED_I18N_PATHS and i18n/locales/en/app.json is regenerated. The English is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…019 T056) Translator descriptions replace the codemod stubs in Modules, Backups, Users, AuditLog, AdminLogs, AdminSettings and ThemeSettings. Audit labels move to the audit.* namespace from data-model.md (audit.verb, audit.noun, audit.action, audit.access), still composed from method and path, with unknown routes shown as before (FR-029). The install-ID reset error renders through intl. The routes join MIGRATED_I18N_PATHS and i18n/locales/en/app.json is regenerated. The English is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…pec 019 T057) conditionMessageText looks up condition.<type>.<reason> (lower-cased) in the active catalog and formats it with status.conditionArgs[type]. English locales, missing entries and entries whose arguments the operator did not record keep the operator's English message, so the English does not change. ServerDetail (Progressing and Ready), the Overview tab and the Networking address assignment use it; the Networking parser still reads the English message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
useModuleText and useModuleTexts read a module's translations from
GET /modules/{name}/locales/{tag} and format them, with the template
text as the fallback for every id the module does not translate (FR-032).
The create-server wizard (template cards and search, versions,
configuration fields, review and preview) and the Version and Game
configuration settings use them; ConfigFields takes an optional text
accessor. English makes no request and renders exactly as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…c 019 T058)
MIGRATED_I18N_PATHS becomes src/**/*.{ts,tsx} (FR-022, SC-001); test
files and the src/test helpers stay exempt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The i18n step builds the list of ids the code uses (extracted dashboard ids, API registry ids and the operator condition ids from the new condition-ids -ids flag) and passes it to i18n-check --used-ids (FR-023). CI also runs the condition-ids drift guard now; make check-i18n does the same locally. No unused entries were reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
docs/translating.md gains a section for developers (intl pattern, ids, descriptions, npm run i18n:extract, the codemod, lint and CI checks, and the helpers for API, condition and module text); web/specs.md records the lint scope, the unused-id check and the new helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…19 T100) npm run screenshots:pseudo starts the dev server with VITE_I18N_PSEUDO=1 and runs the screenshot suite as the en-XA Playwright project. The specs keep driving the UI in English; capture.ts switches the dashboard to en-XA for each screenshot through window.gameplaneI18nTest (installed by I18nProvider only when en-XA is listed, so never in a release), writes the capture to test-results/en-XA and soft-fails on text that is cut off without a title to reveal it (FR-010), then switches back. A new "en-XA screenshots" job in visual-diff.yaml runs it and uploads the captures. Decisions OD-018 and OD-019 (valgul, 2026-10-16). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The first en-XA run found only data text that is already truncated in English: server names, locations and addresses on the mobile Servers cards, endpoint hosts on the Overview tab, module summaries and file names. Each truncated element now carries a title with its full text (FR-010, OD-020); nothing changes visually. The capture helper also creates nested folders for ids such as legacy/dashboard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Before: Gameplane has no translation system. Dashboard text, API errors, notifications and operator conditions are English-only, dates and numbers are hard-coded to
en-US, and game modules can't ship translations.After: Gameplane has a shared language catalog, a checker that runs in CI, and a backend that knows each user's language. The API saves each user's language and an instance default language. It returns localizable 4xx errors as RFC 9457 problem details to clients that ask for them. Notifications render in each destination's language, and the operator publishes condition message ids with their arguments. Modules can ship
locales/*.json, which the operator publishes and the API serves. The dashboard has the i18n runtime and anen-XApseudo-language for spotting untranslated text. The language picker and settings designs are indesign.pen. Nothing visible changes in English yet, and plain-text API error bodies stay byte-identical.This PR carries the cloud-built part of spec 019: 71 of 105 tasks in
specs/019-localization-language-packs/tasks.md. The dashboard UI built from the designs (T044, T045, T052–T060, T073, T089, T095, T100) is being built locally and lands on this same PR. Until that is pushed and CI is green, the PR stays a draft. The rest goes in follow-up PRs:How
i18n/(new Go module, coverage gate 90):icuis an ICU MessageFormat subset with CLDR plurals.packloads and validates packs and applies the 80% listing rule.catalogholds the embedded packs and falls back regional → base → English.modlocalederives module translation ids.cmd/i18n-checkchecks extraction drift, server-message drift and module drift (--module), with one seeded defective fixture per finding code.internal/messagesregistry andhttperr.WriteMessage. Problem details are returned only whenAcceptasks forapplication/problem+json(wildcards never select them), and 5xx responses never echo error text.PUT /users/me/language, the instance default in/admin/config/i18n, and a per-sink language for notifications./modules/{name}/locales/{tag}.018_user_language.sql, because master already uses 016 and 017.status.conditionArgsandcondition.*message ids.<template>-localesConfigMap in the operator namespace, with aLocalesValidcondition (LocalesTooLarge,InvalidEntries,WriteFailed) and a 4 MiB total read cap.sourceHash) and packages module translations, and reports YAML names that cannot become translation ids.src/lib/i18n/(provider, FR-004 resolution order, format helpers, server-message mapping), the user's and instance's language fed into the provider, invalid pack entries dropped at build time, anden-XAbehindVITE_I18N_PSEUDO.webjob builds the manifest and runsi18n-check, and translation-only PRs are labelled docs.make check-i18njoinsmake lint.Test fixes that valgul approved on decision cards: the api-cache Accept header, the
/auth/localemock, the TestModulePacks fixture, the gp-module README fixture, theMigratecall in the preferences test, the validator canonical check, the escaped locale tag, the e2e lint fixes, the Template/Modèle fixture words and the AddressInUse envtest cleanup.Only compile checks and the generators were run locally. Tests and lint run here in CI.
🤖 Generated with Claude Code