Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
ImportExternalTranslationsMaintenanceScript.php
1<?php
2declare( strict_types = 1 );
3
5
6use Exception;
12use MediaWiki\SpecialPage\SpecialPage;
13use MessageGroup;
14
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 );
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 try {
82 $changes[$id] = $comparator->processGroup( $group );
83 } catch ( Exception $e ) {
84 $errorMsg = "Exception occurred while processing group: $id.\nException: $e";
85 $this->error( $errorMsg );
86 error_log( $errorMsg );
87 }
88 }
89
90 // Remove all groups without changes
91 $changes = array_filter( $changes, static function ( MessageSourceChange $change ) {
92 return $change->getAllModifications() !== [];
93 } );
94
95 if ( $changes === [] ) {
96 if ( $importStrategy === ExternalMessageSourceStateImporter::IMPORT_NONE ) {
97 $this->output( "No changes found\n" );
98 }
99
100 return;
101 }
102
103 $info = $importer->import( $changes, $name, $importStrategy );
104 $this->printChangeInfo( $info );
105 }
106
111 private function getGroups(): array {
112 $groups = MessageGroups::getGroupsByType( FileBasedMessageGroup::class );
113
114 // Include all if option not given
115 $include = $this->getOption( 'group', '*' );
116 $include = explode( ',', $include );
117 $include = array_map( 'trim', $include );
118 $include = MessageGroups::expandWildcards( $include );
119
120 // Exclude nothing if option not given
121 $exclude = $this->getOption( 'skipgroup', '' );
122 $exclude = explode( ',', $exclude );
123 $exclude = array_map( 'trim', $exclude );
124 $exclude = MessageGroups::expandWildcards( $exclude );
125
126 // Flip to allow isset
127 $include = array_flip( $include );
128 $exclude = array_flip( $exclude );
129
130 return array_filter( $groups,
131 static function ( MessageGroup $group ) use ( $include, $exclude ) {
132 $id = $group->getId();
133
134 return isset( $include[$id] ) && !isset( $exclude[$id] );
135 }
136 );
137 }
138
139 private function printChangeInfo( array $info ): void {
140 foreach ( $info['processed'] as $group => $languages ) {
141 $newMessageCount = array_sum( $languages );
142 if ( $newMessageCount ) {
143 $this->output( "Imported $newMessageCount new messages or translations for $group.\n" );
144 }
145 }
146
147 if ( $info['skipped'] !== [] ) {
148 $skipped = implode( ', ', array_keys( $info['skipped'] ) );
149 $this->output( "There are changes to check for groups $skipped.\n" );
150 $url = SpecialPage::getTitleFor( 'ManageMessageGroups', $info['name'] )->getFullURL();
151 $this->output( "You can process them at $url\n" );
152 }
153 }
154
155 private function getImportStrategy(): int {
156 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_NONE;
157 if ( $this->hasOption( 'safe-import' ) ) {
158 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_SAFE;
159 }
160
161 if ( $this->hasOption( 'import-non-renames' ) ) {
162 $importStrategy = ExternalMessageSourceStateImporter::IMPORT_NON_RENAMES;
163 }
164
165 return $importStrategy;
166 }
167}
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:58
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.