I18N: Read the revision date key that GlotPress writes into .l10n.php files - #12844
I18N: Read the revision date key that GlotPress writes into .l10n.php files#12844jigneshbhavani wants to merge 1 commit into
Conversation
… files. wp_get_l10n_php_file_data() maps `PO-Revision-Date` onto `po-revision-date`, but GlotPress writes that value under `translation-revision-date`. The key core looks for is absent from every language pack currently served, so the function returns an empty revision date. The name changed upstream. The `de_CH.l10n.php` fixture already in core reports `GlotPress/4.0.0-beta.2` and uses `po-revision-date`, while packs generated by `GlotPress/4.0.3` use `translation-revision-date`. The mapping was correct when the function was added in 6.6 and stopped matching later. `Project-Id-Version` and `X-Generator` still resolve, which is why nothing looked broken. This matters because wp_get_installed_translations() falls back to this reader when a translation has no sibling `.po` file, and the result is sent to api.wordpress.org to decide which language packs are stale. An empty revision date means an installed, current pack is offered again on every check. Accept both spellings, preferring the current one, so files written before and after the rename resolve. `POT-Creation-Date` maps to `pot-creation-date`, which appears in neither format, and is left alone rather than guessed at. The existing coverage did not catch this because the only `.l10n.php` fixture it asserts against predates the rename. Add a fixture in the current format and a test that fails on trunk with an empty string. Props bejignesh. Fixes #65809.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
irozum
left a comment
There was a problem hiding this comment.
Good catch — wp_get_l10n_php_file_data() was still only looking for po-revision-date, but GlotPress renamed that key to translation-revision-date a while back, so PO-Revision-Date silently comes back empty for any current language pack that lacks a sibling .po file, which then causes wp_get_installed_translations() to treat an up-to-date pack as stale on every update check. The fix (checking translation-revision-date first, falling back to po-revision-date) is correctly scoped — I confirmed wp_get_l10n_php_file_data() has a single caller in core (wp_get_installed_translations()), so there's no back-compat surface beyond this file.
I ran the l10n and i18n groups plus PHPStan — all clean, and the counts (267/268 tests, 808/813 assertions, 0 failures) match what's in the PR description. I also grepped for other references to po-revision-date/translation-revision-date in src/ and tests/ and didn't find anything else that would need updating in step with this.
One small thing worth a sentence in the description (not blocking): POT-Creation-Date is left mapped only to pot-creation-date, which per your own table doesn't appear in either fixture format, so it's presumably always empty too — you note this is a separate decision, which seems right, but it might be worth a quick follow-up ticket so it doesn't get lost.
wp_get_l10n_php_file_data()maps the PO headers it returns onto the keys a.l10n.phpfile stores them under:GlotPress writes the revision date under
translation-revision-date. The key core looks for is absent from every language pack currently served from WordPress.org, soPO-Revision-Datealways comes back empty.The key was renamed upstream
X-Generatortests/phpunit/data/languages/de_CH.l10n.php(already in core)po-revision-datetwentytwentyfive-nl_NL.l10n.phptranslation-revision-datesimple-history-es_ES.l10n.phptranslation-revision-dateSo the mapping was correct when the function was introduced in 6.6 and stopped matching when the name changed.
Project-Id-VersionandX-Generatorstill resolve, which is why the failure is silent: only the revision date is lost.The value is intact under the other name. For the Simple History packs, the
.l10n.phpvalue and the.poheader agree to the second:.l10n.phptranslation-revision-date.poPO-Revision-DateWhy it matters
wp_get_installed_translations()falls back to this reader when a translation has no sibling.pofile. That value goes to api.wordpress.org to determine which language packs are out of date. An empty revision date means a pack that is already installed and current gets offered again on every check.Measured on trunk with the Twenty Twenty-Five nl_NL pack, freshly installed, changing nothing but whether the
.pois on disk:wp_get_installed_translations()reportswp_update_themes().popresent2025-08-05 20:37:56+0000.poabsent''In the second row the installed pack is byte-identical to the one the API is serving.
Why the existing tests did not catch it
The only coverage is
Tests_L10n::test_wp_get_installed_translations_for_core(), and the.l10n.phpfixture it asserts against,de_CH.l10n.php, predates the rename and still usespo-revision-date. The assertion passes because the fixture matches the code, not because either matches a current language pack.The change
Each PO header now maps to an ordered list of keys the file may use, preferring
translation-revision-dateand falling back topo-revision-date, so files written before and after the rename both resolve.POT-Creation-Datemaps topot-creation-date, which appears in neither format. I have left it alone rather than guess at an intended source; it is worth a separate decision.Testing
tests/phpunit/data/l10n/translation-revision-date.l10n.phpin the current GlotPress format. It is deliberately indata/l10n/rather thandata/languages/, because the latter isWP_LANG_DIRfor the suite andglob()s*.l10n.php, so a file added there would change whatwp_get_installed_translations()returns for other tests.test_wp_get_l10n_php_file_data_reads_revision_date()covers both spellings. On trunk it fails with'2026-06-26 08:56:45+0000'expected,''actual. With the change it passes, 4 assertions.--group l10n: 267 tests, 808 assertions, 0 failures.--group i18n: 268 tests, 813 assertions, 0 failures.Tests_Locale::test_get_weekday_undefined_index, a PHPUnit 10 deprecation. I confirmed it is identical with the changes stashed, so it is pre-existing and unrelated.phpcsclean.Relationship to #65429
This came out of investigating #65429, but it is not the cause of that report. The reporters there confirmed their
.pofiles were present, which means this fallback never ran on their sites. #65429 remains open and unexplained. Filing separately because the defect stands on its own.Trac ticket: https://core.trac.wordpress.org/ticket/65809
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Drafting the patch, the test and this description. I found the key mismatch by installing real language packs locally and comparing what shipped against what core read, measured the offer counts on the rendered update check with and without the
.popresent, compared the packs against the API response timestamps, traced the rename through theX-Generatorvalues, confirmed the pre-existing test warning against a stashed baseline, and I take responsibility for the result.