# 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.`