Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,117 changes: 780 additions & 337 deletions background.js

Large diffs are not rendered by default.

112 changes: 92 additions & 20 deletions content.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,39 +41,111 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
setTimeout(() => loadingIndicator.remove(), 2000);
}
}

// Translate paragraph by paragraph
// Translate paragraph by paragraph with batch processing
async function translateParagraphs() {
// Create progress indicator
const progressIndicator = document.createElement('div');
progressIndicator.id = 'translationProgressIndicator';
progressIndicator.style.position = 'fixed';
progressIndicator.style.bottom = '20px';
progressIndicator.style.right = '20px';
progressIndicator.style.padding = '10px 15px';
progressIndicator.style.backgroundColor = '#1a73e8';
progressIndicator.style.color = 'white';
progressIndicator.style.borderRadius = '20px';
progressIndicator.style.zIndex = '9999';
progressIndicator.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)';
progressIndicator.style.display = 'flex';
progressIndicator.style.alignItems = 'center';
progressIndicator.style.justifyContent = 'center';
progressIndicator.style.fontFamily = 'Arial, sans-serif';
progressIndicator.style.transition = 'opacity 0.3s';

// Add progress bar
const progressText = document.createElement('div');
progressText.textContent = 'Processing: 0%';
progressIndicator.appendChild(progressText);

document.body.appendChild(progressIndicator);

// Collect paragraphs to translate
const paragraphs = document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, span, div');
let translatedCount = 0;
const elementsToTranslate = [];

for (let i = 0; i < paragraphs.length; i++) {
const element = paragraphs[i];
if (element.textContent.trim() &&
element.childNodes.length === 1 &&
element.childNodes[0].nodeType === Node.TEXT_NODE &&
!element.classList.contains('hinglish-translated')) {
elementsToTranslate.push(element);
}
}

// Listen for progress updates
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'updateProgress' && request.progress >= 0) {
progressText.textContent = `Processing: ${request.progress}%`;
} else if (request.action === 'updateProgress' && request.progress === -1) {
// Hide progress indicator
progressIndicator.style.opacity = '0';
setTimeout(() => progressIndicator.remove(), 300);
}
});

try {
Comment on lines +85 to +96
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid stacking message listeners – move this outside the function

chrome.runtime.onMessage.addListener is created every time translateParagraphs() runs. After a few page-level translations you will have N identical listeners, all firing for each progress message.

Extract the listener to module scope or register it once and remove it when progress === -1.

πŸ€– Prompt for AI Agents
In content.js around lines 85 to 96, the chrome.runtime.onMessage.addListener is
being added inside a function, causing multiple identical listeners to stack up
and fire repeatedly. To fix this, move the entire onMessage.addListener callback
outside of the translateParagraphs() function so it is registered only once at
the module level. Alternatively, register the listener once and remove it when
progress equals -1 to prevent multiple listeners from accumulating.

// Process in batches of 5
const batchSize = 5;
let translatedCount = 0;

for (let i = 0; i < elementsToTranslate.length; i += batchSize) {
const batch = elementsToTranslate.slice(i, i + batchSize);
const promises = batch.map(element => {
return new Promise(async (resolve) => {
try {
const response = await chrome.runtime.sendMessage({
action: "translateText",
text: element.textContent
});

if (response && !response.startsWith("Translation error:")) {
element.textContent = response;
element.classList.add('hinglish-translated');
translatedCount++;
}
} catch (error) {
console.error('Translation error:', error);
}
resolve();
});
Comment on lines +104 to +120
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Refactor away from new Promise(async …)

Using an async executor violates the β€œno-async-promise-executor” rule and can swallow rejections.
The whole wrapper is redundant – the call to chrome.runtime.sendMessage already returns a promise.

-const promises = batch.map(element => {
-  return new Promise(async (resolve) => {
-    try {
-      const response = await chrome.runtime.sendMessage({ … });
-      …
-    } catch (e) {
-      console.error(e);
-    }
-    resolve();
-  });
-});
+const promises = batch.map(async element => {
+  try {
+    const response = await chrome.runtime.sendMessage({ … });
+    …
+  } catch (e) {
+    console.error(e);
+  }
+});

This removes the Biome warning and preserves error propagation.

πŸ“ 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
return new Promise(async (resolve) => {
try {
const response = await chrome.runtime.sendMessage({
action: "translateText",
text: element.textContent
});
if (response && !response.startsWith("Translation error:")) {
element.textContent = response;
element.classList.add('hinglish-translated');
translatedCount++;
}
} catch (error) {
console.error('Translation error:', error);
}
resolve();
});
const promises = batch.map(async element => {
try {
const response = await chrome.runtime.sendMessage({
action: "translateText",
text: element.textContent
});
if (response && !response.startsWith("Translation error:")) {
element.textContent = response;
element.classList.add('hinglish-translated');
translatedCount++;
}
} catch (error) {
console.error('Translation error:', error);
}
});
🧰 Tools
πŸͺ› Biome (1.9.4)

[error] 104-120: Promise executor functions should not be async.

(lint/suspicious/noAsyncPromiseExecutor)

πŸ€– Prompt for AI Agents
In content.js around lines 104 to 120, the code uses a new Promise with an async
executor, which violates best practices and can swallow errors. Refactor by
removing the explicit new Promise wrapper and directly return the promise from
chrome.runtime.sendMessage. Use async/await properly without wrapping in a new
Promise, and handle errors with try/catch to preserve error propagation and
eliminate the Biome warning.

});

const originalText = element.textContent;
await Promise.all(promises);

try {
const response = await chrome.runtime.sendMessage({
action: "translateText",
text: originalText
});

if (response && response !== "Please configure your API key first") {
element.textContent = response;
element.classList.add('hinglish-translated');
translatedCount++;
}
} catch (error) {
console.error('Translation error:', error);
}
// Update progress
const progress = Math.min(100, Math.round((i + batchSize) * 100 / elementsToTranslate.length));
progressText.textContent = `Processing: ${progress}%`;
}

// Complete
progressText.textContent = 'Translation Complete!';
progressIndicator.style.backgroundColor = '#0b8043';
setTimeout(() => {
progressIndicator.style.opacity = '0';
setTimeout(() => progressIndicator.remove(), 300);
}, 2000);

return translatedCount;
} catch (error) {
console.error('Batch translation error:', error);
progressText.textContent = 'Translation Failed';
progressIndicator.style.backgroundColor = '#d93025';
setTimeout(() => {
progressIndicator.style.opacity = '0';
setTimeout(() => progressIndicator.remove(), 300);
}, 2000);
return 0;
}

return translatedCount;
}

// Translate all text nodes (more aggressive approach)
Expand Down
15 changes: 9 additions & 6 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@
],
"host_permissions": [
"https://api.groq.com/*"
],
"background": {
"service_worker": "background.js",
"type": "module"
], "background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup/welcome.html",
Expand All @@ -31,13 +29,18 @@
"32": "icons/icon32.png",
"48": "icons/icon48.png"
}
},
"content_scripts": [
}, "content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["styles/content.css"],
"run_at": "document_idle"
}
],
"web_accessible_resources": [
{
"resources": ["utils/securityHelper.js", "utils/apiRequestManager.js"],
"matches": ["<all_urls>"]
}
]
}
Loading