=== Transleti Translator ===
Contributors: transleti, grupobouso
Tags: translation, multilingual, hreflang, unlimited-translation, woocommerce
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 8.0
Stable tag: 1.9.23
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Free multilingual WordPress plugin — translate manually for free, or unlock unlimited automatic translation with a 7-day trial (no card required).

== Description ==

**The plugin is 100% free and GPL.** You can run a fully multilingual WordPress site with manual translations, hreflang sitemap, language switcher and slug translation without ever paying anything or connecting to an external service.

If you also want automatic translation across every language at once, connect the optional Transleti API — flat-rate, unlimited words and languages, with a 7-day free trial. **No card or payment method is required to start the trial**, and **the API is optional**: the manual workflow keeps working forever, including after the trial ends, even if you never subscribe.

Transleti Translator handles posts, pages, custom post types, WooCommerce products, menus, slugs, SEO meta, and theme strings. A built-in visual editor lets you click on any text in the rendered page and refine its translation in a side-by-side panel — useful both for polishing automatic translations and for translating everything by hand.

= Two ways to use it =

* **Manual mode (free, forever)** — edit each translation directly in the WordPress post editor or via the visual front-end editor. No API key, no subscription, no external connection required. Includes the language switcher, hreflang sitemap, slug translation and 49+ pre-defined language slots.
* **Automatic mode (optional Transleti API)** — connect an API key and the plugin fans out translations to every target language in parallel. Flat-rate, unlimited words, 7-day free trial, no card required to start. If you decide not to subscribe after the trial, the plugin keeps working in manual mode. Manual edits on top of automatic translations are preserved on re-translation.

= Features =

* **Free GPL plugin** — fully functional in manual mode without any external connection or paid service.
* **Visual translation editor** — open any front-end page in an editor frame, click on any string (titles, paragraphs, menu items, buttons, image alts) and edit its translation in a side panel with live preview.
* **Manual translation editor** — review and refine translations directly in the WordPress post editor for every language.
* **Optional unlimited automatic translation** — flat-rate Transleti API subscription, 7-day free trial. No card or payment method required to start the trial; if you do not subscribe, the API simply stops at day 7 and the plugin keeps working in manual mode.
* **Parallel translation** (API mode) — requests fan out to every target language simultaneously. A site with 10 languages translates in roughly the same time as a site with 1.
* **Built on open source** — the plugin itself is GPL, fully auditable, no proprietary lock-in.
* **Theme-agnostic** — works out of the box with Elementor, Gutenberg, classic editor, GeneratePress and any standards-compliant theme.
* **WooCommerce ready** — translates product titles, descriptions, attributes and variations.

= Key features =

* **Multilingual sitemap with hreflang** — separate `<url>` entries per language (the format Google explicitly documents) with self-referential hreflang and `x-default`. Compatible with Yoast SEO, RankMath, SEOPress, AIOSEO and the WordPress core sitemap.
* **SEO meta translation** — titles and descriptions for SEOPress, Yoast, AIOSEO and RankMath.
* **Visual translation editor** — open any front-end page in an editor frame, click on any string (titles, paragraphs, menu items, buttons, image alts) and edit its translation in a side panel with live preview.
* **Manual translation editor** — review and refine translations directly in the WordPress post editor for every language.
* **Manual edit protection** — your manual fixes survive re-translation cycles.
* **Slug translation** — translated URLs (e.g. `/es/contacto/`) for clean per-language SEO.
* **Menu translation** — duplicates and translates navigation menus per language.
* **HTML entity and shortcode protection** — prevents corruption of `&copy;`, `[shortcode]`, and similar in translated output.
* **Custom "do not translate" word list** — keep brand names, product codes and acronyms intact across all languages.
* **Language switcher** — widget, block and shortcode in flag, dropdown or text styles.

= Supported languages =

49+ languages including English, Spanish, French, German, Italian, Portuguese (PT/BR), Dutch, Polish, Romanian, Bulgarian, Hungarian, Finnish, Russian, Ukrainian, Arabic, Hindi, Japanese, Korean, Chinese, Thai, Turkish, and more.

= How it works =

**Manual mode (free):**

1. Install and activate the plugin.
2. Choose your default language and the target languages you want to publish.
3. For each post / page, open the translation editor (in the post editor sidebar or via the visual front-end editor) and type the translation by hand.
4. The language switcher, hreflang sitemap and per-language slugs work out of the box.

**Automatic mode (optional API):**

1. Install and activate the plugin.
2. Sign up at https://transleti.com to get your API key (7 days free, no card required; the API stops automatically at day 7 unless you choose to subscribe).
3. Enter your Transleti API key in the plugin settings.
4. Choose your default language and the languages you want to publish.
5. The plugin runs a background job that translates posts, menus, slugs and SEO meta automatically.
6. Optionally refine any translation manually from the WordPress post editor — your edits are preserved on re-translation.

== Installation ==

1. Upload the `transleti-translator` folder to `/wp-content/plugins/`, or install through the WordPress plugin installer.
2. Activate the plugin via the *Plugins* menu in WordPress.
3. Go to *Settings → Transleti Translator*.
4. Select your default language and target languages.
5. (Optional) Enter a Transleti API key to enable automatic translation. Without a key, you can still translate every string manually from the post editor or the visual editor.
6. Save settings.

== Frequently Asked Questions ==

= Do I need to pay anything to use this plugin? =

No. The plugin is free GPL software and works fully in manual mode without any external connection or paid subscription. Automatic translation is an optional add-on that uses the Transleti API.

= Can I use the plugin without an API key? =

Yes. Without an API key the plugin runs in manual mode: language switcher, per-language slugs, hreflang sitemap and the manual / visual translation editors all work normally. You simply type translations by hand instead of having the plugin generate them.

= Is there a free trial of the automatic translation API? =

Yes. New accounts get 7 days of full access when you sign up at https://transleti.com. **No card or payment method is required to start the trial.** After 7 days the API stops working unless you choose to subscribe — and even then, the plugin itself keeps working in manual mode for free, so you never lose access to your translated content.

= Is the plugin really fast even with many languages? =

Yes. Translation requests for every target language are fanned out in parallel, so adding more languages does not multiply the wait time. A 10-language site translates in roughly the same time window as a 2-language site.

= Does it work with WooCommerce? =

Yes. Product titles, descriptions, short descriptions, attributes and variations are all translated automatically.

= Does it support Elementor, Gutenberg and the classic editor? =

Yes. Elementor pages translate the underlying `_elementor_data` JSON; Gutenberg parses blocks and translates innerHTML and block attributes; classic posts translate `post_content` directly.

= Will Google index the translated pages correctly? =

Yes. The plugin emits a separate `<url>` element per language in the sitemap (the format Google explicitly documents), with bidirectional hreflang and `x-default`. It also outputs `<link rel="alternate" hreflang="...">` tags in the HTML head.

= Can I edit translations manually? =

Yes. There are two ways: (1) the visual editor, which lets you click on any string in the rendered page and edit its translation in a side panel — useful for menus, buttons, widgets and theme strings that don't live in the post editor; and (2) each translated post is a standard WordPress post you can edit from the admin like any other content. Manual edits are detected and preserved during re-translation.

= What happens if I update the source post? =

The plugin detects content changes via MD5 hashing and queues a re-translation. Manual edits to translations are detected and preserved (unless the source change is structural).

== External Services ==

This plugin can optionally connect to the Transleti translation API (`api.transleti.com`) to translate site content automatically into the languages you select. **This connection is optional** — the plugin works in manual mode (typing translations by hand from the WordPress editor or the visual front-end editor) without contacting any external service. No external request is made unless you enter an API key in the plugin settings.

**What data is sent (only in automatic mode):** the text strings to translate (post content, titles, excerpts, menu labels, slugs, SEO meta, theme strings) along with the source and target language codes and your API key.

**When it is sent:** when the background translation cron runs, when you save a post that needs re-translation, or when you trigger a manual translation from the settings page.

**Service provider:** Transleti — `https://transleti.com`

* Terms of Service: https://transleti.com/terms
* Privacy Policy: https://transleti.com/privacy

No personal data of site visitors is sent to the service. Only the text content you choose to translate.

== Screenshots ==

1. Settings page — connect to the Transleti API and choose languages.
2. Visual translation editor — edit translations on the front-end.
3. Language switcher — flag, dropdown or text styles.
4. Multilingual sitemap output with hreflang alternates.

== Changelog ==

= 1.9.23 =
* Fix: WooCommerce Blocks cart / checkout — product short descriptions now translate correctly. WC Blocks pre-renders the cart server-side via a hydration path that bypasses the REST response filter; the plugin now hooks `woocommerce_hydration_request_after_callbacks` so hydrated responses are translated alongside live Store API calls.
* Fix: WooCommerce Blocks Summary truncation — product short descriptions in cart / checkout are no longer clipped to ~15 characters on locales whose WordPress translation breaks the `Word count type. Do not translate!` hint (e.g. pt_BR returning "palavras"). Both the server-side `_x()` value and the client-side `wp.i18n` translation file entry are now sanitised back to a valid value.
* Fix: Store API translation — WC Blocks calls `/wc/store/v1/*` without a language URL prefix from the localized React bundle. The plugin now falls back to `HTTP_REFERER` to detect the visitor's current language so Store API responses match the page they were requested from.
* Doc: readme repositioned to make clear the plugin is free and fully usable in manual mode; the Transleti API (automatic translation) is now described as optional.
* Doc: trial messaging updated to reflect that the 7-day API trial no longer requires a card or payment method. After the trial, the API stops automatically unless you subscribe and the plugin keeps working in manual mode for free.

= 1.9.22 =
* Fix: per-language progress no longer gets stuck below 100% on mixed-script content. Dictionary rows now retire after 3 failed translation attempts (mirroring the existing gettext mechanism), so untranslatable strings stop blocking the percentage indicator.

= 1.9.21 =
* Fix: visual editor — clicks on theme menu items (GeneratePress, Astra, Divi, Elementor Pro mega-menus, etc.) now open the translation panel reliably. Listener moved to `window` capture + `pointerdown` so theme menu togglers that call `stopPropagation()` can no longer swallow the selection click.

= 1.9.20 =
* Fix: visual editor now detects menu items in Hebrew, Greek, Hindi, Thai, Georgian and Armenian (menu translation now bails during preview so the renderer can add translatable markers regardless of script).
* Fix: visual editor — clicking on a string with duplicated text on the same page (e.g. a heading and a menu link with the same label) now opens the translation panel for the selected occurrence.
* Fix: ignore RSS feed `pubDate`/`lastBuildDate` strings in the "stuck translations" notice.
* Improvement: automatic cleanup of orphan sentence segments left over from long-paragraph batching.

= 1.9.x =
* New: visual translation editor — click any text in the rendered front-end and edit its translation in a live side panel. Works on menus, buttons, image alts and theme strings.
* New: 49+ languages supported via the Transleti translation API.
* New: HTML entity and shortcode protection across all translation entry points.
* New: "Do not translate" word list (brand names, product codes, acronyms).
* New: SEO meta translation for SEOPress, Yoast, AIOSEO and RankMath.
* Improvement: manual edit protection — your manual fixes survive re-translation cycles.
* Improvement: parallel translation across all target languages.

= 1.4.4 =
* Feature: drag-and-drop reordering of active languages in the Languages tab (also affects the language switcher order).
* i18n: added 503 "pending translation" page strings for 16 additional languages (Lithuanian, Albanian, Azerbaijani, Basque, Bengali, Catalan, Esperanto, Galician, Irish, Kyrgyz, Latvian, Malay, Persian, Slovenian, Tagalog, Urdu).

= 1.4.3 =
* Compliance: wrapped `language_has_translations()` and `find_original_slug()` direct `$wpdb` probes with `wp_cache_get` / `wp_cache_set` (5-minute TTL, `transleti` cache group).
* Compliance: documented every legitimate direct DB call against core meta tables with `phpcs:ignore` comments explaining why the existing core API can't replace them.

= 1.4.2 =
* Hardening: escaped flag-emoji output in the language switcher shortcode (`render_switcher`, `render_language_list`) via `esc_html()`.
* Hardening: every `ob_start()` callback buffer is now explicitly closed via a paired `ob_end_flush()` registered through `register_shutdown_function()` in the same function scope (frontend page buffer, AJAX response buffer, sitemap xhtml-namespace buffer).

= 1.2.1 =
* Hardening: replaced `fopen`/`fread`/`fclose` with `WP_Filesystem::get_contents()` for the diagnostic log reader.
* Hardening: switched all custom-table existence checks to `$wpdb->prepare( 'SHOW TABLES LIKE %s', ... )` (no more single-quote interpolation).
* Hardening: switched several `$_POST` reads on HTML-bearing fields to `wp_kses_post( wp_unslash( ... ) )`; integer reads now use `absint( wp_unslash( ... ) )`.
* Hardening: added explicit nonce checks (`check_admin_referer`/`wp_nonce_url`) to the string-export download link.
* Compliance: removed redundant `load_plugin_textdomain()` call (WP 4.6+ auto-loads translations from the WP.org directory).
* Compliance: documented every legitimate direct-DB query (custom plugin tables) with localised `phpcs:disable`/`enable` blocks.

= 1.2.0 =
* Compliance: removed comparative/superlative marketing phrasing from the readme.
* Compliance: extracted inline `<script>` blocks to enqueued JS files (language switcher, editor preview).
* Hardening: all `$_GET` / `$_POST` / `$_SERVER` / `$_COOKIE` reads now go through `wp_unslash()` plus a context-appropriate sanitiser (`sanitize_text_field`, `esc_url_raw`).
* Hardening: AJAX nonce check in `ajax_empty_language()` now unslashes and sanitises the nonce before passing it to `wp_verify_nonce()`.

= 1.0.6 =
* Removed redundant `load_plugin_textdomain()` call — translations are now auto-loaded by WordPress 4.6+ for plugins hosted in the directory.
* Switched front-end language redirect from `wp_redirect()` to `wp_safe_redirect()` for additional protection against open-redirect attempts.
* Defense-in-depth: explicit allowlist validation for the language storage key before SQL identifier interpolation in the cache-clearing endpoint.
* Packaging: included a `.pot` template in `languages/` so the Domain Path folder is present in the distributed package.

= 1.0.5 =
* New: separate `<url>` entry per language in the sitemap, matching Google's documented hreflang format.
* New: AIOSEO sitemap compatibility (`aioseo_sitemap_post`/`_term`/`_archive_entry`/`_addl_pages` filters).
* Fix: `xmlns:xhtml` namespace now declared in `<urlset>` so `<xhtml:link>` alternates are valid XML.
* Fix: `/sitemap.xml` no longer redirects to `/en/sitemap.xml` when `add_subdirectory_to_default=yes`.
* Fix: sitemap `<loc>` URLs now use the canonical default-language URL instead of the redirecting unprefixed permalink.
* Fix: HTML head and sitemap hreflang codes now match exactly for bidirectional confirmation.

= 1.0.4 =
* Parallel translation crawling — O(1) in number of languages.
* Render substitution fixes for raw `%1$s` placeholders and `[cookie_*]` shortcodes leaking to public pages.

= 1.0.3 =
* HTML entity and shortcode protection in all translation entry points.
* "Do Not Translate" word list.
* Manual edit protection improvements.

== Upgrade Notice ==

= 1.9.23 =
Fixes WooCommerce Blocks cart / checkout: product short descriptions now translate correctly and are no longer clipped after ~15 characters on locales that mistranslate the "Word count type" hint. Also clarifies that the 7-day API trial requires no card.

= 1.9.22 =
Fixes per-language progress getting stuck around 95-96% on mixed-script content (Arabic, Hebrew, Russian, Greek, Czech). Recommended for all sites with non-Latin target languages.

= 1.9.21 =
Fixes a visual-editor regression where clicks on theme menu items (GeneratePress, Astra, Divi, Elementor Pro) didn't open the translation panel. Recommended for all users editing menus visually.

= 1.9.20 =
Adds visual-editor support for Hebrew, Greek, Hindi, Thai, Georgian and Armenian menus, plus a fix for clicking duplicated strings. Recommended.

= 1.0.6 =
Maintenance release with security hardening and Plugin Directory packaging fixes. Recommended for all users.

= 1.0.5 =
Important multilingual sitemap fix. After upgrading, purge any sitemap cache from your SEO plugin and resubmit the sitemap to Google Search Console.
