Skip to content

feat/locale-language-mapping - #42

Closed
SNO7E-G wants to merge 3 commits into
OnTheGoSystems:masterfrom
SNO7E-G:feat/locale-language-mapping
Closed

feat/locale-language-mapping#42
SNO7E-G wants to merge 3 commits into
OnTheGoSystems:masterfrom
SNO7E-G:feat/locale-language-mapping

Conversation

@SNO7E-G

@SNO7E-G SNO7E-G commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Summary. Maps every Polylang language to the correct WPML code by locale instead of two hardcoded cases, fixing Traditional Chinese, Norwegian and any custom slug.

Problem. lang_slug_to_wpml_format() special-cased only pt and zh; every other slug went to WPML as-is, and WPML stores it verbatim, so any site whose slug differed from the WPML code was migrated into an unresolvable code — silently. Chinese with locale zh_TW mapped to zh-hans: Traditional migrated as Simplified. Norwegian (no/nb_NO), custom slugs (english, br) all wrong.

Change. Resolve by locale — Polylang keeps it in the term description, WPML in icl_languages.default_locale with overrides in icl_locale_map. Runs WPML's own WPML_Locale::get_all_locales() join in reverse. Order: locale via WPML tables → the legacy pt/zh cases (zh now locale-aware) → the slug unchanged. Unmatched slugs recorded via get_unmapped_languages().
Cached per slug. The two locale lookups carry an explicit ORDER BY code so a site that has hand-added a duplicate icl_locale_map row for one locale still resolves to a single deterministic code (a domain-review nit; the schema makes duplicates rare but not impossible).

Risk. Moderate — deliberately changes which code content is written under (that is the fix for zh_TW). A re-run gives different codes. Fallback never returns nothing; the change is that unmatched languages are now reported.

Verified. 18 stub checks over 8 groups against a fixture copied verbatim from WPML 4.9's icl_get_languages_locales(); new code 18/18, original fails 5 then fatals (get_unmapped_languages() absent). Confirmed on a live install (WordPress 7.0.2, Polylang 3.8.6, WPML 4.9.5, MySQL 8.4.3, a modern es/en/de/pt dataset): migrate_languages returned {activated:4, skipped:0} with no warnings; the resolved map was es→es, en→en, de→de, pt→pt-pt; WPML's active set flipped from [en,es] to [de,en,es,pt-pt]; and icl_languages/icl_translations held 0 rows under the raw slug pt — every Portuguese row landed under pt-pt. The pt_PT code resolved through the real icl_languages.default_locale (the modern table path; icl_locale_map had no pt_PT row), so the fix is proven against live WPML tables, not just the stub.

Polylang moved its string translations twice - to post meta in 2.1, then
to language term meta in 3.4 - and this plugin never followed. It still
read post_content, which Polylang stopped writing in 2.1, so string
migration has silently returned nothing on every Polylang version since
2017 while still reporting success.

Read all three locations, newest first. Also fix the same slug-vs-code
confusion in migrate_string_groups(), which indexes WPML's string table
by language code but looked up entries with Polylang slugs, and drop
malformed pairs before they reach WPML.
Pins the behaviour from review: a _pll_strings_translations store that
exists but is empty is authoritative. A site that cleared its string
translations still carries the stale copies Polylang leaves in the old
locations on upgrade, and those must not be re-imported. A populated
storage scenario runs alongside as a positive control, so the check
fails because of the fall-through and not because reading broke.

Self-contained by design: plain `php tests/...`, no WordPress, database
or Composer needed, exit code reports the result. When the repository
gains proper test infrastructure this can move under it.
lang_slug_to_wpml_format() knew about exactly two languages, pt and zh.
Everything else was passed to WPML as the raw Polylang slug, and WPML
stores whatever it is given, so any site whose slug differed from the
WPML code was migrated into a code WPML cannot resolve, silently.

The dependable bridge is the locale: Polylang keeps it in the language
term description, WPML keeps it in icl_languages.default_locale with
per-site overrides in icl_locale_map. This resolves through WPML's own
tables in reverse. Fixes Traditional Chinese (was migrated as
Simplified), Norwegian, and any custom slug. Languages WPML still cannot
match are recorded via get_unmapped_languages() instead of written blind.
@SNO7E-G
SNO7E-G force-pushed the feat/locale-language-mapping branch from b124227 to 9ceeafb Compare August 23, 2026 15:56

@dgwatkins dgwatkins left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks—the self-contained regression test is useful given the repository’s current lack of testing infrastructure.

We’ll handle the additional post-meta scenario and integrate these cases into a proper test suite through a separate internal testing-infrastructure ticket. Please hold off on additional tooling changes for now.

This PR looks good from my side.

Wrong PR, sorry

@dgwatkins

dgwatkins commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

I'm handling this in a separate pull request #44, to be able to adapt it to our new testing infrastructure.

Thanks @SNO7E-G

@dgwatkins dgwatkins closed this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants