Full-page browser translation that handles the dynamically-loaded pages Google Translate and built-in translators leave untouched. 10+ providers, plus an optional on-device model (WebAssembly) so the text never leaves your browser. Chrome & Firefox.
8
stars
872
commits
TypeScript
primary language
Sep 11, 2026
updated
Browser extension that translates web pages, PDFs, and selected text, including content that keeps loading and updating after the page first renders. Works where built-in browser translation falls short.
Built-in browser translation (Chrome, Safari, Firefox) works well for many pages. But if you've run into any of these, TRANSLATE! is for you:
The page keeps changing and translation falls behind. Single-page apps, live feeds, chat threads, infinite scroll -- content that loads and updates after the page first renders. Google Translate and built-in translators usually translate once and miss whatever arrives later. TRANSLATE! watches the page and translates new content as it appears.
The translate bar never shows up. Browsers decide whether to offer translation based on the page's language tag. If the tag is missing, wrong, or matches your browser language, the translate bar silently doesn't appear -- even when the page is clearly in another language. TRANSLATE! lets you translate any page on demand, regardless of what the page declares.
You need to translate a PDF. Chrome's built-in translation does not work on PDFs. TRANSLATE! includes a PDF viewer that translates documents while preserving layout, and lets you save the translated version.
You use Safari or iOS. Safari has Apple's own translation (added in Safari 15 / macOS Monterey), but it supports fewer languages and isn't available on all pages. On iOS, options are even more limited. TRANSLATE! works across Chrome, Safari, Firefox, Edge, and Brave with the same feature set.
You work with less common languages. Translation quality for major pairs like English-Spanish or English-French is good across most services. For less common pairs -- Finnish-Thai, Estonian-Korean, Latvian-Vietnamese -- quality varies significantly between providers. TRANSLATE! lets you route through whichever supported path handles your language pair best, whether that's Chrome Built-in, OPUS-MT, DeepL, or a configured cloud provider.
Pages with mixed languages don't translate correctly. When a page contains text in multiple languages (e.g., a German forum on an English-tagged site), built-in translation often either skips it entirely or translates everything as if it were one language. TRANSLATE! detects language per text node using trigram analysis.
You want control over where your text goes. Built-in translation sends your page text to Google (Chrome), Apple (Safari), or Mozilla's servers (Firefox). TRANSLATE! lets you choose: use Chrome Built-in when available, use your own API keys with supported cloud providers, or run OPUS-MT locally in the browser via WebAssembly. Your text, your choice.
src/offscreen/translategemma.ts), DeepL, OpenAI, Anthropic, and Google Cloud. NLLB-200 (src/providers/nllb-200.ts) is in tree as an opt-in research path. Switch on the fly between the available native, local, and cloud paths.translate_page, translate_selection, detect_language) to any in-page MCP-aware agent via src/content/webmcp.ts. Compatible MCP clients (Claude.ai, agent harnesses) can drive translation directly without going through the popup. End-to-end harness lives in e2e/webmcp-harness.html + e2e/webmcp-integration.spec.ts.chrome://extensions/shortcuts.Ctrl+Shift+P translate page, Ctrl+Shift+T translate selection, Ctrl+Shift+U undo.TRANSLATE! is not a drop-in replacement for built-in translation in every scenario:
If built-in translation works reliably for your languages and pages, you probably don't need this. TRANSLATE! is for the cases where it doesn't.
| Metric | Value |
|---|---|
| Unit tests | 6.5k+ Vitest cases across 160+ files |
| Coverage gates | Enforced in CI via npm run test:coverage |
| Contract tests | Provider interface conformance checks |
| Mutation testing | Stryker configured for core + providers |
| E2E tests | Playwright smoke, integration, and harness flows |
| CI | GitHub Actions: consolidated CI, smoke e2e, coverage, CodeQL, SBOM |
The unit suite runs in about a minute locally, depending on cache state. Coverage thresholds are enforced in CI via npm run test:coverage; see vitest.config.ts for the current gate values.
| Browser | Status | Notes |
|---|---|---|
| Chrome (116+) | Full support | Primary platform, Manifest V3 |
| Chromium-based (Edge, Brave, etc.) | Full support | Load as unpacked extension |
| Safari (macOS, iOS, iPadOS) | Full support | Built via Xcode converter |
| Firefox | Supported | Separate build flow documented below |
npm install
npm run build
chrome://extensions (or the equivalent page in your Chromium-based browser).dist/ directory.If Chrome reports Service worker registration failed. Status code: 15, ensure
you selected the dist/ folder produced by the build step. Loading the repository
root or a directory missing manifest.json will cause the worker to fail.
Run the Safari converter on a Mac to produce an Xcode project for both macOS and iOS/iPadOS:
npm run build:safari
Open the generated project in Xcode to sign and build the extension for the desired platform.
See safari/README.md for detailed iOS/iPadOS deployment steps.
npx vite build --config vite.config.firefox.ts
This produces dist-firefox/, which you can load as a temporary extension in Firefox.
The repository does not currently expose a dedicated package:firefox npm script.
Remove the extension from the browser's extension management page.
Reload the unpacked extension after replacing the files with a newer version.
The repository includes a workflow that builds and signs a Chrome extension package.
CRX_PRIVATE_KEY secret, and uploads translate-extension.crx and translate-extension.zip as artifacts.To sign locally:
npm run build
echo "$CRX_PRIVATE_KEY" | base64 -d > key.pem
npx -y crx pack dist -o translate-extension.crx --zip-output translate-extension.zip -p key.pem
Open the popup and click the gear button to access Settings. The settings page provides:
Use the Diagnostics button on the home page to view usage metrics and run connectivity checks.
| Provider | API Keys | Notes |
|---|---|---|
| OpenAI | platform.openai.com | GPT models |
| Claude (Anthropic) | console.anthropic.com | Claude models |
| DeepL | deepl.com/pro-api | Document translation |
| Google Cloud | cloud.google.com/translate | Translation + Detection |
Chrome Built-in, OPUS-MT, and TranslateGemma are shipped local/native paths and do not require API keys.
See also: docs/PROVIDERS.md
Ctrl+Shift+P.The extension translates visible text, watches for new content via MutationObserver, and caches translations for the session. Failed translations are queued and retried automatically. A status indicator appears in the bottom-right corner while work is in progress.
PDFs open in a built-in viewer. Two translation modes:
Translated PDFs can be saved from the viewer.
Requests are queued to stay within provider limits (default: 60 req/min, 100K tokens/min). The popup shows live usage bars that turn yellow/red as limits approach. If a provider returns 429, the request retries automatically or fails over to the next provider.
Cost tracking is built in -- the popup shows 24-hour and 7-day spend per provider.
Ctrl+Shift+P or the popup button instead.Bearer <key>, DeepL uses DeepL-Auth-Key <key>.Use the Diagnostics panel (popup home page) for cache stats, connectivity checks, and a latency histogram. Copy Report generates a shareable summary for bug reports.
A command-line translator is included:
node cli/translate.js -k <API_KEY> -s <source_lang> -t <target_lang>
Streams translations by default. Use --no-stream for batch mode, -d for debug output. See cli/translate.js --help.
npm install # Install dependencies
npm test # Run the Vitest suite
npm run test:e2e # Run the full web + harness E2E suite
npm run build # Chrome production build (dist/)
npm run build:safari # Safari via Xcode converter
dist/ is not tracked in git. See docs/DEVELOPMENT.md for architecture details, provider internals, and the throttle/registry system.
Use Changesets for all updates. Documentation-only changes should use release type none.
A nightly workflow rebases open PRs to keep branches current with main. See AGENTS.md for details.
This project is licensed under the GPL-3.0-or-later.
813 commits
53 commits
3 commits
2 commits
TypeScript
92.3%
CSS
2.5%
Python
2.1%
JavaScript
1.8%
Shell
1.1%
Full-page browser translation that handles the dynamically-loaded pages Google Translate and built-in translators leave untouched. 10+ providers, plus an optional on-device model (WebAssembly) so the text never leaves your browser. Chrome & Firefox.
8
stars
872
commits
TypeScript
primary language
Sep 11, 2026
updated
Browser extension that translates web pages, PDFs, and selected text, including content that keeps loading and updating after the page first renders. Works where built-in browser translation falls short.
Built-in browser translation (Chrome, Safari, Firefox) works well for many pages. But if you've run into any of these, TRANSLATE! is for you:
The page keeps changing and translation falls behind. Single-page apps, live feeds, chat threads, infinite scroll -- content that loads and updates after the page first renders. Google Translate and built-in translators usually translate once and miss whatever arrives later. TRANSLATE! watches the page and translates new content as it appears.
The translate bar never shows up. Browsers decide whether to offer translation based on the page's language tag. If the tag is missing, wrong, or matches your browser language, the translate bar silently doesn't appear -- even when the page is clearly in another language. TRANSLATE! lets you translate any page on demand, regardless of what the page declares.
You need to translate a PDF. Chrome's built-in translation does not work on PDFs. TRANSLATE! includes a PDF viewer that translates documents while preserving layout, and lets you save the translated version.
You use Safari or iOS. Safari has Apple's own translation (added in Safari 15 / macOS Monterey), but it supports fewer languages and isn't available on all pages. On iOS, options are even more limited. TRANSLATE! works across Chrome, Safari, Firefox, Edge, and Brave with the same feature set.
You work with less common languages. Translation quality for major pairs like English-Spanish or English-French is good across most services. For less common pairs -- Finnish-Thai, Estonian-Korean, Latvian-Vietnamese -- quality varies significantly between providers. TRANSLATE! lets you route through whichever supported path handles your language pair best, whether that's Chrome Built-in, OPUS-MT, DeepL, or a configured cloud provider.
Pages with mixed languages don't translate correctly. When a page contains text in multiple languages (e.g., a German forum on an English-tagged site), built-in translation often either skips it entirely or translates everything as if it were one language. TRANSLATE! detects language per text node using trigram analysis.
You want control over where your text goes. Built-in translation sends your page text to Google (Chrome), Apple (Safari), or Mozilla's servers (Firefox). TRANSLATE! lets you choose: use Chrome Built-in when available, use your own API keys with supported cloud providers, or run OPUS-MT locally in the browser via WebAssembly. Your text, your choice.
src/offscreen/translategemma.ts), DeepL, OpenAI, Anthropic, and Google Cloud. NLLB-200 (src/providers/nllb-200.ts) is in tree as an opt-in research path. Switch on the fly between the available native, local, and cloud paths.translate_page, translate_selection, detect_language) to any in-page MCP-aware agent via src/content/webmcp.ts. Compatible MCP clients (Claude.ai, agent harnesses) can drive translation directly without going through the popup. End-to-end harness lives in e2e/webmcp-harness.html + e2e/webmcp-integration.spec.ts.chrome://extensions/shortcuts.Ctrl+Shift+P translate page, Ctrl+Shift+T translate selection, Ctrl+Shift+U undo.TRANSLATE! is not a drop-in replacement for built-in translation in every scenario:
If built-in translation works reliably for your languages and pages, you probably don't need this. TRANSLATE! is for the cases where it doesn't.
| Metric | Value |
|---|---|
| Unit tests | 6.5k+ Vitest cases across 160+ files |
| Coverage gates | Enforced in CI via npm run test:coverage |
| Contract tests | Provider interface conformance checks |
| Mutation testing | Stryker configured for core + providers |
| E2E tests | Playwright smoke, integration, and harness flows |
| CI | GitHub Actions: consolidated CI, smoke e2e, coverage, CodeQL, SBOM |
The unit suite runs in about a minute locally, depending on cache state. Coverage thresholds are enforced in CI via npm run test:coverage; see vitest.config.ts for the current gate values.
| Browser | Status | Notes |
|---|---|---|
| Chrome (116+) | Full support | Primary platform, Manifest V3 |
| Chromium-based (Edge, Brave, etc.) | Full support | Load as unpacked extension |
| Safari (macOS, iOS, iPadOS) | Full support | Built via Xcode converter |
| Firefox | Supported | Separate build flow documented below |
npm install
npm run build
chrome://extensions (or the equivalent page in your Chromium-based browser).dist/ directory.If Chrome reports Service worker registration failed. Status code: 15, ensure
you selected the dist/ folder produced by the build step. Loading the repository
root or a directory missing manifest.json will cause the worker to fail.
Run the Safari converter on a Mac to produce an Xcode project for both macOS and iOS/iPadOS:
npm run build:safari
Open the generated project in Xcode to sign and build the extension for the desired platform.
See safari/README.md for detailed iOS/iPadOS deployment steps.
npx vite build --config vite.config.firefox.ts
This produces dist-firefox/, which you can load as a temporary extension in Firefox.
The repository does not currently expose a dedicated package:firefox npm script.
Remove the extension from the browser's extension management page.
Reload the unpacked extension after replacing the files with a newer version.
The repository includes a workflow that builds and signs a Chrome extension package.
CRX_PRIVATE_KEY secret, and uploads translate-extension.crx and translate-extension.zip as artifacts.To sign locally:
npm run build
echo "$CRX_PRIVATE_KEY" | base64 -d > key.pem
npx -y crx pack dist -o translate-extension.crx --zip-output translate-extension.zip -p key.pem
Open the popup and click the gear button to access Settings. The settings page provides:
Use the Diagnostics button on the home page to view usage metrics and run connectivity checks.
| Provider | API Keys | Notes |
|---|---|---|
| OpenAI | platform.openai.com | GPT models |
| Claude (Anthropic) | console.anthropic.com | Claude models |
| DeepL | deepl.com/pro-api | Document translation |
| Google Cloud | cloud.google.com/translate | Translation + Detection |
Chrome Built-in, OPUS-MT, and TranslateGemma are shipped local/native paths and do not require API keys.
See also: docs/PROVIDERS.md
Ctrl+Shift+P.The extension translates visible text, watches for new content via MutationObserver, and caches translations for the session. Failed translations are queued and retried automatically. A status indicator appears in the bottom-right corner while work is in progress.
PDFs open in a built-in viewer. Two translation modes:
Translated PDFs can be saved from the viewer.
Requests are queued to stay within provider limits (default: 60 req/min, 100K tokens/min). The popup shows live usage bars that turn yellow/red as limits approach. If a provider returns 429, the request retries automatically or fails over to the next provider.
Cost tracking is built in -- the popup shows 24-hour and 7-day spend per provider.
Ctrl+Shift+P or the popup button instead.Bearer <key>, DeepL uses DeepL-Auth-Key <key>.Use the Diagnostics panel (popup home page) for cache stats, connectivity checks, and a latency histogram. Copy Report generates a shareable summary for bug reports.
A command-line translator is included:
node cli/translate.js -k <API_KEY> -s <source_lang> -t <target_lang>
Streams translations by default. Use --no-stream for batch mode, -d for debug output. See cli/translate.js --help.
npm install # Install dependencies
npm test # Run the Vitest suite
npm run test:e2e # Run the full web + harness E2E suite
npm run build # Chrome production build (dist/)
npm run build:safari # Safari via Xcode converter
dist/ is not tracked in git. See docs/DEVELOPMENT.md for architecture details, provider internals, and the throttle/registry system.
Use Changesets for all updates. Documentation-only changes should use release type none.
A nightly workflow rebases open PRs to keep branches current with main. See AGENTS.md for details.
This project is licensed under the GPL-3.0-or-later.
813 commits
53 commits
3 commits
2 commits
TypeScript
92.3%
CSS
2.5%
Python
2.1%
JavaScript
1.8%
Shell
1.1%