=== WakaLang ===
Contributors: noricku, wakalab
Tags: multilingual, translation, hreflang, language-switcher, i18n
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 0.6.25
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Keep visitors in their language. Lightweight URL-prefix language routing, hreflang, and a language switcher for WordPress.

== Description ==

WakaLang is a lightweight multilingual plugin for WordPress sites that publish manually translated content. It keeps the current language stable through clean URL prefixes such as `/en/about/` and `/ja/about/`, then helps you connect translated posts, terms, menus, navigation blocks, SEO metadata, and `hreflang` output.

The free plugin is complete for manual multilingual publishing and makes no external network calls.

**Free features**

* Register the languages your site offers (code, locale, names, URL prefix, default).
* URL-prefix routing: every page is reachable under each language prefix (`/en/…`, `/ja/…`), with the prefix as the single source of truth for the active language.
* A language switcher with automatic header/footer placement, an editor block, the `[wakalang_switcher]` shortcode, and the `wakalang_language_switcher()` template function — with optional flags rendered as Unicode emoji (no external requests).
* `hreflang` alternate links (and an optional `x-default`) for translated content. If `x_default_url` is left empty, WakaLang derives it from the current page's default-language URL.
* Internal links, menu links, the site/home link, and block-theme (FSE) navigation all keep the current language's URL prefix.
* Link posts, pages, and taxonomy terms into translation groups from a post or term editor, and create draft translations.
* Archive, search, RSS/Atom feeds, and the core `wp-sitemap.xml` are scoped to the current language.
* Translate taxonomy terms (category, tag, custom taxonomy) with per-language name and slug.
* Manage a per-translation SEO title and meta description, handed to WordPress core and to Yoast / Rank Math (their own meta is never touched).
* Translate the site title, tagline, date/time display format, week start day, logo, and site icon per language.
* Optionally show a small "this page is also available in English" bar to visitors whose browser language differs from the page — the visitor's own browser decides (JavaScript), so automatic redirects are never used and page caching keeps working. Off by default.
* Every page's `<html lang>` and, for a right-to-left language, `dir="rtl"` are guaranteed directly from the language registry — independent of whether a language pack is installed.
* Review translation coverage, maintenance checks, FAQ, troubleshooting, support routes, and system information inside wp-admin.

**Privacy**

WakaLang does not call any external service, does not track visitors, and stores no personal data. It runs entirely on your own site.

**Third Party Services**

WakaLang Free does not connect to any third-party service, CDN, telemetry endpoint, license server, or translation API. It serves its assets from your WordPress site and performs language routing locally.

**Optional add-on**

A separate paid add-on is planned for AI-assisted, Markdown-safe translation using an administrator-provided API key, glossary, translation memory, and differential translation. The free plugin contains none of that add-on code and works fully without it.

**Try it first**

Use the Live Preview button on this plugin page to try a bilingual (Japanese/English) demo of WakaLang in WordPress Playground — no install required.

**Getting started**

After activation, open **WakaLang → Languages**, add your languages, set the default language, open **WakaLang → Settings** to choose switcher placement, then use the WakaLang editor panel to assign languages and link translated versions. The full user manual is inside **WakaLang → Guide**.

== Installation ==

1. In WordPress, go to **Plugins → Add New**, search for **WakaLang**, install it, and activate it.
2. To install from a ZIP, go to **Plugins → Add New → Upload Plugin**, upload the WakaLang ZIP, install it, and activate it.
3. Go to **WakaLang → Languages** to register your languages and set a default.
4. Go to **WakaLang → Settings** and choose a header or footer language switcher position, or add the block/shortcode where you want it manually.
5. Open **WakaLang → Guide** for setup steps, usage notes, FAQ, troubleshooting, support routes, and system information.

== Frequently Asked Questions ==

= After installing, what should I do first? =

Add your languages under **WakaLang → Languages**, set the default language, choose switcher placement under **WakaLang → Settings**, then assign languages and translation groups in the post or page editor.

= What should I do if settings are not reflected? =

Flush rewrite rules from **WakaLang → Tools**, clear page/object/CDN caches, and confirm you are viewing a URL with the expected language prefix.

= My translations lost their language after moving the site. What happened? =

Language assignments and translation groups are stored in a WakaLang database table, so a WordPress export (WXR) does not carry them. Move the content first, then use **WakaLang → Tools → Import and export translation relationships** on the old site to download the relationships and on the new site to import them. Objects are matched by post type and slug (never by ID), a preview reports what would happen before anything is written, and rows that cannot be matched are listed with a reason.

= Why is my theme or plugin interface text still in English? =

WakaLang translates your content, URLs, and the site's core "face" fields (site title, tagline, date/time display, logo, and site icon). It does not scan or translate the gettext strings built into themes and plugins (button labels, widget titles, form messages). Install a WordPress language pack for each language under **Settings → General** to translate those automatically. For strings without an official translation, hand-edit them with a dedicated string-translation plugin such as Loco Translate — a complementary tool that WakaLang never installs or changes for you. WakaLang and Loco Translate share the work rather than duplicating it.

= Can I use WakaLang with my theme or cache plugin? =

Yes in normal setups. If root browser-language detection is enabled, exclude the bare site root (`/`) from full-page caching, host cache, and CDN cache, or turn that detection off in **WakaLang → Settings**. Prefixed URLs such as `/en/` and `/ja/` remain safe to cache normally because the URL prefix is the language source of truth. Clear caches after changing URL, menu, or switcher settings.

= What is the difference between Free and Pro? =

WakaLang Free is complete for manual multilingual publishing. WakaLang Pro is a separate add-on for licensed AI-assisted translation workflows and is not bundled in the free WordPress.org plugin.

= Where can I get support? =

Use the WordPress.org support forum for WakaLang Free. Do not post license keys, API keys, account details, payment information, or refund requests in public forum threads; use the Pro support route shown inside the plugin when applicable.

= Does WakaLang Free send my content anywhere? =

No. WakaLang Free makes no external network calls, does not use a CDN, does not include telemetry, and does not perform license checks.

= Does WakaLang support right-to-left (RTL) languages like Arabic and Hebrew? =

Yes. Every page's `<html>` tag gets a `lang` attribute and, for a right-to-left language, `dir="rtl"`, guaranteed directly from your configured language registry rather than from WordPress's own installed language packs — so it is correct even before you install that language's translation files. This covers WCAG success criteria 3.1.1 (Language of Page) and 3.1.2 (Language of Parts) for the language-of-page/switcher parts of your site. The language switcher also marks each right-to-left language's link with `dir="rtl"`.

= What does WakaLang intentionally not do? =

To stay lightweight, WakaLang does not include a visual front-end translation editor, a full theme/plugin string-scanning panel, media/attachment translation, translated or shared slugs, per-language domains or subdomains, WooCommerce or page-builder specific integrations, translation-agency workflows, multisite language networks, or a visitor-facing machine-translation widget. The URL prefix stays the source of truth for the current language, WordPress slugs stay canonical, and no translation credits are sold.

= Is WakaLang actually lightweight? =

The additional database queries, autoload option payload, and TTFB impact WakaLang adds to a front-end page load are measured with a reproducible script and published at https://github.com/my-biz-dev/wakalang/blob/main/docs/benchmarks/frontend-performance.md — run it yourself against the project's local verification stack to confirm the numbers. For hosting recommendations (a persistent object cache, page-cache interaction) see https://github.com/my-biz-dev/wakalang/blob/main/docs/performance.md.

== Screenshots ==

1. Language registry with setup guidance and controls for editing, enabling, and ordering languages.
2. Sectioned language switcher settings for display, style, placement, and the admin-bar menu.
3. Post editor translation panel for assigning a language and linking translated versions.
4. Front-end flag-and-name language switcher output on a prefixed page.
5. Language Switcher block options for labels, flags, style, and current-language visibility.

== Source Code ==

WakaLang ships as readable PHP; the only compiled asset is the block editor script.

* `assets/blocks/language-switcher/build/index.js` is the compiled Language Switcher block editor script. Its human-readable source ships in this plugin under `assets/blocks/language-switcher/src/` (`index.js`, `edit.js`, `block.json`).

To rebuild it, install Node.js, run `npm install`, then `npm run build:blocks` (which runs `@wordpress/scripts`). No other plugin code is minified or generated by a build tool.

== Upgrade Notice ==

= 0.6.0 =
Maintenance and test-coverage release. No action needed: language routing, translation links and your existing settings are unchanged.

= 0.4.0 =
Adds site-to-site export and import of translation relationships, so language assignments and translation groups survive a WordPress (WXR) content move. Nothing changes until you use the new Tools section.

= 0.3.2 =
Adds an opt-in notice on 404 pages linking to an existing translation of the requested path. Off by default; nothing changes until you enable it.

= 0.3.1 =
Adds a per-block language scope for the Query Loop block and a per-language translation permission model. Existing behaviour is unchanged.

= 0.3.0 =
Adds the declarative content schema for translation drafts. hreflang x-default now derives from the current page's default-language URL when x_default_url is left empty; sites that set x_default_url keep the previous behaviour.

= 0.2.5 =
Maintenance update for the plugin details link.

== Changelog ==

= 0.6.24 =
* Add a public API compatibility policy (Issue #723): `docs/COMPATIBILITY_POLICY.md` defines hooks / REST / Abilities / GraphQL / WP-CLI as versioned public API (semver, two-minor deprecation via `_deprecated_hook()`, Abilities schema rules). New stable hooks: `wakalang_root_language_detected`, `wakalang_language_url_prefix`, `wakalang_language_switcher_items`, `wakalang_translation_unlinked`, `wakalang_settings_schema`. `wakalang_hreflang_entries` is now stable (`wakalang_canonical_url` already was, Issue #711). Track A pins the surface in `tests/Fixtures/public-api-snapshot.json`. WakaLang Pro cancels automation jobs on unlink; WPGraphQL `urlPrefix` uses the public prefix filter.
* Split three oversized Pro translation classes while keeping their public constructors, methods, and hooks (Issue #738): `AiTranslationPage` → controller / view / CSV exporter / job diagnostics; `TranslationCoordinator` → kind translators over a shared pipeline; `ReviewRepository` → staging / guards / decisions. Dedicated Track A tests cover `ProviderRequestSupport`, `BlockStructureValidator`, glossary and translation-memory schema helpers, and table-driven auto-translation policy gates.

= 0.6.23 =
* Add a Settings "Content schema" tab (Issue #717): for every translatable post type the detected post meta keys and the registered block types' string attributes are listed with copy / translate-manually / ignore policy selects, stored in the non-autoload `wakalang_content_schema` option and resolved by `ContentSchemaRegistry` as a fourth sibling source — code declarations (the `wakalang_content_schema` filter and `wpml-config.xml`) still win any conflict by the most-restrictive rule, and secret/auth keys stay locked to ignore in the UI. The same declarations are exposed as the `content_schema` key on `wakalang/get-settings` / `wakalang/update-settings` and as `wp wakalang settings get --field=content_schema` / `--content_schema=<json>`.
* Add a Tools "Menu sync" panel (Issue #716): generate a same-hierarchy nav menu per target language from a default-language menu, with each item re-pointed at its translation-group member (the front-end fallback policy governs links with no translation), custom links prefix-swapped under the localizer's exclusion policy, labels copied through the new `wakalang_menu_sync_label` filter (the Pro AI hook-in), and hand-edited labels preserved on re-runs (the sync only relabels items whose label still matches what it last wrote). Re-runs apply a diff (add / delete / re-parent / reorder, keyed by a source-item marker meta) without touching items the user created inside a generated menu; a dry-run preview reports the changes before anything is written (PRG, per-user report), generated menus are proposed for the source menu's theme locations via the per-language MenuLocations store, and block themes get the same operation over `wp_navigation` posts with results registered for the front-end `NavigationRefs` language swap.
* Add an opt-in, non-forced language suggestion banner (Issue #710): a cache-safe front-end script offers a link to another language's published translation of the current page when the visitor's browser language differs, with per-language message overrides in the Tools string-translations store and a session-cookie dismissal. Off by default; the server makes no visitor-dependent decisions, so prefixed URLs stay fully page-cacheable.
* Add a per-language `banner_message` override to the Tools String translations panel.
* Add a Free, AI-free translation structure check (Issue #715): heading outline, link count/href set, image count, Gutenberg block-type sequence, and code-block count are compared on save and stored as `_wakalang_structure_check` post meta. The Translation Hub, Gutenberg sidebar, and classic meta box show a warning (never a publish block) such as "1 missing link"; Hub CSV adds a Structure column per language. WakaLang Pro's QA Engine is not used.
* Split `Plugin::boot()` into per-request-type `Bootstrap\{Core,Frontend,Admin,Cli,Abilities}Registrar` classes (Issue #721): admin/CLI/abilities-only services are no longer generated on a plain front-end render (a front boot drops from 110 to 63 loaded `WakaLang\` classes), and the shared services admin, CLI and the abilities surfaces consume are built once through a memoised `Bootstrap\Container` exposed by `Plugin::container()`. The boot sequence is behaviour-preserving; every hook still registers exactly as before.
* Add a static-state reset seam (Issue #721): classes holding request-scoped statics (`HomeUrlFilter`, `LinkFilter`, `PostsCacheInvalidator`, `Options`, `SettingsSchema`, and Pro's `ChunkResumeStore`) expose `reset_for_tests()`, and `WakaLang\Testing\StateReset` clears them in every test's `set_up()` so Track B results can no longer depend on class statics leaking across tests.

= 0.6.22 =
* Add Pro translation QA rules for HTML balance, link targets, cross-chunk terminology, Japanese register, and repeated sentences, plus a filterable site QA report, CSV export, and Site Health metrics.
* Add Translation Hub AI selection, estimate, and explicit enqueue actions, including review-only bulk SEO and slug candidates across the Hub, WP-CLI, and Abilities API.
* Add a bilingual, saved-response Pro sales demo for structure protection, glossary correction, human review, and incremental translation (Issue #766).
* Reduce front-end query overhead without a persistent object cache by priming a generation-guarded translation target map and avoiding duplicate URL reverse lookups.

= 0.6.21 =
* Backfill source_language_code and record AI-reviewed status.
* Add Gutenberg translation sidebar.
* Address code review findings for flaky test tracking.

= 0.6.20 =
* Guarantee each language's `<html lang>`/`dir` directly from the language registry (not the installed language pack), add a `dir="rtl"` to right-to-left language switcher links, and add a Multilingual Doctor check for language attribute misconfiguration.

= 0.6.19 =
* Add per-language/provider AI usage breakdown with CSV export.
* Refresh plugin screenshots.

= 0.6.18 =
* Add language filter to taxonomy term list tables.
* Memoize UrlResolver::resolve_for_language() per request.
* Batch translation graph priming for REST post collections.
* Stabilize admin site-health and permissions specs.

= 0.6.17 =
* Add translation coverage dashboard widget.
* Scope dashboard widget by allow-list and fix broken empty-state link.
* Keep core sitemap alive alongside an SEO plugin.

= 0.6.16 =
* Translation Exchange (Pro) can now include excerpt, per-translation SEO title/meta description and slugs in an export via opt-in checkboxes, and taxonomy term names as a separate unit type; imports apply the new fields, hold slugs for explicit manual application, and keep title/content-only files working unchanged (Issue #466).

= 0.6.15 =
* Language switcher links now point at the clean translation URLs, matching the hreflang alternates; the preferred-language cookie is written by a small front-end script on click instead of a query-parameter redirect hop (Issue #633). The server-side `?wakalang_switch_language=` flow is kept for backward compatibility.

= 0.6.14 =
* Prevent WP 7.1 handle_404 false positive on sitemap requests.
* Send 200 explicitly and tighten pre_handle_404 test coverage.
* Declare WordPress 7.1 compatibility.

= 0.6.10 =
* Add bulk approve/reject to Translation Review queue.

= 0.6.8 =
* Add translationGroupId field and own i18n catalog.
* Bump minimum Free version to 0.3.1 for TranslationGraphBuilder.
* Suppress nonce-verification false positives in Pro admin pages.
* Guard adapter package against Pro declarations.

= 0.6.7 =
* Move SEO consistency observation off front-end requests.
* Reject a redirected or empty head in the consistency scan.

= 0.6.6 =
* Speed up the Translation Hub and translation coverage report on large sites.

= 0.6.5 =
* Cap default-language assignment to a bounded batch per call.
* Batch translation group lookups in the post list table.
* Restore quality threshold baseline.

= 0.6.4 =
* Memoize merged settings and schema defaults.
* Resolve 404 fallback target via bare permalink.

= 0.6.2 =
* Add bulk language assignment to the post list.
* Add edit, enable/disable, and reorder to the Languages page.
* Add term translation search and draft creation (#442).
* Show source-change diffs and add bulk needs-update resolution.
* Add bulk translation-draft creation to the Translation Hub.
* Add confirm-before-destructive-action and notice dismissal.
* Add versioned DB migrations.
* Resolve menu items via known object id instead of URL reverse lookup.
* Fall back to a display name when no flag emoji resolves.
* Detect and recover from a missing translations table.
* Remove residual WakaLang data.
* Verify critical write results.
* Localize GFMR and CLI notices.

= 0.4.0 =
* Add site-to-site export and import of translation relationships, so language assignments and translation groups survive a WordPress (WXR) content move.

= 0.3.2 =
* Add cross-language 404 fallback resolution.

