21 public function __construct() {
22 parent::__construct();
23 $this->addDescription(
'Script for processing message changes in file based message groups' );
26 '(optional) Comma separated list of group IDs to process (can use * as wildcard). ' .
33 '(optional) Comma separated list of group IDs to not process (can use * ' .
34 'as wildcard). Overrides --group parameter.',
40 '(optional) Unique name to avoid conflicts with multiple invocations of this script.',
46 '(optional) Import "safe" changes: message additions when no other kind of changes.'
49 'skip-group-sync-check',
50 '(optional) Skip importing group if synchronization is still in progress or if there ' .
51 'was an error during synchronization. See: ' .
52 'https://www.mediawiki.org/wiki/Help:Extension:Translate/Group_management#Strong_synchronization'
56 '(optional) Import non renames: if a language in a group has only additions and changes to existing ' .
57 ' strings, then the additions are imported'
59 $this->requireExtension(
'Translate' );
62 public function execute() {
63 $name = $this->getOption(
'name', MessageChangeStorage::DEFAULT_NAME );
64 if ( !MessageChangeStorage::isValidCdbName( $name ) ) {
65 $this->fatalError(
'Invalid name' );
68 $groups = $this->getGroups();
72 $importStrategy = $this->getImportStrategy();
73 $skipGroupSyncCache = $this->hasOption(
'skip-group-sync-check' );
75 $services = Services::getInstance();
76 $groupSyncCache = $services->getGroupSynchronizationCache();
77 $groupSyncCacheEnabled = MediaWikiServices::getInstance()->getMainConfig()
78 ->get(
'TranslateGroupSynchronizationCache' );
80 foreach ( $groups as $id => $group ) {
83 "Group $id expected to be FileBasedMessageGroup, got " . get_class( $group ) .
" instead."
88 if ( $groupSyncCacheEnabled && !$skipGroupSyncCache ) {
89 if ( $groupSyncCache->isGroupBeingProcessed( $id ) ) {
90 $this->error(
"Group $id is currently being synchronized; skipping processing of changes\n" );
94 if ( $groupSyncCache->groupHasErrors( $id ) ) {
95 $this->error(
"Skipping $id due to an error during synchronization\n" );
100 if ( $importStrategy === ExternalMessageSourceStateImporter::IMPORT_NONE ) {
101 $this->output(
"Processing $id\n" );
105 $changes[$id] = $comparator->processGroup( $group, $comparator::ALL_LANGUAGES );
106 }
catch ( Exception $e ) {
107 $errorMsg =
"Exception occurred while processing group: $id.\nException: $e";
108 $this->error( $errorMsg );
109 error_log( $errorMsg );
118 if ( $changes === [] ) {
119 if ( $importStrategy === ExternalMessageSourceStateImporter::IMPORT_NONE ) {
120 $this->output(
"No changes found\n" );
126 if ( $importStrategy !== ExternalMessageSourceStateImporter::IMPORT_NONE ) {
127 $importer = $services->getExternalMessageSourceStateImporter();
128 $info = $importer->import( $changes, $name, $importStrategy );
129 $this->printChangeInfo( $info );
134 $file = MessageChangeStorage::getCdbPath( $name );
136 MessageChangeStorage::writeChanges( $changes, $file );
137 $url = SpecialPage::getTitleFor(
'ManageMessageGroups', $name )->getFullURL();
138 $this->output(
"Process changes at $url\n" );
145 private function getGroups(): array {
146 $groups = MessageGroups::getGroupsByType( FileBasedMessageGroup::class );
149 $include = $this->getOption(
'group',
'*' );
150 $include = explode(
',', $include );
151 $include = array_map(
'trim', $include );
152 $include = MessageGroups::expandWildcards( $include );
155 $exclude = $this->getOption(
'skipgroup',
'' );
156 $exclude = explode(
',', $exclude );
157 $exclude = array_map(
'trim', $exclude );
158 $exclude = MessageGroups::expandWildcards( $exclude );
161 $include = array_flip( $include );
162 $exclude = array_flip( $exclude );
164 $groups = array_filter( $groups,
165 static function (
MessageGroup $group ) use ( $include, $exclude ) {
166 $id = $group->
getId();
168 return isset( $include[$id] ) && !isset( $exclude[$id] );
175 private function printChangeInfo( array $info ):
void {
176 foreach ( $info[
'processed'] as $group => $languages ) {
177 $newMessageCount = array_sum( $languages );
178 if ( $newMessageCount ) {
179 $this->output(
"Imported $newMessageCount new messages or translations for $group.\n" );
183 if ( $info[
'skipped'] !== [] ) {
184 $skipped = implode(
', ', array_keys( $info[
'skipped'] ) );
185 $this->output(
"There are changes to check for groups $skipped.\n" );
186 $url = SpecialPage::getTitleFor(
'ManageMessageGroups', $info[
'name'] )->getFullURL();
187 $this->output(
"You can process them at $url\n" );
191 private function getImportStrategy():
int {
192 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_NONE;
193 if ( $this->hasOption(
'safe-import' ) ) {
194 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_SAFE;
197 if ( $this->hasOption(
'import-non-renames' ) ) {
198 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_NON_RENAMES;
201 return $importStrategy;