From 9b3f3b6afc85b03456b199ef701cefe5871f4c99 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Sat, 11 Jul 2026 01:56:39 +0800 Subject: [PATCH] docs: plan platform localization --- .../plans/2026-07-11-platform-localization.md | 281 ++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-11-platform-localization.md diff --git a/docs/superpowers/plans/2026-07-11-platform-localization.md b/docs/superpowers/plans/2026-07-11-platform-localization.md new file mode 100644 index 0000000..5b0a5e8 --- /dev/null +++ b/docs/superpowers/plans/2026-07-11-platform-localization.md @@ -0,0 +1,281 @@ +# Platform Localization Implementation Plan + +> **Execution note:** implement task-by-task in the current session. Do not use +> subagents. Use TDD for every production boundary and keep commits scoped to a +> single repository. + +**Goal:** Add persisted System/Russian/English language selection to Verstak +Desktop, localize the shell and all official plugins, and establish the public +SDK contract used by future multilingual plugins. + +**Architecture:** Desktop owns the application preference, locale resolution, +shell catalogs, safe plugin-catalog loading, and a generic runtime bridge. Each +plugin owns its manifest and UI catalogs and accesses them through +`api.i18n`. Manifest literals remain English fallbacks. Locale changes update +mounted UI without remounting plugin components. + +**Tech stack:** Go/Wails backend tests, Svelte 4 and plain JavaScript frontend, +TypeScript SDK with Vitest, JSON Schema, browserless Node plugin smoke tests, +Playwright mocked-Wails E2E. + +## Global Constraints + +- `~/git/verstak` is UI reference only; do not copy its implementation. +- Core must not contain official plugin messages or depend on official plugin + IDs. +- Official and third-party plugins use the same manifest and runtime API. +- Store only `system`, `ru`, or `en`; default to `system`. +- Resolve `ru-*` system locales to `ru`, everything else to `en`. +- Do not remount plugins on locale changes or discard form/editor state. +- Preserve existing unrelated generated Wails binding changes in the desktop + worktree. +- Add tests before production changes and observe each focused test fail before + implementing its boundary. + +--- + +## Task 1: SDK localization contract + +**Files:** + +- Modify `verstak-sdk/schemas/manifest.json` +- Modify `verstak-sdk/src/types.ts` +- Modify `verstak-sdk/src/plugin-api.ts` +- Modify `verstak-sdk/src/test-utils.ts` +- Modify `verstak-sdk/src/plugin-api.test.ts` +- Generated by build: `verstak-sdk/dist/*` + +**Contract produced:** + +```ts +interface PluginLocalizationConfig { + defaultLocale: string; + locales: Record; +} + +interface PluginI18nAPI { + getLocale(): 'ru' | 'en'; + t(key: string, params?: Record, fallback?: string): string; + onDidChangeLocale(listener: (locale: 'ru' | 'en') => void): Unsubscribe; +} +``` + +- [ ] Add failing schema/type/mock tests for a valid manifest localization + block, required default catalog, safe relative paths, API shape, fallback, + interpolation, and locale-change notification. +- [ ] Run `npm test -- --run src/plugin-api.test.ts` and confirm RED. +- [ ] Add `localization` to the JSON Schema and TypeScript manifest types. +- [ ] Add `i18n` to `VerstakPluginAPI` and configurable locale/messages to + `createMockPluginAPI`. +- [ ] Run focused tests GREEN. +- [ ] Run `npm test`, `npm run lint`, and `npm run build`. +- [ ] Commit only SDK source/schema/generated dist changes. + +--- + +## Task 2: Desktop application language setting + +**Files:** + +- Modify `verstak-desktop/internal/core/appsettings/manager.go` +- Modify `verstak-desktop/internal/core/appsettings/manager_test.go` +- Modify `verstak-desktop/internal/api/app.go` +- Modify `verstak-desktop/internal/api/app_test.go` + +**Behavior:** missing language becomes `system`; valid updates persist; invalid +updates return an error; unrelated settings remain unchanged. + +- [ ] Add failing manager tests for default, reload, and preservation. +- [ ] Add failing API tests for `GetAppSettings` and accepted/rejected patches. +- [ ] Run focused Go tests and confirm RED. +- [ ] Add `Language` to `appsettings.Config`, default/load normalization, and + update handling without changing unrelated values. +- [ ] Expose and validate `language` in the Wails API. +- [ ] Run focused tests GREEN. +- [ ] Run `gofmt` on changed Go files and `go test ./internal/core/appsettings + ./internal/api`. + +--- + +## Task 3: Plugin localization metadata and safe catalog loading + +**Files:** + +- Modify `verstak-desktop/internal/core/plugin/plugin.go` +- Modify `verstak-desktop/internal/core/plugin/plugin_test.go` +- Modify `verstak-desktop/internal/api/app.go` +- Modify `verstak-desktop/internal/api/app_test.go` +- Generated Wails bindings are intentionally not regenerated over existing + user changes; frontend imports call the binding only after generation is + explicitly reconciled. + +**Backend API:** + +```go +GetPluginLocalization(pluginID, locale string) (map[string]string, string) +``` + +- [ ] Add failing manifest parsing tests for localization metadata. +- [ ] Add failing API tests for declared catalog reads, locale fallback input, + malformed JSON, non-string values, missing declarations, absolute paths, + backslashes, traversal, and containment. +- [ ] Run focused Go tests and confirm RED. +- [ ] Add localization manifest structs and the read-only safe catalog API. +- [ ] Run focused tests GREEN and `go test ./internal/core/plugin ./internal/api`. + +--- + +## Task 4: Frontend localization service + +**Files:** + +- Add `verstak-desktop/frontend/src/lib/i18n/catalogs/en.js` +- Add `verstak-desktop/frontend/src/lib/i18n/catalogs/ru.js` +- Add `verstak-desktop/frontend/src/lib/i18n/index.js` +- Add `verstak-desktop/frontend/tests/i18n-test.mjs` +- Modify `verstak-desktop/frontend/src/main.js` +- Modify `verstak-desktop/frontend/src/lib/test/wails-mock.js` + +- [ ] Add a failing standalone Node test for preference validation, system + locale resolution, interpolation, shell fallback, plugin catalog fallback, + subscription, and contribution-copy localization. +- [ ] Run `node frontend/tests/i18n-test.mjs` and confirm RED. +- [ ] Implement the framework-independent locale store and catalog cache. +- [ ] Initialize it from `GetAppSettings` before mounting Svelte. +- [ ] Extend the Wails mock with language state and plugin catalogs. +- [ ] Run the focused test GREEN and `npm run build`. + +--- + +## Task 5: Runtime `api.i18n` bridge + +**Files:** + +- Modify `verstak-desktop/frontend/src/lib/plugin-host/VerstakPluginAPI.js` +- Modify `verstak-desktop/frontend/src/lib/plugin-host/PluginBundleHost.svelte` +- Modify `verstak-desktop/frontend/tests/plugin-api-contributions-test.mjs` +- Modify `verstak-desktop/frontend/tests/bundle-host-test.cjs` + +- [ ] Extend bridge tests first to require `getLocale`, `t`, and disposable + `onDidChangeLocale` behavior. +- [ ] Confirm focused RED. +- [ ] Preload the plugin catalog before mount and expose the i18n service + through the public API. +- [ ] Keep locale subscriptions under existing API disposal cleanup. +- [ ] Translate host loading/error states through shell catalogs. +- [ ] Confirm bridge/bundle tests GREEN. + +--- + +## Task 6: Language selector and shell migration + +**Files:** + +- Modify `verstak-desktop/frontend/src/App.svelte` +- Modify every Svelte file under `verstak-desktop/frontend/src/lib/shell/` +- Modify every Svelte file under + `verstak-desktop/frontend/src/lib/plugin-manager/` +- Modify `verstak-desktop/frontend/src/lib/plugin-host/PluginBundleHost.svelte` +- Modify `verstak-desktop/frontend/e2e/status-bar.spec.js` +- Add `verstak-desktop/frontend/e2e/localization.spec.js` +- Modify `verstak-desktop/frontend/tests/shell-source-contract-test.mjs` where + assertions intentionally depend on translated literals. + +- [ ] Add failing E2E assertions for the language submenu/radio state, + persistence, Russian system locale, English fallback, and live shell update. +- [ ] Confirm focused Playwright RED. +- [ ] Add the language submenu to StatusBar and persist changes through + `UpdateAppSettings`. +- [ ] Replace shell user-facing literals with shell catalog keys, including + aria labels, tooltips, empty/loading/error/confirmation text. +- [ ] Localize copies of plugin manifests and contributions before display. +- [ ] Confirm focused E2E GREEN, standalone shell tests GREEN, and frontend + production build GREEN. + +--- + +## Task 7: Official plugin localization declarations and catalog checks + +**Files:** + +- Modify every `verstak-official-plugins/plugins/*/plugin.json` +- Add `locales/en.json` and `locales/ru.json` under every official plugin +- Add `verstak-official-plugins/scripts/check-locales.mjs` +- Modify `verstak-official-plugins/scripts/check.sh` +- Modify relevant plugin smoke harness API mocks under + `verstak-official-plugins/scripts/` + +- [ ] Add the locale checker first and confirm it fails for missing metadata + and catalogs. +- [ ] Add localization declarations to all 13 manifests. +- [ ] Add English and Russian manifest/contribution keys to all catalogs. +- [ ] Verify catalog parity, string-only values, safe paths, and required + derived manifest keys. +- [ ] Run `./scripts/check.sh` GREEN before migrating runtime UI strings. + +--- + +## Task 8: Plain-JavaScript official plugin UI migration + +**Files:** + +- Modify `frontend/src/index.js` for activity, browser-inbox, default-editor, + file-preview, files, journal, notes, platform-test, search, secrets, todo, and + trash. +- Expand each plugin's `locales/en.json` and `locales/ru.json`. +- Modify focused `scripts/smoke-*-plugin.js` tests. + +For each plugin, repeat independently: + +- [ ] Add a failing bilingual rendering assertion and a locale-change state + preservation assertion to its existing smoke test. +- [ ] Add a local `t` helper backed only by `api.i18n`. +- [ ] Replace user-visible literals, attributes, empty/loading/error states, + confirmation prompts, and known validation messages with stable keys. +- [ ] Subscribe once at mount, update only rendered text/state, and unsubscribe + at unmount. +- [ ] Run the focused plugin smoke test GREEN before moving to the next plugin. + +Do not translate IDs, paths, user data, logs, API labels in diagnostics, or +provider-returned values. + +--- + +## Task 9: Svelte Sync plugin migration + +**Files:** + +- Modify `verstak-official-plugins/plugins/sync/frontend/src/SyncSettings.svelte` +- Modify `verstak-official-plugins/plugins/sync/frontend/src/SyncStatusBar.svelte` +- Modify `verstak-official-plugins/plugins/sync/frontend/src/index.js` +- Expand `verstak-official-plugins/plugins/sync/locales/en.json` +- Expand `verstak-official-plugins/plugins/sync/locales/ru.json` +- Modify Sync smoke/E2E tests as appropriate. + +- [ ] Add failing English/Russian and live-change assertions. +- [ ] Bridge `api.i18n` into reactive Svelte state without remounting. +- [ ] Translate UI labels and known status/error chrome. +- [ ] Run Sync plugin build and focused tests GREEN. + +--- + +## Task 10: Full verification and documentation + +**Files:** + +- Modify `verstak-docs/04_Plugin_System.md` +- Modify `verstak-docs/07_Full_Implementation_Roadmap.md` +- Modify other contract docs only where the implemented behavior requires it. + +- [ ] Run SDK: `npm test`, `npm run lint`, `npm run build`. +- [ ] Run desktop backend: `go test -count=1 ./...` and `go vet ./...`. +- [ ] Run desktop standalone frontend tests, production build, and focused then + full `npm run test:e2e`. +- [ ] Run official plugins: `./scripts/check.sh` and all plugin builds. +- [ ] Run `git diff --check` in every changed repository. +- [ ] Inspect changed-file lists and ensure pre-existing Wails generated changes + are not staged or overwritten. +- [ ] Update docs to match only verified behavior. +- [ ] Commit scoped changes in each repository. +- [ ] Report exact verification labels. If native Wails/WebKit was not exercised, + state: `GUI behavior was not verified in the real desktop shell.`