=== interPROter ===
Contributors: bastinet
Tags: translation, multilingual, deepl, language switcher, hreflang
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 0.1.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Your WordPress site, in every language. Automatic machine translation stored in your own database, with no external dependency when pages are served.

== Description ==

interPROter translates your whole site automatically and keeps the translations in your own WordPress database.

**Any text on the page gets translated.** interPROter works on the final HTML your site sends to the visitor, so it does not matter which theme or page builder produced the text. Titles, menus, widgets, footer, meta descriptions and Open Graph tags are all covered without registering anything.

**Nobody has to press a button.** A new or changed page is translated within minutes of publishing, and the whole site is checked once an hour. A language is published on its own once every text on the site has a translation.

**The translations are yours.** They live in your own database. Serving a translated page never contacts an outside service. If the translation service is unreachable, nothing breaks: new texts just stay untranslated until the next run.

**Fix a translation by clicking it on the page.** Open any translated page as an editor and click "Fix translations" in the toolbar. Every translated text becomes clickable: you see the source and the translation side by side, and the change takes effect immediately. No separate editor, no searching a list for the right row.

**Human corrections stick.** However you edit a translation — on the page or in the admin list — the automatic runs will never overwrite it. You can also mark texts that should never be translated, such as names.

**Publish when you are ready, or let it publish itself.** By default a language goes live on its own once everything is translated. If nothing may reach visitors before a person has read it, switch that one language to "Require approval": the machine keeps translating, but the language stays hidden until you publish it.

**Search engines are told about every language.**

* Language prefix in the URL (`/de/`, `/en/`) and translated slugs (`/de/zimmer/`). The original slugs keep working.
* `hreflang` tags, translated `canonical`, `html lang`, Open Graph URL and locale.
* A multilingual sitemap at `/wpt-sitemap.xml`.
* Canonical and Open Graph filters for Yoast SEO (verified) and Rank Math (implemented, not yet verified).

**Light.** No JavaScript is added to the front end for translation. A small language switcher with SVG flags is included.

= Where the translations come from =

Translations are produced by machine translation. You can use either:

* **The interPROter translation service** (recommended). The plugin requests a key for your site itself; no account or card is needed. The key starts with a one-time preview allowance of 5,000 characters, and a paid plan (from EUR 149 a year per site, see https://interproter.com/#hinnat) gives a monthly allowance of 1,000,000 characters that renews every month. The service holds the translation engine credentials.
* **Your own DeepL API key**, entered in the settings. The plugin then talks to DeepL directly.

Both are only used when new texts need translating. Visitors never trigger a request to either.

= Requirements =

* A real server cron is strongly recommended. WP-Cron only fires on page loads, so on a quiet site translations would wait for the next visitor. Run `wp cron event run --due-now` every 10 minutes, or point a system cron at `wp-cron.php`.

= What interPROter does not do yet =

We would rather say this here than have you find out.

* Order emails and admin-side texts are not translated.
* Text that is written into the page by JavaScript after loading is not seen by the plugin and stays in the original language.

== External services ==

This plugin connects to outside services only when it needs new translations. Page views never do.

**interPROter translation service** (if selected in settings). The plugin sends the texts to be translated, the source and target language codes, and your site address (so the service can count your allowance). Operated by Bastinet, Finland. Terms: https://interproter.com/terms.html — Privacy: https://interproter.com/privacy.html

**DeepL API** (if you enter your own key). The plugin sends the texts to be translated and the language codes to `api.deepl.com` or `api-free.deepl.com`. DeepL terms: https://www.deepl.com/en/pro-license and privacy policy: https://www.deepl.com/en/privacy

No visitor data is sent to either service.

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/` or install it from the Plugins screen, then activate it.
2. Go to **Translations → Settings**. Add the languages you want and choose where translations come from: the interPROter service key or your own DeepL key.
3. Make sure automatic translation is on (it is by default). The first full run starts within minutes.
4. Check **Translations → Before translation** to see what would be translated and what the plugin suggests leaving out.
5. Once a language is fully translated it is published automatically. You can also publish or unpublish a language by hand.

WP-CLI is supported: `wp interproter` lists the commands.

== Frequently Asked Questions ==

= Does it work with my page builder? =

Yes. interPROter translates the finished HTML, so it does not need to know anything about Elementor, Divi, Gutenberg or a hand-made theme. It has been run on an Elementor site and on a custom theme.

= What happens if I stop paying for the service? =

Your site keeps working in every language, because the translations are already in your database. Only new texts stop getting translated.

= Does deleting the plugin delete my translations? =

No. By default the translation tables stay in your database so a reinstall picks them up. If you want everything removed, turn on *When the plugin is deleted → Also delete all translations and settings* before deleting.

= Does it slow my site down? =

Measured on a test site running the standard WordPress theme unit test content (WordPress 7.1, PHP 8.3, median of eight requests per URL):

* A normal post with 74 translatable texts: **7 extra database queries, 6.6 ms, and 2.5 KB** added to the page.
* The front page with 378 translatable texts: 7 extra queries, 25 ms, 2.4 KB.
* With the plugin installed but no languages added: 4 extra queries and nothing added to the page.

The 2.4 KB is the hreflang tags and the language switcher. No JavaScript is loaded on the front end for translation, and pages in the original language are not touched.

= Can I edit a translation? =

Two ways. On the page: open a translated page, click "Fix translations" in the toolbar, then click the text you want to change. Or in the admin under **Translations**: search for the text, edit it, save. Either way the translation is locked and never overwritten by the automatic run.

= Does it work with WooCommerce? =

Yes, including the cart and the checkout. Measured on WooCommerce 11.1 in a real browser.

Shop, category and product pages translate in full, and every add-to-cart link, product ID and product URL stays exactly as it is in the original language.

The cart and the checkout are React blocks: their text is generated in the visitor's browser, so it never appears in the page the server sends. Two things reach it. The interface itself — "Proceed to Checkout", "Subtotal", "Quantity" — comes from the translations WooCommerce already ships for every language, installed for you when you add a language. Your own product names and descriptions are translated from your own store.

That split is deliberate, and it is also cheaper: standard interface text has been translated well by thousands of people already, and there is no reason to pay a machine to do it again. Your translation budget goes to your own writing.

= Where does a visitor-only page get translated? =

A page that exists only for one visitor — a cart with something in it, a search result, a form's error message — can never be reached by a crawl. Two things cover it. Anything a plugin or theme wrote is already translated, because the page runs in the visitor's language and WordPress's own translations apply. Anything else the plugin writes down as it renders, and the next automatic run translates it.

= Can I stop a language from going live before I have read it? =

Yes. In **Translations → Settings**, switch that language to "Require approval". The machine keeps translating it, but it stays hidden from visitors until you press "Approve and publish". Every other language keeps publishing itself.

= Does it translate URLs? =

Yes. Translated pages get translated slugs based on the translated title, for example `/de/zimmer/`. The original slug under the language prefix keeps working too, so shared and indexed links do not break.

== Changelog ==

= 0.1.1 =
* Version information for the WordPress updates screen (zip downloads from interproter.com). No changes to translation, routing or rendering.
* Plugin Check: input sanitisation and output escaping tightened; 0 errors, 0 warnings.

= 0.1.0 =
* First public version. Automatic translation, translated URLs, hreflang and canonical handling, multilingual sitemap, language switcher, on-page and admin editing, per-language approval gate, WooCommerce support including cart and checkout, WordPress's own language packs for plugin interface text, WP-CLI commands, interPROter service or direct DeepL as translation source.

== Upgrade Notice ==

= 0.1.1 =
Maintenance release. Safe to update; translations and settings are untouched.

= 0.1.0 =
First public version.
