52 private const GROUP_SYNC_INFO_WRAPPER_CLASS =
'smg-group-sync-cache-info';
53 private const RIGHT =
'translate-manage';
59 protected $hasRight =
false;
67 private $synchronizationCache;
69 private $displayGroupSyncInfo;
71 private $jobQueueGroup;
73 public function __construct(
75 NamespaceInfo $nsInfo,
76 RevisionLookup $revLookup,
78 JobQueueGroup $jobQueueGroup
81 parent::__construct(
'ManageMessageGroups' );
82 $this->contLang = $contLang;
83 $this->nsInfo = $nsInfo;
84 $this->revLookup = $revLookup;
85 $this->synchronizationCache = $synchronizationCache;
87 $this->jobQueueGroup = $jobQueueGroup;
90 public function doesWrites() {
94 protected function getGroupName() {
98 public function getDescription() {
99 return $this->msg(
'managemessagegroups' )->text();
102 public function execute( $par ) {
105 $out = $this->getOutput();
106 $out->addModuleStyles(
'ext.translate.specialpages.styles' );
107 $out->addModules(
'ext.translate.special.managegroups' );
108 $out->addHelpLink(
'Help:Extension:Translate/Group_management' );
110 $name = $par ?: MessageChangeStorage::DEFAULT_NAME;
112 $this->cdb = MessageChangeStorage::getCdbPath( $name );
113 if ( !MessageChangeStorage::isValidCdbName( $name ) || !file_exists( $this->cdb ) ) {
114 if ( $this->getConfig()->
get(
'TranslateGroupSynchronizationCache' ) ) {
116 $this->displayGroupSyncInfo->getGroupsInSyncHtml(
117 $this->synchronizationCache->getGroupsInSync(),
118 self::GROUP_SYNC_INFO_WRAPPER_CLASS
123 $this->displayGroupSyncInfo->getHtmlForGroupsWithError(
124 $this->synchronizationCache,
125 self::GROUP_SYNC_INFO_WRAPPER_CLASS,
133 $out->addWikiMsg(
'translate-smg-nochanges' );
138 $user = $this->getUser();
139 $this->hasRight = $user->isAllowed( self::RIGHT );
141 $req = $this->getRequest();
142 if ( !$req->wasPosted() ) {
143 $this->showChanges( $this->
getLimit() );
148 $block = $user->getBlock();
149 if ( $block && $block->isSitewide() ) {
150 throw new UserBlockedError(
153 $this->getLanguage(),
158 $csrfTokenSet = $this->getContext()->getCsrfTokenSet();
159 if ( !$this->hasRight || !$csrfTokenSet->matchTokenField(
'token' ) ) {
160 throw new PermissionsError( self::RIGHT );
163 $this->processSubmit();
170 ini_get(
'max_input_vars' ),
171 ini_get(
'suhosin.post.max_vars' ),
172 ini_get(
'suhosin.request.max_vars' )
175 $limits = array_filter( $limits );
176 return (
int)min( $limits );
179 protected function getLegend(): string {
180 $text = $this->diff->addHeader(
182 $this->msg(
'translate-smg-left' )->escaped(),
183 $this->msg(
'translate-smg-right' )->escaped()
186 return Html::rawElement(
'div', [
'class' =>
'mw-translate-smg-header' ], $text );
189 protected function showChanges(
int $limit ): void {
190 $diff = new DifferenceEngine( $this->getContext() );
191 $diff->showDiffStyle();
192 $diff->setReducedLineNumbers();
195 $out = $this->getOutput();
198 Html::openElement(
'form', [
'method' =>
'post' ] ) .
199 Html::hidden(
'title', $this->getPageTitle()->getPrefixedText(), [
200 'id' =>
'smgPageTitle'
202 Html::hidden(
'token', $this->getContext()->getCsrfTokenSet()->getToken() ) .
203 Html::hidden(
'changesetModifiedTime',
204 MessageChangeStorage::getLastModifiedTime( $this->cdb ) ) .
211 $groupSyncCacheEnabled = $this->getConfig()->get(
'TranslateGroupSynchronizationCache' );
212 if ( $groupSyncCacheEnabled ) {
214 $this->displayGroupSyncInfo->getGroupsInSyncHtml(
215 $this->synchronizationCache->getGroupsInSync(),
216 self::GROUP_SYNC_INFO_WRAPPER_CLASS
221 $this->displayGroupSyncInfo->getHtmlForGroupsWithError(
222 $this->synchronizationCache,
223 self::GROUP_SYNC_INFO_WRAPPER_CLASS,
229 $reader = \Cdb\Reader::open( $this->cdb );
230 $groups = $this->getGroupsFromCdb( $reader );
231 foreach ( $groups as $id => $group ) {
232 $sourceChanges = MessageSourceChange::loadModifications(
233 TranslateUtils::deserialize( $reader->get( $id ) )
235 $out->addHTML( Html::element(
'h2', [], $group->getLabel() ) );
237 if ( $groupSyncCacheEnabled && $this->synchronizationCache->groupHasErrors( $id ) ) {
239 Html::warningBox( $this->msg(
'translate-smg-group-sync-error-warn' )->escaped(),
'center' )
244 $lb =
new LinkBatch();
245 $ns = $group->getNamespace();
246 $isCap = $this->nsInfo->isCapitalized( $ns );
247 $languages = $sourceChanges->getLanguages();
249 foreach ( $languages as $language ) {
250 $languageChanges = $sourceChanges->getModificationsForLanguage( $language );
251 foreach ( $languageChanges as $type => $changes ) {
252 foreach ( $changes as $params ) {
254 $key = $params[
'key'];
256 $key = $this->contLang->ucfirst( $key );
258 $lb->add( $ns,
"$key/$language" );
264 foreach ( $languages as $language ) {
267 $changes[ MessageSourceChange::ADDITION ] = $sourceChanges->getAdditions( $language );
268 $changes[ MessageSourceChange::DELETION ] = $sourceChanges->getDeletions( $language );
269 $changes[ MessageSourceChange::CHANGE ] = $sourceChanges->getChanges( $language );
271 foreach ( $changes as $type => $messages ) {
272 foreach ( $messages as $params ) {
273 $change = $this->formatChange( $group, $sourceChanges, $language, $type, $params, $limit );
274 $out->addHTML( $change );
279 $out->wrapWikiMsg(
"<div class=warning>\n$1\n</div>",
'translate-smg-more' );
286 $this->showRenames( $group, $sourceChanges, $out, $language, $limit );
291 $button =
new ButtonInputWidget( [
293 'label' => $this->msg(
'translate-smg-submit' )->plain(),
294 'disabled' => !$this->hasRight ?
'disabled' : null,
295 'classes' => [
'mw-translate-smg-submit' ],
296 'title' => !$this->hasRight ? $this->msg(
'translate-smg-notallowed' )->plain() : null,
297 'flags' => [
'primary',
'progressive' ],
299 $out->addHTML( $button );
300 $out->addHTML( Html::closeElement(
'form' ) );
303 protected function formatChange(
305 MessageSourceChange $changes,
311 $key = $params[
'key'];
312 $title = Title::makeTitleSafe( $group->
getNamespace(),
"$key/$language" );
313 $id = self::changeId( $group->
getId(), $language, $type, $key );
315 $isReusedKey =
false;
317 if ( $title && $type ===
'addition' && $title->exists() ) {
326 $noticeHtml .= Html::warningBox( $this->msg(
'translate-manage-key-reused' )->text() );
328 } elseif ( $title && ( $type ===
'deletion' || $type ===
'change' ) && !$title->exists() ) {
335 $titleLink = $this->getLinkRenderer()->makeLink( $title );
337 if ( $type ===
'deletion' ) {
338 $content = $this->revLookup
339 ->getRevisionByTitle( $title )
340 ->getContent( SlotRecord::MAIN );
341 $wiki = ( $content instanceof TextContent ) ? $content->getText() :
'';
343 if ( $wiki ===
'' ) {
344 $noticeHtml .= Html::warningBox(
345 $this->msg(
'translate-manage-empty-content' )->text()
349 $oldContent = ContentHandler::makeContent( (
string)$wiki, $title );
350 $newContent = ContentHandler::makeContent(
'', $title );
351 $this->diff->setContent( $oldContent, $newContent );
352 $text = $this->diff->getDiff( $titleLink,
'', $noticeHtml );
353 } elseif ( $type ===
'addition' ) {
356 if ( $sourceLanguage === $language ) {
357 if ( $this->hasRight ) {
358 $menu = Html::rawElement(
361 'class' =>
'smg-rename-actions',
363 'data-group-id' => $group->
getId(),
364 'data-lang' => $language,
365 'data-msgkey' => $key,
366 'data-msgtitle' => $title->getFullText()
371 } elseif ( !self::isMessageDefinitionPresent( $group, $changes, $key ) ) {
372 $noticeHtml .= Html::warningBox(
373 $this->msg(
'translate-manage-source-message-not-found' )->text(),
374 'mw-translate-smg-notice-important'
378 $menu = Html::hidden(
"msg/$id",
'ignore', [
'id' =>
"i/$id" ] );
382 if ( $params[
'content'] ===
'' ) {
383 $noticeHtml .= Html::warningBox(
384 $this->msg(
'translate-manage-empty-content' )->text()
388 $oldContent = ContentHandler::makeContent(
'', $title );
389 $newContent = ContentHandler::makeContent( (
string)$params[
'content'], $title );
390 $this->diff->setContent( $oldContent, $newContent );
391 $text = $this->diff->getDiff(
'', $titleLink . $menu, $noticeHtml );
392 } elseif ( $type ===
'change' ) {
400 $shouldFuzzy = $sourceLanguage === $language && $wiki !== $params[
'content'];
402 if ( $sourceLanguage === $language ) {
403 $label = $this->msg(
'translate-manage-action-fuzzy' )->text();
404 $actions .= Xml::radioLabel( $label,
"msg/$id",
"fuzzy",
"f/$id", $shouldFuzzy );
408 $sourceLanguage !== $language &&
410 !self::isMessageDefinitionPresent( $group, $changes, $key )
412 $noticeHtml .= Html::warningBox(
413 $this->msg(
'translate-manage-source-message-not-found' )->text(),
414 'mw-translate-smg-notice-important'
418 $actions .= Html::hidden(
"msg/$id",
'ignore', [
'id' =>
"i/$id" ] );
421 $label = $this->msg(
'translate-manage-action-import' )->text();
422 $actions .= Xml::radioLabel( $label,
"msg/$id",
"import",
"imp/$id", !$shouldFuzzy );
424 $label = $this->msg(
'translate-manage-action-ignore' )->text();
425 $actions .= Xml::radioLabel( $label,
"msg/$id",
"ignore",
"i/$id" );
429 $oldContent = ContentHandler::makeContent( (
string)$wiki, $title );
430 $newContent = ContentHandler::makeContent( (
string)$params[
'content'], $title );
432 $this->diff->setContent( $oldContent, $newContent );
433 $text .= $this->diff->getDiff( $titleLink, $actions, $noticeHtml );
436 $hidden = Html::hidden( $id, 1 );
439 $classes =
"mw-translate-smg-change smg-change-$type";
446 return Html::rawElement(
'div', [
'class' => $classes ], $text );
449 protected function processSubmit(): void {
450 $req = $this->getRequest();
451 $out = $this->getOutput();
454 $modificationJobs = $renameJobData = [];
455 $lastModifiedTime = intval( $req->getVal(
'changesetModifiedTime' ) );
457 if ( !MessageChangeStorage::isModifiedSince( $this->cdb, $lastModifiedTime ) ) {
458 $out->addWikiMsg(
'translate-smg-changeset-modified' );
462 $reader = \Cdb\Reader::open( $this->cdb );
463 $groups = $this->getGroupsFromCdb( $reader );
464 $groupSyncCacheEnabled = $this->getConfig()->get(
'TranslateGroupSynchronizationCache' );
467 foreach ( $groups as $groupId => $group ) {
470 if ( $groupSyncCacheEnabled && $this->synchronizationCache->groupHasErrors( $groupId ) ) {
471 $postponed[$groupId] = $changes;
475 $sourceChanges = MessageSourceChange::loadModifications( $changes );
476 $groupModificationJobs = [];
477 $groupRenameJobData = [];
478 $languages = $sourceChanges->getLanguages();
479 foreach ( $languages as $language ) {
481 $this->handleModificationsSubmit(
487 $groupModificationJobs
491 $this->handleRenameSubmit(
498 $groupModificationJobs
501 if ( !isset( $postponed[$groupId][$language] ) ) {
502 $group->getMessageGroupCache( $language )->create();
506 if ( $groupSyncCacheEnabled && !isset( $postponed[ $groupId ] ) ) {
507 $this->synchronizationCache->markGroupAsReviewed( $groupId );
510 $modificationJobs[$groupId] = $groupModificationJobs;
511 $renameJobData[$groupId] = $groupRenameJobData;
512 }
catch ( Exception $e ) {
514 "ManageGroupsSpecialPage: Error in processSubmit. Group: $groupId\n" .
518 $errorGroups[] = $group->
getLabel();
522 $renameJobs = $this->createRenameJobs( $renameJobData );
523 $this->startSync( $modificationJobs, $renameJobs );
526 rename( $this->cdb, $this->cdb .
'-' . wfTimestamp() );
528 if ( $errorGroups ) {
529 $errorMsg = $this->getProcessingErrorMessage( $errorGroups, count( $groups ) );
533 'mw-translate-smg-submitted'
538 if ( count( $postponed ) ) {
539 $postponedSourceChanges = [];
540 foreach ( $postponed as $groupId => $changes ) {
541 $postponedSourceChanges[$groupId] = MessageSourceChange::loadModifications( $changes );
545 $this->showChanges( $this->getLimit() );
546 } elseif ( $errorGroups === [] ) {
547 $out->addWikiMsg(
'translate-smg-submitted' );
551 protected static function changeId(
557 return 'smg/' . substr( sha1(
"$groupId/$language/$type/$key" ), 0, 7 );
564 public static function tabify( Skin $skin, array &$tabs ): void {
565 $title = $skin->getTitle();
566 if ( !$title->isSpecialPage() ) {
569 $specialPageFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
570 [ $alias, ] = $specialPageFactory->resolveAlias( $title->getText() );
573 'ManageMessageGroups' =>
'namespaces',
574 'AggregateGroups' =>
'namespaces',
575 'SupportedLanguages' =>
'views',
576 'TranslationStats' =>
'views',
578 if ( !isset( $pagesInGroup[$alias] ) ) {
582 $tabs[
'namespaces'] = [];
583 foreach ( $pagesInGroup as $spName => $section ) {
584 $spClass = $specialPageFactory->getPage( $spName );
586 if ( $spClass ===
null || $spClass instanceof DisabledSpecialPage ) {
589 $spTitle = $spClass->getPageTitle();
591 $tabs[$section][strtolower( $spName )] = [
592 'text' => $spClass->getDescription(),
593 'href' => $spTitle->getLocalURL(),
594 'class' => $alias === $spName ?
'selected' :
'',
603 private static function isMessageDefinitionPresent(
605 MessageSourceChange $changes,
608 $sourceLanguage = $group->getSourceLanguage();
609 if ( $changes->findMessage( $sourceLanguage, $msgKey, [ MessageSourceChange::ADDITION ] ) ) {
614 $sourceHandle =
new MessageHandle( Title::makeTitle( $namespace, $msgKey ) );
615 return $sourceHandle->isValid();
618 private function showRenames(
620 MessageSourceChange $sourceChanges,
625 $changes = $sourceChanges->getRenames( $language );
626 foreach ( $changes as $key => $params ) {
629 if ( !isset( $changes[ $key ] ) ) {
634 $sourceChanges->isEqual( $language, $key ) ) {
642 $secondKey = $sourceChanges->getMatchedKey( $language, $key );
643 $secondMsg = $sourceChanges->getMatchedMessage( $language, $key );
646 $sourceChanges->isPreviousState(
649 [ MessageSourceChange::ADDITION, MessageSourceChange::CHANGE ]
652 $addedMsg = $firstMsg;
653 $deletedMsg = $secondMsg;
655 $addedMsg = $secondMsg;
656 $deletedMsg = $firstMsg;
659 $change = $this->formatRename(
664 $sourceChanges->isEqual( $language, $key ),
667 $out->addHTML( $change );
670 unset( $changes[$secondKey] );
675 $out->wrapWikiMsg(
"<div class=warning>\n$1\n</div>",
'translate-smg-more' );
681 private function formatRename(
689 $addedKey = $addedMsg[
'key'];
690 $deletedKey = $deletedMsg[
'key'];
693 $addedTitle = Title::makeTitleSafe( $group->
getNamespace(),
"$addedKey/$language" );
694 $deletedTitle = Title::makeTitleSafe( $group->
getNamespace(),
"$deletedKey/$language" );
695 $id = self::changeId( $group->
getId(), $language, MessageSourceChange::RENAME, $addedKey );
697 $addedTitleLink = $this->getLinkRenderer()->makeLink( $addedTitle );
698 $deletedTitleLink = $this->getLinkRenderer()->makeLink( $deletedTitle );
700 $renameSelected =
true;
703 $renameSelected =
false;
704 $label = $this->msg(
'translate-manage-action-rename-fuzzy' )->text();
705 $actions .= Xml::radioLabel( $label,
"msg/$id",
"renamefuzzy",
"rf/$id",
true );
708 $label = $this->msg(
'translate-manage-action-rename' )->text();
709 $actions .= Xml::radioLabel( $label,
"msg/$id",
"rename",
"imp/$id", $renameSelected );
711 $label = $this->msg(
'translate-manage-action-import' )->text();
712 $actions .= Xml::radioLabel( $label,
"msg/$id",
"import",
"imp/$id",
true );
717 $label = $this->msg(
'translate-manage-action-ignore-change' )->text();
718 $actions .= Xml::radioLabel( $label,
"msg/$id",
"ignore",
"i/$id" );
722 $addedContent = ContentHandler::makeContent( (
string)$addedMsg[
'content'], $addedTitle );
723 $deletedContent = ContentHandler::makeContent( (
string)$deletedMsg[
'content'], $deletedTitle );
724 $this->diff->setContent( $deletedContent, $addedContent );
729 $menu = Html::rawElement(
732 'class' =>
'smg-rename-actions',
734 'data-group-id' => $group->
getId(),
735 'data-msgkey' => $addedKey,
736 'data-msgtitle' => $addedTitle->getFullText()
741 $actions = Html::rawElement(
'div', [
'class' =>
'smg-change-import-options' ], $actions );
743 $text = $this->diff->getDiff(
745 $addedTitleLink . $menu . $actions,
746 $isEqual ? htmlspecialchars( $addedMsg[
'content'] ) :
''
749 $hidden = Html::hidden( $id, 1 );
753 return Html::rawElement(
755 [
'class' =>
'mw-translate-smg-change smg-change-rename' ],
760 private function getRenameJobParams(
762 MessageSourceChange $sourceChanges,
763 string $languageCode,
766 bool $isSourceLang =
true
768 if ( $selectedVal ===
'ignore' ) {
773 $replacementContent =
'';
774 $currentMsgKey = $currentMsg[
'key'];
775 $matchedMsg = $sourceChanges->getMatchedMessage( $languageCode, $currentMsgKey );
776 $matchedMsgKey = $matchedMsg[
'key'];
779 $sourceChanges->isPreviousState(
782 [ MessageSourceChange::ADDITION, MessageSourceChange::CHANGE ]
785 $params[
'target'] = $matchedMsgKey;
786 $params[
'replacement'] = $currentMsgKey;
787 $replacementContent = $currentMsg[
'content'];
789 $params[
'target'] = $currentMsgKey;
790 $params[
'replacement'] = $matchedMsgKey;
791 $replacementContent = $matchedMsg[
'content'];
794 $params[
'fuzzy'] = $selectedVal ===
'renamefuzzy';
796 $params[
'content'] = $replacementContent;
798 if ( $isSourceLang ) {
799 $params[
'targetTitle'] = Title::newFromText(
800 TranslateUtils::title( $params[
'target'], $languageCode, $groupNamespace ),
803 $params[
'others'] = [];
809 private function handleRenameSubmit(
811 MessageSourceChange $sourceChanges,
816 array &$modificationJobs
818 $groupId = $group->getId();
819 $renames = $sourceChanges->getRenames( $language );
823 foreach ( $renames as $key => $params ) {
826 if ( !isset( $renames[$key] ) ) {
830 $id = self::changeId( $groupId, $language, MessageSourceChange::RENAME, $key );
832 [ $renameMissing, $isCurrentKeyPresent ] = $this->isRenameMissing(
842 if ( $renameMissing ) {
845 $postponed[$groupId][$language][MessageSourceChange::RENAME][$key] = $params;
849 if ( !$isCurrentKeyPresent ) {
854 $selectedVal = $req->getVal(
"msg/$id" );
855 $jobParams = $this->getRenameJobParams(
864 if ( $jobParams ===
null ) {
868 $targetStr = $jobParams[
'target' ];
869 if ( $isSourceLang ) {
870 $jobData[ $targetStr ] = $jobParams;
871 } elseif ( isset( $jobData[ $targetStr ] ) ) {
875 $jobData[ $targetStr ][
'others' ][ $language ] = $jobParams[
'content' ];
879 $title = Title::newFromText(
880 TranslateUtils::title( $targetStr, $language, $groupNamespace ),
887 $matchedKey = $sourceChanges->getMatchedKey( $language, $key );
888 unset( $renames[$matchedKey] );
892 private function handleModificationsSubmit(
894 MessageSourceChange $sourceChanges,
898 array &$messageUpdateJob
900 $groupId = $group->getId();
901 $subchanges = $sourceChanges->getModificationsForLanguage( $language );
904 unset( $subchanges[ MessageSourceChange::RENAME ] );
907 foreach ( $subchanges as $type => $messages ) {
908 foreach ( $messages as $index => $params ) {
909 $key = $params[
'key'];
910 $id = self::changeId( $groupId, $language, $type, $key );
911 $title = Title::makeTitleSafe( $group->
getNamespace(),
"$key/$language" );
913 if ( !$this->isTitlePresent( $title, $type ) ) {
917 if ( !$req->getCheck( $id ) ) {
919 $postponed[$groupId][$language][$type][$index] = $params;
923 $selectedVal = $req->getVal(
"msg/$id" );
924 if ( $type === MessageSourceChange::DELETION || $selectedVal ===
'ignore' ) {
928 $fuzzy = $selectedVal ===
'fuzzy';
935 private function createRenameJobs( array $jobParams ): array {
937 foreach ( $jobParams as $groupId => $groupJobParams ) {
938 $jobs[$groupId] = $jobs[$groupId] ?? [];
939 foreach ( $groupJobParams as $params ) {
941 $params[
'targetTitle'],
943 $params[
'replacement'],
955 private function isTitlePresent( Title $title,
string $type ): bool {
958 ( $type === MessageSourceChange::DELETION || $type === MessageSourceChange::CHANGE ) &&
979 private function isRenameMissing(
981 MessageSourceChange $sourceChanges,
988 if ( $req->getCheck( $id ) ) {
989 return [
false, true ];
992 $isCurrentKeyPresent =
false;
995 $matchedKey = $sourceChanges->getMatchedKey( $language, $key );
996 $matchedId = self::changeId( $groupId, $language, MessageSourceChange::RENAME, $matchedKey );
997 if ( $req->getCheck( $matchedId ) ) {
998 return [
false, $isCurrentKeyPresent ];
1004 $isSourceLang || !$sourceChanges->isEqual( $language, $matchedKey ),
1005 $isCurrentKeyPresent
1009 private function getProcessingErrorMessage( array $errorGroups,
int $totalGroupCount ): string {
1011 if ( count( $errorGroups ) < $totalGroupCount ) {
1012 $errorMsg = $this->msg(
'translate-smg-submitted-with-failure' )
1013 ->numParams( count( $errorGroups ) )
1015 $this->getLanguage()->commaList( $errorGroups ),
1016 $this->msg(
'translate-smg-submitted-others-processing' )
1020 $this->msg(
'translate-smg-submitted-with-failure' )
1021 ->numParams( count( $errorGroups ) )
1022 ->params( $this->getLanguage()->commaList( $errorGroups ),
'' )
1031 private function getGroupsFromCdb( \Cdb\Reader $reader ): array {
1034 foreach ( $groupIds as $id ) {
1037 return array_filter( $groups );
1045 private function startSync( array $modificationJobs, array $renameJobs ): void {
1048 $modificationGroupIds = array_keys( array_filter( $modificationJobs ) );
1049 $renameGroupIds = array_keys( array_filter( $renameJobs ) );
1050 $uniqueGroupIds = array_unique( array_merge( $modificationGroupIds, $renameGroupIds ) );
1052 $jobQueueInstance = $this->jobQueueGroup;
1054 foreach ( $uniqueGroupIds as $groupId ) {
1059 $groupRenameJobs = $renameJobs[$groupId] ?? [];
1061 foreach ( $groupRenameJobs as $job ) {
1062 $groupJobs[] = $job;
1063 $messageUpdateParam = MessageUpdateParameter::createFromJob( $job );
1064 $messages[] = $messageUpdateParam;
1067 $replacement = $messageUpdateParam->getReplacementValue();
1068 $targetTitle = Title::makeTitle( $job->getTitle()->getNamespace(), $replacement );
1069 $messageKeys[] = (
new MessageHandle( $targetTitle ) )->getKey();
1072 $groupModificationJobs = $modificationJobs[$groupId] ?? [];
1074 foreach ( $groupModificationJobs as $job ) {
1075 $groupJobs[] = $job;
1076 $messageUpdateParam = MessageUpdateParameter::createFromJob( $job );
1077 $messages[] = $messageUpdateParam;
1079 $messageKeys[] = (
new MessageHandle( $job->getTitle() ) )->getKey();
1085 $messageIndexInstance->storeInterim( $group, $messageKeys );
1087 if ( $this->getConfig()->
get(
'TranslateGroupSynchronizationCache' ) ) {
1088 $this->synchronizationCache->addMessages( $groupId, ...$messages );
1089 $this->synchronizationCache->markGroupForSync( $groupId );
1091 LoggerFactory::getInstance(
'Translate.GroupSynchronization' )->info(
1092 '[' . __CLASS__ .
'] Synchronization started for {groupId} by {user}',
1094 'groupId' => $groupId,
1095 'user' => $this->getUser()->getName()
1104 DeferredUpdates::addCallableUpdate(
1105 static function () use ( $jobQueueInstance, $groupJobs ) {
1106 $jobQueueInstance->push( $groupJobs );