feat/locale-language-mapping - #42
Closed
SNO7E-G wants to merge 3 commits into
Closed
Conversation
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
force-pushed
the
feat/locale-language-mapping
branch
from
August 23, 2026 15:56
b124227 to
9ceeafb
Compare
dgwatkins
approved these changes
Aug 24, 2026
Contributor
There was a problem hiding this comment.
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
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 onlyptandzh; 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 localezh_TWmapped tozh-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_localewith overrides inicl_locale_map. Runs WPML's ownWPML_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 viaget_unmapped_languages().Cached per slug. The two locale lookups carry an explicit
ORDER BY codeso a site that has hand-added a duplicateicl_locale_maprow 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 modernes/en/de/ptdataset):migrate_languagesreturned{activated:4, skipped:0}with no warnings; the resolved map wases→es, en→en, de→de, pt→pt-pt; WPML's active set flipped from[en,es]to[de,en,es,pt-pt]; andicl_languages/icl_translationsheld 0 rows under the raw slugpt— every Portuguese row landed underpt-pt. Thept_PTcode resolved through the realicl_languages.default_locale(the modern table path;icl_locale_maphad nopt_PTrow), so the fix is proven against live WPML tables, not just the stub.