# File Structure for Translation Service Implementations in FluentRead: A Modular Architecture Guide

> Discover FluentRead's modular file structure for translation service implementations. Learn how isolated modules under entrypoints/service organize engine modules and centralize dispatching.

- Repository: [ThinkStu/fluentread](https://github.com/bistutu/fluentread)
- Tags: architecture
- Published: 2026-02-26

---

**FluentRead organizes every translation engine as an isolated module under `entrypoints/service/`, with each engine exporting a single async function that handles API communication, while a central registry in [`_service.ts`](https://github.com/bistutu/fluentread/blob/main/_service.ts) maps service identifiers to these implementations for dispatch by the background script.**

FluentRead is an open-source browser extension that unifies multiple translation providers under a single interface. Understanding the file structure for translation service implementations in FluentRead is essential for contributors looking to add new engines or customize existing ones. The codebase follows a strict modular pattern where each translation service is self-contained, making the system highly extensible and maintainable.

## Modular Architecture in `entrypoints/service/`

### One File Per Translation Engine

Each translation provider lives in its own TypeScript file within `entrypoints/service/`. This isolation ensures that HTTP logic, authentication handling, and response parsing for each provider never interferes with others.

Key implementation files include:

- [`microsoft.ts`](https://github.com/bistutu/fluentread/blob/main/microsoft.ts) – Microsoft Translator with token refresh logic
- [`youdao.ts`](https://github.com/bistutu/fluentread/blob/main/youdao.ts) – Youdao translation with signature generation
- [`deepl.ts`](https://github.com/bistutu/fluentread/blob/main/deepl.ts) – DeepL API integration with proxy support
- [`deeplx.ts`](https://github.com/bistutu/fluentread/blob/main/deeplx.ts) – DeepLX self-hosted implementation
- [`google.ts`](https://github.com/bistutu/fluentread/blob/main/google.ts) – Google Translate engine
- [`xiaoniu.ts`](https://github.com/bistutu/fluentread/blob/main/xiaoniu.ts) – 小牛翻译 integration
- [`tencent.ts`](https://github.com/bistutu/fluentread/blob/main/tencent.ts) – 腾讯云翻译
- [`hunyuan-translation.ts`](https://github.com/bistutu/fluentread/blob/main/hunyuan-translation.ts) – 腾讯混元大模型翻译
- [`openai.ts`](https://github.com/bistutu/fluentread/blob/main/openai.ts), [`gemini.ts`](https://github.com/bistutu/fluentread/blob/main/gemini.ts), [`claude.ts`](https://github.com/bistutu/fluentread/blob/main/claude.ts) – AI-based translation services

### Standardized Function Signature

Every engine module exports a default async function with a consistent signature. This standardization allows the central registry to invoke any service interchangeably.

```typescript
// entrypoints/service/youdao.ts (example pattern)
export default async function youdao(message: any): Promise<string> {
  // Extract text and context from message
  const { origin, context } = message;
  
  // Perform API call with config from utils/config.ts
  const response = await fetch(apiUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ q: origin, from: config.from, to: config.to })
  });
  
  // Parse and return translated text
  const data = await response.json();
  return data.translation[0];
}

```

## Central Service Registry in [`_service.ts`](https://github.com/bistutu/fluentread/blob/main/_service.ts)

The [`entrypoints/service/_service.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/service/_service.ts) file acts as the central dispatcher. It imports all engine modules and exports a `ServiceMap` object that maps service identifiers to their implementations.

```typescript
// entrypoints/service/_service.ts
import microsoft from './microsoft';
import youdao from './youdao';
import deepl from './deepl';
import google from './google';
// ... other imports

export const _service = {
  [services.microsoft]: microsoft,
  [services.youdao]: youdao,
  [services.deepl]: deepl,
  [services.google]: google,
  // ... other mappings
};

```

The `services` constants are defined in [`entrypoints/utils/option.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/option.ts), ensuring type safety across the codebase. This registry pattern allows the background script to look up and invoke the correct engine dynamically based on user configuration.

## Request Flow from UI to Translation Engine

Understanding the file structure requires seeing how data flows through the system:

1. **UI Layer**: Components call `translateText()` from [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts)
2. **Queue Management**: [`translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/translateApi.ts) uses [`entrypoints/utils/translateQueue.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateQueue.ts) to limit concurrent requests (default: 6 parallel translations)
3. **Background Script**: The queued task sends a `runtime.sendMessage` to [`entrypoints/background.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/background.ts)
4. **Service Dispatch**: [`background.ts`](https://github.com/bistutu/fluentread/blob/main/background.ts) retrieves the current `config.service` value and executes `_service[config.service](message)`
5. **Engine Execution**: The specific module in `entrypoints/service/` performs the HTTP request and returns the translated string

## Adding a New Translation Service

To implement a new provider, modify only two files:

**Step 1**: Create the engine file in `entrypoints/service/`

```typescript
// entrypoints/service/libreTranslate.ts
import { config } from "@/entrypoints/utils/config";

export default async function libreTranslate(message: any): Promise<string> {
  const url = config.proxy[config.service] || "https://libretranslate.com/translate";
  
  const resp = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      q: message.origin,
      source: config.from === "auto" ? "auto" : config.from,
      target: config.to,
      format: "html"
    })
  });
  
  if (!resp.ok) {
    throw new Error(`LibreTranslate failed: ${resp.status}`);
  }
  
  const result = await resp.json();
  return result.translatedText;
}

```

**Step 2**: Register in [`entrypoints/service/_service.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/service/_service.ts)

```typescript
import libreTranslate from "./libreTranslate";

export const _service = {
  // ... existing services
  [services.libreTranslate]: libreTranslate,
};

```

**Step 3** (Optional): Add the identifier to [`entrypoints/utils/option.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/option.ts) if not already present.

## Key Files in the Translation Architecture

| File | Purpose |
|------|---------|
| `entrypoints/service/` | Directory containing one module per translation engine (e.g., [`microsoft.ts`](https://github.com/bistutu/fluentread/blob/main/microsoft.ts), [`youdao.ts`](https://github.com/bistutu/fluentread/blob/main/youdao.ts), [`deepl.ts`](https://github.com/bistutu/fluentread/blob/main/deepl.ts)) |
| [`entrypoints/service/_service.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/service/_service.ts) | Central registry mapping service identifiers to implementation functions |
| [`entrypoints/utils/option.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/option.ts) | Defines `services` constants and helper predicates (`isMachine`, `isAI`) |
| [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts) | Public API for UI components; handles caching, retries, and queueing |
| [`entrypoints/utils/translateQueue.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateQueue.ts) | Concurrency controller limiting parallel translation requests |
| [`entrypoints/background.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/background.ts) | Message broker that dispatches requests to the appropriate service module |
| [`entrypoints/utils/config.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/config.ts) | Runtime configuration store (selected service, API keys, language pairs) |

## Summary

- **FluentRead** uses a modular file structure where each translation service is isolated in its own file under `entrypoints/service/`.
- The **[`_service.ts`](https://github.com/bistutu/fluentread/blob/main/_service.ts)** registry acts as a central dispatcher, mapping service identifiers to engine implementations.
- Adding a new provider requires creating a single file in `entrypoints/service/` and registering it in [`_service.ts`](https://github.com/bistutu/fluentread/blob/main/_service.ts).
- The architecture separates concerns: UI components use [`translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/translateApi.ts), queue management handles concurrency, and [`background.ts`](https://github.com/bistutu/fluentread/blob/main/background.ts) routes requests to the specific engine.
- This design makes the codebase **extensible**, **testable**, and **maintainable** for contributors adding new translation providers.

## Frequently Asked Questions

### Where are translation services implemented in FluentRead?

All translation engines are implemented as individual TypeScript modules in the `entrypoints/service/` directory. Each file (such as [`microsoft.ts`](https://github.com/bistutu/fluentread/blob/main/microsoft.ts), [`youdao.ts`](https://github.com/bistutu/fluentread/blob/main/youdao.ts), or [`deepl.ts`](https://github.com/bistutu/fluentread/blob/main/deepl.ts)) exports a single async function that handles the HTTP communication with that specific provider's API.

### How do I add a new translation service to FluentRead?

To add a new service, create a new file in `entrypoints/service/` that exports a default async function receiving a message object and returning a translated string. Then import and register this function in [`entrypoints/service/_service.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/service/_service.ts) by adding it to the `_service` map using the appropriate service identifier from [`utils/option.ts`](https://github.com/bistutu/fluentread/blob/main/utils/option.ts).

### What is the role of [`_service.ts`](https://github.com/bistutu/fluentread/blob/main/_service.ts) in FluentRead's translation architecture?

The [`entrypoints/service/_service.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/service/_service.ts) file serves as the central registry that maps service identifiers (like `services.microsoft` or `services.youdao`) to their corresponding implementation functions. When the background script receives a translation request, it uses this map to dispatch the request to the correct engine module based on the user's current configuration.

### How does FluentRead handle concurrent translation requests?

FluentRead implements a concurrency controller in [`entrypoints/utils/translateQueue.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateQueue.ts) that limits the number of simultaneous translation requests (defaulting to 6 parallel translations). When UI components call `translateText()` from [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts), requests are enqueued and processed according to this limit, preventing rate limiting issues with external APIs and managing browser resource usage.