# How FluentRead Implements Translation Caching: A Deep Dive into the Browser Extension's LocalStorage Strategy

> Discover how FluentRead implements translation caching using browser localStorage to avoid redundant calls to remote translation services. Learn about its efficient strategy for faster translations.

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

---

**FluentRead stores every translation result in the browser's localStorage and retrieves it on subsequent requests, ensuring identical source texts are never sent to the remote translation service twice.**

FluentRead is an open-source browser extension developed by **bistutu/fluentread** that provides seamless webpage translation. To minimize network traffic and improve performance, the extension implements a robust **translation caching** mechanism using the browser's localStorage API. This article examines the complete caching architecture, from key generation to cache lifecycle management.

## How Translation Caching Works in FluentRead

The caching system operates through a deterministic key-value store where translation results are indexed by a composite key derived from the source text and translation configuration.

### Cache Key Generation

Before any translation occurs, FluentRead constructs a unique cache key in [`entrypoints/utils/cache.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/cache.ts) using the `buildKey` function. This key incorporates the current configuration—including translation style, service provider, model selection, target language, and the original message text—to ensure that changes in any parameter generate distinct cache entries.

```typescript
// entrypoints/utils/cache.ts
function buildKey(message: string) {
    const { service, model, to, style, customModel } = config;
    const selectedModel = model[service] === customModelString
        ? customModel[service] : model[service];
    // prefix_style_service_model_to_message
    return [prefix, style, service, selectedModel, to, message].join('_');
}

```

The key format follows the pattern `prefix_style_service_model_to_message`, guaranteeing that a translation of "Hello" to Spanish using GPT-4 receives a different cache entry than the same text translated to French or using a different model.

### Reading from the Cache

When the `translateText` function in [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts) receives a translation request, it first queries the cache using `cache.localGet(origin)` at line 40. If a cached result exists and the `config.useCache` flag is enabled, the function returns the stored translation immediately without invoking the remote API.

```typescript
// entrypoints/utils/translateApi.ts
const cachedResult = cache.localGet(origin);   // ← line 40
if (cachedResult) return cachedResult;

```

If caching is disabled via user configuration, the lookup is bypassed and always returns `null`, forcing a fresh translation request.

### Writing Translation Results

After successfully retrieving a translation from the remote service, the result is persisted to localStorage if caching is enabled. The `cache.localSet(origin, result)` call at line 74 in [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts) stores the mapping between source text and translated content.

```typescript
// entrypoints/utils/translateApi.ts
if (useCache) {
    cache.localSet(origin, result);            // ← line 74
}

```

This write operation ensures that subsequent identical requests will hit the cache rather than the network.

## Cache Lifecycle Management

FluentRead provides several mechanisms to manage cache size and freshness, preventing unbounded localStorage growth and allowing users to clear stale data.

### Automatic Cleanup with cache.cleaner()

The `cache.cleaner()` function runs automatically once every 24 hours or on page load to remove expired entries. It identifies stale cache items by checking host-specific timestamps and purges entries that exceed the retention period. This background maintenance ensures the cache does not accumulate obsolete translations indefinitely.

### Manual Cache Clearing

Users can invoke `cache.clean()` to immediately remove **all** cached translations associated with the current site. This function deletes every localStorage key that starts with the internal prefix `flcache_`, effectively resetting the translation history for the domain.

```typescript
import { cache } from '@/entrypoints/utils/cache';

// Remove all cached translations for the current site
cache.clean();

```

### Bidirectional Mappings with localSetDual()

For advanced use cases requiring reverse lookups, FluentRead offers `cache.localSetDual()`. This method stores both "source → translation" and "translation → source" mappings simultaneously, enabling applications to retrieve the original text when given a translated string.

```typescript
import { cache } from '@/entrypoints/utils/cache';

// Store both directions for reverse lookups
cache.localSetDual('你好', 'Hello');
const original = cache.localGet('Hello'); // → '你好'

```

## DOM-Level Translation Caching

When FluentRead processes webpage content, it leverages the same caching infrastructure at the DOM level. The translation routine in [`entrypoints/main/trans.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/main/trans.ts) checks for cached text node content before invoking the translation pipeline.

At line 213, the code queries the cache using the node's text content as the lookup key:

```typescript
// entrypoints/main/trans.ts
let cached = cache.localGet(node.textContent);   // ← line 213
if (cached) bilingualAppendChild(node, cached);

```

If a cached translation exists, the extension immediately appends the translated text to the DOM using `bilingualAppendChild`, bypassing the network request entirely. This optimization significantly improves performance when users revisit pages or navigate back to previously translated content.

## Configuration and Usage Examples

FluentRead exposes the translation caching behavior through the `config.useCache` flag, which users can toggle in the extension settings. When disabled, the extension operates in "fresh translation" mode, bypassing all cache reads and writes.

### Basic Translation with Automatic Caching

```typescript
import { translateText } from '@/entrypoints/utils/translateApi';

// First call hits the remote service and stores the result
const english = await translateText('你好世界');   // → 'Hello World'

// Second call retrieves the cached value instantly
const englishAgain = await translateText('你好世界'); // → 'Hello World' (from localStorage)

```

### Clearing the Translation Cache

```typescript
import { cache } from '@/entrypoints/utils/cache';

// Remove all cached translations for the current site
cache.clean();

```

### Using Bidirectional Cache Mappings

```typescript
import { cache } from '@/entrypoints/utils/cache';

// Store both directions for reverse lookups
cache.localSetDual('你好', 'Hello');
const reverseLookup = cache.localGet('Hello'); // → '你好'

```

## Summary

FluentRead implements a robust **translation caching** system using the browser's localStorage API to eliminate redundant network requests. The architecture centers on deterministic cache key generation that incorporates translation configuration parameters, ensuring accurate cache hits only when service settings match. Key implementation files include [`entrypoints/utils/cache.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/cache.ts) for core storage operations, [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts) for cache-aware translation orchestration, and [`entrypoints/main/trans.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/main/trans.ts) for DOM-level cache utilization. The system provides automatic cleanup mechanisms, manual clearing capabilities, and optional bidirectional mappings for advanced use cases, all controllable via the `config.useCache` configuration flag.

## Frequently Asked Questions

### How does FluentRead generate cache keys for translations?

FluentRead generates deterministic cache keys by concatenating the translation configuration—including style, service provider, selected model, target language, and the original message text—into a single string separated by underscores. This approach, implemented in the `buildKey` function within [`entrypoints/utils/cache.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/cache.ts), ensures that any change in translation parameters creates a distinct cache entry, preventing incorrect cache hits when users switch languages or models.

### Can users disable translation caching in FluentRead?

Yes, users can disable translation caching through the `config.useCache` configuration flag available in the extension settings. When this flag is set to false, the `translateText` function in [`entrypoints/utils/translateApi.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/translateApi.ts) bypasses all cache read and write operations, forcing every translation request to hit the remote service regardless of whether identical text has been translated previously.

### How does FluentRead prevent the translation cache from growing indefinitely?

FluentRead implements automatic cache cleanup through the `cache.cleaner()` function, which executes once every 24 hours or on page load to remove expired entries based on host-specific timestamps. Additionally, users can manually invoke `cache.clean()` to immediately purge all cached translations for the current site by deleting every localStorage key prefixed with `flcache_`, effectively preventing unbounded storage growth.

### What is the purpose of bidirectional caching in FluentRead?

The `cache.localSetDual()` method stores both "source → translation" and "translation → source" mappings simultaneously, enabling reverse lookups where the original text can be retrieved from its translated counterpart. This functionality supports advanced use cases such as reverting translations or identifying source material from translated content, though it consumes twice the storage space per entry compared to unidirectional caching.