
Engineering · Research note
How does a piece of text become a reliable webpage translation?
From DOM extraction and shared scheduling to output validation and safe writeback: 18 diagrams explain the architecture, data flows and design trade-offs of the Browser Script Manager translation system.
On this page
The engineering core of this translation system turns a constantly changing webpage into work that is schedulable, reusable, and writable back after identity checks. The translation service produces the text; the extension makes sure the result appears in the right place at the right time.
Follow a source passage through the entire system
Browser Script Manager combines translation and other features in a single Manifest V3 extension. The following traces the default translation flow for webpage paragraphs: each arrow identifies the data it carries, and each box's swimlane indicates its execution boundary. The next section covers how the selected-text and Translation Center entry points differ.
Version data
Candidates
or source text /
blocked status
update
Confirm termination after the adapter returns
Report failure status separately
Requeue only when policy permits
Translation content
recheck
renderable translation
Enter the persistence queue in normal mode
status update
write to memory
Read each data flow as text
- 01 Extract source text and declare segments → 02 Receive and establish demand identity: source segments; version data
- 02 Receive and establish demand identity → 03 Rules, shared work, and local lookups: page binding + source text
- C Freeze document-context candidates → 03 Rules, shared work, and local lookups: context; candidates
- C Freeze document-context candidates → 01 Extract source text and declare segments: release the first segments after freezing and confirming the connection
- 03 Rules, shared work, and local lookups → 07 Send status and result notifications: local result; or source text /; blocked status
- 03 Rules, shared work, and local lookups → 04 Schedule, batch, and reserve quota: local miss, with external sending permitted
- V Update reading position → 04 Schedule, batch, and reserve quota: reading position; update
- 04 Schedule, batch, and reserve quota → 05 Call the translation service: API request
- 05 Call the translation service → 06 Termination checks and result validation: raw response / usage; confirm termination after the adapter returns
- 06 Termination checks and result validation → 07 Send status and result notifications: valid segments → translation available; report failure status separately
- 06 Termination checks and result validation → 04 Schedule, batch, and reserve quota: failed items / items needing repair; requeue only when policy permits
- 07 Send status and result notifications → 08 Check versions and assemble the whole paragraph: version status; translation content
- 08 Check versions and assemble the whole paragraph → 09 Schedule and commit the DOM: whole-paragraph text result
- G Retain the current source identity → 09 Schedule and commit the DOM: current source; recheck
- 06 Termination checks and result validation → 10 Local translation memory and persistence status: valid and still applicable; renderable translation; enter the persistence queue in normal mode
- 10 Local translation memory and persistence status → 07 Send status and result notifications: local persistence operation; status update
- 10 Local translation memory and persistence status → 11 Cloud synchronization storage: encrypted upload
- 11 Cloud synchronization storage → 10 Local translation memory and persistence status: decrypt and merge; write to memory
Expand Figure 01B — Local decisions, lookup failures, and the external-send gate, branch by branch
or disk write failed
reevaluate
Read each data flow as text
- D1 Apply rules and pinned translations first → P Return local status / result: local handling
- D1 Apply rules and pinned translations first → D2 Does shared work with the same semantic key exist?: translation needed
- D2 Does shared work with the same semantic key exist? → P Subscribe to existing shared work: already exists
- D2 Does shared work with the same semantic key exist? → D3 Look up persisted translation memory: new shared work: register before lookup
- D3 Look up persisted translation memory → P A persisted translation already exists: hit
- D3 Look up persisted translation memory → E Failed to read a saved translation: read failure
- E Failed to read a saved translation → D3 Look up persisted translation memory: retry reading
- D3 Look up persisted translation memory → D4 Look up the legacy translation cache: confirmed miss
- D4 Look up the legacy translation cache → P Reuse the old translation and upgrade its storage: hit
- D4 Look up the legacy translation cache → D5 Decide whether to send externally only after a confirmed miss: miss / read failure / no legacy key
- D5 Decide whether to send externally only after a confirmed miss → P Three no-dispatch exits: no dispatch
- D5 Decide whether to send externally only after a confirmed miss → D6 Prioritize and batch, then approve a request attempt: external sending permitted; enter the dispatch queue
- D6 Prioritize and batch, then approve a request attempt → W Wait / block; do not send an API request: not yet ready; or disk write failed
- W Wait / block; do not send an API request → D6 Prioritize and batch, then approve a request attempt: conditions recover; reevaluate
- D6 Prioritize and batch, then approve a request attempt → T Start the translation-service adapter: conservative debit committed
Why account for service worker restarts?
Chrome's extension service worker is event-driven and may terminate while idle; ordinary JavaScript globals are not automatically saved. This project therefore writes translation memory and quotas to IndexedDB and lets pages redeclare active demands after reconnecting. This is lifecycle design, not a claim that the worker never stops.
Platform reference: Official Chrome documentation: service worker lifecycle (accessed 2026-10-25).
Different entry points share different parts
Translation entry points share background resources and dispatch-approval mechanisms. Page batches, selected-text streams, and the Translation Center still retain their own output behavior.
| Entry point | How it enters the system | Current presentation behavior |
|---|---|---|
| Webpage paragraphs | Paragraph → sentence units → shared translation flow | Wait for the final result, then update the screen only after confirming it still applies; no incremental temporary previews |
| Document title | Independent text unit, assigned the priority of content near the visible area | Manage only the top-level document; use request versions to prevent stale results from overwriting new titles |
| Subtitles | Independent text unit, assigned the priority of visible content | Return completed segments to the subtitle-rendering flow |
| Selected text · LLM | Background text streaming; shared resource and quota approval | Accumulated plain text can update the screen continuously, unlike page-batch response parsing |
| Translation Center | Look up translation memory, then issue translation requests as needed | Update cards after receiving the full response; use request identity to isolate cancellations and stale responses |
First distinguish position, work, and requests
A page binding records a demand on the screen; shared work represents a reusable translation task; a request attempt is one operation against a particular translation resource.
Scroll wide diagrams horizontally; text is selectable.
How do two identical demands arriving together avoid duplicate sends?
The background scheduler indexes the “lookup in progress” work before the first asynchronous memory lookup. Later page demands subscribe to the same work; even if the earlier lookup has not returned, no identical task is created. This allows duplicate demands to merge even during asynchronous lookups.
Extract identifiable source text, not a bundle of HTML
Scroll wide diagrams horizontally.
Identify paragraphs first
Traverse using the DOM, display types, and exclusion rules, skipping the tool's own output, hidden content, and pronunciation annotations.
Then split into sentences
Use the browser's text-segmentation capability; above 2000 UTF-16 units, look for clause punctuation first, then grapheme boundaries.
Finally, retain identity
Each segment retains its original range, segment order, and source version; rebuild text units after the source changes.
Why must UTF-16, visible characters, and tokens stay distinct?
UTF-16 code units are the units used for JavaScript string length; an emoji may occupy several units, and multiple Unicode code points may form one visible character. A grapheme describes a grouping of these visible text units; tokens are determined by a model's tokenizer.
The default 2000 is the string-length limit per text unit. If a single grapheme exceeds it, the input is reported as too large. Without browser text-segmentation support, the fallback processes code points individually and cannot guarantee complete grouping of compound visible characters.
Short segments also use a local heuristic: after removing noise such as URLs, a single Latin-alphabet word may be skipped, while short segments containing Chinese, Japanese, or Korean text can be retained. This reduces fragmented requests but may miss meaningful words. Selected-text translation does not use the same short-text threshold as page translation.
Further reading: Browser text segmentation.
Serve the current reading position first, then preload ahead
The page knows “where the source text is”; the background decides “which passage is worth translating now.” The preload region changes with reading direction and speed, while scheduling priorities are compared across pages.
Region illustration; lengths are not drawn to scale in screen pixels
Reading: 3 viewport heights ahead; paragraph registration extends 0.5 viewport heights beyond translation.
JavaScript disabled: the static example above uses Reading, Down, height 800px, and margin 1000px.
Expand preload formulas and scrolling algorithm
When the configured margin is ≤0, both sides return 0. Swap the upper and lower ranges when reading upward. Scroll speed is smoothed with an EMA: α=1−exp(−dt/200), new speed = old speed + (instantaneous speed − old speed) × α. dt is in ms, and instantaneous speed is in px/s; at intervals of 400ms or more, use the new sample directly.
A direction change requires accumulated reverse movement of max(120px, 0.35H). Forward speed of 2.5 viewport/s can trigger fast-scanning mode for 2 seconds. These thresholds reduce observation-region rebuilds caused by small backward movements; they are engineering heuristics, not a model of reading intent.
Scheduling example: 1 concurrency slot, single-item requests; P1 is focused, and each of three pages has 3 visible passages
Rules first decide what may be translated, then protect key terms
Search for multiple phrases in one pass
Include overlapping matches
Then compare rule specificity and identifier
Obtain a stable selection order
Convert to ⟦n⟧ placeholders
Do not scan replaced content again
Term-protection example; model reply is illustrative
Sent to the model
Reply and restore
→ The Rust Belt uses the Rust language.
Rule precedence and Aho–Corasick's precise role
Handle whole-page disabling first, followed by whole-sentence keep-source / fixed translations, user-pinned translations, and no-external-send rules; only then replace phrases with placeholders. Banning external sending still permits locally saved translations to appear.
Aho–Corasick finds multiple phrases; “leftmost, longest” emerges from the subsequent sort and cursor-based selection together. Scanning uses UTF-16 code units and does not understand natural-language word boundaries. The full process also includes match expansion and sorting, so its total cost cannot simply be written as O(n).
Matching supports arbitrary text, exact whole sentences, and literal phrases, but not arbitrary regular expressions. If compilation or matching fails, the system can fall back to a more direct reference scanner.
Context must stay stable and obey the same external-send rules
Translation configurations with document context enabled freeze candidate text before the first batch is sent. The background then selects eligible content under the current policy, preventing “paragraphs forbidden from translation” from being sent indirectly as context for other sentences.
At most 16 body-text blocks
Candidates total ≤6000 UTF-16 units
Total length at most 1500 UTF-16 units
Compute context fingerprint
Separate from the sentences to translate
Context provides background only and does not need its own translation output. Different contexts can produce different semantic keys.
Limitations remain
A bounded window at the beginning of a document does not guarantee coverage of the whole text; translation entry points also use different contexts.
Ask locally first: has this semantic contract already been translated?
Semantic key: which translation is this?
Page key: what should reopening a page restore?
Page keys manage restoration intent and page associations; semantic keys determine which translation corresponds to a source sentence.
| Data layer | Persistence strategy | Design trade-offs |
|---|---|---|
| Translation memory | No expiry or automatic eviction; defaults: 512 MiB counted content / 200,000 entries / 1 MiB per entry | Reject new writes when full to protect existing records. These figures exclude total IndexedDB index and additional storage overhead. |
| Legacy cache | Defaults: 30 days / 128 MiB; LRU eviction | A reconstructible cache with a retention strategy different from saved translations. |
| Rules / pinned translations | Persistent policy data | User-specified behavior, not an ordinary LRU cache. |
Which results can be reused after changing models or pages?
Page translation's semantic identity does not directly include the provider or model. With other semantic conditions unchanged, switching models can still hit an old result. Only “force retranslation” skips translation memory and the legacy cache, replacing memory under the same semantic key after successful result validation.
Selected-text translation and the Translation Center use their own entry-point contracts, and their translation configurations include the provider identifier. Thus, a provider A card in the Translation Center does not use a provider B card's results; changing the model within the same provider configuration preserves the existing identity.
Context, rules, and versions are also part of the semantic contract, with translations found by exact hash matching. Identical sentences on different pages can share results only when their other semantic conditions also match; merely similar text does not automatically hit.
Batching saves requests; dispatch approval protects resources and quotas
Candidate work is ordered by reading demand first, then an available translation resource is selected, and finally the system tries to form a batch. Larger batches combine more work; visible content uses smaller thresholds so the first results need not wait for too many sentences.
Use the smaller of the user setting and the visible-content threshold
Combine according to the translation flow's batch settings
Items in a batch must be compatible
If multiple pages appear within the T1 / T3 candidate window, keep dispatches single-item to avoid skipping another page just to fill one page's batch. Work requiring individual repair is not batched either.
Scroll wide diagrams horizontally.
Concurrency
Check the whole system, an individual translation resource, and all relevant quota groups together. Their initial default limits are 16, 12, and 16 concurrent slots, respectively.
Send rate
Each translation resource's token bucket replenishes capacity for 8 requests per second by default, accumulating at most 16. It controls the start cadence, not a guarantee of 8 completions per second.
Time-window quotas
Check requests per minute, tokens per minute, and requests per day according to configuration. Record additional usage when actual usage is higher; do not automatically refund reservations when it is lower or unreported.
Algorithm: when to wait for time, and when to wait for events?
| Condition | Dispatch decision | Meaning |
|---|---|---|
| a > L | Block the demand | This demand itself exceeds the limit; waiting cannot make it fit unless the configuration changes. |
| D ≤ 0 | Pass this quota check | Concurrency, send-rate, and other quota checks must still pass. |
| 0 < D ≤ S | Wait until a specified time | Scan time buckets to find when enough debits will expire. |
| D > S | Wait for a state change | Even if all committed debits expire, pending reservations plus the new demand still exceed the limit. |
For one translation resource, use the latest time threshold; if slots must also be released or writes completed, wait for those events. Across candidate work items, find the earliest possible wakeup time. Fixed-capacity circular time buckets prevent memory from growing without bound with historical requests: 62 buckets of 1 second for the minute window; 1442 buckets of 60 seconds for the daily window.
A debit's time-bucket index is ceil(attribution time ÷ bucket duration), rounded upward. When creating a persistence snapshot, the attribution time of pending debits is set at least 1000ms beyond now; after the transaction completes, ensure it is not before the current time, using conservative expiry. The request token bucket uses integer counts: one request equals 1,000,000 microunits. This is unrelated to the tokens into which models split text.
Algorithm: resource selection, token estimation, and optional adaptation
When multiple translation resources are available, first compare “compatible demand within the candidate window ÷ available concurrency,” using a denominator of at least 1. Then compare load, routing priority, and stable resource-identifier order. This heuristic selects among resources for the current candidates; it does not solve for a globally optimal allocation.
This local estimate determines whether dispatch is allowed; it may differ from the provider's actual tokenization and cannot replace the account's remaining allowance. Page batches also include translation instructions and context in the estimate, so source character count alone cannot stand in for tokens-per-minute usage.
Adaptive concurrency is off by default. When enabled, the concurrency limit starts at half the hard limit, rounded up. When a successful response arrives and the statistics window has reached 20 seconds, check whether the previous window had at least 10 successes, pending work, and no congestion; only then add 1 slot. Capacity congestion halves the limit, at most once per adjustment cycle. Automatic fallback switching is also off by default and switches to other resources under eligible conditions only when explicitly enabled.
The model returns a data protocol; only validated output becomes a translation
Default page-batch translation maps each result using short identifiers. Output order may differ, but identifiers, translations, and placeholders must all pass validation. This separates “the entire response is invalid” from “only a few items need repair.”
Synthetic data example. The source language is auto-detected, the target is Traditional Chinese for Taiwan, and no extra context is supplied. Response order is deliberately reversed, but items still map one-to-one by identifier.
Translation items sent
| Item identifier | Source text |
|---|---|
| 1 | Hello. |
| 2 | Goodbye. |
Translation results received
| Item identifier | Translation |
|---|---|
| 2 | 再見。 |
| 1 | 你好。 |
→ renderable translation → final result
Blank / overly long translation / placeholder mismatch
→ retry individually later
Wrong version, invalid JSON, extra prose
→ reject the entire response
| Translation service | Actual network behavior | Response requirements |
|---|---|---|
| DeepSeek / OpenAI / Google | Low-level automatic resending is disabled: each operation issues at most 1 network request, with retries managed by the upper-level scheduler. Custom service URLs must still satisfy the corresponding service's connection rules. | Streamed text goes to the response parser and must conform to the structured data format. |
| Microsoft | Within one operation, obtain Edge authentication first, then send the translation request; each phase is limited to 1 network request, for at most 2 total. | Check the returned item count, restore the same item identifiers by original position, and convert to the unified format. |
Which tolerances are allowed? Which numbers are not token limits?
The parser permits a leading reasoning section enclosed in designated markers, and Markdown fences that enclose the entire response and are unlabeled or labeled JSON. Valid whitespace and reordered data fields are accepted too. It does not guess and extract JSON from arbitrary prose. Large streaming increments are processed in chunks of 32,768 UTF-16 units, preserving text, escape, and Unicode parsing state across chunks.
| Boundary | Default value | Measurement |
|---|---|---|
| Entire text response | 262,144 | 2 × UTF-16 length, including envelope text |
| Network data volume of the model response | 16 MiB | Text-response budget × 64, including SSE and JSON envelopes |
| Per-item translation | 24,000 | UTF-16 code units |
The product direction is “auto-detect source → Traditional Chinese for Taiwan.” Page translation and shared settings use different Traditional Chinese language tags; Microsoft additionally converts via an ISO language mapping table, falling back to a Traditional Chinese tag when no mapping is found. Integrations across services must handle these differences in language representation.
The system prompt asks the model to ignore instructions in the source and context, and to use plain text for translation content. This expresses the intended behavior but cannot guarantee elimination of prompt injection or translation errors. DeepSeek's thinking mode is off by default, and users may adjust it.
However quickly a result returns, first verify that the page is still the same
While translation runs, a dynamic webpage may change text, replace paragraphs, or navigate away, and the user may be selecting text. Background completion only means a candidate result is available; before actually updating webpage nodes, check the current source and interaction state.
Scroll wide diagrams horizontally.
Enough budget in this frame
→ update now
Retain only this paragraph's latest update plan
→ wait until protection no longer applies
Retain the update plan for now
→ recheck next frame
Time is checked only after each block update. The first block that exceeds budget but must update atomically may still commit alone. Thus, 4ms is a yield budget, not a hard maximum duration for every webpage update.
| Display mode | How source text is handled | How translations are written |
|---|---|---|
| Bilingual | Keep source text in place; if an old translation exists, replace it only when the new update plan commits. | Create nodes for the translation, then hand them to the rendering queue for updates. |
| Translation only | Temporarily retain the original node objects, then remove them from the page; restore by reinserting those same nodes. | The main path builds translations from text and line-break nodes; model text is not executed as HTML. |
Finer rendering strategies: coalescing, deferral, and avoiding unnecessary rewrites
The rendering-cadence controller coalesces arriving results and adjusts cadence using recent work duration: new cost estimate = 0.6 × old cost estimate + 0.4 × current duration; next interval = min(1000ms, 2 × new cost estimate). A 250ms timer provides a fallback when the browser's animation-frame callback has not arrived. This tracks work duration, not the full cost of browser layout and painting.
Retain only the latest pending update plan per block, with at most 128 deferred plans. Beyond that, the system can record “refresh needed” markers, capped at 4096. Reconciliation after page changes coalesces into one in-progress job per paragraph plus one rerun-pending marker.
Rendering summaries use “text length + 32-bit FNV-1a hash” to decide whether rewriting can be skipped, unlike the background's SHA-256 semantic identity; different content can still have identical summaries. Multi-sentence translations are combined in original translation-unit order, with joins estimated from Chinese, Japanese, and Korean spacing rules rather than reproducing the original whitespace character for character.
Retaining the same original nodes helps preserve object relationships; event bindings, layout, and interaction behavior still depend on the website's own structure and update approach.
Being able to read a translation does not mean it is saved
Scroll wide diagrams horizontally.
How does the persistence queue bound memory?
| Area | Entry limit | Estimated byte limit |
|---|---|---|
| Main persistence queue | 32 | 16 MiB |
| Additional waiting area | 64 | 8 MiB |
| Content retained after persistence failure | 64 | 8 MiB |
Waiting content and content retained after persistence failure have a 10-minute retention period, checked and cleaned up during later queue operations or retries. Capacity is estimated as “source UTF-8 bytes + translation UTF-8 bytes × 2 + 1024,” which may differ from actual memory use. When full, the queue pauses new page-translation dispatches; requests already sent may finish.
This queue exists only in runtime memory. When the background service ends, content whose write has not completed is not automatically restored on restart. The diagram depicts page-translation persistence states; interactive entry points only enqueue persistence work and do not wait for the same complete on-screen state flow.
Cancellation revokes commit authority; retries need a clear reason
Scroll wide diagrams horizontally.
These are adjustable defaults. The normal page-retry policy defaults to 4 actual sends, including the first, with a cumulative execution-time budget of 180 seconds. Oversized multi-item batches also have a repair path that splits them into individually requeued items. Demands never attempted and only waiting off-screen are exempt from the normal 30-minute demand expiry.
| Failure | Handling | Why distinguish it? |
|---|---|---|
| HTTP 401 / ordinary 403 / 404 | Treat as authentication, permission, or model-configuration problems; block the relevant translation resource. | Blind retries will not fix configuration. |
| HTTP 429 · capacity-related | Set a cooldown for the limited resource or quota scope; keep work queued until the resource becomes available again. | Retry only after load drops. |
| HTTP 402 / 429 · billing or insufficient allowance | No further retries by default; allowance-related 403 responses belong here too. Forwarding to another resource remains possible if fallback switching is explicitly enabled and an available resource satisfies the independent-fallback conditions. | Billing / account-allowance problems are not transient congestion. |
| HTTP 408 / 409 / 425 / 5xx | Treat as temporary server failures that may be retried. | May recover over time, still subject to attempt and budget limits. |
| HTTP 413 / oversized input | Split multi-item batches into individual retries; block the work if a single item remains too large. | An oversized batch does not mean every item is untranslatable individually. |
Retry timing, wakeups, and clock jumps
Delayed retries for ordinary work use full jitter: choose a random delay between zero and the upper wait bound each time. Capacity-related HTTP 429 instead sets a cooldown for the limited resource or quota scope, using the server-specified wait time, or the base delay if none is provided, without random jitter.
Jitter spreads out retries; the response header Retry-After adds a lower time bound, accepting seconds or an HTTP date and accounting for server clock differences. Server-requested waits are retained for at most 7 days.
Wakeup scheduling is coalesced into one timer for the earliest deadline; when the expected wait is at least 30 seconds, a browser background alarm supplements it. Clock checks compare elapsed system time with elapsed monotonic time: a difference over 5 seconds, or a system-clock rollback over 5 seconds, pauses new dispatches. Conservative recovery occurs only after 2 stable seconds without another anomaly.
The cancellation diagram describes network attempts already sent. Attempts with reserved slots but not yet sent may end and release their slots first; if an ongoing debit transaction later commits successfully, that conservative debit remains even if the service was never called. Network operations whose termination cannot be confirmed quarantine the relevant resources and retain their slots until a late termination notice arrives. Restarting the background service establishes a new execution generation: old requests no longer occupy concurrency slots, but the known quota ledger is retained.
“Local first” must still explain where data goes
Source units / document context sent to the background
Receive versioned status and result notifications
The same record includes page associations
Page-restoration intent is saved separately
Separate from page-visible settings
No additional local application-layer encryption
LLMs may also receive eligible context
Return according to each service's protocol
Encrypted by the shared sync service before upload
Sync return path writes to local memory
Settings exposed to the page remove API keys, request headers, and provider options; settings sync also excludes those fields, transmitting only settings allowed for synchronization.
| Mechanism | Actual behavior | Boundaries to retain |
|---|---|---|
| No external sending | Prohibit sending that work to translation services; locally saved translations may still be looked up. | Context candidates must also pass policy checks; translation-memory sync is handled separately according to the user's opt-in. |
| Incognito | Do not look up, save, or sync translation memory for that incognito work. | Dispatch and quota metadata without text content is still saved. |
| Translation network requests | Omit browser credentials, reject redirects, and restrict destination origins; remote connections use HTTPS. | Explicitly specified local / private-network hosts may use HTTP. |
| Sync encryption | Derive keys with HKDF-SHA-256 and encrypt sync data objects with AES-256-GCM. | Encryption protects sync content; local settings isolation remains a separate responsibility. |

Comments & discussion
Connecting to the comment service…