Backstory
I'm just a regular PC user and far from programming; I tried something with HTML and PHP back in the distant 2000s. Currently, I've started learning Python online, but what I've done below was done without any knowledge of code at all.
Why? Working with international correspondence in Thunderbird, I constantly faced the need to translate email texts. Constantly copying to the browser and back was time-consuming. That's how the idea came about to create an extension that integrates a translator directly into the email client. At the time of the idea, there were no analogues available, so I decided to implement this particular application. Besides the need for this software, I was also interested in experimenting after reading about Vibe Coding.
For this work, I decided to use Deepseek as a sufficiently powerful AI among the free options available. Plus, I hadn't seen articles about implementing full-fledged software with it (mostly everyone uses GPT4 on a paid basis), so I decided to experiment. All the technical information and descriptions of trials and errors below were also written with Deepseek's help.
Tech Stack
- Language: JavaScript (WebExtensions API)
- Platform: Thunderbird 78.0+
- Translation API: Google Translate
- Tools: Eclipse, Git, GitHub
Application Architecture
text
BuxarTranslate/
├── src/ # Source code
│ ├── background.js # Background process
│ ├── content.js # Scripts for DOM manipulation
│ └── popup/ # Popup window
├── docs/ # Documentation
├── scripts/ # Build scripts
└── build/ # Built packages
Key Features
1. Dual Translation Display
function showTranslation(originalText, translatedText) {
// Instant notification
browser.notifications.create({
type: "basic",
title: "Translation",
message: translatedText.substring(0, 100) + "..."
});
// Detailed window
showDetailedWindow(originalText, translatedText);
}
2. Context Menu Integration
browser.menus.create({
id: "translate-text",
title: "Translate to %s",
contexts: ["selection"]
});
browser.menus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "translate-text") {
translateSelectedText(info.selectionText);
}
});
3. Multilingual Interface
Support for 6 languages through Thunderbird's locale system:
English
Russian
German
Spanish
French
Italian
Challenges and Their Solutions: Real Development Hurdles
Problem 1: Popup Icon After Text Selection
Task: Implement a translation icon that appears immediately after selecting text in an email (similar to Google Translate in browsers).
Why it didn't work (Deepseek's opinion):
- Thunderbird API limitations for working with selected text
- Difficulties with positioning elements relative to the selection
- Conflicts with the native context menu
Failed implementation attempt:
// Unsuccessful attempt to show icon next to selection
document.addEventListener('selectionchange', function() {
const selection = window.getSelection();
if (selection.toString().trim()) {
showTranslateIcon(selection.getRangeAt(0));
}
});
Question to the community: Are there working examples of implementing popup icons in Thunderbird extensions? Which APIs should be used?
Problem 2: Conflict Between Translation Windows and Native Notifications
Task: Open the translation window under the toolbar icon, but it would close instantly due to Thunderbird's standard notifications. I gave Deepseek the task to block the standard notification window, but it blocked both. Gave the task to show them sequentially, it only showed them simultaneously. And most interestingly, gave the task to delay showing ours by 5 seconds while the standard one opens and closes, but it could only delay the standard one and make it pause 5 seconds before closing, while ours still opened for fractions of a second without delay. In short, I gave up and moved on.
What we tried:
// Attempt 1: Direct window opening - closed immediately
browser.windows.create({
url: "popup/translation.html",
type: "popup",
width: 400,
height: 300
});
// Attempt 2: Delayed opening - didn't work
setTimeout(() => {
openTranslationWindow(); // Still overlapped by notification
}, 100);
// Attempt 3: Disabling notifications - lost functionality
browser.notifications.clear("translate-notification");
Solution: Had to abandon toolbar integration and implement a separate independent translation window.
Question to the community: How to properly manage the lifecycle of windows in Thunderbird extensions? Is there a way to prevent automatic closing?
Problem 3: Timer in the Separate Translation Window
Task: Implement a countdown in seconds in the translation window to show progress.
Problem: The timer worked incorrectly — sometimes freezing, sometimes showing wrong time.
Problematic code:
// Timer worked unstably
let seconds = 0;
const timer = setInterval(() => {
seconds++;
document.getElementById('timer').textContent = seconds + ' sec';
}, 1000); // Often got disrupted or stopped
Question to the community: What are the best practices for working with timers in Thunderbird extension windows? How to synchronize time between different execution contexts?
Problem 4: Security Issues During Verification
Task: Pass security verification when publishing in the official store.
Problems (Deepseek's opinion):
- Use of
eval()in code (inherited from examples) - Potential XSS vulnerabilities when working with DOM
- Unsafe practices when working with external APIs
I won't reveal the real problems, but I remember one: validation wouldn't pass an implementation with raw HTML code among JavaScript code. Deepseek rewrote everything in JavaScript, and yes, there were some issues with calling object functions as I understood, but Deepseek handled the rewriting for Thunderbird submission very quickly.
Solution:
// WAS (dangerous):
const result = eval('(' + jsonResponse + ')');
// BECAME (safe):
const result = JSON.parse(jsonResponse);
// WAS (vulnerable):
element.innerHTML = userContent;
// BECAME (safe):
element.textContent = userContent;
Quick fix: Code analysis with ESLint security rules and manual audit of all data input points.
Problem 5: Integration with Context Menu in Different Thunderbird Versions (Deepseek's opinion; I didn't see problems in this case since the application wasn't tested on other versions and therefore had no errors)
Solution: Universal approach with API capability checks:
// Checking beforeShowContextMenu support
if (browser.menus.onShown) {
browser.menus.onShown.addListener(handleContextMenu);
} else {
// Fallback for old versions
browser.menus.create({/* basic menu */});
}
Problem 6: Automatic Closing of Translation Window on Focus Loss
Task: Implement behavior where the translation window automatically closes when the user clicks outside it (similar to tooltips or dropdown menus).
What we tried:
// Attempt 1: Tracking blur event on window
window.addEventListener('blur', function() {
window.close(); // Didn't work stably
});
// Attempt 2: Checking active element
document.addEventListener('click', function(event) {
if (!event.target.closest('.translation-window')) {
window.close(); // Closed even when clicking inside the window
}
});
// Attempt 3: Focus tracking via Page Visibility API
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
window.close(); // Worked incorrectly on different OS
}
});
// Attempt 4: Checking via requestAnimationFrame
function checkWindowFocus() {
requestAnimationFrame(() => {
if (!document.hasFocus()) {
window.close();
} else {
checkWindowFocus();
}
});
}
checkWindowFocus(); // High load and false triggers
Special difficulties:
- Focus events work differently on different OS (Windows, Linux, macOS)
- Extension window can lose focus due to system notifications
- Race conditions occurred when quickly switching between windows
Temporary solution: Added manual close button, added configurable auto-close timer, and left standard OS window behavior.
Question to the community: What are reliable ways to track focus loss for extension windows? Is there a cross-platform solution that works stably on Windows, Linux, and macOS?
Publishing Process
1. Package Preparation
# Build XPI file
zip -r buxartranslate.xpi src/ manifest.json locales/
2. Publishing on addons.thunderbird.net
- Developer account verification
- Upload XPI file
- Fill in metadata
- Pass moderation
3. Multilingual Description Support (apparently Deepseek is talking about a website we also slapped together)
Using HTML formatting for beautiful display:
<strong>BuxarTranslate</strong> - translator for Thunderbird...
<ul>
<li>Instant translation of selected text</li>
<li>Support for 100+ languages</li>
</ul>
Performance and Optimization (nothing like this was in the task, I don't know if Deepseek really set such goals)
- Caching frequent requests
- Lazy loading of resources
- Minimizing memory usage
- Optimizing network requests
Project Statistics
- Version: 1.0.1
- Size: ~250 KB
- Load time: < 2 sec
- Support: Thunderbird 78.0+
Future Plans (half of what's written is Deepseek's fiction)
- Adding Yandex.Translate API
- Translating entire emails
- Dictionary with saved translations
- Voice pronunciation
Addressing the Community
Developing for Thunderbird raised several difficult questions for which we couldn't find unambiguous answers in the documentation:
- Implementation of popup icons - is this even possible in principle in modern versions of Thunderbird?
- Window management - how to prevent conflicts between native notifications and custom windows?
- Timers and multithreading - which approaches work stably in different execution contexts?
If you have experience solving similar tasks or have faced similar challenges - share your solutions in the comments!
Conclusions
Developing even such a seemingly simple extension as a translator required deep immersion into the specifics of the Thunderbird platform. The flexibility of the WebExtensions API simultaneously opens possibilities and creates specific limitations.
Resources that helped:
- MDN WebExtensions
- Thunderbird Extension Docs
- Thunderbird Community
Final Thoughts
The above are Deepseek's conclusions, but mine are as follows: Developing Thunderbird extensions with Deepseek turned out to be an engaging process. The main functionality took 14 hours to develop, polishing and translations took another 10 hours.
Plus copying translations to the site and figuring out how to work with Git, Eclipse, and uploading to the Thunderbird site. In total, I probably spent about 30-40 hours (about 2 weeks if you count that I didn't work around the clock). In your opinion, how long would a professional programmer take to write this without AI?
By the way, I drew the logo in Alice AI.
In general, don't be too harsh and I'm really looking forward to feedback on the code quality and functionality. Links to repositories with code, the site with description, and the ready extension are below.
Links:
Top comments (0)