31 private $groupSynchronizationCache;
33 private $jobQueueGroup;
37 private $messageIndex;
39 public const IMPORT_NONE = 1;
41 public const IMPORT_SAFE = 2;
44 public const IMPORT_NON_RENAMES = 3;
46 public function __construct(
49 JobQueueGroup $jobQueueGroup,
50 LoggerInterface $logger,
53 $this->config = $config;
54 $this->groupSynchronizationCache = $groupSynchronizationCache;
55 $this->jobQueueGroup = $jobQueueGroup;
56 $this->logger = $logger;
57 $this->messageIndex = $messageIndex;
66 public function import( array $changeData,
string $name,
int $importStrategy ): array {
71 $groupSyncCacheEnabled = $this->config->get(
'TranslateGroupSynchronizationCache' );
73 foreach ( $changeData as $groupId => $changesForGroup ) {
74 $group = MessageGroups::getGroup( $groupId );
76 unset( $changeData[$groupId] );
81 $this->logger->warning(
82 '[ExternalMessageSourceStateImporter] Expected FileBasedMessageGroup, ' .
83 'but got {class} for group {groupId}',
85 'class' => get_class( $group ),
89 unset( $changeData[$groupId] );
93 $processed[$groupId] = [];
94 $languages = $changesForGroup->getLanguages();
97 $groupSafeLanguages = self::identifySafeLanguages( $group, $changesForGroup, $importStrategy );
99 foreach ( $languages as $language ) {
100 if ( !$groupSafeLanguages[ $language ] ) {
101 $skipped[$groupId] =
true;
105 $additions = $changesForGroup->getAdditions( $language );
106 if ( $additions === [] ) {
110 [ $groupLanguageJobs, $groupProcessed ] = $this->createMessageUpdateJobs(
111 $group, $additions, $language
114 $groupJobs = array_merge( $groupJobs, $groupLanguageJobs );
115 $processed[$groupId][$language] = $groupProcessed;
119 $changesForGroup->removeAdditions( $language,
null );
120 $group->getMessageGroupCache( $language )->create();
124 if ( $groupSyncCacheEnabled && isset( $skipped[$groupId] ) ) {
125 $this->groupSynchronizationCache->markGroupAsInReview( $groupId );
128 if ( $groupJobs !== [] ) {
129 if ( $groupSyncCacheEnabled ) {
130 $this->updateGroupSyncInfo( $groupId, $groupJobs );
132 $jobs = array_merge( $jobs, $groupJobs );
142 $processed = array_filter( $processed );
144 $file = MessageChangeStorage::getCdbPath( $name );
145 MessageChangeStorage::writeChanges( $changeData, $file );
146 $this->jobQueueGroup->push( $jobs );
149 'processed' => $processed,
150 'skipped' => $skipped,
156 private function createMessageUpdateJobs(
161 $groupId = $group->getId();
164 foreach ( $additions as $addition ) {
166 $name =
"{$addition['key']}/$language";
168 $title = Title::makeTitleSafe( $namespace, $name );
170 wfWarn(
"Invalid title for group $groupId key {$addition['key']}" );
174 $jobs[] = MessageUpdateJob::newJob( $title, $addition[
'content'] );
178 return [ $jobs, $processed ];
185 private function updateGroupSyncInfo(
string $groupId, array $groupJobs ): void {
187 $groupMessageKeys = [];
188 foreach ( $groupJobs as $job ) {
189 $messageParams[] = MessageUpdateParameter::createFromJob( $job );
192 $groupMessageKeys[(
new MessageHandle( $job->getTitle() ) )->getKey()] =
true;
195 $group = MessageGroups::getGroup( $groupId );
196 if ( $group ===
null ) {
198 throw new RuntimeException(
"Did not find group $groupId" );
201 $this->messageIndex->storeInterim( $group, array_keys( $groupMessageKeys ) );
203 $this->groupSynchronizationCache->addMessages( $groupId, ...$messageParams );
204 $this->groupSynchronizationCache->markGroupForSync( $groupId );
207 '[ExternalMessageSourceStateImporter] Synchronization started for {groupId}',
208 [
'groupId' => $groupId ]
216 private static function identifySafeLanguages(
218 MessageSourceChange $changesForGroup,
221 $sourceLanguage = $group->getSourceLanguage();
222 $safeLanguagesMap = [];
223 $modifiedLanguages = $changesForGroup->getLanguages();
226 $safeLanguagesMap[ $sourceLanguage ] =
false;
227 foreach ( $modifiedLanguages as $language ) {
228 $safeLanguagesMap[ $language ] =
false;
231 if ( !self::isLanguageSafe( $changesForGroup, $sourceLanguage, $importStrategy ) ) {
232 return $safeLanguagesMap;
235 $sourceLanguageKeyCache = [];
236 foreach ( $changesForGroup->getAdditions( $sourceLanguage ) as $change ) {
237 if ( $change[
'content'] ===
'' ) {
238 return $safeLanguagesMap;
241 $sourceLanguageKeyCache[ $change[
'key'] ] =
true;
244 $safeLanguagesMap[ $sourceLanguage ] =
true;
250 if ( $sourceLanguageKeyCache ) {
251 array_splice( $modifiedLanguages, array_search( $sourceLanguage, $modifiedLanguages ), 1 );
254 foreach ( $modifiedLanguages as $language ) {
255 if ( !self::isLanguageSafe( $changesForGroup, $sourceLanguage, $importStrategy ) ) {
259 foreach ( $changesForGroup->getAdditions( $language ) as $change ) {
260 if ( $change[
'content'] ===
'' ) {
264 $msgKey = $change[
'key'];
266 if ( !isset( $sourceLanguageKeyCache[ $msgKey ] ) ) {
270 $sourceHandle =
new MessageHandle( Title::makeTitle( $groupNamespace, $msgKey ) );
271 $sourceLanguageKeyCache[ $msgKey ] = $sourceHandle->isValid();
274 if ( !$sourceLanguageKeyCache[ $msgKey ] ) {
279 $safeLanguagesMap[ $language ] =
true;
282 return $safeLanguagesMap;
285 private static function isLanguageSafe(
286 MessageSourceChange $changesForGroup,
287 string $languageCode,
290 if ( $importStrategy === self::IMPORT_SAFE ) {
291 return $changesForGroup->hasOnly( $languageCode, MessageSourceChange::ADDITION );
296 return $changesForGroup->getDeletions( $languageCode ) === [];