Informacje techniczne
Documentation E-Toolkit Lingua
Instructions, technical specifications and change history — always in line with the current version of the product.
Technical compliance
WordPress
From version 6.4
Tested up to 7.1WooCommerce
Optional integration
PHP
From version 7.4
Knowledge base
Documentation
User Manual Set-up, operation and troubleshooting.
E-Toolkit Lingua — User Guide
Getting started
- Open ET Lingua → Settings → Languages.
- Select the site languages and choose the default language. The URL code, locale, and name are filled automatically; expand Advanced settings to change them.
- Under Content types and Taxonomies, select the elements that should support translations.
- In the post editor, select a language in the Language and translations panel.
- Click Create next to a target language. Lingua creates a separate draft containing a copy of the source content.
You can also enter the ID of an existing post and save the content to connect completed language versions without creating a copy. Disconnect removes only the relationship between existing versions; it does not delete the post or term.
The panel identifies the source language of the group. From another version, use Set this post as source or Set this term as source. This changes the relationship, not the content.
In Gutenberg, one Language and translations document panel shows the current language, source language, and status of every version. It can create a missing draft, open a translation, connect an existing post by ID, disconnect a version, and change the source language. The legacy metabox appears only in the Classic Editor.
When the title, excerpt, content, or link changes in the source version, the remaining versions become Outdated. This status appears in the editor, as an orange marker beside the pencil on list screens, and in the dashboard summary. The summary also counts groups missing a version in each language. Saving the corrected translation makes it current again. Formatting and technical Gutenberg block settings alone do not make a translation outdated.
Create all missing adds missing versions to a persistent queue. At most three drafts are created in one batch, so a large language set does not block the dashboard. The open editor displays progress and starts further batches through REST, while WP-Cron continues after the screen is closed. You can cancel, resume, or retry the queue after an error.
Translation memory
Lingua divides titles, excerpts, content blocks, and translatable ACF fields — including fields embedded in ACF blocks — into small segments. Changing one paragraph makes only that fragment outdated and changes the post status to Partially outdated. Block layout settings are not treated as text.
The editor sidebar shows the translation status and an Open translator button. The full-screen workspace groups text by block and displays the source and translation side by side. You can approve a corrected draft. If identical source text later appears in another post, the approved translation is offered as a suggestion; it is never inserted automatically.
Edit a segment directly or select Use suggestion, then save without reloading the editor. You can save one phrase or edit several fields and click Save all. A counter shows pending changes. A manual save immediately approves the segment. Lingua updates only the relevant title, excerpt, block, or ACF field. Required placeholders such as %s, {{name}}, and shortcodes must remain in the translation. Each segment keeps up to 20 recent changes and provides an Undo change button.
After saving new source content, Refresh segments in the translation reindexes the source and current version. When explicitly requested, it also adds missing blocks even if automatic structure synchronization is disabled. Existing translated blocks remain unchanged, and new fields appear as missing.
Automatic translation
Open ET Lingua → Settings → Automation, select DeepL or OpenAI, and configure an API key. The key can be stored in a non-autoloaded WordPress option or, preferably in production, defined in wp-config.php as ETLG_DEEPL_API_KEY or ETLG_OPENAI_API_KEY. Keys are never returned to JavaScript or REST.
In a target version, Translate automatically adds missing and outdated segments to a persistent queue. In the full-screen translator, you can translate one segment or click Translate all automatically. A batch contains no more than 8 segments and 50,000 characters. The queue uses a lock, retries temporary failures with increasing delays, continues through WP-Cron, and can be cancelled or resumed.
Automatic translations have Draft status. They are not approved or published automatically. When processing finishes, review the results in the translator and approve the correct segments. printf placeholders, {{...}} tokens, HTML, shortcodes, URLs, and email addresses are protected and must return unchanged from the API. You can also add one proper name or term per line to the protected terms list.
An optional monthly character limit stops the next batch before it is sent. This is a local safeguard in the WordPress installation; provider billing and account limits still apply.
Synchronization and ACF
Under ET Lingua → Settings → Synchronization, configure the featured image and page template. A field can remain independent, be copied once when a translation is created, remain synchronized with the source, or be ignored.
You can also synchronize Gutenberg block structure. Containers and block order are copied from the source, while content in existing matching text blocks remains in the translation language. New blocks are copied with source text and the version stays outdated until reviewed.
When ACF PRO is active, each field in the field group editor receives an ET Lingua translations setting. Keep the automatic policy or select one for the field. Images, files, galleries, choice fields, and structural fields synchronize by default; text fields remain independent for translation.
Synchronized ACF image, file, gallery, relationship, post object, page link, and taxonomy fields map IDs to equivalents in the target language. If translated media does not exist, the source file is retained. Relationships, post links, and terms without an equivalent are omitted to prevent content in the wrong language from appearing.
On ACF Options Pages, select the language in the admin bar or beside the Save button. Values are stored separately for each language, and a new language initially falls back to default-language values. Only fields explicitly set to Always synchronize remain shared.
The ACF Link field search and the native WordPress Insert/edit link dialog show only posts and pages matching the language selected in the dashboard.
Enable Media under Content types to create separate language records with independent alternative text, caption, and description, without copying the physical file. If disabled, one attachment is shared by all languages. Media details show the language and actions for creating or editing other versions, and the media modal respects the current admin language.
Synced patterns, block navigation, template parts, and site templates are also available under Content types. After the appropriate types are enabled, Pattern and Navigation block references resolve to the published equivalent in the current language. Internal links in block content are redirected to published translations while preserving query parameters and anchors.
When a technical Site Editor content type is enabled, the Language and translations sidebar can create a translation, connect an existing item by ID, disconnect a version, and change the source language. A template part or template supplied only by theme files must first be saved in the Site Editor so it receives a database record.
WooCommerce
When WooCommerce is active, a separate WooCommerce settings tab shows support for products and variations and the translation completeness of the Shop, Cart, Checkout, My Account, and Terms pages.
Each language has a separate product with its own name, description, short description, slug, categories, tags, and global attribute values. SKU, stock, taxes, dimensions, shipping, downloadable files, and download limits come from the source product. Saving the source refreshes technical data and WooCommerce lookup data for the other languages.
Under ET Lingua → Settings → WooCommerce, select a pricing strategy. Shared prices suit a typical multi-currency setup where another plugin converts one base price. Separate prices per language allow independent regular and sale prices and sale schedules for each product and variation translation. When switching back to shared prices, physical data and lookup synchronization runs in background batches.
Select a review strategy in the same form. Shared reviews and ratings display comments from the whole translation group, use one average rating, and recognize a purchase of any product equivalent. Separate reviews and ratings retain native WooCommerce lists for each language. Existing stores default to separate reviews.
The strategy applies consistently to the classic Reviews tab, Product Reviews blocks and pagination, public Store API, and WooCommerce REST API. In shared mode, Store API returns the product name and link in the requested language even when the review was submitted for another record in the group.
Expand a language to configure localized account and order endpoint slugs, for example /orders/ and /de/bestellungen/. An empty field keeps the native WooCommerce slug. Saving refreshes permalinks automatically, and duplicate slugs for different endpoints are rejected.
Translating a variable product automatically creates and connects corresponding variations. Global attribute values map to translated terms, while each variation uses one source SKU and shared inventory. Grouped products map their components to available translations. External products share the destination URL, while their button text can be translated independently.
Related products, upsells, and cross-sells are shown only in the current language. A missing or unpublished version never causes a product from another language to appear.
Global WooCommerce attribute names such as “Color” appear automatically in the woocommerce-attributes group on the Strings tab. Attribute values such as “Red” remain taxonomy terms and are translated as terms.
Payment method names and descriptions and shipping method instance names appear in woocommerce-checkout. Text configured directly in WooCommerce can therefore differ by language without duplicating gateways or shipping zones.
Downloadable product file names appear in woocommerce-downloads after the product is saved. The physical file, download limit, and expiry remain shared; product and file names in My Account, order details, email, and REST API use the correct language. Signed download URLs are not rewritten by language routing.
The cart retains an item when the language changes but presents its published equivalent in the current language. Stock is always reduced atomically on the source product. The checkout language is stored with the order and used when products are read again or WooCommerce messages are generated.
Stock reservations from classic checkout and Checkout Blocks are totaled across the translation group. Concurrent purchases in two languages therefore cannot reserve the same shared stock separately. A partial refund restores the specified amount; a later cancellation restores only the remaining quantity that had previously been reduced.
Customer links generated from an order use the stored order language, including messages sent later from a queue or resent from the dashboard. This applies to order view, payment retry, confirmation, and cancellation links. Order-key and nonce parameters are preserved.
The Order language field on the order edit screen assigns a language to manually created or imported orders. A legacy order without this value first uses the language stored on an item and then the site default. The language is saved before an admin email action runs.
The product catalog, classic WooCommerce queries, and Store API use the same language filter based on the Lingua relationship table. WooCommerce system pages resolve to their published language equivalents. Configure product, category, and tag bases with other addresses under ET Lingua → Settings → URLs.
The language switcher preserves the current category, tag, and safe account or checkout endpoint, such as the orders list or an individual order view. Actions such as logout and payment-method removal are not transferred.
The integration declares compatibility with HPOS and Cart and Checkout Blocks. Orders are accessed only through WooCommerce APIs, never through direct post-table queries.
Custom subjects, headings, and additional customer email content are registered in woocommerce-emails. The translation is selected from the stored order language, including emails resent from the dashboard or sent in the background.
Coupon restrictions assigned to products, variations, or categories apply to all their language versions, for both allowed lists and exclusions. The same product added to the cart in two languages remains one line item: its quantity increases, while its name and link use the customer's current language.
Categories, tags, and taxonomies
Select supported taxonomies under ET Lingua → Settings → Taxonomies. Choose a language when adding a term. While editing, create an equivalent in another language or enter the ID of an existing term from the same taxonomy. A new equivalent receives a temporary name containing the language code; translate it before publishing the site.
The Languages column on content and term lists displays active-language flags. A pencil opens an existing version, and + creates a missing translation.
The switcher above the list and the flag menu in the WordPress admin bar set the current dashboard language. Lists show only posts or terms in that language, so connected versions do not appear as duplicate rows. The selection is remembered separately for each user.
Language switcher
Add the Language switcher block in Gutenberg or the ET Lingua — Language switcher widget. Both display a dropdown and can show a flag, name, code, and optionally hide missing translations.
You can also use , for example:
By default, languages without a published translation of the current content are hidden. If this behavior is disabled, their links open the language home page. Under ET Lingua → Settings → URLs, each language can instead have a published fallback page, such as an English offer page or German contact page.
The language version sets the document locale, for example en-GB for /en/. Lingua also generates hreflang, x-default, the correct canonical for published posts, pages, and public term equivalents, and a matching og:url. A canonical set manually in Yoast SEO, Rank Math, or SEOPress takes precedence.
Language prefixes are preserved in previews, pagination, feeds, archives, and REST URLs generated on the frontend. WordPress, Yoast SEO, and Rank Math sitemaps use the public URLs of the correct language versions.
When creating a post translation, Lingua initially copies Yoast SEO and Rank Math titles, descriptions, keyphrases, and social descriptions. They then become independent fields in the content translator and XLIFF. The primary SEO category maps automatically to an existing target-language equivalent.
In WordPress Multisite, every site has its own languages, relationships, and translation memory. Network activation prepares existing sites, and later sites are initialized automatically. The ET Lingua license is shared across the network, including subsites on separate domains, and only a super administrator can activate or deactivate it.
Switcher in a menu
Under Appearance → Menus, expand ET Lingua and click Add to menu. Move the new item as needed, then configure its flag, name, code, and missing-translation behavior. On the frontend, it uses the same dropdown as the shortcode: the button shows the current language and the list shows the remaining versions.
Classic menus and widgets
Enable Classic menus under ET Lingua → Settings → Taxonomies. In Appearance → Menus, select the menu language in Language and translations. Create copies the menu structure, nested items, and extension settings. Links to posts and terms immediately map to available translations.
Assign the source menu to a theme location only once. Lingua automatically selects the connected menu for the current language and falls back to the source menu when no version exists.
The Appearance → Widgets screen uses the language selected in the admin bar. The default language keeps the native WordPress layout; every other language has separate sidebars and widget instances. On first use, start empty or click Copy default layout. Editing the copy later does not change the source-language widget content.
Language URLs
Under ET Lingua → Settings → URLs, choose directories, subdomains, or separate domains. Directory mode can include or omit the default-language code. Subdomains require wildcard DNS or separate language records. Separate domains must point to the same WordPress installation and have valid HTTPS certificates. Saving refreshes permalink rules and supported plugin caches.
You can define separate public content-type and taxonomy bases for every language, such as /products/ and /de/produkte/. An empty field retains the base registered by WordPress, the theme, or a plugin.
Posts without an assigned language are treated as default-language content. A post assigned to another language does not appear in default-language lists, archives, or search.
The same slug may be used in different languages because the language directory separates the URLs, for example /contact/ and /de/contact/. This also applies to products and nested pages. WordPress still adds a numeric suffix if two items conflict within one language. Translate each version's slug independently in its editor.
Theme and plugin strings
Texts registered through the API appear under ET Lingua → Settings → Strings. Filter them by group or search by name, source text, or domain, then fill translations for all languages. Each string has its own source language. If theme strings are Polish while the site default is English, select them, choose Polish in the source-language controls, and click Change source language. The English translation field then becomes available.
When a provider is configured under Automation, Translate with DeepL/OpenAI fills one field while preserving HTML and placeholders. Filters can show entries missing a selected language. Select up to 50 results on the current page and click Translate selected with DeepL/OpenAI. Review the suggestions and click Save translations. Plural forms require manual input. A missing translation safely falls back to the source text. If no integration has registered a string, use Add string manually to create the first group.
The Export and import translations card supports CSV or JSON and either All languages or a Selected language pair. An all-language export contains the base language and every target language. Complete it in a spreadsheet or send it to a translator without changing technical fields or structure. Import updates only changed translations. An empty translation removes the existing value, while a row whose source text changed is safely skipped.
The plugin does not scan PHP files automatically during dashboard or frontend requests. Only strings deliberately registered by a theme or plugin appear until you run a scan.
The scanner lets you select a theme or plugin, an optional gettext-domain filter, and excluded paths. Its domain list contains only values detected in the selected source. Selecting all domains imports each phrase into its real domain group, even if it differs from the domain declared in the theme or plugin header. Selecting etoolkit excludes strings from other domains, such as woocommerce strings in overridden templates. Enter one relative exclusion per line, for example woocommerce, vendor/custom-package, or includes/legacy.php. Settings are remembered per source. vendor, node_modules, .git, dist, and tests are always skipped.
Select an active theme, parent theme, or installed plugin at the top of the tab. The scanner analyzes PHP, JavaScript, JSX, and TypeScript and first displays a preview. Only Import selected strings stores the selected results. Dependency directories and generated files are skipped, and each scan has safe size limits.
Diagnostics
Under ET Lingua → Settings → Diagnostics, check relationship tables and indexes, object consistency, URL rules, and persistent object-cache status. Checks run only when the tab is opened. Available actions clear only the translation cache or safely refresh URL rules.
Developer documentation Functions, hooks, filters and integration tips.
E-Toolkit Lingua — Developer Guide
Public PHP functions
lingua_get_current_language()— language code of the current view.lingua_get_default_language()— site's default language.lingua_get_languages()— configured languages.lingua_is_post_type_translatable($post_type)— checks post-type support.lingua_get_object_language($object_id, $object_type = 'post')— language of a post or term.lingua_get_translation($object_id, $language, $object_type = 'post')— equivalent ID in a language.lingua_get_translations($object_id, $object_type = 'post')—language => IDmap.lingua_get_source_language($object_id, $object_type = 'post')— source language of a group.lingua_get_translation_status($object_id, $object_type = 'post')—current,partial, oroutdated.lingua_set_object_language($object_id, $language, $object_type = 'post')— assigns a language.lingua_set_source_language($object_id, $language, $object_type = 'post')— sets the source language.lingua_connect_translations($objects, $object_type = 'post')— connects a map of equivalents.lingua_disconnect_translation($object_id, $object_type = 'post')— disconnects an object.lingua_translate_url($url, $language)— returns the URL for a language.lingua_render_switcher($attributes = [])— returns language-switcher HTML.lingua_get_field_policy($field_name, $post_type, $post_id = 0)— returnstranslate,copy_once,sync, orignore.lingua_register_string($group, $name, $value, $args = [])— registers a dynamic string.lingua_unregister_string($group, $name)— removes a dynamic string and its translations.lingua_translate_string($group, $name, $fallback = '', $language = '')— returns a translated string.lingua_enqueue_automatic_translation($object_id, $provider = '', $segment_ids = [])— queues automatic translation.lingua_preload_products($product_ids)— preloads data before a WooCommerce product loop.lingua_flush_translation_cache()— clears relationship caches after an external import.
Call these functions after plugins load, for example on init or later.
Reading languages and translations
$language = lingua_get_current_language();
$post_id = get_the_ID();
$english_id = lingua_get_translation($post_id, 'en');
if ($english_id) {
printf(
'<a href="%s">%s</a>',
esc_url(get_permalink($english_id)),
esc_html__('English', 'my-theme')
);
}Connect existing versions:
lingua_connect_translations([
'pl' => 123,
'en' => 456,
], 'post');Dynamic strings
Register strings under stable group and key names:
add_action('init', function (): void {
lingua_register_string('theme-header', 'contact_button', 'Contact us', [
'text_domain' => 'my-theme',
'context' => 'Button in the header',
]);
});
echo esc_html(lingua_translate_string(
'theme-header',
'contact_button',
'Contact us'
));The lingua_translated_string($value, $group, $name, $language, $source) filter changes the value before it is returned.
Language switcher
echo lingua_render_switcher([
'show_flag' => '1',
'show_name' => '1',
'show_code' => '0',
]);Available filters:
lingua_translate_url($url, $language)— final URL in a language.etlg_switcher_items($items, $attributes, $object_id)— switcher items.etlg_switcher_html($html, $items, $attributes, $object_id)— final switcher HTML.etlg_switcher_object_id($object_id)— object used to resolve equivalents.etlg_switcher_object_type($object_type, $object_id)— switcher object type.etlg_switcher_object_url($url, $object_id, $object_type)— public object URL.etlg_menu_switcher_items($items, $args, $context)— classic-menu switcher items.
add_filter('etlg_switcher_html', function (string $html): string {
return '<div class="header-language-switcher">' . $html . '</div>';
});Fields and data synchronization
The lingua_field_policy($policy, $field_name, $post_type, $post_id, $value) filter changes a field policy:
add_filter('lingua_field_policy', function (string $policy, string $field_name, string $post_type): string {
if ($post_type === 'product' && $field_name === 'internal_note') {
return 'ignore';
}
return $policy;
}, 10, 3);Additional filters:
lingua_synchronized_meta_value($value, $meta_key, $source_id, $target_id, $post_type)— maps synchronized metadata.lingua_translation_post_data($data, WP_Post $source, $language)— new post-draft data.lingua_translation_term_data($data, WP_Term $source, $language)— new term data.lingua_menu_item_excluded_meta($keys)— extra metadata omitted when copying menu items.
Segments and translation status
lingua_translation_segments($segments, $post_id, WP_Post $post)— adds text segments.lingua_block_translation_attributes($attribute_names)— text block-attribute names.lingua_source_hash_payload($payload, $post_id, WP_Post $post)— data affecting freshness.lingua_segment_previous_value($value, WP_Post $post, $segment)— previous custom-segment value.lingua_segment_write($result, WP_Post $post, $segment_key, $translation)— writes a custom segment.
add_filter('lingua_source_hash_payload', function (array $payload, int $post_id): array {
$payload['product_note'] = get_post_meta($post_id, '_product_note', true);
return $payload;
}, 10, 2);Actions:
lingua_translation_status_changed($object_id, $status, $object_type).lingua_segment_updated($post_id, $segment_id, $value, $segment).lingua_automatic_translation_saved($object_id, $segment_ids, $provider).
Translation relationship lifecycle
lingua_before_object_language_changeandlingua_object_language_changed— before and after changing an object's language.lingua_before_connect_translationandlingua_translation_connected— before and after connecting an equivalent.lingua_before_disconnect_translationandlingua_translation_disconnected— before and after disconnecting an equivalent.lingua_before_source_language_changeandlingua_source_language_changed— before and after changing the source language.lingua_before_create_translationandlingua_translation_created— before and after creating a translation.lingua_etfb_translation_sync_failed($translation_id, WP_Error $error, $source_id)— Form Builder schema synchronization failed and ET Lingua restored the previous schema.
add_action('lingua_translation_created', function (int $translation_id, int $source_id, string $language, string $object_type): void {
// Synchronize the new translation with a custom integration.
}, 10, 4);Routing and SEO
etlg_should_filter_query($enabled, WP_Query $query)— post filtering by language.etlg_should_filter_term_query($enabled, WP_Term_Query $query)— term filtering.etlg_should_localize_home_url($enabled, $url)—home_url()localization.etlg_hreflang_items($items, $context)— alternate-version links.etlg_canonical_url($url, $context, $original_url)— final canonical URL.etlg_open_graph_url($localized_url, $original_url)— finalog:url.etlg_should_purge_page_cache($enabled)— automatic page-cache purge.etlg_multilingual_conflict_detected($detected)— another multilingual engine was detected.
Skip filtering for one query without changing it globally:
$query = new WP_Query([
'post_type' => 'post',
'etlg_skip_language' => true,
]);WooCommerce
etlg_woocommerce_order_language($language, $order)— order language.etlg_woocommerce_store_api_should_skip($skip)— skips filtering for the current Store API request.- action
etlg_preload_products($product_ids)— products being prepared before reading.
Preload a known product list before a custom loop:
$product_ids = array_map('absint', $product_ids);
lingua_preload_products($product_ids);
foreach ($product_ids as $product_id) {
$product = wc_get_product($product_id);
}REST API
Namespace: et-lingua/v1.
GET /languages— languages.GET /objects/{id}/translations?object_type=post|term— equivalent map.POST /objects/{id}/language— assigns a language.POST /objects/{id}/source-language— changes the source language.POST /translations/connect— connects objects.DELETE /objects/{id}/translations/{translation_id}— disconnects an equivalent.GET /objects/{id}/segments— translation segments.POST /objects/{id}/segments/{segment_id}— saves one segment.POST /objects/{id}/segments/batch— saves multiple segments.
Write operations require an account that can edit the affected objects.
WP-CLI
wp lingua languages— lists languages.wp lingua translations <id> [--type=post|term]— lists object equivalents.wp lingua connect <source-id> <translation-id> --language=<code> [--type=post|term]— connects objects.wp lingua disconnect <id> [--type=post|term]— disconnects an object.