Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
ImportExternalTranslationsMaintenanceScript.php
1<?php
2declare( strict_types = 1 );
3
5
6use Exception;
8use MediaWiki\Context\RequestContext;
13use MediaWiki\MediaWikiServices;
14use MediaWiki\SpecialPage\SpecialPage;
15use MessageGroup;
16
19 public function __construct() {
20 parent::__construct();
21 $this->addDescription( 'Script for processing message changes in file based message groups' );
22 $this->addOption(
23 'group',
24 '(optional) Comma separated list of group IDs to process (can use * as wildcard). ' .
25 'Default: "*"',
26 self::OPTIONAL,
27 self::HAS_ARG
28 );
29 $this->addOption(
30 'skipgroup',
31 '(optional) Comma separated list of group IDs to not process (can use * ' .
32 'as wildcard). Overrides --group parameter.',
33 self::OPTIONAL,
34 self::HAS_ARG
35 );
36 $this->addOption(
37 'name',
38 '(optional) Unique name to avoid conflicts with multiple invocations of this script.',
39 self::OPTIONAL,
40 self::HAS_ARG
41 );
42 $this->addOption(
43 'safe-import',
44 '(optional) Import "safe" changes: message additions when no other kind of changes.'
45 );
46 $this->addOption(
47 'skip-group-sync-check',
48 '(optional) Skip importing group if synchronization is still in progress or if there ' .
49 'was an error during synchronization. See: ' .
50 'https://www.mediawiki.org/wiki/Help:Extension:Translate/Group_management#Strong_synchronization'
51 );
52 $this->addOption(
53 'import-non-renames',
54 '(optional) Import non renames: if a language in a group has only additions and changes to existing ' .
55 ' strings, then the additions are imported'
56 );
57 $this->requireExtension( 'Translate' );
58 }
59
60 public function execute() {
61 $name = $this->getOption( 'name', MessageChangeStorage::DEFAULT_NAME );
63 $this->fatalError( 'Invalid name' );
64 }
65
66 $groups = $this->getGroups();
67 $changes = [];
68 $comparator = Services::getInstance()->getExternalMessageSourceStateComparator();
69
70 $importStrategy = $this->getImportStrategy();
71 $skipGroupSyncCache = $this->hasOption( 'skip-group-sync-check' );
72
73 $services = Services::getInstance();
74 $importer = $services->getExternalMessageSourceStateImporter();
75
76 $statusFormatter = MediaWikiServices::getInstance()
77 ->getFormatterFactory()
78 ->getStatusFormatter( RequestContext::getMain() );
79
80 foreach ( $groups as $id => $group ) {
81 $status = $importer->canImportGroup( $group, $skipGroupSyncCache );
82 if ( !$status->isOK() ) {
83 $this->error( $statusFormatter->getMessage( $status )->plain() );
84 continue;
85 }
86
87 try {
88 $changes[$id] = $comparator->processGroup( $group );
89 } catch ( Exception $e ) {
90 $errorMsg = "Exception occurred while processing group: $id.\nException: $e";
91 $this->error( $errorMsg );
92 error_log( $errorMsg );
93 }
94 }
95
96 // Remove all groups without changes
97 $changes = array_filter( $changes, static function ( MessageSourceChange $change ) {
98 return $change->getAllModifications() !== [];
99 } );
100
101 if ( $changes === [] ) {
102 if ( $importStrategy === ExternalMessageSourceStateImporter::IMPORT_NONE ) {
103 $this->output( "No changes found\n" );
104 }
105
106 return;
107 }
108
109 $info = $importer->import( $changes, $name, $importStrategy );
110 $this->printChangeInfo( $info );
111 }
112
117 private function getGroups(): array {
118 $groups = MessageGroups::getGroupsByType( FileBasedMessageGroup::class );
119
120 // Include all if option not given
121 $include = $this->getOption( 'group', '*' );
122 $include = explode( ',', $include );
123 $include = array_map( 'trim', $include );
124 $include = MessageGroups::expandWildcards( $include );
125
126 // Exclude nothing if option not given
127 $exclude = $this->getOption( 'skipgroup', '' );
128 $exclude = explode( ',', $exclude );
129 $exclude = array_map( 'trim', $exclude );
130 $exclude = MessageGroups::expandWildcards( $exclude );
131
132 // Flip to allow isset
133 $include = array_flip( $include );
134 $exclude = array_flip( $exclude );
135
136 return array_filter( $groups,
137 static function ( MessageGroup $group ) use ( $include, $exclude ) {
138 $id = $group->getId();
139
140 return isset( $include[$id] ) && !isset( $exclude[$id] );
141 }
142 );
143 }
144
145 private function printChangeInfo( array $info ): void {
146 foreach ( $info['processed'] as $group => $languages ) {
147 $newMessageCount = array_sum( $languages );
148 if ( $newMessageCount ) {
149 $this->output( "Imported $newMessageCount new messages or translations for $group.\n" );
150 }
151 }
152
153 if ( $info['skipped'] !== [] ) {
154 $skipped = implode( ', ', array_keys( $info['skipped'] ) );
155 $this->output( "There are changes to check for groups $skipped.\n" );
156 $url = SpecialPage::getTitleFor( 'ManageMessageGroups', $info['name'] )->getFullURL();
157 $this->output( "You can process them at $url\n" );
158 }
159 }
160
161 private function getImportStrategy(): int {
162 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_NONE;
163 if ( $this->hasOption( 'safe-import' ) ) {
164 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_SAFE;
165 }
166
167 if ( $this->hasOption( 'import-non-renames' ) ) {
168 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_NON_RENAMES;
169 }
170
171 return $importStrategy;
172 }
173}
This class implements default behavior for file based message groups.
Factory class for accessing message groups individually by id or all of them as a list.
Class is used to track the changes made when importing messages from the remote sources using importE...
Minimal service container.
Definition Services.php:59
Base maintenance script containing constants and methods used in multiple scripts Hopefully the const...
Interface for message groups.
getId()
Returns the unique identifier for this group.
Finds external changes for file based message groups.