feat: add Russian translation for Live Mode UI#317
Conversation
- Add skill/i18n/ directory for translations - Add en.json as base reference - Add ru.json with complete Russian translation - Add README with usage instructions
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a84afcb9a1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ## Usage | ||
|
|
||
| 1. Copy the desired translation file (e.g., `ru.json`) to your project root as `live_translations.json` | ||
| 2. The Live Mode server will automatically load translations from this file |
There was a problem hiding this comment.
Wire translations into live mode
When users copy ru.json as instructed, nothing consumes it: /live.js assembly in skill/scripts/live-server.mjs only injects token/port/vocabulary and concatenates the browser script parts, and repo-wide search for live_translations only hits this README. Since the new JSON files are never read or sent to live-browser.js, the Russian locale remains a no-op and Live Mode stays English.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR wires up optional i18n support for the Live Mode in-browser UI. Server-side,
Confidence Score: 5/5Safe to merge — all changes are additive and isolated to dev-server infrastructure; the existing UI is unaffected, and missing or malformed translation files degrade gracefully to no-op. The server-side loading and browser-side injection code is correct, well-bounded, and consistent with how IMPECCABLE_VOCAB is already handled. Translation loading fails safely with a console warning. No existing behaviour is altered. skill/i18n/ru.json — singular/plural distinction between "Apply copy edit" and "Apply copy edits" is collapsed to the plural Russian form. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User as User (Browser)
participant Server as live-server.mjs
participant FS as Filesystem
participant Assembler as browser-script-parts.mjs
participant Window as window (Browser Global)
User->>Server: GET /live.js
Server->>FS: readLiveBrowserScriptParts()
FS-->>Server: live-browser.js + parts
Server->>FS: loadTranslations() → live_translations.json
FS-->>Server: "translations {} (or {} if missing/invalid)"
Server->>Assembler: "assembleLiveBrowserScript({ token, port, vocabulary, translations, parts })"
Assembler-->>Server: prelude + body JS string
Server-->>User: application/javascript response
User->>Window: "window.__IMPECCABLE_TRANSLATIONS__ = { ... }"
User->>Window: "window.__IMPECCABLE_T__ = function(key) { ... }"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User as User (Browser)
participant Server as live-server.mjs
participant FS as Filesystem
participant Assembler as browser-script-parts.mjs
participant Window as window (Browser Global)
User->>Server: GET /live.js
Server->>FS: readLiveBrowserScriptParts()
FS-->>Server: live-browser.js + parts
Server->>FS: loadTranslations() → live_translations.json
FS-->>Server: "translations {} (or {} if missing/invalid)"
Server->>Assembler: "assembleLiveBrowserScript({ token, port, vocabulary, translations, parts })"
Assembler-->>Server: prelude + body JS string
Server-->>User: application/javascript response
User->>Window: "window.__IMPECCABLE_TRANSLATIONS__ = { ... }"
User->>Window: "window.__IMPECCABLE_T__ = function(key) { ... }"
Reviews (3): Last reviewed commit: "fix: add missing translation strings for..." | Re-trigger Greptile |
| 1. Copy the desired translation file (e.g., `ru.json`) to your project root as `live_translations.json` | ||
| 2. The Live Mode server will automatically load translations from this file |
There was a problem hiding this comment.
No translation-loading mechanism exists in the codebase
The README states "The Live Mode server will automatically load translations from live_translations.json," but no such loading code exists. Searches across live-browser.js, live-server.mjs, and live-inject.mjs find zero references to live_translations, translations, or any i18n dispatch. The UI strings (e.g., 'Applying variant...', ariaLabel: 'Pick element') are plain string literals hardcoded in live-browser.js. Until an implementation is added to read live_translations.json and substitute those literals at runtime, copying ru.json to the project root has no effect whatsoever.
| { | ||
| "Pick element": "Pick element", | ||
| "Generate variants": "Generate variants", | ||
| "Create variants": "Create variants", | ||
| "Steer the page": "Steer the page", | ||
| "Steer": "Steer", | ||
| "Accept": "Accept", | ||
| "Discard": "Discard", | ||
| "Discard all variants": "Discard all variants", | ||
| "Done": "Done", | ||
| "Cancel": "Cancel", | ||
| "Clear": "Clear", | ||
| "Apply": "Apply", | ||
| "Applying ": "Applying ", | ||
| "Apply copy edits": "Apply copy edits", | ||
| "Saved. Click ": "Saved. Click ", | ||
| "Toggle DESIGN.md panel": "Toggle DESIGN.md panel", | ||
| "Edit copy": "Edit copy", | ||
| "Detect anti-patterns": "Detect anti-patterns", | ||
| "Voice input": "Voice input", | ||
| "Stop voice input": "Stop voice input", | ||
| "Impeccable live mode": "Impeccable live mode", | ||
| "Selected element: ": "Selected element: ", | ||
| "Clear selection": "Clear selection", | ||
| "Variant applied": "Variant applied", | ||
| "Exit live mode": "Exit live mode", | ||
| "No detector issues found.": "No detector issues found.", | ||
| "Describe the change": "Describe the change", | ||
| "Describe the new element": "Describe the new element", | ||
| "Insert new element": "Insert new element", | ||
| "Save": "Save", | ||
| "Insert": "Insert", | ||
| "Pick": "Pick", | ||
| "Tune": "Tune", | ||
| "Applying variant...": "Applying variant...", | ||
| "Keep fixing": "Keep fixing", | ||
| "Note…": "Note…", | ||
| "apply is running...": "apply is running...", | ||
| "Resize placeholder": "Resize placeholder", | ||
| "Close panel": "Close panel", | ||
| "Variants ready. If the picked element isn't visible, retrace the path that revealed it - they'll appear automatically.": "Variants ready. If the picked element isn't visible, retrace the path that revealed it - they'll appear automatically.", | ||
| "Do's and Don'ts": "Do's and Don'ts", | ||
| "Freeform": "Freeform", | ||
| "Bolder": "Bolder", | ||
| "Quieter": "Quieter", | ||
| "Distill": "Distill", | ||
| "Polish": "Polish", | ||
| "Typeset": "Typeset", | ||
| "Colorize": "Colorize", | ||
| "Layout": "Layout", | ||
| "Adapt": "Adapt", | ||
| "Animate": "Animate", | ||
| "Delight": "Delight", | ||
| "Overdrive": "Overdrive" | ||
| } |
There was a problem hiding this comment.
String count in PR description is incorrect
The PR description states "54 strings," but both en.json and ru.json contain 53 key-value pairs. This is a minor discrepancy, but it suggests the files were not carefully verified before submission.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| "Apply": "Apply", | ||
| "Applying ": "Applying ", | ||
| "Apply copy edits": "Apply copy edits", |
There was a problem hiding this comment.
Trailing-space keys are a fragile pattern for any future implementation
Three keys — "Applying ", "Saved. Click ", and "Selected element: " — have trailing spaces, indicating they are partial strings meant to be concatenated with dynamic content at runtime. A translation system that does a simple key lookup on the full UI string would need to reconstruct those dynamic parts after the translated prefix, which isn't documented anywhere. Any future implementation will need explicit handling for these partial-string keys, or the approach needs to change (e.g., using a placeholder like "Applying {{name}}").
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
- Add loadTranslations() function to read live_translations.json from project root - Add translations parameter to assembleLiveBrowserScript() - Inject window.__IMPECCABLE_TRANSLATIONS__ into browser script prelude - Add window.__IMPECCABLE_T__() helper function for string translation - Translations are now loaded and available in the browser UI
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cc5c5c5. Configure here.
| // UI translations for i18n support | ||
| `window.__IMPECCABLE_TRANSLATIONS__ = ${JSON.stringify(translations || {})};\n` + | ||
| // Translation helper: returns translated string or falls back to key | ||
| `window.__IMPECCABLE_T__ = function(key) { return (window.__IMPECCABLE_TRANSLATIONS__ && window.__IMPECCABLE_TRANSLATIONS__[key]) || key; };\n`; |
There was a problem hiding this comment.
Translations never reach live UI
High Severity
This change loads live_translations.json, injects window.__IMPECCABLE_TRANSLATIONS__, and defines window.__IMPECCABLE_T__, but none of the assembled live browser script parts call that helper or read those translations. Copying ru.json therefore leaves the Live Mode UI in English despite the PR’s localized UI goal.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit cc5c5c5. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc5c5c515e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| `window.__IMPECCABLE_TRANSLATIONS__ = ${JSON.stringify(translations || {})};\n` + | ||
| // Translation helper: returns translated string or falls back to key | ||
| `window.__IMPECCABLE_T__ = function(key) { return (window.__IMPECCABLE_TRANSLATIONS__ && window.__IMPECCABLE_TRANSLATIONS__[key]) || key; };\n`; |
There was a problem hiding this comment.
Route UI strings through the translation helper
With live_translations.json present, /live.js now emits the translations and helper here, but the browser UI never calls it: repo-wide search for __IMPECCABLE_T__ only finds this prelude, while skill/scripts/live-browser.js still assigns hard-coded labels/status text and command labels from LIVE_COMMANDS. As a result copying ru.json still leaves Live Mode in English. Fresh evidence after the prior review is that the helper was added, but it has zero call sites; the UI strings need to be wrapped at render time.
Useful? React with 👍 / 👎.


Summary
Changes
This PR adds internationalization support for the Impeccable Live Mode UI panel. The Russian translation covers all UI elements including:
Usage
Users can now copy skill/i18n/ru.json to their project root as live_translations.json to get a fully localized Live Mode experience.
Testing
Verified that all 54 translation keys match the strings used in live-browser.js.
Note
Low Risk
Additive, opt-in JSON loading with empty-object and key fallback; no auth or data-path changes.
Overview
Adds optional i18n for Impeccable Live Mode: projects can place
live_translations.jsonat the repo root (documented underskill/i18n/), and the live server reads it when serving/live.js.The assembled browser prelude now injects
window.__IMPECCABLE_TRANSLATIONS__andwindow.__IMPECCABLE_T__(key)(translate or fall back to the English key). Shipped catalogs includeen.jsonas the key reference andru.jsonwith a full Russian UI pass (~60 strings: picker, commands, status copy, etc.).Reviewed by Cursor Bugbot for commit 4049e09. Bugbot is set up for automated code reviews on this repo. Configure here.