Translation workbench — 375 px, English · עברית · العربية
Frames 2a–2c at a phone width. The locale grid becomes one column, the bilingual editor stacks source above translation instead of side by side, “Save all” moves to a sticky bar, and the autofill confirmation becomes a BottomSheet.
en · ltr · 375 · translation index
Translations
en · ltr · 375 · locale editor (fr)
Français fr
250 of 250 · M 248 1 changed
he · rtl · 375 · editing ar
العربية ar
120 מתוך 250 תורגמו
en · ltr · 375 · autofill confirmation
Autofill 250 strings into 日本語?
Machine translation from English (en). Every new row is badged M.
Human-reviewed strings are never overwritten — the service enforces it, not this switch.
States at 375 px
Same states as frames 2a–2c; the edit you typed always survives a failed request.
loading
autofill running
Determinate progress; both actions disabled until it finishes.
partial failure
save failed
Couldn't save — your edit is kept and marked unsaved.
403 — read-only
Editing translations needs translate. No save bar is shown.
Rules the implementation must keep
- At ≤ 40em the locale grid is one column and the bilingual editor stacks source above translation in each row — the source is never hidden behind a tap, because a translator can't translate what they can't see.
- “Save all” and “Autofill missing” sit in a sticky bar at the bottom of the screen, above the home-indicator inset
(
--safe-area-bottom). Per-row actions (Mark reviewed, Keep as-is, Save row) are full-width and ≥ 44 px tall. - RTL is per cell, not per page. In a Hebrew UI editing Arabic, the chrome is RTL, the source stays
dir="ltr"(it is English), and the target input isdir="rtl". Never a per-locale stylesheet. - The autofill confirmation is a BottomSheet with the same count, source locale and human-preservation guarantee as frame 2c;
overwrite_machinedefaults off; progress is determinate; a partial failure keeps what was written. - Machine output stays badged M and the Source changed warning is inline on its row at every width.
Test hooks: [data-frame='16-mobile-translation-workbench'] · [data-device='375'] · [data-panel='translation-index-mobile'] · [data-panel='locale-editor-mobile'] · [data-locale='he'][data-dir='rtl'] · [data-source-dir='ltr'] · [dir='rtl'][data-locale='ar'] · [data-translation-input='item'] · [data-warning='source-changed'] · [data-control='editor-actions'] · [data-action='save-all'] · [data-action='autofill'] · [data-dialog='autofill'][data-presentation='bottom-sheet'] · [data-guarantee='human-preserved'] · [data-state='running'] · [data-error='autofill-partial'] · [data-error='save-failed'] · [data-error='FORBIDDEN'] · [data-rules='mobile-translation-workbench']
Playwright drives the real workbench at { viewport: 375×812, locale: en | he-IL }: no horizontal scroll, the source cell renders above
its input, the sticky bar stays inside the viewport while scrolling, and an RTL target input has dir='rtl' while its source has dir='ltr'.
Tokens only — no raw hex, spacing or type outside tokens.css / frame.css / mobile.css.