Skip to content

Automatic Translation

On this page

Available in LATW AI Translator for WPML PRO (version 2.2.0 and later).

#What it does

Normally you translate content by opening the plugin’s Translations screen and pressing a
button. Automatic translation removes that step: as soon as a new post, page or product is
published, the plugin sends it to the AI on its own and WPML receives the finished translation
a short while later.

It was built for sites where content does not arrive by hand — a product feed from a supplier,
a CSV importer, an app that posts articles through the API. You publish, and the translations
appear.

Important: every automatic translation is billed by your AI provider, exactly like a manual
one. The settings page includes daily limits so an importer that misbehaves cannot run up a bill
overnight — see Daily Limit and Daily Cost Limit.

#How it works, step by step

  1. Someone (or something) publishes a new post.
  2. The plugin notes the post and starts a short countdown — 60 seconds by default.
  3. If the post is saved again during the countdown, the countdown restarts. This is deliberate:
    importers usually write the same product several times in a row (first the text, then the
    price, then the stock level, then the images), and we want to translate it once, after it has
    settled — not four times.
  4. Once the countdown runs out, the plugin’s regular every-minute background task picks the post
    up and sends it to the AI, in the same way as if you had pressed Translate yourself.
  5. The translation lands in WPML and the post is done.

#What does not start a translation

  • Editing content that is already published. Only content entering one of the selected
    states counts — a brand-new post being published, or a draft going live. Re-saving a published
    post does nothing at all. A stock or price sync that touches every product every few hours will
    therefore not trigger anything.
  • Content that is already translated. If a post already has a translation in every target
    language, it is skipped.
  • Translations themselves. A translated post is never treated as new content to translate,
    so there is no loop.
  • Drafts in progress, trashed posts and media attachments.

Keeping existing translations up to date when the original changes remains a manual decision on
the Translations screen.


#The settings

All options live in LATW AI Translator → Settings → Automation.

#Master switch — “Automatic translation is ON / OFF”

The one control on the page that changes what your site does on its own. While it is off, nothing
below has any effect and the plugin behaves exactly as before. Turn it on and the plugin starts
watching for new content.

The panel shows a plain-language summary of what will happen once you save — which content types
go to which languages, how long the delay is, and which daily limits apply — plus a warning if
your current selection would translate nothing.

#Content Types

Which kinds of content are watched: Posts, Pages, Products, or any custom type your theme or
plugins register. Tick everything you want translated automatically.

Nothing happens until at least one type is ticked. This is the usual reason automatic
translation appears to “not work”.

#Trigger When Content Becomes

The state a post has to enter for a translation to start. Published is the default and is
what most sites want.

Option Translation starts when…
Published a post goes live (new post published, or a draft published)
Draft a post is first saved as a draft — useful if you want translations ready before publishing
Pending review a contributor submits a post for review
Private a post is published privately
Scheduled a post is scheduled for a future date

You can tick more than one. Remember that only the move into that state counts — a post that is
already published and gets edited is not re-translated.

#Delay Before Translating

How many seconds to wait after publication before sending the content to the AI. Default 60,
minimum 30.

Every further save of that post restarts the countdown. So the delay is not “translate 60 seconds
later” so much as “translate 60 seconds after the last time anything touched this post” — which is
what stops half-built imported products from being translated mid-import.

  • Content written by people in the editor: the default 60 seconds is fine.
  • Content coming from an importer that writes in several passes: raise it to 300 seconds (5 min)
    or more, so the importer is definitely finished.

#Target Languages

Which languages new content is translated into.

Leave all boxes unchecked to reuse the Target Languages you already picked on the
Translation tab. Tick specific languages here only if automatic translation should cover a
narrower set than your manual translations — for example, translate everything into German by hand
but let only French run automatically.

#Daily Limit

The maximum number of automatic translations per day. 0 means no limit.

One post translated into three languages counts as three.

This is the safety net. If a feed misfires and recreates 5,000 products, the limit stops the run
once it is reached. Nothing is lost — the remaining posts keep waiting and go out automatically
once the limit resets the next day (or as soon as you raise it). While a limit is holding content
back, a warning appears on the plugin’s own screens telling you how many items are waiting.

The day is counted in UTC, so it rolls over at the same moment regardless of your site’s timezone.

#Daily Cost Limit

The maximum amount, in US dollars, to spend on automatic translations per day. 0 means no
limit.
It counts only automatic translations — anything you start by hand is not included.

One caveat worth understanding: the exact cost of a translation is only known once it comes back
from the provider, so this limit reacts with a slight delay and can be overshot a little. If you
want a hard, immediate stop, set the Daily Limit above as well.

#Settings this feature reuses

Automatic translation is not a separate translation engine — it uses everything already configured
elsewhere in the plugin:

  • Processing Mode (Settings → General): synchronous, batch or background.
  • Provider, model and prompt settings (Settings → Translation).
  • Outdated Translations mode, if a post it handles turns out to need a delta update.

#Where to check on it

The plugin Dashboard has an Automatic Translation card showing, at a glance:

  • whether the feature is Active, Disabled, or currently blocked by a daily limit
  • the content types and languages it covers
  • Waiting — how many posts are queued up, and when the next one is due
  • Translated today — count, against your daily limit if you set one
  • Cost today — spend, against your cost limit if you set one

#Developer reference

This section is for developers integrating an importer or custom workflow. Everything above works
without touching any of it.

#Actions you can call

Both bypass the Content Types and Trigger rules — calling them is an explicit statement that this
post should be translated — but every safety guard (translations are never sources, no re-entry
during write-back, daily limits, license and language rules) still applies.

// Schedule with the normal debounce delay. Best for an importer that may still
// write to the post: repeated saves push the countdown forward as usual.
do_action( 'latwaitrp_translate_post', $post_id, array( 'de', 'fr' ) );

// Dispatch immediately, no waiting for the next cron tick. Use when you know
// you have finished writing the post.
do_action( 'latwaitrp_translate_post_now', $post_id, array( 'de', 'fr' ) );

The second argument is optional; omit it (or pass null) to use the configured target languages.

#Filters

Filter Arguments Purpose
latwaitrp_auto_translate_enabled bool $enabled Force the feature on or off in code.
latwaitrp_auto_translate_post_types array $types Override the watched post types.
latwaitrp_auto_translate_delay int $seconds, int $post_id Per-post delay. Values below 30 are clamped to 30.
latwaitrp_auto_translate_target_languages array $langs, int $post_id Per-post target languages.
latwaitrp_should_auto_translate bool $should, int $post_id, string $context Final veto before a post is marked. $context is e.g. transition:draft->publish, api, api_now.
latwaitrp_auto_translate_batch_size int $size Posts dispatched per cron tick (default 25).

Example — skip products that have no price yet:

add_filter( 'latwaitrp_should_auto_translate', function ( $should, $post_id, $context ) {
    if ( get_post_type( $post_id ) === 'product' && ! get_post_meta( $post_id, '_price', true ) ) {
        return false;
    }
    return $should;
}, 10, 3 );

#Notifications

Action Arguments Fired when
latwaitrp_auto_translation_scheduled int $post_id, int $run_after A post is marked for automatic translation.
latwaitrp_auto_translation_dispatched int $post_id, array $langs, array $queue_ids The post has been sent to the translation pipeline.
latwaitrp_auto_translation_skipped int $post_id, string $reason A post was considered and skipped. Reasons include post_status:trash, not_a_source_post, already_translated, filtered.

#Implementation notes

  • Trigger hook: transition_post_status. It is the only hook that can distinguish a first
    publication from an ordinary edit — save_post and wp_after_insert_post fire on both and
    cannot see the previous status.
  • Marking, not scheduling: a due post is stored as post meta _latwaitrp_auto_run_after
    (a Unix timestamp), and the existing every-minute cron event
    (latwaitrp_check_response_statuses, priority 5) dispatches whatever has come due. A 500-product
    import therefore writes 500 rows of post meta rather than 500 entries into WordPress’s single
    serialised cron option. A per-post language override from the developer API is stored
    alongside as _latwaitrp_auto_run_after_langs and consumed on dispatch.
  • Debounce: wp_after_insert_post, woocommerce_new_product and woocommerce_update_product
    only push an existing mark forward. A save on a post that carries no mark does nothing.
  • Loop protection: writing a translation back sets LATWAITRP_TS_Service::$writing_translation,
    and LATWAITRP_TS_Service::is_source_post() is checked both at marking and again at dispatch
    time (WPML may not have registered a brand-new post’s language yet at the first check).
  • Quiet period at dispatch: if post_modified_gmt is newer than the delay allows, the post is
    pushed back another full delay instead of being translated half-written.
  • Concurrency: the worker holds a 5-minute transient lock (latwaitrp_auto_translate_lock), so
    two overlapping cron runs cannot process the same posts.
  • Queue rows created this way are stamped translation_type = 'auto' or 'auto-delta', which
    is what the daily limits and the dashboard card count.
  • Shared entry point: the Translate button and the automatic trigger both call
    LATWAITRP_TS_Service::translate_post_now(), so identical language, license and freemium rules
    apply to each.
  • Uninstall removes all latwaitrp_auto_* options and deletes both post meta keys.

#Options written by this feature

latwaitrp_auto_enabled, latwaitrp_auto_post_types, latwaitrp_auto_statuses,
latwaitrp_auto_delay, latwaitrp_auto_target_languages, latwaitrp_auto_daily_limit,
latwaitrp_auto_daily_cost_limit, latwaitrp_auto_limit_hit.


#Troubleshooting

Symptom Likely cause
Nothing is being translated The master switch is off, no Content Type is ticked, or no target language is selected (and none is set on the Translation tab either).
New posts are ignored, but manual translation works The post’s status is not among the ones ticked under Trigger When Content Becomes, or the post already has translations in every target language.
Everything stopped part-way through the day A daily limit was reached. Check the Dashboard card — the waiting items resume tomorrow, or immediately if you raise the limit.
Translations arrive much later than the delay suggests WP-Cron is not firing reliably. Check the WP Cron Health card on the Dashboard; a real server cron job is recommended for busy sites.
Nothing happens and no API key is set Posts are held, not dropped. They go out on the next tick after a valid API key is saved.
Editing a published post does not re-translate it Working as designed. Use the Translations screen to update existing translations.