Tools
Geometric fragments flow from blank sheets through three prism gates and emerge rearranged, representing webpage translation, validation and writeback.

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.

01

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.

Figure 01AEnd-to-end data flow: how incoming source text returns as a translation in the right placeHTML nodes + explicit connections
Main path01 → 02 → 03; take 04 → 05 → 06 only after confirming that no usable translation exists.
Local bypassRule/memory results or blocked status go directly to 07.
Return-path split06 → 07 → 08 → 09 handles presentation; 06 → 10 handles persistence.
Webpage and page-side scriptsDOM and each page's lifecycle
Extension background / local dataCross-page work, policies, resources, and storage
External servicesTranslation APIs and optional synchronization
01Extract source text and declare segments
Extract text → register paragraphsSplit sentences while retaining source rangesSend text, version, and position dataDOM nodes remain on the webpage side
02Receive and establish demand identity
The background service receives and passes it to the schedulerVerify the source using the browser-provided senderCreate page bindings and normalize source textTrack segment versions and lifecycles
CFreeze document-context candidates
Read baseline source text from the beginning of the documentFreeze the first set of candidates; send a separate context messageUsable only after background rules are applied
03Rules, shared work, and local lookups
Rules / pinned translations → share identical workSaved translation memory → legacy cacheSee 01B for hit / miss / error branches
VUpdate reading position
Observe the visible area and scroll directionReport visibility, position, and ahead/behind informationAffect the priority of queued workThis update does not resend source text
04Schedule, batch, and reserve quota
Priority tier → service resource → compatible batchDispatch approval: reserve concurrency slots and quotaCommit the quota's IndexedDB transaction firstStart the translation-service adapter only after success
05Call the translation service
Language model: instructions + source text + contextMicrosoft: source-text list + target languageThe service adapter assembles the actual requestReturn the raw response to the adapter first
GRetain the current source identity
Baseline source text and reading generationLocal request attempt and node connectivityRecheck when writing back to the DOM
06Termination checks and result validation
Check the request and generation, then release the concurrency slotRecheck commit authority / termination reasonValidate response format, numbering, and preservation markersPass errors / items needing repair to the retry policy
07Send status and result notifications
Version, renderable translation, and persistence statusSource text / local result / blocked / completeA completed segment does not mean the DOM has updated
08Check versions and assemble the whole paragraph
The page rejects stale notificationsWait for the whole paragraph according to rendering cadenceCombine translation and source text; report failures separately
09Schedule and commit the DOM
Build content fragments and a rendering planProtect selections + limit work per frameCheck the source text and local request before committingUpdate bilingual containers or translation-only text
10Local translation memory and persistence status
Local results: persistence queue → transactionSync backfill: write directly to translation memoryReport local persistence success / failureSync reads only persisted translation memory
11Cloud synchronization storage
Opt in to translation-memory syncReceive / provide encrypted data objectsDecrypt locally, merge, then write to memorySync does not directly update the webpage DOM
Source segments
Version data
Page binding + source text
Context
Candidates
Release the first segments after freezing and confirming the connection
Local result
or source text /
blocked status
Local miss, with external sending permitted
Reading position
update
API request
Raw response / usage
Confirm termination after the adapter returns
Valid segments → translation available
Report failure status separately
Failed items / items needing repair
Requeue only when policy permits
Version status
Translation content
Whole-paragraph text result
Current source
recheck
Valid and still applicable
renderable translation
Enter the persistence queue in normal mode
Local persistence operation
status update
Encrypted upload
Decrypt and merge
write to memory
Read each data flow as text
  1. 01 Extract source text and declare segments → 02 Receive and establish demand identity: source segments; version data
  2. 02 Receive and establish demand identity → 03 Rules, shared work, and local lookups: page binding + source text
  3. C Freeze document-context candidates → 03 Rules, shared work, and local lookups: context; candidates
  4. C Freeze document-context candidates → 01 Extract source text and declare segments: release the first segments after freezing and confirming the connection
  5. 03 Rules, shared work, and local lookups → 07 Send status and result notifications: local result; or source text /; blocked status
  6. 03 Rules, shared work, and local lookups → 04 Schedule, batch, and reserve quota: local miss, with external sending permitted
  7. V Update reading position → 04 Schedule, batch, and reserve quota: reading position; update
  8. 04 Schedule, batch, and reserve quota → 05 Call the translation service: API request
  9. 05 Call the translation service → 06 Termination checks and result validation: raw response / usage; confirm termination after the adapter returns
  10. 06 Termination checks and result validation → 07 Send status and result notifications: valid segments → translation available; report failure status separately
  11. 06 Termination checks and result validation → 04 Schedule, batch, and reserve quota: failed items / items needing repair; requeue only when policy permits
  12. 07 Send status and result notifications → 08 Check versions and assemble the whole paragraph: version status; translation content
  13. 08 Check versions and assemble the whole paragraph → 09 Schedule and commit the DOM: whole-paragraph text result
  14. G Retain the current source identity → 09 Schedule and commit the DOM: current source; recheck
  15. 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
  16. 10 Local translation memory and persistence status → 07 Send status and result notifications: local persistence operation; status update
  17. 10 Local translation memory and persistence status → 11 Cloud synchronization storage: encrypted upload
  18. 11 Cloud synchronization storage → 10 Local translation memory and persistence status: decrypt and merge; write to memory
Solid lines: main request / result pathLocal branches / status reportsDashed lines: auxiliary updates / optional sync
How to read the diagram: Persistence and DOM commit branch from valid results, with no fixed completion order. Document context is frozen before the first source-text demands are sent; reading-position updates carry only visibility and position. The diagram shows data dependencies, not a time scale; crossing lines without a junction do not indicate a merge.
Two key exits: 07 emits versioned status and result notifications; after segments finish, whole-paragraph assembly and DOM commit are still required. 10 handles local persistence, and failed writes retry only through the persistence queue. The sync return path at 11 writes to local translation memory, which later becomes available through normal lookups.
Expand Figure 01B — Local decisions, lookup failures, and the external-send gate, branch by branch
Figure 01BBackground decision flow: which demands actually call the translation service?HTML branching diagram
Read the main path downwardD1 → D2 → D3 → D4 → D5 → D6 → T.
Read exits to the rightP returns to overview 07; E is a read failure; W is waiting / blocked.
D1Apply rules and pinned translations first
Disable page / keep source / fixed translation / pinned translationFor text needing translation, establish semantic conditions and preservation markersA ban on external sending still permits saved translations
PReturn local status / result
Disabled page → keep source textKeep source → local decision, without a translationFixed or pinned translation → local decision with a translationConnect to overview 07: status and result notifications
D2Does shared work with the same semantic key exist?
Yes: add a result subscriberNo: register shared work awaiting lookup firstThen begin the asynchronous translation-memory lookup
PSubscribe to existing shared work
It may be looking up, queued, translating, or completeReuse its status / subsequent resultsConnect to overview 07; do not create duplicate work
D3Look up persisted translation memory
Exact lookup by the full semantic keyHandle hits, misses, and read failures separatelyRead failures do not trigger external sending by default
PA persisted translation already exists
Renderable translation + persisted statusConnect to overview 07; do not call the translation service
EFailed to read a saved translation
Pause external sending: saved translations cannot be readRetry local reading firstContinue only after explicitly choosing to bypass the failure
D4Look up the legacy translation cache
Look up an exact record only if a corresponding legacy key existsMiss / read failure / no matching key → next gate
PReuse the old translation and upgrade its storage
Renderable translation + saving statusSend separately to the persistence queue to upgrade to the new translation memoryConnect to overview 07 + Overview 10
D5Decide whether to send externally only after a confirmed miss
Check no-external-send rules and document dispatch policyThen check whether eligible service resources existOnly permitted demands enter the dispatchable queue
PThree no-dispatch exits
External sending forbidden → block and report the reasonLocal translations only → keep source and retain the demandNo available service resource → block and prompt configurationKeep source text and report the corresponding status
D6Prioritize and batch, then approve a request attempt
Priority tier / service resource / compatible batchConcurrency slots + rate allowance + time-window quotaAfter successful reservation, persist the quota debit firstThe API request must wait until the disk write succeeds
WWait / block; do not send an API request
Quota or concurrency unavailable: wait for time / eventsThe demand itself exceeds limits: pause external sendingFailed to persist the debit: stop new dispatchesReevaluate when conditions recover
TStart the translation-service adapter
Connect to overview 05: actual network requestResponse validation / repair and presentation return to overview 06–10
Local handling
Translation needed
Already exists
New shared work: register before lookup
Hit
Read failure
Retry reading
Confirmed miss
Hit
Miss / read failure / no legacy key
No dispatch
External sending permitted; enter the dispatch queue
Not yet ready
or disk write failed
Conditions recover
reevaluate
Conservative debit committed
Read each data flow as text
  1. D1 Apply rules and pinned translations first → P Return local status / result: local handling
  2. D1 Apply rules and pinned translations first → D2 Does shared work with the same semantic key exist?: translation needed
  3. D2 Does shared work with the same semantic key exist? → P Subscribe to existing shared work: already exists
  4. D2 Does shared work with the same semantic key exist? → D3 Look up persisted translation memory: new shared work: register before lookup
  5. D3 Look up persisted translation memory → P A persisted translation already exists: hit
  6. D3 Look up persisted translation memory → E Failed to read a saved translation: read failure
  7. E Failed to read a saved translation → D3 Look up persisted translation memory: retry reading
  8. D3 Look up persisted translation memory → D4 Look up the legacy translation cache: confirmed miss
  9. D4 Look up the legacy translation cache → P Reuse the old translation and upgrade its storage: hit
  10. D4 Look up the legacy translation cache → D5 Decide whether to send externally only after a confirmed miss: miss / read failure / no legacy key
  11. D5 Decide whether to send externally only after a confirmed miss → P Three no-dispatch exits: no dispatch
  12. 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
  13. 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
  14. W Wait / block; do not send an API request → D6 Prioritize and batch, then approve a request attempt: conditions recover; reevaluate
  15. D6 Prioritize and batch, then approve a request attempt → T Start the translation-service adapter: conservative debit committed
How to read the diagram: On initial declaration, identical existing work is shared; new work is registered before lookup. A local-memory read failure is not treated as a missing record. Incognito mode or explicit retranslation may skip the memory lookup, but still require dispatch-policy and resource approval; this main path depicts the normal lookup route.
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).

02

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
Each entry point has its own retry strategy: Automatic service switching for page translation is off by default; selected-text translation also has an “LLM returns an empty string → try an enabled standard translator” fallback, plus up to 2 additional retries (waiting 800 / 1600ms).
03

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.

Figure 02Three identities, three lifecyclesSVG architecture diagram
Three lifecycle layers: page bindings, shared work, and request attempts Two page bindings share work ①; compatible work can be included in a single request attempt. This is a conceptual example; batching must still satisfy document and other constraints. Page demands Semantically identical work One network attempt Page binding A1 A source passage on page A Position, source version, subscription Page binding B1 The same semantic demand on page B With its own DOM / version Shared work ① The same semantic key Shared result and retry lifecycle Shared work ② Another compatible work item Request attempt α Service resource + quota reservation Included work: ①, ② Background generation / termination state Deduplication: share only identical semantic contracts Batching: document, context, priority tier, and service resource must be compatible Different page bindings for the same text do not imply two API calls. Canceling one subscription need not cancel the others.

Scroll wide diagrams horizontally; text is selectable.

Why this matters: Duplicate demands can share results, and retries need not recreate DOM identity. Leaving one page need not cancel work that another page still needs. The batching shown is only conceptual and still requires compatibility checks.
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.

04

Extract identifiable source text, not a bundle of HTML

Figure 03One DOM, two reading responsibilitiesSVG · synthetic example
Two DOM-reading responsibilities and sentence-split positions DOM reading branches into source-identity checking and translation-request text, each reading the source text it needs. The UTF-16 ranges of the Hello and Goodbye sentences are [0,6) and [7,15). Original DOM · synthetic example 漢(かん)字: includes a reading annotation + translation container added by the tool DOM identity remains on the webpage side Source checking / document context Read baseline source text: 漢字 (in this example) Exclude readings and tool output; use source text from OCR / reading annotations Translation-request text Extract translatable text → split sentences Background normalization: CRLF → LF, NFC, trim whitespace Another sentence-splitting example: Hello. Goodbye. Source block Hello. Goodbye. Record original UTF-16 positions Segment 1 Hello. Range: [0, 6) Segment 2 Goodbye. Range: [7, 15) Split sentences The two DOM-reading paths have different responsibilities; sentence ranges still refer to the original source, and normalization does not rewrite source positions.

Scroll wide diagrams horizontally.

One path extracts text to translate and splits it into sentences; the other reads a consistent representation of the source to check identity and establish document context. Both paths avoid treating system-generated translations as new source text.

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.

05

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.

Figure 04Change the reading state to see how the preload region changesInteractive formula illustration · not a performance measurement
Above · behind the reading direction400 px
Current viewport — visible text firstViewport height H = 800 px
Below · ahead in the reading direction2400 px

Region illustration; lengths are not drawn to scale in screen pixels

Translation range ahead2400 px
Paragraph-registration range ahead2800 px
Range behind400 px

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.

Why this matters: Declare soon-to-be-read paragraphs to the background first; slow reading and fast scrolling use different ranges. Setting the preload margin to 0 disables preloading both ahead and behind.
Expand preload formulas and scrolling algorithm
Ahead range = min(10000, max(configured margin, round((multiplier + lead) × H))) Behind range = min(configured margin, round(0.5 × H)) Multiplier: not yet scrolled 1.5 / reading 3 / fast scanning 5 Lead: translation region 0 / paragraph-registration region 0.5

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.

Figure 05Scheduling priority: from on-screen demand to cross-page fairnessHTML ordering diagram
T0
Focused page · visiblePrioritize the content in front of the user
T1
Other pages · visibleDispatch round-robin across pages within the same tier
T2
Focused page · near the visible areaAhead in the reading direction first, then document order
T3
Other dispatchable demandsDispatch round-robin across pages; do not dispatch content explicitly outside the range

Scheduling example: 1 concurrency slot, single-item requests; P1 is focused, and each of three pages has 3 visible passages

P1.1P1.2P1.3P2.1P3.1P2.2P3.2P2.3P3.3
Why this matters: Changing focus reorders work not yet sent; normally running requests are not preempted. Round-robin dispatch improves fairness within a tier, but lower-priority tiers may still wait.
Read positions before updating the screen: The page first reads paragraph positions in a batch, then inserts placeholders. Later translation processing reuses position data supplied by the visibility observer, reducing interleaved layout reads and DOM writes.
06

Rules first decide what may be translated, then protect key terms

Figure 06Glossary: find matches first, then choose replacementsHTML algorithm diagram
1 · Find all candidatesAho–Corasick trie
Search for multiple phrases in one pass
Include overlapping matches
2 · SortLeftmost → longest → priority
Then compare rule specificity and identifier
Obtain a stable selection order
3 · Select non-overlapping phrasesAdvance the cursor in one direction
Convert to ⟦n⟧ placeholders
Do not scan replaced content again

Term-protection example; model reply is illustrative

The Rust Belt uses Rust.
At the same start position, choose the longer phrase first; a shorter term cannot displace Rust Belt even with higher priority

Sent to the model

The ⟦1⟧ uses ⟦2⟧.

Reply and restore

⟦1⟧ uses ⟦2⟧.
→ The Rust Belt uses the Rust language.
Why this matters: Turn controlled terms into verifiable preservation markers. Each placeholder must appear exactly once; missing, duplicate, or model-invented markers cannot go straight to the screen.
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.

07

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.

Figure 07From document candidates to bounded translation contextHTML data flow
First document candidates50ms quiet period / maximum 200ms capture window
At most 16 body-text blocks
Candidates total ≤6000 UTF-16 units
Apply policy in the backgroundExclude candidates marked no-external-send, keep-source, fixed-translation, pinned-translation-only, or protected by placeholders
Final document contextEligible title + first 8 eligible body-text blocks
Total length at most 1500 UTF-16 units
Compute context fingerprint
Why freeze candidates: the same snapshot does not change with message batching, reconnection order, or where scrolling starts

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.

Why this matters: A stable snapshot supports reusable semantic identity; policy checks must also cover background text that is “sent indirectly.”
08

Ask locally first: has this semantic contract already been translated?

Figure 08Local first, with read errors distinguished from missing recordsHTML decision diagram
01
Rules and pinned translations
Fixed results / keeping source text can be decided locally
02
Persisted translation memory
Hit → use directly; read failure → stop external sending by default
03
Legacy exact-match cache
Hit → use it and try upgrading its storage
04
Confirm no record exists before checking dispatch policy
External sending permitted → resource approval; local only → keep source

Semantic key: which translation is this?

Normalized source textTranslation entry pointSource / target languageTranslation configurationPrompt versionGlossary versionContext fingerprintRule fingerprintOutput contractPrivacy partition
Consistent data representation → SHA-256 → semantic key

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.

Why this matters: “Cannot read a saved translation” and “no translation ever existed” are different states. A temporary read failure does not automatically mean consent to resend the source externally and pay for another translation.
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.

09

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.

Figure 09Two batch thresholds, the same compatibility checksHTML condition diagram
Visible content · T0 / T1Batch-extension threshold: at most 3 items / 900 UTF-16 units
Use the smaller of the user setting and the visible-content threshold
Other dispatchable contentInitial defaults: 8 items / 2400 UTF-16 units
Combine according to the translation flow's batch settings
Append in candidate order; stop expanding when the next item is incompatible

Items in a batch must be compatible

Document and page connectionPriority tierTranslation configurationContextPrivacy partitionTranslation resourcetoken quota

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.

Why this matters: Throughput must be balanced against time to first result, and batching must not bypass fairness. Batch thresholds limit aggregation size; actual speed and cost still depend on content and service responses.
900 is not an absolute character limit per request: The first item enters the batch before total length is checked when appending others. A single sentence-split translation unit may exceed 900; prompts and context are not included in this source-text length either. UTF-16 code units, model tokens, and network bytes are three different measures.
Figure 10Concurrency slots and quota ledgers: two distinct lifecyclesSVG lifecycle diagram
Manage concurrency slots separately from quota ledgers Dispatch approval checks concurrency slots, rate allowance, and quota groups together, persisting before the API call. Release the concurrency slot after confirming network-request termination; committed conservative debits remain until the time window expires, while rate allowance replenishes at its own rate. One API request attempt Requires a concurrency slot Requires request / token allowance Concurrency slots Global / service resource / quota group Reservations or network requests not yet terminated Time-window quota ledger Windowed request / token counts Record conservative time-window debits Approve together Commit the IndexedDB transaction first Request record + rate and quota ledgers Sending is allowed only after transaction success Call the translation service Leave evidence of the debit before sending Disk write failure: do not send an API request Transaction complete Network request confirmed terminated Completed / cancellation confirmed / failed Release the concurrency slot Subsequent work can use the freed slot Time-window debit remains Wait for the counting interval to expire; lower actual usage does not automatically refund the reservation Separately Concurrency slots track occupancy; time-window quotas retain debits; request-rate allowance replenishes at its own rate. A network request ending does not directly refund rate allowance; cancellation after a successful debit may also retain debits for unsent requests.

Scroll wide diagrams horizontally.

Why this matters: A request ending only means the network operation no longer occupies a concurrency slot; it does not mean the provider did not bill it. Persisting conservative debits first also retains known usage across background-service restarts. Tokens controlling the send rate replenish over time separately; ending a request does not directly return consumed tokens.

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?
D = S + P + a − L S = conservative debits committed to the time-window ledger that have not expired P = reservations whose send commit has not completed a = new demand L = configured limit
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.

Estimate base = ceil(sum of all character weights) + 4 Character weight: 1 if the Unicode code point is greater than 0x2E80, otherwise 0.34 Full interactive prompt: ceil(sum of bases for all nonempty fragments × 1.2) + 256 Interactive output reservation: the request's specified limit, or 4096 if unspecified

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.

10

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.”

Figure 11From streamed text to a committable translationHTML protocol and branching diagram

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 你好。
Streaming response parser — retain state and scan new characters incrementallyEnvelope → JSON structure → data fields → item identifiers → text and Unicode; complete items may produce temporary previews.
Validate the whole response after the network operation succeeds and the model finishes normally
Valid itemsAccept result → restore placeholders
→ renderable translation → final result
Individual items need repairMissing / duplicate known identifiers
Blank / overly long translation / placeholder mismatch
→ retry individually later
Entire response invalidUnknown identifiers / fields, duplicate field names
Wrong version, invalid JSON, extra prose
→ reject the entire response
Why this matters: First establish “whose complete result this is,” then decide whether to use it. Previews are revocable temporary results and never become persistent cache entries; page paragraphs update only after the final result is confirmed.
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.

11

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.

Figure 12Late old results must not overwrite newer source textSVG sequence diagram · synthetic illustration
How asynchronous translations avoid overwriting new source text After the website changes the source, an old result must not overwrite the new version even if it arrives later; identity is checked both upon receiving results and when committing the DOM. This synthetic sequence includes no latency measurements. Website / source Translation background Page validation / presentation Source version 1 Capture request A Send A Request attempt A Wait for translation service Website changes to version 2 New segments / reading generation Send B Request attempt B New-version semantic demand A responds after the source changes The result still belongs to the old source Check version Reject stale result Do not update DOM B completes Complete translation Recheck source text Matches current identity Queue / commit rendering plan Check upon receipt: background generation → document generation → source version → result-notification version Before committing the DOM, recheck the local reading generation, request attempt, source text, and node connectivity.

Scroll wide diagrams horizontally.

Why this matters: Background execution generation, document version, source version, and result-update sequence are checked in layers; work already in the rendering queue must also verify the local translation round and request identity. Cancellation and version checking work together to handle asynchronous races.
Figure 13One batch of results can update across different animation framesHTML rendering schedule
Paragraph A · ready to commitIdentity matches; no selection
Enough budget in this frame
→ update now
Paragraph B · text being selectedProtect the user's selection
Retain only this paragraph's latest update plan
→ wait until protection no longer applies
Paragraph C · wait for next frameThis frame has reached its work budget
Retain the update plan for now
→ recheck next frame
Recheck source text before committing; do not clear the user's selection or freeze other paragraphs
4 msTime budget before yielding work
8Blocks / observation root / frame
256Estimated webpage nodes
32 KiBBytes calculated from UTF-16

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.

Why this matters: Separating result-arrival cadence from webpage-write cadence lets translation updates coexist with reading, selection, and IME composition. If text remains selected after releasing the mouse or touch, protection still applies.
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.

12

Being able to read a translation does not mean it is saved

Figure 14One result, two completion pathsSVG state diagram
Result availability and persistence success are separate states Segment translations can be passed to the page for assembly while saving; persistence succeeds only when the local transaction completes, and failed persistence retries only the local write. Actual display still passes through the page's rendering queue. Result passes validation Response format / preservation markers validated Produce a renderable translation Translation result available Persistence status: in progress Wait for page assembly / scheduled rendering Local persistence queue Wait for IndexedDB transaction The queue itself is not persisted Persistence failed When material is still retained and retryable “Retry save” repeats only the disk write Transaction complete Persistence status: complete Only then may it be marked saved on this device Failure Success Persistence queue full → pause new translation requests; in-flight requests may finish. Background restarts do not automatically restore unsaved material.

Scroll wide diagrams horizontally.

Why this matters: If local persistence temporarily fails, validated translations may remain on screen; “retry save” repeats only local writing, avoiding turning a storage error into another model request.
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.

13

Cancellation revokes commit authority; retries need a clear reason

Figure 15Sending a cancellation signal does not mean the network operation has endedSVG lifecycle diagram
Different lifecycles for cancellation and restart Cancellation first revokes result-commit authority, then waits for confirmed network-request termination. By default, failure to confirm termination within 5 seconds quarantines the service resource; restarting the background service switches generation and retains known quota consumption. Running Concurrency slot occupied Retains result-commit authority Cancellation requested Revoke result-commit authority Send cancellation signal Canceling Still waiting for network-request termination confirmation Do not release the concurrency slot yet Termination confirmation received Release the concurrency slot Even a late success cannot commit a result No confirmation within the default 5 seconds Network termination state unknown Quarantine the service resource; retain the concurrency slot Grace period exceeded Late termination Background service restarts Switch to a new background generation Release old slots; retain debit counts Reconnect: page confirms connection → resends context and active-segment snapshot → background rebuilds demands. Text being saved does not automatically revive after restart; only committed translation memory and quota ledgers are persistent.

Scroll wide diagrams horizontally.

Why this matters: First prevent canceled results from reaching the screen, then wait for evidence of actual termination. Returning a concurrency slot while the underlying request still runs would underestimate real concurrency.
25 sWait for first content
20 sNo-new-content streaming deadline
90 sTimeout threshold per attempt
5 sGrace period to await termination after cancellation

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.

Wait upper bound = min(delay cap, base delay × 2^(attempt count−1)) Retry-eligible time = max(server-specified time, now + floor(random value × wait upper bound)) Random value is in [0, 1); floor means round down

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.

14

“Local first” must still explain where data goes

Figure 16Source text, translations, and keys have different boundariesHTML data-boundary diagram
Webpage and content scripts
Source text and DOMDOM nodes remain on the webpage side
Source units / document context sent to the background
Receive versioned status and result notifications
Extension storage
Translation memoryNormalized source text, translation, producer
The same record includes page associations
Page-restoration intent is saved separately
Sensitive translation-service settingsAPI keys / request headers / service options
Separate from page-visible settings
No additional local application-layer encryption
External network
Translation serviceReceive text to translate
LLMs may also receive eligible context
Return according to each service's protocol
Opt in to translation-memory syncIncludes normalized source text and translation
Encrypted by the shared sync service before upload
Sync return path writes to local memory
Sync excludes: page associations, last-used times, and page-restoration intent.
Sync still includes: translation content itself; it cannot be described merely as “syncing a little metadata.”

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.

Why this matters: Settings isolation, transport encryption, and local hits solve different problems. Local-first behavior can avoid some duplicate requests; text still leaves the device whenever a remote translation service is actually called.
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.
15

Reconnect the design to the problems it solves

Figure 17From reading needs to explainable engineering trade-offsHTML design comparison
The same sentence appears repeatedly
Separate page bindings / shared work + semantic keysShare semantically identical work; retain distinct identities when context or rules change.
Manage one extra state layer in exchange for explicit reuse boundaries.
Visible content keeps waiting
Visibility tiers + small-batch dispatchServe the focused visible area first, then preload ahead of reading.
Lower-priority tiers may wait; equal simultaneous progress across pages is not guaranteed.
Unstable model output
Item-identifier mapping + placeholder validationSeparate whole-response errors from individual-item repair.
An extra parsing cost; semantic correctness still depends on translation quality.
Requests span cancellation / restart
Execution generations + persisted quota debitsSeparate revoking commit authority from retaining known consumption.
Conservative reservations may overestimate usage; unknown termination pauses dispatch first.
Webpage updates and user interactions
Version checks + selection protection + per-frame budgetsRecheck source text before commit and defer writes for affected blocks.
There may still be a wait between translation completion and actual display.
Temporary local-storage failure
Separate result availability from completed persistenceValidated translations remain usable; persistence failures retry only the disk write.
Results not fully saved are not guaranteed recoverable after the background process restarts.
This architecture's value lies in splitting “translation” into separately inspectable responsibilities. Every result has a source identity, every external send is approved, and every screen update must prove again that it still applies.

Eight key boundaries for understanding this system

Streaming capability is separate from page displayThe lower layer can provide temporary previews; webpage paragraphs wait for final results. LLM translation of selected text updates using streamed text.
Resources are shared, but entry points still differDispatch approval is shared; response parsing, context, entry-point retries, and on-screen states differ.
Exact memory is separate from similarity searchA semantic key is the SHA-256 of the full translation conditions; similar text does not automatically hit.
Source-string length is separate from tokens2000, 900, and 2400 are UTF-16 thresholds at different stages; they must not be restated as token counts.
Concurrency slots are separate from quota debitsTermination can release a concurrency slot; consumption from sent requests remains in the time window.
4ms is a cooperative budgetOne indivisible update can exceed the budget, and the page can still drop frames.
Visible, saved, and synced are separateResult available, persisted, and sync complete are three independently advancing states.
Safeguards are separate from quality guaranteesPlain-text output and version checks reduce rendering risks; translation quality, cost, and performance still require separate measurement.

Comments & discussion

Connecting to the comment service…