Repository navigation
Milestone v1.3.0: Extension multilingual UI - #150
Open
LakshmanTurlapati wants to merge 56 commits into
Open
LakshmanTurlapati wants to merge 56 commits into
LakshmanTurlapati wants to merge 56 commits into
Conversation
The control panel is the largest package-owned surface, so its labels, hints, and status text need the same catalog override as the side panel. Co-authored-by: Cursor <cursoragent@cursor.com>
First-run pages and FSB-authored overlay controls need the same locale override, while task titles and model summaries stay on the raw payload. Co-authored-by: Cursor <cursoragent@cursor.com>
Leftover package sentences now fail CI unless they are cataloged, and the side panel and control panel can store a locale without restarting Chrome. Co-authored-by: Cursor <cursoragent@cursor.com>
Align the extension, showcase, skill, docs, and store metadata at 0.9.93 through sync-product-version, add the 0.9.93 changelog entry and the release-notes rail entry, and update the v1.3.0 planning notes to match. MCP stays at 0.11.1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Define placeholders for the 52 copy_* messages that used $NAME$-style
tokens without one. Chrome rejects such catalogs ("Variable $NAME$ used
but not defined."), which blocked the extension from loading. The catalog
gate now fails on any undefined placeholder.
- Move the locale boot on the control panel, unlock, and microphone pages
into ui/ui-locale-page.js. MV3's default CSP blocked the inline scripts,
so the language select stayed empty and static markup never translated.
- Expose _locales/*/messages.json as web-accessible so the content-script
overlay can load catalogs; content scripts load only the active locale
and English, fetching others on a language switch.
- Skip the chrome.i18n.getMessage fallback for named substitutions, which
Chrome drops ("Actions: " instead of "Actions: 5").
- Restore the denial reason in the blocked-origin consent hint.
- apply() now only re-translates static text and attributes that still show
a catalog message, and live nodes whose text it last wrote. Counters,
provider headings, and status lines set by page scripts are left alone,
and markExact clears stale live keys.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Reuse the booted fsbUiLocale instance when content scripts are injected again, so the overlay keeps its catalogs and language override. - Store site map memory text in English through siteMapMemoryText(); only the toast is localized. Drop the now-unused copy_00834dcdc3 message. - Split the microphone instruction into lead, label, and tail keys so the bold label survives apply(), and skip keyed nodes with child markup. - Prune detached overlay roots in watchChrome so they are not retained. - Keep mounted language pickers in step with changes made elsewhere. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Load the browser-language catalog in content scripts so overlay text drawn through chrome.i18n before boot() finishes is recognised and switched to the chosen language. - Wrap 59 cataloged but unkeyed control panel text runs in data-i18n spans, and key the theme toggle aria-label. - Translate cloned consent and pending-request template rows, and keep the API test button label keyed when runFullApiTest rewrites it. - Make verify-extension-copy require a data-i18n (or translate="no") hook for static HTML text, including short labels. - Apply static translations on onboarding boot and key the header tag with a new entry_onboarding_tag message in all seven locales. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolve version conflicts between this branch's extension 0.9.93 bump and main's MCP 0.11.2 release in mcp/README.md and the llms source and public files. Keep main's wording and historical release notes, and regenerate the current extension/MCP pair with `sync-product-version.mjs extension 0.9.93` so the current release lines read extension 0.9.93 with fsb-mcp-server 0.11.2. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… messages
The autopilot statusUpdate handlers compared the shown status text against
English transient labels, but addStatusMessage() now renders them through
fsbUiLocale. In non-English locales every run logged the translated
"Starting automation..." as a completed action. Add fsbUiLocale.isLine() and
use it in the side panel and popup so translated labels are still skipped.
Onboarding passed four strings through obExact() that were not in the exact
map, so they stayed English. Use the keyed ob() form, reuse entry_key_valid,
and add entry_key_required, entry_discovering_models, and entry_no_models to
all seven catalogs.
The copy gate missed these because it skipped strings inside template ${...}
expressions and sentences that open with a placeholder. Scan both, and cover
the cases with fixture and isLine regression tests.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…in JS The side panel login and payment prompts, the history list, and the action count label wrote English straight into innerHTML, so they stayed English in every locale. The payment prompt also rendered catalog strings (state labels, the no-methods detail) without looking them up. Route that copy through a new spLine() helper backed by the exact maps, add escapeAttr() for attribute values, and add copy_* keys in all seven catalogs. Count labels become whole messages with a $COUNT$ placeholder, with a singular form. The popup count label and the onboarding LM Studio "Loaded chat model" label get the same treatment. Drop promptDetail, handoffDetail, and safeSubtext from showLoginPrompt: authPrompt is always null and safeSubtext was never rendered. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The automation overlay header, the trigger watch badge, the element inspector check rows, and the crawl overlay were written as English markup, and the replay speed button carried hard-coded English labels. refreshOwnedChrome() fixed some of these after the fact, but the badge, inspector rows, and crawl title never changed language. Render them through ov() with entry_* keys, reusing the existing automating, stop, planning, initializing, replay speed, and pages messages. The watch badge counts now use $COUNT$ messages in both the template and show(). ov() also fills $NAME$ placeholders when the locale module is missing, as ob() and fsbUiLine() already do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The connection test card, session list and log viewer, replay step
detail, credential and payment cards, site explorer and research views,
memory list and detail views, and the site graph legend all built their
labels as English markup in options.js, so none of them changed language.
Add fsbUiHtml() (escaped fsbUiLine() for templates), fsbUiEscape() (also
escapes quotes, for attributes), and fsbUiMarkup() for "Step $CURRENT$ of
$TOTAL$", whose placeholders hold the step counter spans. Add panel_* keys
in all seven catalogs and panel-exact.js, and turn count fragments
("12 pages", "(3 forms)", "...and 5 more") into whole messages with
placeholders and singular forms.
The research empty state now uses the control panel's cataloged sentence,
which names the Reconnaissance section, instead of "Site Explorer".
providers-panel-ui.test.js loads the new helpers into the sandbox it runs
runFullApiTest in.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
verify-extension-copy.mjs skipped every string containing < or >, so
English written inside markup that JS builds (the login prompt, control
panel views, overlay chrome) passed the gate untranslated. It also
stripped comments with a regex that read the // in /^https?:\/\// as a
comment, which shifted string scanning for the rest of the file and hid
three plain sentences in sidepanel.js.
Replace the comment stripper and string extractor with one tokenizer that
skips comments and regex literals and recurses into ${...} expressions.
Strings that contain markup now go through the HTML rule: text and
labelled attributes must reach a locale helper or sit in a data-i18n or
translate="no" element, and a catalog match alone does not count.
Partial tags at ${...} boundaries are trimmed, </> are decoded,
trailing separators no longer make a token copy, and GitHub is a brand.
Add a bad-markup fixture that the old gate passes, a panel-exact parity
check, and a test that every literal passed to the control panel and side
panel copy helpers resolves to a catalog key on that page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Move nav label keys onto the generated .nav-label leaf so apply() translates them. - Re-copy translated native options into the custom dropdown menus after boot and on language change, via a new refresh() export. - Translate the replay play/pause toggle label and refresh the crawl overlay title. - Write early unlock and microphone page text with fill() so boot re-translates it. - Point phase contract and version parity tests at the archived v0.9.91 planning paths. - Note in the changelog that fsb-mcp-server stays at 0.11.2. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tes line pins - The replay interpolation test evaluates ReplayPlayerOverlay on its own, so it now also loads the module's ov() locale helper that _renderSpeed calls. - messages.xlf points releaseNotes.meta.title and .description at lines 88 and 89, where the 0.9.93 rail entry moved them, so ng extract-i18n has no diff.
…ts pins background.js now loads utils/ui-locale.js, so the lattice bridge smoke test expects 335 importScripts mentions and 331 call sites.
…atus copy
- Overlay translates the English phase labels and default details the service worker sends (exact matches only, active-phase ellipsis kept) and sets lang on its own container; the host page is untouched.
- Side panel: Stop tooltip and pending label, delegation consent, preflight and run-card copy as $NAME$ templates with keyed start-rejection reasons, status lines and error bubbles through the exact maps; popup and options status and toast copy cataloged.
- ui-locale: exact-map lookups use own keys only (fixes the line('constructor') crash) and <html lang> follows the UI language on extension pages; the service worker no longer loads the module.
- 84 new keys in all seven catalogs; ja/ko/de entries keep Grok Build and LM Studio, and the i18n gate now protects provider names.
- Tests cover overlay label drift, template fills in every locale, the Stop tooltip, status lines and lang sync; drop the unused microphone errorMessage helper.
The release-notes page opened on "notes pending" for the current release. Add the 0.9.93 hero and five illustrated sections (language picker, live switch, localized manifest name, what stays as written, catalog gates), translate the 63 new units into es, de, ja, ko, zh-CN and zh-TW, allowlist the 27 invariant samples and identifiers, and point the llms summary at it.
Replace the placeholder "Version bump" entry with what 0.9.93 ships, dated 2026-10-18, keeping the version-alignment sentence the parity test pins. Note in the MCP changelog that 0.11.2 pairs with extension 0.9.93, and match the store listing summary to the manifest description.
The overlay, status and delegation strings added 84 keys to each catalog, so the release notes and changelog now say 1,230 instead of 1,146.
Current Cline (VS Code extension, JetBrains plugin, and CLI) reads one shared settings file, ~/.cline/data/settings/cline_mcp_settings.json, and imports its old VS Code extension-storage file only once. The installer kept writing that old file, so install --cline reported success while FSB never appeared. It now targets the shared file, honoring Cline's CLINE_MCP_SETTINGS_PATH, CLINE_DATA_DIR, and CLINE_DIR overrides, and uses the old file only when no shared settings directory exists. Cline entries set timeout: 1800 so run_task outlives Cline's fixed 60-second request timeout, and reinstalls keep the timeout, disabled, and autoApprove settings Cline stores on the entry. Cline also joins the first-class client surfaces: the onboarding and showcase install pickers with its logo, the client alias table and owner-chip label (VS Code reports "Cline", the CLI "@cline/core"), the telemetry label on both the collector and the server allowlist, and a conservative pricing fallback. Adding it to the home install picker shifts $localize line numbers, so the seven xlf catalogs were re-extracted and synced; only line numbers changed. Versions move to extension 0.9.95 and fsb-mcp-server 0.11.5 through version:set:mcp and version:set:extension, with matching changelog entries, and the Grok Bot plugin now pins fsb-mcp-server@0.11.5. Merging publishes fsb-mcp-server@0.11.5 to npm automatically.
…p the picker in Advanced settings - With nothing saved, FSB takes the first supported entry in Chrome's preferred-languages list (English counts), region subtags pick the variant, and the time zone only settles a bare zh; no match falls back to the UI language - The language picker moves out of the side panel and the control panel header into a Language card under Advanced settings > Appearance; "Automatic" clears the saved choice - The themed dropdown rebuilds a select's menu when its options arrive after page start, so the picker renders as a custom dropdown - Settings card titles take the rest of the header row so long descriptions wrap beside the icon - Side panel HTML/CSS pins updated; sidepanel.css is back to main
- Legend, axis titles and the tooltip token count go through the locale helper; the service worker, which loads analytics.js without it, keeps English - New panel keys for "Input Tokens", "Output Tokens" and "$COUNT$ tokens" in all seven catalogs (Spanish keeps "tokens", allowlisted) - updateChartLocale() re-labels the chart in place on a language change, and weekday ticks use the UI language
FSB now picks its interface language from Chrome's language list and keeps the picker only in the control panel under Advanced Settings, so the release notes and changelog say so. The hero, the default-language bullet (now two bullets), the picker location, and the Automatic option are reworded and retranslated in all six site languages. The section 01 side-panel mock loses its language dropdown and the seven autonym units behind it, along with their allowlist entries; the header shows the panel's icon buttons instead and the status word still cycles.
The Automatic hint and the token-chart strings added four keys to each catalog, so the release notes and changelog now say 1,234.
Versions follow #155: extension 0.9.95 and fsb-mcp-server 0.11.5. The manifest keeps its localized name and description tokens, and CHANGELOG.md carries one 0.9.95 entry for both the multilingual interface and Cline.
…port The multilingual interface and official Cline support ship together as 0.9.95, so the section written as 0.9.93 would have left the current release on "notes pending". The rail entry, documented versions, both template guards, and every unit id move to 0.9.95; the hero chips, the fsb-mcp-server line, and the footer now cite extension 0.9.95 with MCP 0.11.5. The hero now names both changes, and a new section 06 covers Cline: the shared settings file install --cline writes, the 1,800-second timeout, the settings a reinstall keeps, Cline labeling, and the rerun command for existing users. All seven locales are translated and the invariant literals are allowlisted.
…abels
Client labels:
- The extension allowlist renames FSB Autopilot to Autopilot, drops
Windsurf, and adds Muse, Grok Bot, and Dots. The MCP server list gets
the same three and drops Windsurf; Autopilot stays off it so an outside
client cannot claim the extension's own label.
- Telemetry counts the new labels by name. The telemetry server keeps
accepting Windsurf, since extensions older than 0.9.95 still send it and
one unknown label rejects the whole batch.
- The Grok Bot plugin sends client "Grok Bot".
Antigravity:
- install --antigravity replaces install --windsurf. It writes
~/.gemini/config/mcp_config.json and falls back to the older
~/.gemini/antigravity/mcp_config.json only when ~/.gemini/config does
not exist. An empty config file now parses as {} because Antigravity
creates its file empty.
- Onboarding, client aliases, the register-time chip label, the showcase
home, agents, and support pages, llms.txt, READMEs, skill references,
and the icon-support doc say Antigravity, with a single-color
Antigravity mark in place of the Windsurf logo. The four showcase units
that named Windsurf keep their ids and line numbers.
- Windsurf's default-model cost row is removed from both pricing copies.
Templated lines were filled with line() before markExact() saw them, so they lost their catalog key and stayed in the old language after a switch. - markExact(node, template, subs) keeps the template's key and stores the subs; fill() and apply() translate a sub that is catalog copy itself (a provider fallback, a start-failure reason) along with its template. - Delegation consent, preflight failure, and run-header copy hand templates and subs to markExact() instead of filled lines. - The side panel status line and automation runner pass the template and subs through, so "Step N complete" follows a switch. - The overlay records the English behind its pill, detail, and log lines and redraws them on a language change unless they were replaced since. - The Grok Build compatibility line is translated on success.
- line() translates a substitution that is catalog copy itself ("this
site", "Unknown error"); domains and provider names stay as sent. The
side panel map also resolves "Unknown error" and "Card".
- The stopped-run heading is a template with a singular form, so it keeps
its key and re-renders on a switch.
- A delegated start that fails without a detail or a consent challenge
shows a template instead of a concatenated sentence.
- The No API Key detail is passed unfilled, so it follows a switch with
its title.
- Every Grok Build test result keeps a live key that wins over the idle
hint, and the no-message fallback is cataloged.
- The overlay redraws its action counter on a language change.
- An explorer exception uses the "failed to start" template.
- The payment confirmation translates "on $DOMAIN$", "on this page", and
the Card fallback; brand names and the domain stay as sent.
Six keys were added to each catalog (now 1,240), and the release notes,
changelog, and site catalogs say so.
Seven widgets kept the previous language until their next update because they were written as filled strings with no record of their key. - Side panel: the "N actions completed" count goes through markExact() with its template, and a language change re-runs the delegated Stop sync so its accessible name and "Stopping Automation…" label follow. - Control panel: the crawl card's progress line, page count and Stop label carry live keys. A crawl failure with no domain says the cataloged "Unknown"; the popup's model fallback had the same bug. - Overlay: writeKeyed() records the key, template and subs behind a text or attribute, and refreshOwnedChrome() redraws it unless it was replaced since. It covers the trigger badge (now a watched root), the crawl overlay domain and page lines, the replay speed name and tooltip, and the action counter it replaces. No catalog keys were added.
The playback test rebuilds ReplayPlayerOverlay from ov() and the class body. The speed labels now go through writeKeyed(), so the harness includes it and its WeakMap too.
…background agents The server registered 72 tools while the READMEs said 69 and the website, llms files and onboarding said 68. start_visual_session and end_visual_session have only returned TOOL_REMOVED since 0.9.0, and back duplicated go_back, so all three are gone and the server lists exactly 69. mcp-version-parity now counts the built server's tools and fails when any published claim disagrees: both READMEs and their per-category tables, onboarding, the showcase pages and every translation, and the llms files. Background agents were retired in v0.9.45rc1 but their data and code stayed. On extension update, background.js now deletes bgAgents, fsb_sync_queue, the old notice flag and any fsb_agent_* alarms. The control-panel list of old agent names, extension/agents/, about 4,700 lines of commented-out agent code across the extension and both dashboards, and the unused executeAutomationTask are removed. The server drops /api/agents and the agent-only /api/stats; server-py drops its agents, stats and SSE routers. The agents and agent_runs tables stay.
- The collapsed "N actions completed" count is written through markExact() with its template, so apply() redraws it on a switch. - The owner header and the locked composer tooltip carry the owning agent's name, which stays as sent, so they are not keyed. The popup now registers _refreshOwnerCopy() with fsbUiLocale.onChange to rebuild both from the stored name; _ownerLockTitle() builds the tooltip. - owner-chip.test.js extracts the new helper and asserts the tooltip, because refreshOwnerChip() swallows its own errors.
The count check only read "N tools", "N MCP tools", "N registered (MCP) tools" and "N-tool" in raw text, and a file with no matches passed. Five live strings still said 68: the onboarding "68 available" row, "68 MCP tools" on the home and agents pages (with MCP wrapped in a span), "68 MCP browser tools" in the agents schema, and "68 granular tools" in the support FAQ, plus their translations in every catalog. The check now strips markup before matching, also reads "granular", "MCP browser" and "Tools ... N available" claims, and fails when a source that should state the count no longer contains one it can read. Before the strings were fixed it failed on exactly those five sources and four catalog units; now all of them say 69.
…uncements A completed or restart-lost run, and the side panel's polite live region, stayed in English after a language change. Co-authored-by: Cursor <cursoragent@cursor.com>
Popup owner labels stay as sent, including catalog words and dollar sequences, while error reasons that are catalog copy still follow the language. Co-authored-by: Cursor <cursoragent@cursor.com>
A reinstall was rewriting Continue and Cline configs when only property order differed, because equality compared serialized JSON. Co-authored-by: Cursor <cursoragent@cursor.com>
…d2web/ Moves the benchmark from bench/online-mind2web to a top-level mind2web/ folder: the Claude Code + FSB MCP harness, the WebJudge-based judge, the calibration scripts, configs, schema, reports, and the three published result folders (final-review, benchmark-publication, final-reviewed). Raw trajectories and caches stay gitignored. Paths that depended on the old folder depth are adjusted, the previous "assisted" naming is replaced with "reviewed", and the sha256 seals, audit, and result files are re-keyed to the new paths with hashes recomputed only for the files this move edited.
On a fresh clone the gated Online-Mind2Web dataset cache, the pinned Claude CLI and the local postmortem sample are not present, so the tests that read them now skip with a stated reason, matching the existing dataset skips. The two tests that exercise the real MCP error mapper skip until mcp/src/errors.ts passes native outcome fields through, and run automatically once it does.
… into the multilingual UI branch start_visual_session, end_visual_session and back leave the server in fsb-mcp-server 0.11.5, which stays a patch release; both changelogs fold #161's notes into the 0.11.5 and 0.9.95 entries. The conflicts were where this branch had translated text or code that #161 edits or deletes: - The popup and side panel keep their locale boot block, which shared a hunk with the deleted agent comments. - Onboarding keeps its catalog lookups, and its four tool-count messages read 69 in all seven catalogs. - The support FAQ, its seven xlf units and the llms sources keep this branch's wording with 69 tools. - The six catalog keys used only by the removed sunset notice and agent comments are gone from every catalog and key map.
…ultilingual UI branch Adds mind2web/ unchanged: the Claude Code + FSB MCP harness, the WebJudge judge and calibration scripts, configs, and the published result folders. Nothing outside mind2web/ changes. config/fsb-tool-names.json still lists the 72 tools the benchmark ran against, including the three #161 removes, because it records the surface the published runs used. The harness tests give the same result as on #162 alone: 357 pass, 0 fail, 24 skipped.
This was referenced Oct 22, 2026
The side panel filled or stored some of its own copy as finished strings,
so a language change or a tab-switch replay could not translate it again:
- Progress history saved "Step N complete" in English while the live
status used the catalog template.
- Catalog notices such as "No active automation to stop." were translated
in the bubble but saved in English, and replay showed the saved text.
- The delegated failure bubble received a filled sentence with an already
translated reason, so it kept the language it was drawn in.
Assistant rows now save their catalog source next to the readable text
(uiMessage: { english, subs }), and replay re-keys it; model output, user
text and tool rows stay raw. A substitution can be a nested source, so
"Error: $ERROR$" and its reason translate together. Legacy
"Step N complete" rows replay translated too.
The recon, replay and session messages that pre-translated their text now
pass the template instead. The background-communication, generic and stop
errors were keyed only through text(), so they are added to the exact map
to keep translating after that change. No catalog keys are added.
… branch #163 replaced the home page feature cards with the benchmark leaderboard, so the cards this branch had edited are gone with them. The home schema keeps #163's benchmark feature and this branch's Antigravity wording, the llms sources keep the benchmark sentence with 69 tools and 0.9.95/0.11.5, and the test chain runs both branches' new suites. messages.xlf is a fresh extraction of the merged templates. Each locale takes every unit's translation from the side whose English source matches (2,475 from this branch, 16 from #163), so sync-xliff-targets preserves all 2,491 units with nothing seeded, changed, or left for review.
Russian becomes the eighth extension UI language. extension/_locales/ru
carries all 1,241 keys; only the brand keys (ext_name, locale_seed_brand)
stay "FSB". The picker lists it as Русский after Deutsch, and the
automatic language resolves ru, ru-RU and ru_RU to it through the
existing primary-subtag rule.
- ui-locale.js: ru in PUBLIC_LOCALES, the folder map and the native
labels.
- verify-extension-i18n.mjs: ru in DEFAULT_LOCALES. The gate reads that
list, not the folders on disk, so without it the catalog would ship
unchecked.
- Ukrainian, Belarusian and Kazakh are not mapped to Russian; a test
pins that alongside the ru-RU case.
- Russian has one/few/many plurals while the code picks between two
English templates, so count messages use the counter form
("Действий выполнено: $COUNT$") that reads correctly for any number.
The catalog was translated in batches against a shared glossary, each
batch reviewed independently, then checked for cross-batch consistency
and by a blind back-translation of the most visible strings.
Russian becomes the eighth showcase locale. messages.ru.xlf translates 2,120 units; the other 372 copy their source by rule (315 allLocales entries, 56 units with no readable text, and the new Готово label). sync-xliff-targets is a byte-for-byte no-op on every catalog. - Registries (Angular and Express), angular.json, the localized 404 and the scripts that keep their own lists (sync, hreflang, bundle budgets) gain ru. Accept-Language ru-* and a saved fsb-locale=ru open /ru/. - The sitemap and llms files carry the Russian variant of every marketing route; lastmod and generated dates are unchanged. - v0.9.95 is unreleased, so its release notes and changelog now say eight languages and 1,241 keys (also correcting the stale 1,240) in every site language. The Ready cycle gains Готово, and its keyframes stretch to eight 2-second slots (rnLoc8, 16s). - The translation-quality gate also rejects Russian translator notes such as «(англ.)». - Tests: ru cases for Accept-Language and the legacy redirects (which were also missing ko), the build smoke and parity locale lists, and the hreflang spec now counts LOCALES.length + 1.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Milestone v1.3.0: Extension multilingual UI (Phases 66-71)
Goal: Every package-owned user-facing string in the Chrome extension can render in
en,es,de,ru,ja,ko,zh-CN, andzh-TW.Status: All six phase verifications passed. Two later review rounds found no blockers and their fixes are in. The language follows Chrome's language list, with the picker only in the control panel's Advanced settings. #155 (official Cline support) is merged into this branch, so the branch ships extension 0.9.95 and fsb-mcp-server 0.11.5, with 0.9.95 release notes covering both changes. Antigravity replaces Windsurf as an install target, and Muse, Grok Bot, and Dots are allowed client labels. #161 (dead MCP tools and background-agent leftovers) and #162 (Online-Mind2Web harness) are merged too, so 0.11.5 also stops registering three tools that did nothing useful, leaving 69. Russian is added to the extension interface and the showcase (Round 9). CI is green and the extension loads and switches language in Chrome. Not merged.
The extension resolves its UI locale at runtime through
extension/utils/ui-locale.jsand ships eight_localescatalogs with 1,241 keys each. The side panel, popup, options and control panel, onboarding, unlock, microphone permission, and FSB-authored overlay chrome read from those catalogs and fall back to English rather than a blank label. By default the language follows Chrome's language list (Settings › Languages). A Language card in the control panel's Advanced settings saves anfsbUiLocaleoverride that applies without restarting Chrome; choosing Automatic clears it. User text, model output, page content, secrets, logs, and the MCP wire are unchanged. With #155 merged in, the branch moves the product version to 0.9.95 and fsb-mcp-server to 0.11.5.Changes
Plan 66-01: Locale resolver, seed catalogs, and CI gate
The resolver maps public codes to Chrome folders (
zh-CNtozh_CN), applies the showcase alias rules, prefers a saved override over the browser language, and never reads the website cookie.scripts/verify-extension-i18n.mjsfails on a missing key, an empty message, a placeholder mismatch between locales, copied English that is not on the hash-bound allowlist, or a dropped protected literal such asFSB.Key files:
extension/utils/ui-locale.js,extension/_locales/*/messages.json,extension/_locales/same-source-allowlist.json,scripts/verify-extension-i18n.mjs,tests/extension-ui-locale.test.js,tests/fixtures/extension-i18n/Plan 67-01: Manifest, side panel, and popup
The manifest uses
__MSG_ext_name__and__MSG_ext_description__withdefault_locale: en. Side-panel and popup resting chrome usesdata-i18n, and exact runtime status text refreshes after the catalogs load.Key files:
extension/manifest.json,extension/ui/sidepanel.html,extension/ui/sidepanel.js,extension/ui/popup.html,extension/ui/popup.js,extension/ui/owner-chip.jsPlan 68-01: Options and control panel
All 336 control-panel keys resolve in every locale. Exact options status strings go through
fsbUiSet, so vault, payment, pairing, and log messages refresh after boot. Provider names stay in English.Key files:
extension/ui/control_panel.html,extension/ui/options.js,extension/utils/panel-exact.jsPlan 69-01: Onboarding, entry pages, and overlay chrome
Onboarding, unlock, and microphone-permission copy come from the catalogs. Overlay controls such as Stop, Done, and the replay-speed caption are localized, while the task title and model summary stay raw. The locale module loads before
visual-feedback.jsin both content-script injection lists.Key files:
extension/ui/onboarding.js,extension/ui/unlock.*,extension/ui/microphone-permission.*,extension/content/visual-feedback.js,extension/background.js,extension/ws/ws-client.jsPlan 70-01: Coverage audit
scripts/verify-extension-copy.mjsfails when an in-scope UI file keeps a package-owned English sentence outside the catalog. Logs, provider names, and other producer-owned text are exempt. Leftover chrome was cataloged in all seven locales (Russian, added in Round 9, carries it too).Key files:
scripts/verify-extension-copy.mjs,extension/utils/copy-exact.js,tests/fixtures/extension-i18n/bad-sentence/ui.jsPlan 71-01: Language control
The control panel gets a Language card under Advanced settings › Appearance, listing Automatic, English, Español, Deutsch, 日本語, 한국어, 简体中文, and 繁體中文 (round 3 moved it there from the side panel and control panel headers). Open extension pages and registered overlay shadow roots re-render on
chrome.storage.onChanged.Key files:
extension/utils/ui-locale.js,extension/ui/sidepanel.*,extension/ui/control_panel.html,extension/ui/options.*Also in this branch
fsb-mcp-servermoves to 0.11.5 with Add official Cline support; ship extension 0.9.95 and MCP 0.11.5 #155's Cline installer fix./release-notesopens on 0.9.95 notes covering both changes, in all eight site languages.npm testnow starts with the three i18n checks, which also run alone asnpm run test:extension-i18n.scripts/sync-product-version.mjskeeps the__MSG_tokens in the manifest. The name onchrome://extensionsbecomesFSBinstead ofFSB v<version>, and the description becomes "FSB is a universal AI-powered browser automation assistant.".planning/milestones/v0.9.91-*, and the v1.3.0 roadmap, requirements, research, and phase records are added.Requirements Addressed
All 20 v1 requirements in
.planning/REQUIREMENTS.mdare mapped to these phases.Verification
tests/extension-ui-locale.test.js(261 passed),scripts/verify-extension-i18n.mjs(all seven locales),scripts/verify-extension-copy.mjs(13 files), plus the version-sync, delegation side panel, MCP session settings, onboarding provider clicks, remote-control rebrand, side-panel tab-aware smoke, and owner-chip tests.npm run version:checkreports extension 0.9.95 and MCP 0.11.5.extension/ai/tool-definitions.jshave no diff against the merge base, so MCP tool schemas and bridge message types are byte-stable. Undermcp/, only the README changes: the version sync rewrites its compatibility lines to the current extension version.extension/: the service worker registered as "FSB 0.9.93", onboarding and the offscreen document opened, and no CSP or catalog errors were logged. The side panel, control panel, popup, onboarding, unlock, and microphone-permission pages rendered in English, then in Japanese afterfsbUiLocalewas set toja. The side panel re-rendered live without a reload. The language select lists 8 options. A web page fetched_locales/ja/messages.json(1,146 keys), so content scripts can load the catalogs. The in-page overlay was not opened.tests/trigger-cap-settings-ui.test.jsfails the same 2 checks here and on main. It is not part ofnpm test.CI: both previously failing jobs are fixed in
66409c33and87f59af7.tests/lattice-replay-playback.test.jsevaluatesReplayPlayerOverlayon its own, so it now also loads the module'sov()helper that_renderSpeedcalls. That failure had stopped thenpm testchain early. With it fixed,tests/lattice-provider-bridge-smoke.test.jsalso failed, becausebackground.jsnow loadsutils/ui-locale.js. Its pins now expect 335importScriptsmentions and 331 call sites. Locally, every segment ofnpm testpasses, andnpm run validate:extensionpasses.messages.xlfnow pointsreleaseNotes.meta.titleandreleaseNotes.meta.descriptionat lines 88 and 89, song extract-i18nhas no diff. The build, hreflang, video SEO, marketing i18n SEO, and bundle-budget steps also pass locally.Review findings (fixed)
A code review of this branch raised six findings. All six are fixed on the branch and were re-checked against the code:
$NAME$-style placeholder now has aplaceholdersentry. A check against Chrome's catalog rules finds no undefined placeholders in any of the seven locales, and the extension loads in Chrome.control_panel.html,unlock.html, andmicrophone-permission.htmlnow start the locale module fromui/ui-locale-page.js._locales/*/messages.jsonis inweb_accessible_resources.chrome.i18n.getMessage.t()sends named substitutions down the English path instead.fsbUiLine()and appendsclassified.reason.data-i18noverwrote JS-owned text.apply()re-translates a node only while it still shows a catalog message, and live nodes written byfill()are tracked separately.Second review (fixed)
A later review found no blockers but some FSB-owned text still showing in English in a non-English UI, plus stale release text. Fixed in
63b5b262,536d1aaa,3121d8f6, andb7c46e1e:lang; the host page is untouched._restoreLegacyStopControlno longer writes English over the translated tooltip, and the pending "Stopping Automation…" label is translated.$NAME$templates, so the provider name stays raw and the sentence is translated.langattribute. Extension pages set<html lang>from the active UI language on boot and on change.line('constructor')threw); the service worker no longer loads the unused locale module (pins back to 334/330); an unused microphone helper and two stale comments are gone.CHANGELOG.mddescribes what 0.9.93 ships;mcp/CHANGELOG.mdnoted the 0.11.2 pairing (dropped after the Add official Cline support; ship extension 0.9.95 and MCP 0.11.5 #155 merge, since 0.11.5 pairs with 0.9.95); the store listing summary matches the manifest description; the llms summary counts sixteen versions.84 keys were added to each catalog (now 1,230). Checks on the combined branch: both i18n gates,
extension-ui-locale(216/216), the targeted delegation, overlay, side panel, and smoke tests, the fullnpm testchain, all 14 showcase CI gates, andsync-xliff-targetsas a byte-identical no-op. A headless Chrome for Testing run with network blocked confirmed<html lang>switches on all six pages, the stop tooltip stays translated, the Grok Build preflight heading renders in Japanese, Chrome accepts the three-placeholder message, and the overlay shows 操作中… / ブラウザ操作を実行中 while "Clicked the Submit button" stays English.Round 3: automatic language, picker in Advanced settings
Fixed in
9303c1dc4,a28ba73a3,3b8e9415b, and92d9cb252:chrome.i18n.getAcceptLanguages()(falling back tonavigator.languages) and uses the first language it supports. English counts, so English-first users stay in English. Regional variants map to the nearest catalog (es-MX→ Spanish,zh-TW/zh-HK/zh-MO→ Traditional,zh-CN/zh-SG→ Simplified); a barezhtakes a regionalzh-*later in the list, else the time zone (Taipei, Hong Kong, Macau → Traditional). If nothing in the list is supported, Chrome's UI language decides, then English.sidepanel.cssis byte-identical tomainagain.Verified: both i18n gates,
extension-ui-locale(261/261 on Node 24 and 20),delegation-sidepanel-ui,settings-card-select-clipping,validate:extension, the fullnpm testchain, and all 14 showcase gates. In headless Chrome for Testing: azh-TW,enlanguage list with an English UI renders 繁體中文 with no saved choice;en-US,jastays English; picking 日本語 in the Advanced settings dropdown re-renders the control panel and an open side panel without a reload and keeps an unsaved edit; Automatic clears the override; the chart reads 入力トークン/出力トークン.Merged #155 (official Cline support)
118ca8ff2merges #155 into this branch, andf662c7d49updates the release notes. Versions follow #155: extension 0.9.95 and fsb-mcp-server 0.11.5.default_localeand the__MSG_ext_name__/__MSG_ext_description__tokens at version 0.9.95, andnpm run version:checkreports extension 0.9.95 and MCP 0.11.5.CHANGELOG.mdhas one 0.9.95 entry for the multilingual interface and Cline support.mcp/CHANGELOG.mdkeeps Add official Cline support; ship extension 0.9.95 and MCP 0.11.5 #155's 0.11.5 entry and drops this branch's note that 0.11.2 paired with 0.9.93.v0993tov0995. The hero now covers both changes, the version chips read 0.9.95 and 0.11.5, and a new section 06 covers Cline: the shared settings file, the 1,800-second timeout, the settings kept on reinstall, and theinstall --clinererun for existing users. It is translated into all seven site languages.ng extract-i18nmatches them.validate:extensionand the fullnpm testchain pass. All 14 showcase gates pass, with 2,498 units × 6 locales and no extraction diff.mcp-version-paritypasses 202/202 andversion-syncpasses. No locale's prerendered/release-notesshows "notes pending".Client labels and Antigravity
35cd5179achanges the MCP client labels and replaces Windsurf with Antigravity. Versions stay at extension 0.9.95 and fsb-mcp-server 0.11.5, which is not on npm yet, so both ship together.FSB AutopilottoAutopilot(the overlay badge reads "Autopilot"), dropsWindsurf, and addsMuse,Grok Bot, andDots. The MCP server list gets the same three and dropsWindsurf; it still leaves Autopilot out so an outside client cannot claim it. Telemetry counts the new labels by name. The telemetry server keeps acceptingWindsurf, because extensions older than 0.9.95 still send it and one unknown label rejects the whole batch.plugins/grok-botnow tells Bot to sendclient: "Grok Bot". Until the Web Store extension updates to 0.9.95, the extension there still rejects that label.install --antigravityreplacesinstall --windsurf. It writes~/.gemini/config/mcp_config.json, the global file in Antigravity's MCP docs, and falls back to~/.gemini/antigravity/mcp_config.json, which older releases read, only when~/.gemini/configdoes not exist. Antigravity creates that file empty, so the config writer now reads an empty file as{}instead of failing to parse it. The platform count stays 21, andsetupprints an Antigravity section.llms.txt, both READMEs, the skill references, anddocs/mcp-custom-icons.mdsay Antigravity. A single-color Antigravity mark replaces the Windsurf logo in both asset folders. The four showcase units that named Windsurf keep their ids and line numbers in all seven catalogs. Windsurf's default-model cost row is gone.--windsurf), visual-session contract, philosophy parity, telemetry allowlist, pricing, onboarding, merged clients view, and tab follow. All 15 showcase gates pass, with no extraction diff, andsync-xliff-targetsis a no-op.version:check,mcp-version-parity(202/202), andversion-syncpass. In headless Chrome for Testing, onboarding shows Antigravity with its logo and--antigravityin the client fan, and the built showcase renders the Antigravity chip on the home and agents pages in English and Japanese.Round 5: copy that follows a language change
40ad76a10keeps templated copy live, and0d42f5af0fixes the 8 places a review found still English or stuck in the old language.markExact()the English template and its subs instead of a filled line, so the node keeps its catalog key and re-renders on a switch. The overlay remembers the English behind its pill, detail, log lines, and action counter and redraws them unless something replaced them since.line()now translates a sub value that is itself catalog English ("this site", "Unknown error", "Selected provider", a start-failure reason). Domains, provider names, and other raw values stay as sent. The side panel map also resolvesUnknown errorandCard, which only the control panel map had.Cardfallback, while brand names and the domain stay as sent.extension-ui-locale(284/284) pass, as dodelegation-sidepanel-ui,providers-panel-ui, and the overlay and side panel suites.sync-xliff-targetsis a no-op.Round 6: counters and labels a language change missed
f9be8f267fixes 7 more places that kept the previous language until their next update. Each was written as a filled string, so nothing recorded the key it came from. No catalog keys were added; the count stays at 1,240.markExact()with its template.apply()only knew the idle tooltip.writeKeyed()helper records the key, template and subs behind a text or attribute, andrefreshOwnedChrome()redraws it unless something replaced it since. It covers:extension-ui-locale: 301/301. Its drift guard now also checks thewriteKeyed()fallbacks againsten/messages.json.validate:extension, and all 16pretestand 305testsegments pass.9e3568baddswriteKeyed()to the replay-player harness inlattice-replay-playback, which rebuilds the class from its helpers.Round 7: the popup follows a language change too
00c4949d8closes the two popup gaps that round 6 fixed in the side panel. No catalog keys were added.markExact()with its template, so it keeps its key andapply()redraws it on a switch.fill()would translate a name that is also catalog copy, such as "Autopilot"._refreshOwnerCopy(). It rebuilds "Owned by …" and the locked composer tooltip from the stored owner name, and one helper,_ownerLockTitle(), builds the tooltip.extension-ui-localepasses 309/309 andowner-chippasses 90/90.owner-chipnow asserts the tooltip, becauserefreshOwnerChip()swallows its own errors.validate:extension, and all 16pretestand 305testsegments pass.Merged #161 and #162
3d170bfbdmerges #161 (dead MCP tools and background-agent leftovers) andd9a927b0emerges #162 (Online-Mind2Web harness). Versions stay at extension 0.9.95 and fsb-mcp-server 0.11.5, so #161's tool removals ship in 0.11.5 as a patch.start_visual_session,end_visual_sessionandbackare no longer registered, so the server lists 69 tools.tests/mcp-version-parity.test.jschecks every published count against the built server. The background-agent leftovers are gone:extension/agents/, the commented-out agent code, the control panel's list of old agent names, and the agent sync routes inshowcase/serverandserver-py. On update, the extension deletesbgAgents,fsb_sync_queue, the notice flag, and anyfsb_agent_*alarms.fsbUiLocale.boot()block, which is kept. Remove dead MCP tools, pin the tool count to 69, and finish retiring background agents #161's leftover "/agent Slash Command Handler" banner above it is dropped.ob()lookups, with 69 in the four count fallbacks.support.schema.faq.mcp.ainmessages.xlfand its six translations, and both llms sources, keep this branch's wording (Antigravity, 0.9.95/0.11.5) with 69 tools.llms*.txtare regenerated.TOOL_REMOVEDwording.CHANGELOG.mdfolds Remove dead MCP tools, pin the tool count to 69, and finish retiring background agents #161 into the 0.9.95 entry, in a new Removed section.mcp/CHANGELOG.mdfolds it into 0.11.5, whose compatibility note no longer says tool schemas are unchanged. The 0.11.5 notes inmcp/README.mdmention the removal.entry_feat_tools,entry_agent_desc,entry_mcp_2b,entry_sum_68) say 69 in all seven catalogs. Remove dead MCP tools, pin the tool count to 69, and finish retiring background agents #161's parity check doesn't read_locales, so every language would otherwise have kept showing 68.panel-exact.js/copy-exact.js. Each catalog now has 1,241 keys.mind2web/unchanged: 186 files, nothing outside it.config/fsb-tool-names.jsonstill lists 72 tools because it records the surface the published runs used.version:checkreports 0.9.95 and 0.11.5. After rebuildingmcp/build,mcp-version-paritypasses 359/359,mcp-tool-smoke149/149 andmcp-lifecycle-smoke13/13; the drift smoke also passes.extension-ui-localepasses 848/848; both i18n gates andvalidate:extensionpass.pretestand 305testsegments pass.test:ci93, hreflang 848, marketing SEO on 28 pages, and bundle budgets. Every locale's prerendered/supportsays 69.Round 8: saved lines follow a language change
11a3c3ae0fixes three side-panel lines that kept the language they were saved or drawn in, along with the messages built the same way. No catalog keys were added; the count stays at 1,241.uiMessage: { english, subs }source, and replay re-keys it. User text, model output and tool rows stay raw.Error: $ERROR$, so a language change could not rebuild it. A substitution can now be a nested source, so the template and the reason translate together without mixing languages.text(), so they are added to the exact map; without that they would have regressed to English.extension-ui-localepasses 1,751/1,751. Its new keyed-error check fails 24/24 without the exact-map entries.validate:extensionpass.sidepanel-message-log-smoke(61),sidepanel-progress-tick-setter-routing(14),owner-chip(90),sidepanel-background-tab-completion(54) anddelegation-sidepanel-tab-follow(62) pass.pretestand 305testsegments pass.Merged main (#163)
40d045384brings in #163 (the Online-Mind2Web benchmark on the home page and README), which had made this PR conflict withmain.llms*.txtare regenerated.npm testand the phase contract run both branches' new suites.messages.xlfis a fresh extraction of the merged templates. Each locale takes every unit's translation from the side whose English source matches: 2,475 units from this branch and 16 from Lead the showcase and README with the Online-Mind2Web benchmark #163.sync-xliff-targetspreserves all 2,491 units, with nothing seeded, changed or left for review.version:check,mcp-version-parity(346/346),benchmark-assets-parity(55/55) and the phase contract (1,212/1,212) pass.pretestand 306testsegments pass.test:ci98, hreflang 848, marketing SEO on 28 pages, and bundle budgets.Round 9: Russian
dad5f26d5adds Russian to the extension interface andf853713afadds it to the showcase at/ru/. Both pickers list it as Русский after Deutsch.extension/_locales/rucarries all 1,241 keys; only the brand keys (ext_name,locale_seed_brand) stay "FSB".ui-locale.jsaddsruto the public list, folder map and labels, andru,ru-RUandru_RUresolve to it automatically.verify-extension-i18n.mjsgainsruin its own locale list; without that, the gate would not have read the new catalog.messages.ru.xlftranslates 2,120 units, and the other 372 copy their source by rule (315allLocalesentries, 56 with no readable text, and the new Готово label). The Angular and Express registries,angular.json, the localized 404, the sitemap and llms files, and the scripts that keep their own lists (sync, hreflang, bundle budgets) all gainru.Accept-Language: ru-*and a savedfsb-locale=ruopen/ru/.count === 1). Count messages use the counter form («Действий выполнено:rnLoc8, 16s).extension-ui-locale1,952/0; both i18n gates across 8 locales;validate:extension.sync-xliff-targetsis a byte-for-byte no-op.pretestand 306testsegments pass.Release
Merging lands extension 0.9.95 on
main(from 0.9.92) and fsb-mcp-server 0.11.5. 0.11.5 is not on npm yet, sonpm-publish.ymlpublishes it and creates themcp-v0.11.5release on that push. 0.11.5 also removesstart_visual_session,end_visual_sessionandback(from #161); a client that still calls one gets its MCP host's unknown-tool error, andgo_backreplacesback. The showcase deploys automatically. The extension itself is only released when anextension-v0.9.95tag is pushed. If #149 merges later, its 1.0.0 is the larger version and stands; keep this PR's__MSG_manifest tokens anddefault_localewhen resolving that merge.Follow-ups
releaseNotes.v0995.047). That describes the language work, but 0.11.5 now also removes three tools; rewording it touches all eight site languages.start_visual_session.automationError'sError: …line, a few overlay reconnect strings, anddelegation-feed.js,providers-panel.js,voice-input-settings.js,speech-to-text.js.ov()output placed in overlayinnerHTML.Key Decisions
fsbUiLocaleinchrome.storage.local. The websitefsb-localecookie is not read.__MSG_strings follow the browser UI language, so the name onchrome://extensionsdoes not follow the in-extension choice.