FluentRead Content Script Explained: How content.ts Orchestrates Page Translation

The content.ts script serves as the central orchestrator that injects UI components, registers translation triggers, and manages the lifecycle of FluentRead's page translation features on every matched website.

FluentRead is an open-source browser extension that translates web content in real-time. At the heart of this functionality lies entrypoints/content.ts, the content script that runs inside every web page the extension matches. This script coordinates configuration loading, UI mounting, event handling, and cleanup to deliver seamless translation experiences.

What Is the FluentRead Content Script?

Browser extensions use content scripts to execute JavaScript in the context of web pages. In FluentRead, entrypoints/content.ts acts as the primary entry point that bridges the extension's background logic with the user's browsing experience. It runs on <all_urls> matches, meaning it activates on virtually every website the user visits.

Core Responsibilities of content.ts

The script organizes its workflow into four distinct operational areas.

Initialization and Configuration Validation

Before mounting any UI elements, content.ts waits for the extension's configuration to load using await configReady. It immediately aborts execution if the user has disabled the extension:

await configReady;
if (config.on === false) return;

This early exit prevents unnecessary resource consumption when FluentRead is toggled off.

UI Component Mounting

Once validated, the script dynamically injects interactive elements based on user preferences. It conditionally mounts four primary components:

if (config.disableFloatingBall !== true) {
  mountFloatingBall();               // Draggable quick-toggle button
}
if (config.disableSelectionTranslator !== true) {
  mountSelectionTranslator();        // Hover-to-translate functionality
}
mountTranslationStatusComponent();   // Visual feedback overlay
mountNewApiComponent();              // Advanced settings interface

Each mount function resides in dedicated utility files under entrypoints/utils/.

Event Wiring and Translation Triggers

The content script registers multiple input mechanisms for triggering translations. It sets up manual translation hotkeys through setupManualTranslationTriggers() and configures the floating ball shortcut via setupFloatingBallHotkey().

For automatic translation of English pages, it invokes autoTranslationEvent(). Additionally, it listens for background script messages to handle cache clearing, floating ball toggles, and context menu actions:

browser.runtime.onMessage.addListener((msg, _, reply) => {
  if (msg.type === 'contextMenuTranslate') {
    if (msg.action === 'fullPage') {
      autoTranslateEnglishPage();
      reply({ status: 'success', action: 'translated' });
    } else if (msg.action === 'restore') {
      restoreOriginalContent();
      reply({ status: 'success', action: 'restored' });
    }
    return true;
  }
  return false;
});

Lifecycle Management and Cleanup

To prevent memory leaks and orphaned processes, content.ts registers a beforeunload listener that cancels pending translations, unmounts UI components, and clears caches when the user navigates away:

window.addEventListener('beforeunload', () => {
  // Cleanup logic: cancel translations, unmount UI, clear caches
});

Integration with the FluentRead Architecture

The content script does not operate in isolation. It imports core translation logic from entrypoints/main/trans.ts, which provides handleTranslation, autoTranslateEnglishPage, and restoreOriginalContent. Configuration management resides in entrypoints/utils/config.ts, while UI components are modularized into floatingBall.ts, selectionTranslator.ts, and related utilities.

This separation of concerns allows content.ts to focus solely on orchestration—deciding when to load, what to display, and how to respond to user input—while delegating implementation details to specialized modules.

Summary

  • content.ts serves as the primary content script entry point for FluentRead, executing on every matched web page.
  • It validates configuration before mounting any UI components to respect user preferences and disabled states.
  • The script dynamically injects four key UI elements: the floating ball, selection translator, status overlay, and advanced settings interface.
  • It wires multiple translation triggers including hotkeys, context menu actions, and automatic page translation.
  • Comprehensive cleanup logic prevents memory leaks when users navigate away from pages.

Frequently Asked Questions

What happens if I disable FluentRead in the settings?

When the extension is disabled (config.on === false), content.ts exits immediately after the configuration loads. This prevents any UI injection, event registration, or background processing, ensuring zero performance impact on your browsing experience.

Can I use FluentRead without the floating ball interface?

Yes. The content script checks config.disableFloatingBall before calling mountFloatingBall(). If you disable this feature in settings, the draggable toggle button will not appear, though you can still trigger translations via hotkeys or the selection translator.

How does the content script handle page navigation?

content.ts registers a beforeunload event listener that executes cleanup routines when you leave a page. This cancels pending translation requests, removes injected UI components, and clears temporary caches to free memory and prevent orphaned processes.

Where does the actual translation logic reside?

While content.ts orchestrates the user interface and events, the core translation engine lives in entrypoints/main/trans.ts. This module exports functions like handleTranslation and autoTranslateEnglishPage, which the content script imports and invokes based on user interactions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →