=== Aipogeo Context Translate === Contributors: yfsystem Tags: translation, ai, multilingual, localization Requires at least: 6.7 Tested up to: 7.1 Requires PHP: 8.0 Stable tag: 2.1.1 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Translate your site with an AI that reads the whole page first, then fix whatever it got wrong before your visitors see it. == Description == Most translation tools work one string at a time. The engine sees "Home", or "Post", or a lone product name, and guesses. Guess wrong and your menu reads like nonsense to anyone who speaks the language. This plugin hands the entire rendered page to an AI model instead. The model can see the headline above a button and the paragraph below it before it decides what that button means. Translations go into the plugin's own table and are served under a language directory, `/en/` or `/ja/`. Your posts are never touched. Because the work happens after WordPress has finished rendering, it also covers menus, widgets, meta tags, alt text and placeholders — not just the post body. AI translation is never perfect, so there is a screen for fixing it. Pick a page, read the original and the translation side by side, change any line you disagree with. Your edits stay put; the next run will not overwrite them. = Three ways to get pages translated = * **By hand.** Open a page, press translate, watch it fill in. * **In the background.** While you have the admin open, your browser feeds pending pages to the server one at a time. * **When a visitor arrives.** Anything still missing gets translated on the spot. You can also tell the plugin to keep serving the original page until the translation is, say, 80% complete. All three share per-page locks: two editors working at the same time will not translate the same page twice or double your API bill, while different pages translate in parallel without queueing behind each other. A lock left behind by a crashed job expires by itself once the request timeout passes. = What you can set up = * **Languages.** URL prefix, hreflang and regional variants, order in the switcher, and who gets to see them — everyone, search engines only, or human visitors only. * **The instruction sent to the AI.** Rewrite it if the default tone is wrong for your site; just keep the three variables it needs. Translated URL paths get their own instruction, so the main one stays about prose. * **Replacement rules, per language.** For the brand names and terms the model keeps getting wrong. Plain text, exact match or regular expression. * **The language switcher.** A floating button you can drag anywhere, which remembers where you left it. Or hand it a container id and style it yourself. Flags are optional. = Also taken care of = * Internal links point at the right language. * URL paths can be translated too, and the translated address still resolves back to the correct post. * hreflang, including x-default and regional variants. * Sitemap URLs are localized, and robots.txt gets a Sitemap line per language. = What it costs you = **Bring your own API key.** OpenAI, Claude, Gemini, DeepSeek and OpenRouter all work out of the box, and the model name usually tells the plugin which one you mean. You pay that provider for what you translate; the plugin adds nothing on top, and with this option it contacts nobody but the provider you configured. **Or subscribe.** If you would rather not open an account with an AI provider, top up a balance and pick a model, there is a paid subscription at https://translate.aipogeo.com . Connect your site once and translation runs through Aipogeo: it holds the AI credentials, and the subscription is billed by token — the same unit the AI model itself charges in, counting both the text sent and the translation returned. This is the one option that sends the text being translated to a server of ours — section 3 under External Services says exactly what that involves. The bring-your-own-key path stays free and complete. Nothing is held back to push you toward the subscription. Be realistic about time. A long page is a lot of text, and the model thinks about all of it — that is the point, and it is also why there is a progress bar and a stop button. == Installation == 1. Upload the `aipogeo-context-translate` folder to `/wp-content/plugins/`. Everything it needs is in `vendor/` already. If you are installing from a source checkout instead, run `composer install --no-dev` once in the plugin folder. 2. Activate the plugin. 3. Open Aipogeo Context Translate, go to the translation settings, and tell it what language your site is written in. Then either add your own AI model and API key, or click "Connect to Aipogeo" to use a subscription — connecting fills the key in for you, so there is nothing to copy by hand. 4. Add the languages you want under language management. 5. Translate a page and see how it reads. Once you trust it, turn on background translation and let it work through the rest. == Frequently Asked Questions == = Which AI services can I use? = The bundled php-ai library supports OpenAI, Claude, Gemini, DeepSeek and OpenRouter. Pick a model and the plugin works out which one you mean; if you are going through a gateway with an unfamiliar model name, choose the protocol yourself. If your server cannot reach the provider directly, there is a proxy setting. = Where do the translations live? = In their own table, keyed by the source text and the language pair. A string that shows up in your header on every page is stored once, not once per page. Deactivating the plugin leaves your content exactly as it was. = Will it translate things that should stay put? = `script` and `style` are skipped, along with WordPress core endpoints and static assets. Add the `not-translate` class to anything else you want left alone, or `not-translate-url` on a link to keep that address as it is. = Do I have to translate the whole site at once? = No. Translate the pages that matter, leave the rest, and let visitors or the background worker pick up the slack over time. == External Services == This plugin sends text to an AI service in order to translate it. Nothing is sent until you have configured one of the options below and asked for a translation. Which service is contacted depends entirely on that choice. = 1. The AI provider you configure yourself = Under **Translation Settings → AI service**, choosing "The settings below only" (or "Automatic" with no site-wide provider set up) makes the plugin call the API endpoint you enter, using the API key you enter. That is typically OpenAI, Anthropic, Google Gemini or DeepSeek, but it can be any relay or self-hosted gateway whose address you supply. * **What is sent:** the text extracted from the page being translated, the source and target language names, and your translation prompt. * **When:** each time a translation runs — manually, in the background, or on a visitor request if live translation is enabled. * **Terms and privacy:** these are the provider's own. Please read them before entering a key. For the four built-in providers: OpenAI — https://openai.com/policies/terms-of-use / https://openai.com/policies/privacy-policy , Anthropic — https://www.anthropic.com/legal/consumer-terms / https://www.anthropic.com/legal/privacy , Google Gemini — https://policies.google.com/terms / https://policies.google.com/privacy , DeepSeek — https://cdn.deepseek.com/policies/en-US/deepseek-open-platform-terms-of-service.html / https://cdn.deepseek.com/policies/en-US/deepseek-privacy-policy.html . = 2. This site's own AI configuration = Choosing "This site's AI settings only" hands the request to the AI client built into WordPress 7.0 and later. The provider and credentials are the ones the site owner has configured for the whole site; this plugin neither stores nor sees them. The terms and privacy policy are those of whichever provider is set up there. = 3. The Aipogeo subscription service = Aipogeo runs a paid subscription at https://translate.aipogeo.com . It is off unless you pick "Subscription" and connect an access key. When it is on, the plugin stops calling an AI provider directly: it sends each batch to Aipogeo, Aipogeo calls the AI provider with its own credentials, and the subscription is billed by token. This is the one option where the text being translated leaves your site for a server of ours, so here is what that means in full. * **What is sent:** your access key; this site's home URL, which binds the subscription to a site and lets the service reject keys used elsewhere; and the translation instruction, which contains the text to be translated along with the source and target language. * **What comes back:** the translation, and the number of tokens billed. * **Onward:** to produce the translation, Aipogeo passes the text to a third-party AI provider under its own account. Which provider is in use is listed on the privacy policy page. * **How long it is kept:** the text and the translation live only for the length of the request. Aipogeo does not store them and does not use them for training. * **What is never sent:** your posts as such, your database, or anything about your visitors — only the strings queued for translation. * **When:** when you connect a subscription, activate or release this site, refresh the subscription status, and once per batch while a translation runs. A failed request is refunded and not billed. * **Service provider:** AIPOGEO. * **Terms of service:** https://translate.aipogeo.com/terms * **Privacy policy:** https://translate.aipogeo.com/privacy If you do not use the subscription, none of the above applies: with your own API key the plugin contacts nobody but the provider you configured. == Third-Party Libraries == Two front-end libraries ship with the plugin as their official minified builds, unmodified. Sources and licenses: * **Ace Editor** 1.4.2, BSD 3-Clause. Copyright (c) 2010, Ajax.org B.V. Unminified source: https://github.com/ajaxorg/ace Build the plugin bundles: https://github.com/ajaxorg/ace-builds * **Choices.js**, MIT. Copyright (c) 2016 Josh Johnson. Unminified source: https://github.com/Choices-js/Choices The PHP libraries under `vendor/` are installed by Composer and ship as plain readable source. See `composer.json` and `composer.lock` for exact versions, and `assets/vendor/CREDITS.md` for the full list. == Changelog == = 2.1.1 = * Fixed the DeepSeek privacy policy link under External Services: the address it used had been retired and answered with a 404. Both DeepSeek links now point at the current documents. * The subscription panel on Translation Settings loads its script from a proper enqueued file instead of markup printed into the page, so the script honours the usual dependency and caching rules. * Option and transient names built at runtime now spell the plugin prefix out in full at the point of use, which makes it plain that nothing this plugin writes can collide with another plugin's data. = 2.1.0 = * Translations bought through the Aipogeo subscription are now carried out by the service itself: the plugin sends the text, the service calls the AI provider with its own credentials and sends the translation back. No AI platform key is kept on your site for this route, and there is nothing to configure beyond the access key. * Subscription usage is counted and shown in tokens, the same unit the service bills in, so what the settings screen reports matches your account. = 2.0.1 = * The two default translation prompts are now written in English instead of Chinese, so the plugin is usable out of the box whatever language your site is in. A prompt you have edited yourself is left alone; to pick the new default up, clear the prompt box and save, or press Reset to default. = 2.0.0 = * Renamed the plugin to Aipogeo Context Translate. The text domain, option names and database tables moved with it, so settings and translations saved by an earlier version are not carried over. * The subscription screens are now in English like the rest of the plugin, so they can be translated on translate.wordpress.org along with everything else. * The readme now documents every external service the plugin can contact, what is sent to each and when. = 1.2.0 = * New: translations can be requested through an Aipogeo subscription. Enter one access key and the site is ready to translate — no AI platform account, no top-ups, no model to pick. Activating, checking the subscription and unbinding the site are all on the settings screen, and there is a one-click connect that fetches the key for you. The two existing routes — your own API key, or the site-wide AI configuration of WordPress 7.0 — are untouched. * The AI service section now shows only the settings that belong to the option you picked under "Where translations are requested". The subscription key on its own for the subscription service; nothing to fill in for the site-wide configuration; the model, endpoint and API key only when you bring your own AI account. Fewer unrelated fields to read past on a first run. * Fixed: the subscription option only appeared on WordPress 7.0 and later, so sites on 6.x could not choose it at all. It is always available now, and on 6.x — where there is no site-wide AI configuration — the choice is between the subscription service and your own AI account. = 1.1.3 = * The language switcher no longer loses its layout to the theme around it. Its styles are now anchored to the switcher's own id, so a theme rule such as `.some-menu a { display: block }` can no longer flatten the entries, and the flag and language name in every row start on the same line as the one on the button. Rows also set their own text alignment instead of inheriting the theme's, which on a right-aligned menu left every row starting somewhere different. Custom styling still works — target the same id. = 1.1.2 = * The language switcher's dropdown now lines up with the left edge of the button, so the language shown on the button and the entries below it sit in one column. It still flips to the right edge when the menu would not fit there, which is what happens in its default spot in the top right corner. * When the switcher is placed inside a theme container, its menu is positioned against the switcher itself rather than whatever ancestor happened to be positioned, so it lands where it should and keeps its stacking order. = 1.1.1 = * The language switcher's dropdown is now as wide as its longest entry instead of being squeezed to the width of the button, which left language names behind a horizontal scrollbar. It still never gets narrower than the button, stops growing at 280px, and trims anything longer with an ellipsis. * The same goes for the language dropdown on the settings and language screens: it opens as wide as the longest language name, up to 480px, rather than being held to the width of the field. Its search box stays in place while the list scrolls. * Both lists reserve room for their scrollbar, so a list long enough to scroll no longer has its content pushed sideways into a second scrollbar. = 1.1.0 = * WordPress 6.7 and later is enough again; 7.0 is no longer required. On 6.9 and later, page output is still handed to the output buffer WordPress opens for template enhancements; on earlier versions the plugin opens one of its own and closes it in the same request, so translated pages are served either way. * The choice of where translation requests are sent only appears on WordPress 7.0 and later, which is where a site-wide AI provider can be configured. On earlier versions that row explains the situation instead, and requests go to the plugin's own AI service settings. * A site saved with "this site's AI settings only" and later moved to WordPress 6.x falls back to the plugin's own AI service settings rather than failing every translation. = 1.0.0 = * Renamed the plugin to Aipogeo Context Translate. The option names, database tables and text domain moved with it, so translations and settings saved by an earlier version are not carried over. * Translations can now be requested through the AI provider configured for the whole site in WordPress 7.0, so you no longer have to enter a second API key here. The plugin's own model, key, gateway and relay settings are still there for anything the site-wide configuration does not cover, and a new option on the settings screen decides which of the two is used. * Page output is handed to the output buffer WordPress opens for template enhancements instead of one the plugin opened itself, and the robots.txt buffer is now closed in the same request step that opens it. Both changes keep the buffer stack aligned with other plugins. * WordPress 7.0 is now the minimum, for the site-wide AI configuration and the template enhancement output buffer. * Prompts, translations and replacement rules submitted from the admin screens are sanitized before they are stored, and every value inside a submitted JSON payload is checked individually rather than trusted after decoding. * The admin menu icon style is enqueued rather than printed inline. * Translation files are no longer shipped with the plugin; translations come from translate.wordpress.org once the plugin is published there. = 0.6.1 = * Elements marked as not to be translated now get a little breathing room: 4px of padding on the left and right. Languages such as Chinese and Japanese are written without spaces between words, so a brand name or model number wrapped in `not-translate` tends to sit flush against the text around it — and once the AI has reordered the sentence, it reads as one run-on word. The padding applies to `class="not-translate"`, `class="notranslate"`, `translate="no"` and `translate="0"`, and only when the class attribute is exactly that marker, so elements of your own that merely carry the marker alongside other classes keep their layout untouched. = 0.6.0 = * Translate all now runs five pages at a time instead of one after another, which cuts the wall-clock time of a full run by roughly the same factor. A slot frees up the moment a page finishes, and the next language's list is fetched while the last pages of the current one are still being translated, so the slots never sit idle between languages. * The progress area lists every page currently being translated, each with its own language and elapsed time. * Stop still lets the pages already sent finish, it just does not start new ones. * Worth knowing: with several pages in flight at once, text they share — menus, footers, cookie notices — can be sent to the AI more than once during the first run, because none of them is stored yet when the batch starts. Later runs cost nothing extra for those, and each page still holds its own lock, so no page is ever translated twice at the same time. = 0.5.1 = * Fixed translated pages coming out with scrambled markup on sites whose theme or page builder keeps an HTML template inside a `