日本語版は README.ja.md を参照してください。
A Chrome extension that translates rendered Markdown on GitHub — READMEs, docs, issues, and pull requests — using Chrome's built-in Translator API (on-device translation).
- Code blocks and inline code (
pre,code, etc.) are never translated - A button at the bottom right toggles between the translation and the original
- Pick the target language from the toolbar popup (defaults to your browser's UI language)
- The source language is detected automatically with the LanguageDetector API, so non-English pages are translated too
- Translation runs entirely on your device — no API key, nothing sent to external servers
- Chrome 138 or later (Translator / LanguageDetector APIs are available in stable)
- On first use, a translation model is downloaded per language pair (progress is shown on the button)
npm install && npm run build— compilessrc/*.tsintocontent.js/popup.jswith esbuild (npm run watchrebuilds on change)- Open
chrome://extensions - Enable "Developer mode" in the top right corner
- Click "Load unpacked" and select this directory
bash tools/setup-chrome.sh downloads a standalone Chrome into .chrome/
(no root needed), then npm run screenshot drives it with the extension
loaded and saves before/after screenshots (1280x800, Web Store size) to
screenshots/. Optional: npm run screenshot -- <github-url> <name>,
SCALE=2 for 2x renders, TARGET_LANG=<code> for other languages.
Open any page on github.com / gist.github.com that renders Markdown — a
README, a .md file view, a wiki page, or an issue / PR body and its
comments — and a button appears at the bottom right. Click it to translate,
click again to restore the original text.
To change the target language, click the extension icon in the toolbar and pick a language in the popup. Changing it reverts the current translation.
Comments loaded lazily after translating are picked up by toggling the button off and on again.
All rendered Markdown on GitHub lives inside .markdown-body elements. The
content script walks their text nodes with a TreeWalker, skips anything
inside the exclusion selectors (pre, code, kbd, samp, .highlight,
…), and replaces the rest with translated text. Originals are kept per node
and restored on toggle.
The dominant page language is detected from the container text; text nodes
of 20+ characters are also detected individually, so mixed-language pages
work. Text already in the target language is skipped, and a Translator
instance is created and cached per language pair. The target language is
stored in chrome.storage.sync, and the UI is localized via chrome.i18n
(English / Japanese).
To amortize the per-call overhead of the on-device model, node texts are
grouped by source language and batched into single translate() calls
(up to 50 nodes / 4000 characters per call, joined with blank lines). If
the separator does not survive translation, the batch falls back to
per-node calls. Sources are TypeScript (src/), bundled with esbuild.