Documentation
How to translate a WordPress site with AI Translate for WPML — what it touches, what it deliberately leaves alone, and what it costs.
Requirements
- WPML Multilingual CMS — required. With the languages you want already set up. WPML String Translation is only needed for the Strings tab.
- Advanced Custom Fields — optional. Without it, titles, slugs and content are still translated. With it, every text field as well. The free ACF covers text, textarea and wysiwyg; repeaters and flexible content need ACF PRO.
- An OpenAI API key. You use your own, so you pay OpenAI directly for what you translate. There are no credits and no per-word fee.
WPML is the one thing that cannot be missing: linking a translation to its original goes through WPML's own API, and that is what this plugin does. ACF is where it pulls ahead of everything else — nobody else translates those fields — but it is an extra, not a condition.
Getting started
- Install and activate the plugin. A new AI Translate menu appears.
- Go to Settings and paste your OpenAI API key. The field never shows the key back — leave it empty to keep the one you saved.
- Pick the model. The default,
gpt-4o-mini, is what the cost figures on this site are based on. - Choose whether new translations are created as drafts or published. Draft is the default, so you can review before anything goes live.
- Tick the content types to translate. Only the ones WPML has marked as translatable show up here.
- Open the Content tab. Every original appears with its status per language.
The Content tab
One row per original, one column per target language. Each cell tells you where that translation stands:
| Status | What it means |
|---|---|
| Missing | No translation yet. Translate creates it. |
| Outdated (N) | The original changed since the last pass. Update re-translates only the N fields that changed. |
| Up to date | Nothing to do. |
| External | A translation exists that this plugin did not create — made by hand, or by another tool. It is never touched unless you force it. |
The plugin stores a hash per field on each translation. That is how it knows what changed, and why editing one paragraph does not mean paying to translate the whole page again.
Filters and batches
Filter by content type, language and status. The checkboxes are per cell, not per row: with several target languages, selecting a whole row would fire one API call per language, and you rarely want all of them at once.
Translate selected processes what you ticked. Translate everything pending processes what is pending in the current filtered view. Both run one request at a time and log every result; if one item fails the batch carries on.
What gets translated
For each item: the title, the slug, the content if there is any, and every text field ACF holds for it — including fields nested inside repeaters, flexible content and groups, at any depth.
A field is translated when all of these are true:
- Its ACF definition still exists. Values left behind by field groups you deleted or rebuilt are ignored, exactly as the editor ignores them.
- The stored key matches the field it points to. When ACF groups get rebuilt, references can cross over; writing to those would put a translation in the wrong field.
- It is a text type:
text,textareaorwysiwyg. - ACFML does not mark it as copy-only, and it is not in your exclusion list.
Hover the number in the Fields column to see exactly which keys will be sent. If a post shows fewer fields than you expect, that is where to look first.
What it leaves alone
Images, galleries, URLs, booleans, dates and relational fields are copied as they are,
never translated. HTML tags and attributes are preserved; only visible text and the
alt and title attributes are translated. URLs, emails,
shortcodes and placeholders like {{name}} are left untouched.
Excluding fields
In Settings → Excluded ACF fields, one pattern per line. They are matched against both the ACF field name and the full meta key, and wildcards work:
country— a field holding a code likeES*_code— every field whose name ends in_codecredits_*_name— the person's name inside a credits repeater
Use it for references, codes, proper names and anything that must read identically in every language.
TaxonomiesPro
The Taxonomies tab translates term names, slugs, descriptions and the ACF fields attached to terms, with the same statuses and batches as content.
Separately from that, every translation keeps its terms, because WordPress does not copy them on its own:
- On a taxonomy WPML does not treat as translatable, the term is shared across languages and the same one is assigned.
- On a translatable one, the translated term is assigned — created on the spot if it does not exist yet and the setting allows it.
When a term cannot be assigned, the log says which one and why, rather than dropping it silently.
ACF optionsPro
For themes that store one set of option values per language — the usual setup with ACF and WPML. When a language set is created, every field is copied first, images and links included, and then the text ones are translated. Otherwise that language would end up with no logo and no links.
Languages you filled in by hand show as External and are left alone.
StringsPro
Theme and plugin strings registered in WPML String Translation — buttons, labels, validation messages. Pick a domain first: a large site can hold thousands of strings across dozens of domains, so they are not all loaded at once.
Source languagePro
Translations normally start from the WPML default language. They do not have to. It is common for the default to be one language for URLs and SEO while the texts are actually written in another.
Set the language content is really written in, and the WPML default becomes one more target: it shows up in the list as pending or outdated like any other, and gets translated from the real source.
Fixing a wrong languagePro
For a single item written in the wrong language — the classic case of an English draft sitting in the Spanish original. The fix language link on the row:
- Copies the content as it is to the language it is actually written in. No API cost: it is the same language.
- Translates the original over itself into the site's source language, saving a backup first.
- Refreshes the existing translations so they are not marked outdated: their meaning did not change, only the language of the source did.
What it costs
You pay OpenAI directly. At current gpt-4o-mini rates, translating a
30,000-word site into one language costs around four cents. One euro
covers roughly half a million words.
Three things keep it there:
- Only text fields are sent. Images, URLs and numbers never leave your site.
- Only changed fields are re-sent when you update a translation.
- Requests are batched, so the instructions are not repeated for every single field.
Troubleshooting
A content type is missing from the list
WPML does not have it set as translatable. Check WPML → Settings → Post Types Translation. Without that, WPML cannot link a translation to its original.
A post shows fewer fields than it has
Hover the number in the Fields column to see what will be sent. Values whose ACF field group was deleted or rebuilt are ignored on purpose — the editor does not show them either.
A translation lost its category
The log says which term could not be assigned. Usually the taxonomy is translatable but the term has no translation in that language yet.
Everything shows as External
Those translations were not created by this plugin, so it has no record of what they were translated from. Force them once and they come under its control from then on.
The translation came back in the wrong language
Check Source language in Settings. If your originals are written in a language other than the WPML default, the plugin needs to be told.