282 lines
11 KiB
Markdown
282 lines
11 KiB
Markdown
# 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<string, string>;
|
|
}
|
|
|
|
interface PluginI18nAPI {
|
|
getLocale(): 'ru' | 'en';
|
|
t(key: string, params?: Record<string, string | number>, 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.`
|