{"id":347942,"date":"2026-08-31T04:56:18","date_gmt":"2026-08-31T04:56:18","guid":{"rendered":"https:\/\/cn.wordpress.org\/plugins\/ai-context-translator\/"},"modified":"2026-08-31T04:55:43","modified_gmt":"2026-08-31T04:55:43","slug":"aipogeo-context-translate","status":"publish","type":"plugin","link":"https:\/\/mn.wordpress.org\/plugins\/aipogeo-context-translate\/","author":23540446,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"2.1.1","stable_tag":"2.1.1","tested":"7.1","requires":"6.7","requires_php":"8.0","requires_plugins":null,"header_name":"Aipogeo Context Translate","header_author":"AIPOGEO","header_description":"Translate a whole site with an AI that reads each page in full, proofread the result page by page, and serve it under a language directory with hreflang and a language switcher.","assets_banners_color":"5450e6","last_updated":"2026-08-31 04:55:43","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/translate.aipogeo.com\/","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":53,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"2.1.1":{"tag":"2.1.1","author":"yfsystem","date":"2026-08-31 04:55:43","revision":3673384}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3673383,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3673383,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3673383,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3673383,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["2.1.1"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[2353,1734,99,2333],"plugin_category":[48],"plugin_contributors":[278424],"plugin_business_model":[],"class_list":["post-347942","plugin","type-plugin","status-publish","hentry","plugin_tags-ai","plugin_tags-localization","plugin_tags-multilingual","plugin_tags-translation","plugin_category-language-tools","plugin_contributors-yfsystem","plugin_committers-yfsystem"],"banners":{"banner":"https:\/\/ps.w.org\/aipogeo-context-translate\/assets\/banner-772x250.png?rev=3673383","banner_2x":"https:\/\/ps.w.org\/aipogeo-context-translate\/assets\/banner-1544x500.png?rev=3673383","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/aipogeo-context-translate\/assets\/icon-128x128.png?rev=3673383","icon_2x":"https:\/\/ps.w.org\/aipogeo-context-translate\/assets\/icon-256x256.png?rev=3673383","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Most translation tools work one string at a time. The engine sees \"Home\", or\n\"Post\", or a lone product name, and guesses. Guess wrong and your menu reads\nlike nonsense to anyone who speaks the language.<\/p>\n\n<p>This plugin hands the entire rendered page to an AI model instead. The model\ncan see the headline above a button and the paragraph below it before it\ndecides what that button means.<\/p>\n\n<p>Translations go into the plugin's own table and are served under a language\ndirectory, <code>\/en\/<\/code> or <code>\/ja\/<\/code>. Your posts are never touched. Because the work\nhappens after WordPress has finished rendering, it also covers menus, widgets,\nmeta tags, alt text and placeholders \u2014 not just the post body.<\/p>\n\n<p>AI translation is never perfect, so there is a screen for fixing it. Pick a\npage, read the original and the translation side by side, change any line you\ndisagree with. Your edits stay put; the next run will not overwrite them.<\/p>\n\n<h4>Three ways to get pages translated<\/h4>\n\n<ul>\n<li><strong>By hand.<\/strong> Open a page, press translate, watch it fill in.<\/li>\n<li><strong>In the background.<\/strong> While you have the admin open, your browser feeds\npending pages to the server one at a time.<\/li>\n<li><strong>When a visitor arrives.<\/strong> Anything still missing gets translated on the\nspot. You can also tell the plugin to keep serving the original page until\nthe translation is, say, 80% complete.<\/li>\n<\/ul>\n\n<p>All three share per-page locks: two editors working at the same time will not\ntranslate the same page twice or double your API bill, while different pages\ntranslate in parallel without queueing behind each other. A lock left behind\nby a crashed job expires by itself once the request timeout passes.<\/p>\n\n<h4>What you can set up<\/h4>\n\n<ul>\n<li><strong>Languages.<\/strong> URL prefix, hreflang and regional variants, order in the\nswitcher, and who gets to see them \u2014 everyone, search engines only, or human\nvisitors only.<\/li>\n<li><strong>The instruction sent to the AI.<\/strong> Rewrite it if the default tone is wrong\nfor your site; just keep the three variables it needs. Translated URL paths\nget their own instruction, so the main one stays about prose.<\/li>\n<li><strong>Replacement rules, per language.<\/strong> For the brand names and terms the model\nkeeps getting wrong. Plain text, exact match or regular expression.<\/li>\n<li><strong>The language switcher.<\/strong> A floating button you can drag anywhere, which\nremembers where you left it. Or hand it a container id and style it yourself.\nFlags are optional.<\/li>\n<\/ul>\n\n<h4>Also taken care of<\/h4>\n\n<ul>\n<li>Internal links point at the right language.<\/li>\n<li>URL paths can be translated too, and the translated address still resolves\nback to the correct post.<\/li>\n<li>hreflang, including x-default and regional variants.<\/li>\n<li>Sitemap URLs are localized, and robots.txt gets a Sitemap line per language.<\/li>\n<\/ul>\n\n<h4>What it costs you<\/h4>\n\n<p><strong>Bring your own API key.<\/strong> OpenAI, Claude, Gemini, DeepSeek and OpenRouter all\nwork out of the box, and the model name usually tells the plugin which one you\nmean. You pay that provider for what you translate; the plugin adds nothing on\ntop, and with this option it contacts nobody but the provider you configured.<\/p>\n\n<p><strong>Or subscribe.<\/strong> If you would rather not open an account with an AI provider,\ntop up a balance and pick a model, there is a paid subscription at\nhttps:\/\/translate.aipogeo.com . Connect your site once and translation runs\nthrough Aipogeo: it holds the AI credentials, and the subscription is billed by\ntoken \u2014 the same unit the AI model itself charges in, counting both the text\nsent and the translation returned. This is the one option that sends the text\nbeing translated to a server of ours \u2014 section 3 under External Services says\nexactly what that involves.<\/p>\n\n<p>The bring-your-own-key path stays free and complete. Nothing is held back to\npush you toward the subscription.<\/p>\n\n<p>Be realistic about time. A long page is a lot of text, and the model thinks\nabout all of it \u2014 that is the point, and it is also why there is a progress bar\nand a stop button.<\/p>\n\n<h3>External Services<\/h3>\n\n<p>This plugin sends text to an AI service in order to translate it. Nothing is\nsent until you have configured one of the options below and asked for a\ntranslation. Which service is contacted depends entirely on that choice.<\/p>\n\n<h4>1. The AI provider you configure yourself<\/h4>\n\n<p>Under <strong>Translation Settings \u2192 AI service<\/strong>, choosing \"The settings below only\"\n(or \"Automatic\" with no site-wide provider set up) makes the plugin call the API\nendpoint you enter, using the API key you enter. That is typically OpenAI,\nAnthropic, Google Gemini or DeepSeek, but it can be any relay or self-hosted\ngateway whose address you supply.<\/p>\n\n<ul>\n<li><strong>What is sent:<\/strong> the text extracted from the page being translated, the\nsource and target language names, and your translation prompt.<\/li>\n<li><strong>When:<\/strong> each time a translation runs \u2014 manually, in the background, or on a\nvisitor request if live translation is enabled.<\/li>\n<li><strong>Terms and privacy:<\/strong> these are the provider's own. Please read them before\nentering a key. For the four built-in providers:\nOpenAI \u2014 https:\/\/openai.com\/policies\/terms-of-use \/ https:\/\/openai.com\/policies\/privacy-policy ,\nAnthropic \u2014 https:\/\/www.anthropic.com\/legal\/consumer-terms \/ https:\/\/www.anthropic.com\/legal\/privacy ,\nGoogle Gemini \u2014 https:\/\/policies.google.com\/terms \/ https:\/\/policies.google.com\/privacy ,\nDeepSeek \u2014 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 .<\/li>\n<\/ul>\n\n<h4>2. This site's own AI configuration<\/h4>\n\n<p>Choosing \"This site's AI settings only\" hands the request to the AI client built\ninto WordPress 7.0 and later. The provider and credentials are the ones the site\nowner has configured for the whole site; this plugin neither stores nor sees\nthem. The terms and privacy policy are those of whichever provider is set up\nthere.<\/p>\n\n<h4>3. The Aipogeo subscription service<\/h4>\n\n<p>Aipogeo runs a paid subscription at https:\/\/translate.aipogeo.com . It is off\nunless you pick \"Subscription\" and connect an access key. When it is on, the\nplugin stops calling an AI provider directly: it sends each batch to Aipogeo,\nAipogeo calls the AI provider with its own credentials, and the subscription is\nbilled by token.<\/p>\n\n<p>This is the one option where the text being translated leaves your site for a\nserver of ours, so here is what that means in full.<\/p>\n\n<ul>\n<li><strong>What is sent:<\/strong> your access key; this site's home URL, which binds the\nsubscription to a site and lets the service reject keys used elsewhere; and\nthe translation instruction, which contains the text to be translated along\nwith the source and target language.<\/li>\n<li><strong>What comes back:<\/strong> the translation, and the number of tokens billed.<\/li>\n<li><strong>Onward:<\/strong> to produce the translation, Aipogeo passes the text to a\nthird-party AI provider under its own account. Which provider is in use is\nlisted on the privacy policy page.<\/li>\n<li><strong>How long it is kept:<\/strong> the text and the translation live only for the\nlength of the request. Aipogeo does not store them and does not use them for\ntraining.<\/li>\n<li><strong>What is never sent:<\/strong> your posts as such, your database, or anything about\nyour visitors \u2014 only the strings queued for translation.<\/li>\n<li><strong>When:<\/strong> when you connect a subscription, activate or release this site,\nrefresh the subscription status, and once per batch while a translation runs.\nA failed request is refunded and not billed.<\/li>\n<li><strong>Service provider:<\/strong> AIPOGEO.<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/translate.aipogeo.com\/terms<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/translate.aipogeo.com\/privacy<\/li>\n<\/ul>\n\n<p>If you do not use the subscription, none of the above applies: with your own API\nkey the plugin contacts nobody but the provider you configured.<\/p>\n\n<h3>Third-Party Libraries<\/h3>\n\n<p>Two front-end libraries ship with the plugin as their official minified builds,\nunmodified. Sources and licenses:<\/p>\n\n<ul>\n<li><strong>Ace Editor<\/strong> 1.4.2, BSD 3-Clause. Copyright (c) 2010, Ajax.org B.V.\nUnminified source: https:\/\/github.com\/ajaxorg\/ace\nBuild the plugin bundles: https:\/\/github.com\/ajaxorg\/ace-builds<\/li>\n<li><strong>Choices.js<\/strong>, MIT. Copyright (c) 2016 Josh Johnson.\nUnminified source: https:\/\/github.com\/Choices-js\/Choices<\/li>\n<\/ul>\n\n<p>The PHP libraries under <code>vendor\/<\/code> are installed by Composer and ship as plain\nreadable source. See <code>composer.json<\/code> and <code>composer.lock<\/code> for exact versions, and\n    assets\/vendor\/CREDITS.md for the full list.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>aipogeo-context-translate<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.\nEverything it needs is in <code>vendor\/<\/code> already. If you are installing from a\nsource checkout instead, run <code>composer install --no-dev<\/code> once in the plugin\nfolder.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Open Aipogeo Context Translate, go to the translation settings, and tell it what\nlanguage your site is written in. Then either add your own AI model and API\nkey, or click \"Connect to Aipogeo\" to use a subscription \u2014 connecting fills\nthe key in for you, so there is nothing to copy by hand.<\/li>\n<li>Add the languages you want under language management.<\/li>\n<li>Translate a page and see how it reads. Once you trust it, turn on background\ntranslation and let it work through the rest.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"which%20ai%20services%20can%20i%20use%3F\"><h3>Which AI services can I use?<\/h3><\/dt>\n<dd><p>The bundled php-ai library supports OpenAI, Claude, Gemini, DeepSeek and\nOpenRouter. Pick a model and the plugin works out which one you mean; if you\nare going through a gateway with an unfamiliar model name, choose the protocol\nyourself. If your server cannot reach the provider directly, there is a proxy\nsetting.<\/p><\/dd>\n<dt id=\"where%20do%20the%20translations%20live%3F\"><h3>Where do the translations live?<\/h3><\/dt>\n<dd><p>In their own table, keyed by the source text and the language pair. A string\nthat shows up in your header on every page is stored once, not once per page.\nDeactivating the plugin leaves your content exactly as it was.<\/p><\/dd>\n<dt id=\"will%20it%20translate%20things%20that%20should%20stay%20put%3F\"><h3>Will it translate things that should stay put?<\/h3><\/dt>\n<dd><p>script and <code>style<\/code> are skipped, along with WordPress core endpoints and\nstatic assets. Add the <code>not-translate<\/code> class to anything else you want left\nalone, or <code>not-translate-url<\/code> on a link to keep that address as it is.<\/p><\/dd>\n<dt id=\"do%20i%20have%20to%20translate%20the%20whole%20site%20at%20once%3F\"><h3>Do I have to translate the whole site at once?<\/h3><\/dt>\n<dd><p>No. Translate the pages that matter, leave the rest, and let visitors or the\nbackground worker pick up the slack over time.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>2.1.1<\/h4>\n\n<ul>\n<li>Fixed the DeepSeek privacy policy link under External Services: the address it\nused had been retired and answered with a 404. Both DeepSeek links now point\nat the current documents.<\/li>\n<li>The subscription panel on Translation Settings loads its script from a proper\nenqueued file instead of markup printed into the page, so the script honours\nthe usual dependency and caching rules.<\/li>\n<li>Option and transient names built at runtime now spell the plugin prefix out in\nfull at the point of use, which makes it plain that nothing this plugin writes\ncan collide with another plugin's data.<\/li>\n<\/ul>\n\n<h4>2.1.0<\/h4>\n\n<ul>\n<li>Translations bought through the Aipogeo subscription are now carried out by\nthe service itself: the plugin sends the text, the service calls the AI\nprovider with its own credentials and sends the translation back. No AI\nplatform key is kept on your site for this route, and there is nothing to\nconfigure beyond the access key.<\/li>\n<li>Subscription usage is counted and shown in tokens, the same unit the service\nbills in, so what the settings screen reports matches your account.<\/li>\n<\/ul>\n\n<h4>2.0.1<\/h4>\n\n<ul>\n<li>The two default translation prompts are now written in English instead of\nChinese, so the plugin is usable out of the box whatever language your site is\nin. A prompt you have edited yourself is left alone; to pick the new default\nup, clear the prompt box and save, or press Reset to default.<\/li>\n<\/ul>\n\n<h4>2.0.0<\/h4>\n\n<ul>\n<li>Renamed the plugin to Aipogeo Context Translate. The text domain, option names\nand database tables moved with it, so settings and translations saved by an\nearlier version are not carried over.<\/li>\n<li>The subscription screens are now in English like the rest of the plugin, so\nthey can be translated on translate.wordpress.org along with everything else.<\/li>\n<li>The readme now documents every external service the plugin can contact, what\nis sent to each and when.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>New: translations can be requested through an Aipogeo subscription. Enter one\naccess key and the site is ready to translate \u2014 no AI platform account, no\ntop-ups, no model to pick. Activating, checking the subscription and\nunbinding the site are all on the settings screen, and there is a one-click\nconnect that fetches the key for you. The two existing routes \u2014 your own API\nkey, or the site-wide AI configuration of WordPress 7.0 \u2014 are untouched.<\/li>\n<li>The AI service section now shows only the settings that belong to the option\nyou picked under \"Where translations are requested\". The subscription key on\nits own for the subscription service; nothing to fill in for the site-wide\nconfiguration; the model, endpoint and API key only when you bring your own\nAI account. Fewer unrelated fields to read past on a first run.<\/li>\n<li>Fixed: the subscription option only appeared on WordPress 7.0 and later, so\nsites on 6.x could not choose it at all. It is always available now, and on\n6.x \u2014 where there is no site-wide AI configuration \u2014 the choice is between\nthe subscription service and your own AI account.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>The language switcher no longer loses its layout to the theme around it. Its\nstyles are now anchored to the switcher's own id, so a theme rule such as\n  .some-menu a { display: block } can no longer flatten the entries, and the\nflag and language name in every row start on the same line as the one on the\nbutton. Rows also set their own text alignment instead of inheriting the\ntheme's, which on a right-aligned menu left every row starting somewhere\ndifferent. Custom styling still works \u2014 target the same id.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>The language switcher's dropdown now lines up with the left edge of the\nbutton, so the language shown on the button and the entries below it sit in\none column. It still flips to the right edge when the menu would not fit\nthere, which is what happens in its default spot in the top right corner.<\/li>\n<li>When the switcher is placed inside a theme container, its menu is positioned\nagainst the switcher itself rather than whatever ancestor happened to be\npositioned, so it lands where it should and keeps its stacking order.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>The language switcher's dropdown is now as wide as its longest entry instead\nof being squeezed to the width of the button, which left language names behind\na horizontal scrollbar. It still never gets narrower than the button, stops\ngrowing at 280px, and trims anything longer with an ellipsis.<\/li>\n<li>The same goes for the language dropdown on the settings and language screens:\nit opens as wide as the longest language name, up to 480px, rather than being\nheld to the width of the field. Its search box stays in place while the list\nscrolls.<\/li>\n<li>Both lists reserve room for their scrollbar, so a list long enough to scroll\nno longer has its content pushed sideways into a second scrollbar.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>WordPress 6.7 and later is enough again; 7.0 is no longer required. On 6.9 and\nlater, page output is still handed to the output buffer WordPress opens for\ntemplate enhancements; on earlier versions the plugin opens one of its own and\ncloses it in the same request, so translated pages are served either way.<\/li>\n<li>The choice of where translation requests are sent only appears on WordPress\n7.0 and later, which is where a site-wide AI provider can be configured. On\nearlier versions that row explains the situation instead, and requests go to\nthe plugin's own AI service settings.<\/li>\n<li>A site saved with \"this site's AI settings only\" and later moved to WordPress\n6.x falls back to the plugin's own AI service settings rather than failing\nevery translation.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Renamed the plugin to Aipogeo Context Translate. The option names,\ndatabase tables and text domain moved with it, so translations and settings\nsaved by an earlier version are not carried over.<\/li>\n<li>Translations can now be requested through the AI provider configured for the\nwhole site in WordPress 7.0, so you no longer have to enter a second API key\nhere. The plugin's own model, key, gateway and relay settings are still there\nfor anything the site-wide configuration does not cover, and a new option on\nthe settings screen decides which of the two is used.<\/li>\n<li>Page output is handed to the output buffer WordPress opens for template\nenhancements instead of one the plugin opened itself, and the robots.txt\nbuffer is now closed in the same request step that opens it. Both changes keep\nthe buffer stack aligned with other plugins.<\/li>\n<li>WordPress 7.0 is now the minimum, for the site-wide AI configuration and the\ntemplate enhancement output buffer.<\/li>\n<li>Prompts, translations and replacement rules submitted from the admin screens\nare sanitized before they are stored, and every value inside a submitted JSON\npayload is checked individually rather than trusted after decoding.<\/li>\n<li>The admin menu icon style is enqueued rather than printed inline.<\/li>\n<li>Translation files are no longer shipped with the plugin; translations come\nfrom translate.wordpress.org once the plugin is published there.<\/li>\n<\/ul>\n\n<h4>0.6.1<\/h4>\n\n<ul>\n<li>Elements marked as not to be translated now get a little breathing room: 4px of\npadding on the left and right. Languages such as Chinese and Japanese are\nwritten without spaces between words, so a brand name or model number wrapped\nin <code>not-translate<\/code> tends to sit flush against the text around it \u2014 and once the\nAI has reordered the sentence, it reads as one run-on word. The padding applies\nto <code>class=\"not-translate\"<\/code>, <code>class=\"notranslate\"<\/code>, <code>translate=\"no\"<\/code> and\n  translate=\"0\", and only when the class attribute is exactly that marker, so\nelements of your own that merely carry the marker alongside other classes keep\ntheir layout untouched.<\/li>\n<\/ul>\n\n<h4>0.6.0<\/h4>\n\n<ul>\n<li>Translate all now runs five pages at a time instead of one after another, which\ncuts the wall-clock time of a full run by roughly the same factor. A slot frees\nup the moment a page finishes, and the next language's list is fetched while the\nlast pages of the current one are still being translated, so the slots never sit\nidle between languages.<\/li>\n<li>The progress area lists every page currently being translated, each with its own\nlanguage and elapsed time.<\/li>\n<li>Stop still lets the pages already sent finish, it just does not start new ones.<\/li>\n<li>Worth knowing: with several pages in flight at once, text they share \u2014 menus,\nfooters, cookie notices \u2014 can be sent to the AI more than once during the first\nrun, because none of them is stored yet when the batch starts. Later runs cost\nnothing extra for those, and each page still holds its own lock, so no page is\never translated twice at the same time.<\/li>\n<\/ul>\n\n<h4>0.5.1<\/h4>\n\n<ul>\n<li>Fixed translated pages coming out with scrambled markup on sites whose theme\nor page builder keeps an HTML template inside a <code>&lt;script type=\"text\/html\"&gt;<\/code>\nblock \u2014 video lightboxes, carousels and similar components are usually built\nthis way. PHP's HTML parser treats the first closing tag inside such a block\nas the end of the script, so the rest of the template leaked into the page,\nelements closed in the wrong order and stray closing tags were dropped. The\ncontents of <code>script<\/code> and <code>style<\/code> are now kept out of the parser's way and put\nback untouched, byte for byte.<\/li>\n<li>As a side effect, text belonging to those templates is no longer picked up as\ntranslatable content.<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>Translate all no longer stops at the language picked in the toolbar. It starts\nwith that language and then works through the pending pages of every other\ntarget language on its own, so a site with several languages can be filled in\none run instead of one round per language.<\/li>\n<li>The progress line now names the language currently being translated, and its\ncounters cover all target languages together.<\/li>\n<li>Each language's page list is fetched when its turn comes, so pages translated\nin the meantime by the background worker are not translated again.<\/li>\n<\/ul>\n\n<h4>0.4.1<\/h4>\n\n<ul>\n<li>Fixed the language menu being hidden behind other page elements on some\nthemes. The menu now carries its own stacking order, so it stays on top even\nwhen the switcher is docked into a theme container instead of floating.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>A page is now sent to the AI in one request whenever it fits. Batches used to\nbe capped at 6,000 characters and 50 items, which split an ordinary page into\nseven or eight requests \u2014 most of them nowhere near the character limit,\nbecause menu items, buttons and alt texts are only a few words each. The item\ncap is now 1,000, and the character cap follows the model instead of a fixed\nnumber.<\/li>\n<li>Max output tokens now decides how much of a page goes into one request. It is\nconverted to characters (about 1.6 per token for Chinese, Japanese and Korean,\n4 for languages written in the Latin alphabet) and never drops below 65,535\ncharacters. Left at 0 \u2014 the default \u2014 the plugin reckons with 65,536 tokens,\nwhich is where single-reply limits sit these days, so an ordinary page goes\nout in a single request. Note that this is about how much a model can write\nback in one reply, not about its context window: a million-token context says\nhow much it can read.<\/li>\n<li>Fewer requests also means the instruction is sent once per page instead of\nonce per batch, and the AI sees the whole page at once, which is what the\ncontext-aware translation is about in the first place.<\/li>\n<\/ul>\n\n<h4>0.3.1<\/h4>\n\n<ul>\n<li>Fixed pages coming back as 404 on sites whose rewrite rules or security layer\nreject unknown query parameters. Pages used to be fetched with <code>?apgt_src=1<\/code>\nappended; the address is now requested exactly as it is, and the marker that\ntells the front end not to substitute translations travels in the\n  X-APGT-Source request header instead. <code>apgt_src<\/code> still works if you add it\nby hand to look at an untranslated page.<\/li>\n<li>Source pages are now fetched with <code>Cache-Control: no-cache<\/code>, so a caching\nplugin cannot hand back a stale copy of the page being translated.<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Translate Pages: when the source page cannot be fetched, the response now\ncarries the details of the request that failed \u2014 the address that was actually\nrequested, the IP it resolved to, any redirects, the response headers and the\nfirst few hundred characters of the body. It also states whether the response\ncame from WordPress at all, which tells you straight away if a 404 was served\nby the web server or a security layer rather than by WordPress.<\/li>\n<li>The details are logged to the browser console on the Translate Pages screen,\nand a short summary is appended to the error shown in the status bar.<\/li>\n<li>New setting, Translation Settings \u2192 Fetching source pages \u2192 Fetch IP: enter an\nIP address and pages are fetched straight from it, for servers that cannot\nreach their own domain because it resolves to a CDN or a load balancer, or\nbecause their DNS does not know it. The Host header and the HTTPS certificate\nkeep using your domain, so servers hosting several sites are unaffected. Empty\nby default, which uses normal DNS. The filter <code>apgt_fetch_resolve_ip<\/code> can\noverride the stored value.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Translation Settings and Languages: the language dropdowns are searchable now.\nType a language name, an ISO code or the name in its own script to filter the\nlist instead of scrolling through every language.<\/li>\n<li>Translate Pages: the current line is highlighted on both sides at once, so the\nline you are reading in the source is easy to find in the translation.<\/li>\n<li>Translate Pages: fixed the two panes losing sync near the end of long pages.\nWhen the translation wrapped to a different height than the source, the last\nlines of the taller pane could not be scrolled into view.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Admin: translation settings, language management, page translation and\ntranslation data screens.<\/li>\n<li>Translation: by hand, background worker and on-the-fly, sharing per-page locks.<\/li>\n<li>Front end: language directory routing, internal link localization, hreflang,\nand a language switcher.<\/li>\n<li>SEO: localized sitemap URLs, and per-language Sitemap lines in robots.txt.<\/li>\n<li>Admin interface available in English, Simplified Chinese and Traditional\nChinese. Language names in the admin follow the admin language too.<\/li>\n<\/ul>","raw_excerpt":"Translate your site with an AI that reads the whole page first, then fix whatever it got wrong before your visitors see it.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/347942","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=347942"}],"author":[{"embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/yfsystem"}],"wp:attachment":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=347942"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=347942"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=347942"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=347942"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=347942"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=347942"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}