DEV Community

Cover image for How I Built a Thunderbird Translator Without Coding Experience Using AI
BuxarNET
BuxarNET

Posted on

How I Built a Thunderbird Translator Without Coding Experience Using AI

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);
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
});
Enter fullscreen mode Exit fullscreen mode

3. Multilingual Interface

Support for 6 languages through Thunderbird's locale system:

English
Russian
German
Spanish
French
Italian
Enter fullscreen mode Exit fullscreen mode

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));
    }
});
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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 */});
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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:

  1. Implementation of popup icons - is this even possible in principle in modern versions of Thunderbird?
  2. Window management - how to prevent conflicts between native notifications and custom windows?
  3. 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)