Problem
Translation is all-or-nothing per document. An editor who wants to retranslate one paragraph, or fix
one field the model got wrong, has to re-run the whole document — which under overwrite also
discards any hand edits made to other fields in that locale, and under skip_existing cannot touch the
field at all because it already has a value.
The blast radius also matters on failure: a provider error partway through a large document is a
document-sized problem, where it could have been a field-sized one.
Suggested shape
A per-field translate action in the admin: an icon or button next to a localized field that translates
just that field into the current locale. The plumbing largely exists — the field-level config already
knows which fields are translatable (isTranslatableLeaf, the exclude flag), and
createOpenAIProvider returns a provider whose translate(Record<number, string>, sourceLng, targetLng) is directly callable with a single entry.
Note on scope
This would not reach fields the field walker cannot see. In our case that is uiStrings, a localized
json field on a Payload global, which no amount of per-field UI helps with since the plugin has
no globals key at all. We are routing around that separately and are deliberately not asking for
globals support.
Problem
Translation is all-or-nothing per document. An editor who wants to retranslate one paragraph, or fix
one field the model got wrong, has to re-run the whole document — which under
overwritealsodiscards any hand edits made to other fields in that locale, and under
skip_existingcannot touch thefield at all because it already has a value.
The blast radius also matters on failure: a provider error partway through a large document is a
document-sized problem, where it could have been a field-sized one.
Suggested shape
A per-field translate action in the admin: an icon or button next to a localized field that translates
just that field into the current locale. The plumbing largely exists — the field-level config already
knows which fields are translatable (
isTranslatableLeaf, theexcludeflag), andcreateOpenAIProviderreturns a provider whosetranslate(Record<number, string>, sourceLng, targetLng)is directly callable with a single entry.Note on scope
This would not reach fields the field walker cannot see. In our case that is
uiStrings, a localizedjsonfield on a Payload global, which no amount of per-field UI helps with since the plugin hasno
globalskey at all. We are routing around that separately and are deliberately not asking forglobals support.