=== Effortless Taiwan Mandarin Helper ===
Contributors: domclic
Donate link: https://id7.dev/donate/?plugin=effortless-taiwan-mandarin-helper
Tags: taiwanese mandarin, translation, chinese, pinyin, bopomofo
Requires at least: 7.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.0.34
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Translate any text into Taiwanese Mandarin with Pinyin and Bopomofo annotations, powered by OpenAI, Anthropic, or WordPress's own core AI Client.

== Description ==

Effortless Taiwan Mandarin Helper translates any text into natural Taiwanese Mandarin (Traditional Chinese as used in Taiwan). Results include Hanyu Pinyin with tone marks and Bopomofo annotations rendered with the BpmfHuninn font.

**Features:**

* Admin quick-lookup tool (WP Admin → Tools → Mandarin Translator)
* Embeddable front-end shortcode: `[eltmh_translator]` or `[eltmh_translator text="Hello"]`
* Supports OpenAI (ChatGPT 4o, default), Anthropic (Claude), or WordPress's own core AI Client (WP 7.0+, site-configured provider)
* Indefinite translation cache — identical inputs never hit the API twice
* Detects source language automatically
* Settings → Mandarin Helper → Display: site-wide show/hide toggles for each result row (Original, Chinese, Pinyin, Bopomofo, English), overridable per-shortcode

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/`.
2. Activate the plugin from the Plugins screen.
3. Go to **Settings → Mandarin Helper** and choose a provider: enter your OpenAI or Anthropic API key, or select "WordPress AI Client" to use the provider already configured for WordPress core (WP 7.0+).
4. Use the admin tool at **Tools → Mandarin Translator** or embed the shortcode on any page.

== Shortcode Usage ==

Basic (visitor types their own text):
`[eltmh_translator]`

With preset text (pre-fills the textarea; renders immediately if already cached):
`[eltmh_translator text="Hello, how are you?"]`

== Frequently Asked Questions ==

= Which AI provider should I use? =
OpenAI (gpt-4o) is the default and produces fast, accurate results. Anthropic (claude-sonnet-4-6) is an excellent alternative. Both use the same translation prompt.

= Are translations cached? =
Yes. Every unique translation is cached indefinitely in your WordPress database. You can clear the cache at **Settings → Mandarin Helper**.

= What is the character limit per translation? =
500 characters per request.

== External services ==

This plugin relies on a third-party AI API, chosen by the site administrator in Settings → Mandarin Helper, to perform the translation. The text a visitor submits through the shortcode form is sent to whichever provider is configured — no other data (name, email, IP address) is sent.

* **OpenAI API** — Used when OpenAI is selected as the provider (default). The submitted text is sent to OpenAI's Chat Completions API (model: gpt-4o) to generate the translation, Pinyin and Bopomofo. Terms: https://openai.com/policies/row-terms-of-use/ — Privacy policy: https://openai.com/policies/row-privacy-policy/
* **Anthropic API** — Used when Anthropic is selected as the provider. The submitted text is sent to Anthropic's Messages API (model: claude-sonnet-4-6) to generate the translation, Pinyin and Bopomofo. Terms: https://www.anthropic.com/legal/consumer-terms — Privacy policy: https://www.anthropic.com/legal/privacy
* **WordPress AI Client** — Used when "WordPress AI Client" is selected as the provider. The plugin makes no direct API call in this case; it delegates to whichever AI provider the site administrator has already configured for WordPress core (WP 7.0+). Refer to that provider's own terms and privacy policy.

== Changelog ==

= 1.0.34 =
* Fix: POST /translate's rate limit (10 requests/minute) previously exempted every logged-in user entirely, so any authenticated account (e.g. a Subscriber on a site with open registration) had unlimited calls to this billable AI-translation endpoint. The nonce checked by permission_callback is intentionally obtainable by any visitor from the public /nonce route, so it was never meant to be the cost-control mechanism — the rate limit is. Logged-in callers are now capped at the same 10/minute, keyed per account rather than per IP.

= 1.0.33 =
* Fix: the "WordPress AI Client" provider's JSON schema request was missing `additionalProperties: false` and didn't list every property in `required` (with a nullable type for the optional "english" field). Sites whose core AI Client connector routes to OpenAI's Structured Outputs API were getting a `400 Bad Request` ("'additionalProperties' is required to be supplied and to be false") on every translation. OpenAI and Anthropic direct-key providers were unaffected.

= 1.0.32 =
* Update: raised `Requires at least` to WordPress 7.0, since the "WordPress AI Client" provider option depends on core's `wp_ai_client_prompt()`, which only ships in WP 7.0+.

= 1.0.31 =
* Fix: guarded the `wp_ai_client_prompt()` call site with a direct, literal `function_exists()` check in the same conditional (previously the guard lived one method away), so WordPress.org's Plugin Check no longer flags it as incompatible with this plugin's `Requires at least: 6.0` floor.

= 1.0.30 =
* Feature: added "WordPress AI Client" as a third provider option (Settings → Mandarin Helper), for sites running WordPress 7.0+ that want to use their site-configured AI provider instead of a plugin-specific API key. OpenAI and Anthropic remain first-class, permanent options.

= 1.0.29 =
* Feature: added Settings → Mandarin Helper → Display section with site-wide show/hide checkboxes for each result row (Original, Chinese, Pinyin, Bopomofo, English). Per-shortcode attributes (e.g. `pinyin="no"`) still override the site-wide default.

= 1.0.28 =
* Fix: replaced the bare `__return_true` permission_callback on GET /nonce with a named, documented callback (`allow_public_nonce_request()`) explaining why the endpoint is intentionally public, so automated plugin-review scans stop flagging it for manual re-review.

= 1.0.27 =
* Fix: trimmed the readme's Tags line from 6 to 5 (removed "language learning"), per WordPress.org's tag limit.
* Update: Tested up to WordPress 7.1.

= 1.0.26 =
* Fix: corrected the plugin header's `Author` field, which incorrectly read "DomClic" instead of "domclic".

= 1.0.25 =
* Fix: removed the Plugin URI and Author URI headers (pointed at a promotional domain, not permitted for submission), and added the required Donate link plus a dismissible donate notice on the Settings screen.
* Fix: the plugin's name in the Plugins list is now forced to stay in English, so a GlotPress community translation of the "Plugin Name" header can no longer rename the brand on non-English sites.
* Docs: added the required "External services" section disclosing the OpenAI/Anthropic API calls.

= 1.0.24 =
* Update: Confirmed compatibility with WordPress 7.0.

= 1.0.23 =
* Update: Tested up to WordPress 7.0.

= 1.0.22 =
* Enhancement: Show version as "vX.X.X" left of textarea, opposite the character counter; both made smaller.

= 1.0.21 =
* Enhancement: Rename Tools page to "Mandarin Helper"; add version title to frontend widget.

= 1.0.20 =
* Enhancement: Show "Done!" in the spinner area after a successful translation.

= 1.0.19 =
* Enhancement: Show plugin version next to each admin page title and in the frontend widget.

= 1.0.18 =
* Fix: Recover from AI responses wrapped in markdown code fences or prefixed with plain text.
* Fix: Surface the actual provider error message (e.g. quota exceeded, rate limit) instead of a generic HTTP status code.

= 1.0.17 =
* feat: clear button now also hides results and enables Previous to return to the last translation

= 1.0.16 =
* fix: copy button icon enlarged (font-size 1.3em)

= 1.0.15 =
* fix: copy button now appears inline inside the label, immediately after the colon (e.g. "Pinyin: ⎘")

= 1.0.14 =
* fix: copy buttons now appear next to row labels (Pinyin, Bopomofo, etc.) instead of after the content text

= 1.0.13 =
* feat: copy buttons on result rows, character counter on textarea, API key test buttons, provider-aware cache keys, anonymous rate limiting (10 req/min), cache eviction cap (500 entries), model selection dropdowns, aria-live on results div

= 1.0.12 =
* Revert: removed Web Speech API speaker buttons (Pinyin, Bopomofo, English rows).

= 1.0.11 =
* Feature: Web Speech API speaker buttons on Pinyin, Bopomofo, English rows.

= 1.0.10 =
* Improvement: dictionary upgraded to full CC-CEDICT (121,366 entries, all word lengths); greedy segmentation extended to 6-char matches for accurate compound-word tooltips (~2.4 MB gzip, lazy-loaded).

= 1.0.9 =
* Feature: dictionary tooltips now work on the Bopomofo row as well as the Chinese row; BpmfHuninn font is preserved via CSS inheritance so Bopomofo annotations continue to render correctly.

= 1.0.8 =
* Feature: × clear button inside the textarea — appears when there is text, clears and refocuses on click.

= 1.0.7 =
* Feature: inline dictionary — hover any Chinese character or 2-character word in the result to see a tooltip with the Traditional form, Pinyin, and English gloss. Powered by CC-CEDICT (72,626 entries, lazy-loaded on first hover, ~1.2 MB gzip).

= 1.0.6 =
* Feature: translation history stored in localStorage (up to 50 entries); ← Previous / Next → arrows let you navigate past translations; last translation is restored on page reload.

= 1.0.5 =
* Fix: shortcode display attributes (pinyin/zhuyin/original/chinese/translation="no") now work correctly — JS renderResult() guards against missing elements.

= 1.0.4 =
* Remove: TOCFL/HSK vocabulary level selector removed.
* Feature: shortcode display attributes — pinyin/zhuyin/original/chinese/translation="yes/no".
* Improvement: system prompt explicitly prefers Taiwanese Mandarin vocabulary over Mainland Chinese.

= 1.0.3 =
* Feature: TOCFL (A1–C2) and HSK (1–6) vocabulary level selector in the widget — translations target the chosen learner level.
* Feature: shortcode display attributes — control which result rows are shown: pinyin="yes/no" zhuyin="yes/no" original="yes/no" chinese="yes/no" translation="yes/no".
* Improvement: system prompt now explicitly prefers Taiwanese Mandarin vocabulary and expressions over Mainland Chinese equivalents.

= 1.0.2 =
* Feature: when input is Chinese (Simplified or Traditional), also show an English translation in the results panel.

= 1.0.1 =
* Fix: check HTTP status codes in OpenAI and Anthropic API calls to surface meaningful errors on 401/429 instead of "Invalid JSON".
* Fix: add nonce-refresh REST endpoint (`/eltmh/v1/nonce`) and update front-end JS to fetch a fresh nonce on page load, preventing 403 errors on full-page-cached sites.

= 1.0.0 =
* Initial release.
