When saving translation it creates page in "Translation:" namespace but "Pagename/lang" is not updated (previously, saving translation made two edits).
Impact
Translation pages (glossary) are not created or updated. This means users do not see some latest translations.
Workarounds
Null / dummy edits to translations unit in the corresponding languages. For example, add a space at the end of a translation. It will enable Save button, but will be ignored during save.
Cause
Changes due to T228675: Remove direct access to the text table from the Translate extension. made it so that text contents are loaded in a separate query. In environments with replication lag (as in, Wikimedia production and in none of out test environments), it could now fail to find the text contents with the following errors.
- batch loading fails to find the contents, causing fallback (separate loading) to be used for the newly translated translation unit:
Use of Revision::getRevisionText was deprecated in MediaWiki 1.32. [Called from ThinMessage::translation in /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/Message.php at line 170]
- Sometimes (but not always) it also fails to find the title information:
MediaWiki\Revision\RevisionStore::getTitle fell back to READ_LATEST and got a Title. <ul> <li>RevisionStore.php line 367 calls wfBacktrace()</li> <li>RevisionStore.php line 1849 calls MediaWiki\Revision\RevisionStore->getTitle()</li> <li>RevisionStore.php line 1816 calls MediaWiki\Revision\RevisionStore->newRevisionFromRowAndSlots()</li> <li>Revision.php line 880 calls MediaWiki\Revision\RevisionStore->newRevisionFromRow()</li> <li>Message.php line 170 calls Revision::getRevisionText()</li> <li>MessageCollection.php line 910 calls ThinMessage->translation()</li> <li>MessageCollection.php line 250 calls MessageCollection->initMessages()</li> <li>TPParse.php line 182 calls MessageCollection->loadTranslations()</li> <li>TranslateRenderJob.php line 62 calls TPParse->getTranslationPageText()</li> <li>PageTranslationHooks.php line 219 calls TranslateRenderJob->run()</li> <li>PageTranslationHooks.php line 199 calls PageTranslationHooks::updateTranslationPage()</li> <li>TranslateEditAddons.php line 248 calls PageTranslationHooks::onSectionSave()</li> <li>Hooks.php line 174 calls TranslateEditAddons::onSave()</li> <li>Hooks.php line 202 calls Hooks::callHook()</li> <li>PageUpdater.php line 1239 calls Hooks::run()</li> <li>Database.php line 3972 calls MediaWiki\Storage\PageUpdater->MediaWiki\Storage\{closure}()</li> <li>DBConnRef.php line 68 calls Wikimedia\Rdbms\Database->doAtomicSection()</li> <li>DBConnRef.php line 635 calls Wikimedia\Rdbms\DBConnRef->__call()</li> <li>AtomicSectionUpdate.php line 39 calls Wikimedia\Rdbms\DBConnRef->doAtomicSection()</li> <li>DeferredUpdates.php line 383 calls AtomicSectionUpdate->doUpdate()</li> <li>DeferredUpdates.php line 281 calls DeferredUpdates::attemptUpdate()</li> <li>DeferredUpdates.php line 226 calls DeferredUpdates::run()</li> <li>DeferredUpdates.php line 145 calls DeferredUpdates::handleUpdateQueue()</li> <li>MediaWiki.php line 669 calls DeferredUpdates::doUpdates()</li> <li>ApiMain.php line 550 calls MediaWiki::preOutputCommit()</li> <li>ApiMain.php line 508 calls ApiMain->executeActionWithErrorHandling()</li> <li>api.php line 83 calls ApiMain->execute()</li> <li>api.php line 3 calls require()</li> </ul>
- This too fails to find the context, throwing an error:
Deferred update AtomicSectionUpdate_MediaWiki\Storage\PageUpdater::getAtomicSectionUpdate failed: Main slot of revision 19462971 not found in database! #0 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision/RevisionStore.php(1608): MediaWiki\Revision\RevisionStore->constructSlotRecords('19462971', Object(Wikimedia\Rdbms\ResultWrapper), 0, Object(Title)) #1 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision/RevisionStore.php(1719): MediaWiki\Revision\RevisionStore->loadSlotRecords('19462971', 0, Object(Title)) #2 [internal function]: MediaWiki\Revision\RevisionStore->MediaWiki\Revision\{closure}() #3 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision/RevisionSlots.php(165): call_user_func(Object(Closure)) #4 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision/RevisionSlots.php(107): MediaWiki\Revision\RevisionSlots->getSlots() #5 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision/RevisionRecord.php(192): MediaWiki\Revision\RevisionSlots->getSlot('main') #6 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision/RevisionRecord.php(175): MediaWiki\Revision\RevisionRecord->getSlot('main', 1, NULL) #7 /srv/mediawiki/php-1.35.0-wmf.1/includes/Revision.php(882): MediaWiki\Revision\RevisionRecord->getContent('main') #8 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/Message.php(170): Revision::getRevisionText(Object(stdClass)) #9 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/MessageCollection.php(910): ThinMessage->translation() #10 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/MessageCollection.php(250): MessageCollection->initMessages() #11 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/tag/TPParse.php(182): MessageCollection->loadTranslations() #12 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/tag/TranslateRenderJob.php(62): TPParse->getTranslationPageText(Object(MessageCollection), true) #13 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/tag/PageTranslationHooks.php(219): TranslateRenderJob->run() #14 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/tag/PageTranslationHooks.php(199): PageTranslationHooks::updateTranslationPage(Object(TranslatablePage), 'uk', Object(User), 64, '') #15 /srv/mediawiki/php-1.35.0-wmf.1/extensions/Translate/TranslateEditAddons.php(248): PageTranslationHooks::onSectionSave(Object(WikiPage), Object(User), Object(WikitextContent), '', 0, 66, Object(Revision), Object(MessageHandle)) #16 /srv/mediawiki/php-1.35.0-wmf.1/includes/Hooks.php(174): TranslateEditAddons::onSave(Object(WikiPage), Object(User), Object(WikitextContent), '', 0, NULL, NULL, 66, Object(Revision), Object(Status), false, 0) #17 /srv/mediawiki/php-1.35.0-wmf.1/includes/Hooks.php(202): Hooks::callHook('PageContentSave...', Array, Array, NULL) #18 /srv/mediawiki/php-1.35.0-wmf.1/includes/Storage/PageUpdater.php(1239): Hooks::run('PageContentSave...', Array) #19 /srv/mediawiki/php-1.35.0-wmf.1/includes/libs/rdbms/database/Database.php(3972): MediaWiki\Storage\PageUpdater->MediaWiki\Storage\{closure}(Object(Wikimedia\Rdbms\DatabaseMysqli), 'MediaWiki\\Stora...') #20 /srv/mediawiki/php-1.35.0-wmf.1/includes/libs/rdbms/database/DBConnRef.php(68): Wikimedia\Rdbms\Database->doAtomicSection('MediaWiki\\Stora...', Object(Closure)) #21 /srv/mediawiki/php-1.35.0-wmf.1/includes/libs/rdbms/database/DBConnRef.php(635): Wikimedia\Rdbms\DBConnRef->__call('doAtomicSection', Array) #22 /srv/mediawiki/php-1.35.0-wmf.1/includes/deferred/AtomicSectionUpdate.php(39): Wikimedia\Rdbms\DBConnRef->doAtomicSection('MediaWiki\\Stora...', Object(Closure)) #23 /srv/mediawiki/php-1.35.0-wmf.1/includes/deferred/DeferredUpdates.php(383): AtomicSectionUpdate->doUpdate() #24 /srv/mediawiki/php-1.35.0-wmf.1/includes/deferred/DeferredUpdates.php(281): DeferredUpdates::attemptUpdate(Object(AtomicSectionUpdate), Object(Wikimedia\Rdbms\LBFactoryMulti)) #25 /srv/mediawiki/php-1.35.0-wmf.1/includes/deferred/DeferredUpdates.php(226): DeferredUpdates::run(Object(AtomicSectionUpdate), Object(Wikimedia\Rdbms\LBFactoryMulti), Object(Monolog\Logger), Object(BufferingStatsdDataFactory), 'post') #26 /srv/mediawiki/php-1.35.0-wmf.1/includes/deferred/DeferredUpdates.php(145): DeferredUpdates::handleUpdateQueue(Array, 'run', 1) #27 /srv/mediawiki/php-1.35.0-wmf.1/includes/MediaWiki.php(669): DeferredUpdates::doUpdates('run', 1) #28 /srv/mediawiki/php-1.35.0-wmf.1/includes/api/ApiMain.php(550): MediaWiki::preOutputCommit(Object(DerivativeContext)) #29 /srv/mediawiki/php-1.35.0-wmf.1/includes/api/ApiMain.php(508): ApiMain->executeActionWithErrorHandling() #30 /srv/mediawiki/php-1.35.0-wmf.1/api.php(83): ApiMain->execute() #31 /srv/mediawiki/w/api.php(3): require('/srv/mediawiki/...') #32 {main}
This previously worked, so what is different? The new code always loaded from DB_REPLICA, while the old code uses a separate logic to determine whether to load from DB_MASTER.
Fixes
Applied the same logic to the new batch loading code, to read from master consistently.
Also deferred the updating of the translation page. This probably did not fix the issue, but it has other advantages such as reducing user visible saving delay, better ordering and encapsulation.