DocsHow a string is resolved5 min read

How a string is resolved

One request, four possible answers. Knowing where an answer came from explains its cost, its latency and why the same word can translate twice.

originwhat it meanscost
cacheOur shared cache still holds this string for this projectnone
approvedYour team approved it in the Inbox; the row is the answernone
pendingThe model produced it and nobody has reviewed it yetnone
modelLive model call, stored as pending review so it happens oncesource characters

You only pay for a model call, and you pay for the source text, not the translation it produces. The same 40-character string seen for the hundredth time is free.

Context is part of the identity

A string is stored under a hash of lowercased text + target + context. So «Account» with no context and «Account» with screen:checkout are two different strings, and they are allowed to be two different translations. This is the entire product: a word without a screen is a guess.

t('Account')                     // → «الحساب» as a bill, perhaps
t('Account', 'screen:settings')   // → «الحساب» as a menu item
t('Account', 'screen:checkout')   // → different string entirely, and different storage

// The screen: prefix is a convention, not a parser. The dashboard groups on it —
// an Inbox row whose context says screen:checkout lands under a "checkout"
// screen, and export?screen=checkout can select it. Any other text in the
// context is passed to the model as written.
screen:<name>
Letters, digits, dash, underscore. Worth using consistently — it powers the screen filter and the nested export.
tone:
Free text that reaches the model. "tone:formal", "tone:friendly with the customer" — the model takes it literally.
max length
160 characters, and no < or > anywhere — the service refuses both, on purpose, because context is part of a prompt.

The glossary is a constraint, not a hint

A glossary term is matched against the source text and pinned into what the model is told. If the model then ignores it, the response is flagged as drift and the row is marked in the Inbox — you get the translation and the warning, never a silent rewrite of your term.

Where things are held

  • SDK memory, then localStorage (Flutter: shared_preferences) — 30 days, 1000 entries by default, keyed by the same text+target+context.
  • The shared server cache — the first place every device is answered from. 30 days.
  • Your project’s approved record. Approved strings outrank pending ones, so a cold cache never sends the model back out on work you already paid for.