Skip to content

Conversation

@Rishiraj-Yadav
Copy link

@Rishiraj-Yadav Rishiraj-Yadav commented Jan 23, 2026

Summary

Adds a Chrome Extension demo that translates webpages in-place using the Lingo.dev SDK with batch translation, caching, and restore functionality.

Changes

  • Implemented in-page translation workflow using LingoDotDevEngine (localizeObject) from Lingo.dev SDK

  • Added Chrome MV3 extension architecture (popup UI + content script + background service worker)

  • Added batch translation support for faster translation on large pages

  • Added restore feature to revert translated text back to original without page reload

  • Added improved modern popup UI with status + progress feedback

  • Included README with setup and local run instructions

Testing

Business logic tests added:

  • All tests pass locally (manual verification via Chrome extension testing)
  • Loaded extension via chrome://extensions → Load unpacked (dist/)
  • Verified translation works on static page (Wikipedia)
  • Verified translation works on SPA page (Discord / dynamic pages)
  • Verified Restore returns original content
  • Verified no API key is committed (placeholder used)

Visuals

Required for UI/UX changes:

Before :
image

After

Screenshot 2026-01-23 093800 Screenshot 2026-01-23 093906

Checklist

  • [] Changeset added (not needed for demo submission)
  • Tests cover business logic (manual integration testing done)
  • No breaking changes (new demo folder only, no existing code modified)

Closes #1761

Summary by CodeRabbit

  • New Features

    • Lingo Live Page Translator Chrome extension: in-place AI-powered page translation with batch processing, progress/status feedback, target-language selection, and restore-original content.
  • Documentation

    • Added a comprehensive README with features, workflow, API key guidance, and local build/load instructions.
  • Chores

    • Added release metadata entries for related packages and patch version bumps.

✏️ Tip: You can customize this high-level summary in your review settings.

@sumitsaurabh927
Copy link
Contributor

hi @Rishiraj-Yadav great project!

Your PR is missing changeset though. It is required for demo apps as well.

Please add the changeset by following instructions here. Make sure you've joined our discord to see this message. If you haven't you need to:

  1. Join our discord here
  2. Go through the instructions to add changeset and add it to your PR

Please also sign your commits

@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Adds a new "Lingo Live Page Translator" Chrome extension demo: MV3 manifest, content script, background service worker using Lingo.dev SDK, popup UI (HTML/CSS/JS), Vite build config, package manifest, README, and changeset entries.

Changes

Cohort / File(s) Summary
Changesets & Packaging
.changeset/plenty-sloths-smash.md, .changeset/spotty-jars-kick.md, community/lingo-live-page-translator/package.json
Adds two changeset entries and a new package manifest (ESM, Vite build scripts, dependency on lingo.dev).
Extension Manifest
community/lingo-live-page-translator/public/manifest.json
New Chrome MV3 manifest declaring permissions, host_permissions, module service_worker background.js, action popup, icons, and content_script injection.
Background / SDK Integration
community/lingo-live-page-translator/src/background.js
New background service worker that initializes LingoDotDevEngine (API key placeholder), handles translateBatch messages, implements per-text caching, constructs content objects for batch localization, and returns mapped translations.
Content Script (DOM work)
community/lingo-live-page-translator/public/content-script.js
New content script extracting/filtering text nodes, batching (≤20), messaging background for translations, applying translated text to DOM and storing originals for restore; includes SKIP_TAGS and translation state tracking.
Popup UI (HTML/CSS/JS)
community/lingo-live-page-translator/public/popup.html, community/lingo-live-page-translator/public/popup.css, community/lingo-live-page-translator/public/popup.js
Adds popup markup, styles, and logic: language selector, Translate/Restore controls, progress/status UI, and messaging to active tab with error handling and UI state management.
Build Config
community/lingo-live-page-translator/vite.config.js
Vite config exporting build options, publicDir, outDir, Rollup input for background and custom entryFileNames to emit background.js.
Documentation
community/lingo-live-page-translator/README.md
New README describing extension purpose, workflow, prerequisites, API key instructions, build steps, and Chrome load instructions.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Popup as Popup UI
    participant Content as Content Script
    participant Background as Background Service Worker
    participant LingoSDK as Lingo.dev SDK

    User->>Popup: select language, click Translate
    Popup->>Content: chrome.tabs.sendMessage { action: "translatePage", targetLocale }
    Content->>Content: extractTextNodes() & batch texts (≤20)
    Content->>Background: chrome.runtime.sendMessage { action: "translateBatch", texts, sourceLocale, targetLocale }
    Background->>Background: check cache for each text
    Background->>LingoSDK: localizeObject(contentObject, { sourceLocale, targetLocale })
    LingoSDK-->>Background: return translated contentObject
    Background->>Background: map translations to original indices, update cache
    Background-->>Content: return translations array
    Content->>Content: apply translations to DOM & store originals
    Content-->>Popup: optional completion/status
    Popup->>User: show status/progress
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hop between tags, soft and spry,

Batching phrases beneath the sky,
Lingo hums and letters rearrange,
I swap words gently — quick to change,
Then tuck originals back, safe and sly.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add Lingo Live Page Translator Chrome extension' clearly and concisely describes the main change: introducing a new Chrome extension demo for page translation using Lingo.dev.
Description check ✅ Passed The PR description follows the template with all key sections completed: Summary, Changes, Testing (with manual verification details), Visuals (before/after screenshots), and Checklist. The description comprehensively documents the implementation and testing approach.
Linked Issues check ✅ Passed The PR fully meets the objectives from issue #1761: added a demo app to /community/ directory, included a comprehensive README explaining the app, how to run it locally, and which Lingo.dev features it showcases (LingoDotDevEngine.localizeObject for batch translation).
Out of Scope Changes check ✅ Passed All changes are in-scope and confined to the new /community/lingo-live-page-translator/ directory with no modifications to existing code or breaking changes outside the demo folder.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@community/lingo-live-page-translator/public/popup.css`:
- Around line 134-148: The .btn rule currently removes the default focus
indicator (outline: none) which breaks keyboard accessibility; add explicit
focus styles for keyboard users by defining .btn:focus and/or .btn:focus-visible
rules that provide a visible, high-contrast focus indicator (for example a
visible outline or box-shadow ring) while keeping the existing visual design,
and ensure the selector targets keyboard focus (use :focus-visible if available)
so mouse clicks don't always show the ring.

In `@community/lingo-live-page-translator/README.md`:
- Around line 42-80: The README has an unclosed fenced code block (the opening
"```bash" near the top) causing subsequent sections to render as code; close
that initial fence immediately after the npm install line and then fence the
subsequent inline examples properly (wrap "src/background.js" and the code
snippets for const LINGO_API_KEY and the replacement key in appropriate
triple-backtick blocks with language tags, and fence "npm run build" and "dist/"
as bash/text blocks), and optionally add section separators (---) between steps
so steps 2–4 render as normal markdown and the file paths/commands show as
intended.
- Around line 36-37: Update the README line that lists the Lingo.dev API key so
the bare URL is converted to proper Markdown link syntax; replace the plain "Get
it from: https://lingo.dev" text with a Markdown link such as "Get it from:
[https://lingo.dev](https://lingo.dev)" (locate the line with "A Lingo.dev API
key" and the following URL text to make the change).
🧹 Nitpick comments (4)
community/lingo-live-page-translator/public/popup.css (1)

14-17: Duplicate .container selector with conflicting styles.

The .container rule appears twice with different border-radius values:

  • Line 16: border-radius: 0;
  • Line 261: border-radius: 18px;

The second declaration wins due to CSS cascade, but this creates confusion. Consider consolidating into a single rule.

♻️ Suggested consolidation
 .container {
   background: white;
-  border-radius: 0;
+  border-radius: 18px;
+  overflow: hidden;
+  box-shadow: 0 10px 30px rgba(0,0,0,0.18);
 }
-
-/* ... later in file ... */
-
-.container {
-  border-radius: 18px;
-  overflow: hidden;
-  box-shadow: 0 10px 30px rgba(0,0,0,0.18);
-}

Also applies to: 260-264

community/lingo-live-page-translator/src/background.js (1)

31-32: Cache key delimiter could cause collisions.

The cache key ${texts[i]}__${sourceLocale}__${targetLocale} uses __ as a delimiter, which could exist in the original text, potentially causing key collisions.

Consider using JSON or a safer delimiter
-    const key = `${texts[i]}__${sourceLocale}__${targetLocale}`;
+    const key = JSON.stringify([texts[i], sourceLocale, targetLocale]);
community/lingo-live-page-translator/public/popup.js (1)

80-102: Restore handler doesn't disable buttons during operation.

Unlike the translate handler, the restore operation doesn't call setButtonsDisabled(true) at the start, allowing users to potentially trigger multiple operations simultaneously.

Add button disable/enable for restore
 restoreBtn.addEventListener("click", async () => {
   try {
+    setButtonsDisabled(true);
     showStatus("Restoring original content...", "info");
     showProgress(50, "Restoring...");

     const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

     chrome.tabs.sendMessage(tab.id, { action: "restoreOriginal" }, (res) => {
       if (chrome.runtime.lastError) {
         showStatus("Error: Could not restore. Try refreshing.", "error");
         hideProgress();
+        setButtonsDisabled(false);
         return;
       }

       showProgress(100, "Restored!");
       showStatus("↩️ Original text restored!", "success");
       hideProgress();
+      setButtonsDisabled(false);
     });
   } catch (err) {
     showStatus(`❌ ${err.message}`, "error");
     hideProgress();
+    setButtonsDisabled(false);
   }
 });
community/lingo-live-page-translator/public/content-script.js (1)

50-55: Source locale is hardcoded to "en".

The sourceLocale is always "en" regardless of the actual page language. This limits the extension's usefulness on non-English pages.

Consider detecting the page language or allowing user selection:

Option: Detect from HTML lang attribute
+function detectSourceLocale() {
+  const htmlLang = document.documentElement.lang;
+  return htmlLang?.split('-')[0] || 'en';
+}
+
 async function translatePage(targetLocale) {
   if (isTranslating) throw new Error("Translation already running");
   isTranslating = true;
+  const sourceLocale = detectSourceLocale();

   // ... in the sendMessage call:
       const res = await chrome.runtime.sendMessage({
         action: "translateBatch",
         texts: batch,
-        sourceLocale: "en",
+        sourceLocale,
         targetLocale
       });

Comment on lines +134 to +148
.btn {
flex: 1;
padding: 12px 16px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
outline: none;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Consider adding focus styles for keyboard accessibility.

The button has outline: none (line 147) but no :focus or :focus-visible styles are defined. This removes the default focus indicator, making keyboard navigation difficult for users who don't use a mouse.

♿ Suggested fix
 .btn-primary:active {
   transform: translateY(0);
 }

+.btn-primary:focus-visible {
+  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.4);
+}
+
 .btn-primary:disabled {
   opacity: 0.6;
🤖 Prompt for AI Agents
In `@community/lingo-live-page-translator/public/popup.css` around lines 134 -
148, The .btn rule currently removes the default focus indicator (outline: none)
which breaks keyboard accessibility; add explicit focus styles for keyboard
users by defining .btn:focus and/or .btn:focus-visible rules that provide a
visible, high-contrast focus indicator (for example a visible outline or
box-shadow ring) while keeping the existing visual design, and ensure the
selector targets keyboard focus (use :focus-visible if available) so mouse
clicks don't always show the ring.

Comment on lines 36 to 37
- A Lingo.dev API key
Get it from: https://lingo.dev
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use proper markdown link syntax for URL.

The bare URL should be wrapped in markdown link syntax for better rendering and accessibility.

 - A Lingo.dev API key  
-  Get it from: https://lingo.dev
+  Get it from: [https://lingo.dev](https://lingo.dev)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- A Lingo.dev API key
Get it from: https://lingo.dev
- A Lingo.dev API key
Get it from: [https://lingo.dev](https://lingo.dev)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

37-37: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In `@community/lingo-live-page-translator/README.md` around lines 36 - 37, Update
the README line that lists the Lingo.dev API key so the bare URL is converted to
proper Markdown link syntax; replace the plain "Get it from: https://lingo.dev"
text with a Markdown link such as "Get it from:
[https://lingo.dev](https://lingo.dev)" (locate the line with "A Lingo.dev API
key" and the following URL text to make the change).

Comment on lines 42 to 80
```bash
npm install


🔑 2) Add Your Lingo.dev API Key

Open:

src/background.js


Find:

const LINGO_API_KEY = "YOUR_LINGO_API_KEY";


Replace it with your real key:

const LINGO_API_KEY = "lingo_xxxxxxxxxxxxxxxxxxxxx";



🏗️ 3) Build the Extension
npm run build


After building, a new folder will be created:

dist/


🧩 4) Load into Chrome

Open: chrome://extensions

Enable Developer Mode (top right)

Click Load unpacked

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Unclosed code block breaks README formatting.

The code block opened at line 42 (```bash) is never closed. This causes sections 2, 3, and 4 to render as code instead of formatted markdown. The closing ``` is missing after npm install.

📝 Suggested fix
 ### 📦 1) Install Dependencies
 ```bash
 npm install
+```
 
+---
 
 🔑 2) Add Your Lingo.dev API Key
 
 Open:
-
-src/background.js
-
+```
+src/background.js
+```
 
 Find:
-
-const LINGO_API_KEY = "YOUR_LINGO_API_KEY";
-
+```js
+const LINGO_API_KEY = "YOUR_LINGO_API_KEY";
+```
 
 Replace it with your real key:
-
-const LINGO_API_KEY = "lingo_xxxxxxxxxxxxxxxxxxxxx";
-
+```js
+const LINGO_API_KEY = "lingo_xxxxxxxxxxxxxxxxxxxxx";
+```
 
+---
 
 🏗️ 3) Build the Extension
+```bash
 npm run build
-
+```
 
 After building, a new folder will be created:
-
-dist/
-
+```
+dist/
+```
 
+---
+
 🧩 4) Load into Chrome
 
-Open: chrome://extensions
+1. Open: `chrome://extensions`
+2. Enable **Developer Mode** (top right)
+3. Click **Load unpacked**
+4. Select the `dist/` folder
🤖 Prompt for AI Agents
In `@community/lingo-live-page-translator/README.md` around lines 42 - 80, The
README has an unclosed fenced code block (the opening "```bash" near the top)
causing subsequent sections to render as code; close that initial fence
immediately after the npm install line and then fence the subsequent inline
examples properly (wrap "src/background.js" and the code snippets for const
LINGO_API_KEY and the replacement key in appropriate triple-backtick blocks with
language tags, and fence "npm run build" and "dist/" as bash/text blocks), and
optionally add section separators (---) between steps so steps 2–4 render as
normal markdown and the file paths/commands show as intended.

@Rishiraj-Yadav
Copy link
Author

@sumitsaurabh927 done with changeset and also with sign commits

Updated README to clarify API key replacement instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build Demo Apps, Integrations etc & Win Exclusive Lingo.dev Swag!

2 participants