Human review
AI translation is the fast path, not the only path. The dashboard lets a person check each translation and mark it reviewed, so a team can tell "translated" apart from "checked by a human" — useful before a release, or for the strings that matter most (legal copy, pricing, onboarding).
The checkbox
Every translated, non-primary language cell in the translations table has a checkbox under it: "Mark as reviewed" when unchecked, "Reviewed" once ticked. It means exactly one thing: a person looked at that cell and accepted it. The primary language has no checkbox — it's the source text, not a translation — and an empty cell has none either, since there is nothing yet to review.
Ticking or unticking the box saves immediately; there is no separate save step.
Editing a cell yourself also marks it reviewed. The moment you type a correction and save it, the box for that language switches to checked — a value you typed is a value you already reviewed.
When a review mark is cleared
The mark is per language, and it does not survive a rewrite. If the AI regenerates a cell —
for example after you add a plural form or a new select value, or after you emptied the
cell and a client asked for the string again — the reviewed mark for that language is cleared, so nobody trusts a check that was made
against text that no longer exists. Other languages of the same row keep their own marks.
Filtering and sorting
The toolbar has a "Filter by review" dropdown:
- Reviewed or not — every row (the default).
- To review — only rows with at least one translated language still unchecked.
- Reviewed — only rows where every translated language is checked.
A row with nothing translated yet appears in neither "To review" nor "Reviewed": there is nothing on it to check.
The "Sort" dropdown orders the table A to Z on the source text (the default), or by creation date, newest first or oldest first, on top of whichever review filter is active. Newest first is the natural order for a review session: what the AI translated since your last pass comes first.
The line under the toolbar, "X of Y rows reviewed", counts rows that have at least one translated language (Y) against those where every translated language is checked (X).
Reviewing one row at a time
"Review one by one" switches the table for a panel showing a single row: the source text, and every translated language next to its own checkbox and its own inline editor. Use Previous / Skip to move through the queue, or Approve all languages to check every pending language of the row in one action. A row leaves the queue the moment its last language is checked, so the panel moves to the next one on its own. Once nothing is left, the panel says so. "Back to the table" returns to the normal view at any point.
The queue only ever holds rows with something left to check, in the table's current namespace and sort order.
In the data
reviewed_languages travels with the row everywhere a translation does: on every row the
API returns from GET /project/translations, and in the JSON produced by
GET /project/translations/export. It is a comma-separated list of language codes, in your
SDK's dialect (v2 or v3 — see Upgrading to v3).
Marking a review from a script
PUT /project/translations/:id/review is the same call the dashboard makes. It takes the
same two credentials as the other /project/* routes: your API key as a bearer token, and
your dashboard session as the i18nkeyless_express_jwt cookie (or an Authorization: JWT ... header).
curl -X PUT https://api.i18n-keyless.com/project/translations/123/review \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
--cookie "i18nkeyless_express_jwt=YOUR_SESSION_JWT" \
-d '{
"languages": ["fr", "es"],
"reviewed": true
}'
languages takes one or several codes at once — one for a single checkbox, all the pending
ones for an "approve all" action. reviewed is true to mark them checked, false to take
the mark back. The response carries the row as it stands after the change, under
data.translation, the same shape GET /project/translations returns.