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