MediaWiki REL1_31
Updater.php
Go to the documentation of this file.
1<?php
8namespace LocalisationUpdate;
9
13class Updater {
21 public function isDirectory( $path ) {
22 $filename = basename( $path );
23 return strpos( $filename, '*' ) !== false;
24 }
25
35 public function expandRemotePath( $info, $repos ) {
36 $pattern = $repos[$info['repo']];
37 unset( $info['repo'], $info['orig'] );
38
39 // This assumes all other keys are used as variables
40 // in the pattern. For example name -> %NAME%.
41 $keys = [];
42 foreach ( array_keys( $info ) as $key ) {
43 $keys[] = '%' . strtoupper( $key ) . '%';
44 }
45
46 $values = array_values( $info );
47 return str_replace( $keys, $values, $pattern );
48 }
49
57 public function readMessages( ReaderFactory $readerFactory, array $files ) {
58 $messages = [];
59
60 foreach ( $files as $filename => $contents ) {
61 $reader = $readerFactory->getReader( $filename );
62 try {
63 $parsed = $reader->parse( $contents );
64 } catch ( \Exception $e ) {
65 trigger_error( __METHOD__ . ": Unable to parse messages from $filename", E_USER_WARNING );
66 continue;
67 }
68
69 foreach ( $parsed as $code => $langMessages ) {
70 if ( !isset( $messages[$code] ) ) {
71 $messages[$code] = [];
72 }
73 $messages[$code] = array_merge( $messages[$code], $langMessages );
74 }
75
76 $c = array_sum( array_map( 'count', $parsed ) );
77 // Useful for debugging, maybe create interface to pass this to the script?
78 # echo "$filename with " . get_class( $reader ) . " and $c\n";
79 }
80
81 return $messages;
82 }
83
92 public function findChangedTranslations( $origin, $remote, $blacklist = [] ) {
93 $changed = [];
94 foreach ( $remote as $key => $value ) {
95 if ( isset( $blacklist[$key] ) ) {
96 continue;
97 }
98
99 if ( !isset( $origin[$key] ) || $value !== $origin[$key] ) {
100 $changed[$key] = $value;
101 }
102 }
103 return $changed;
104 }
105
113 public function fetchFiles( FetcherFactory $factory, $path ) {
114 $fetcher = $factory->getFetcher( $path );
115
116 if ( $this->isDirectory( $path ) ) {
117 $files = $fetcher->fetchDirectory( $path );
118 } else {
119 $files = [ $path => $fetcher->fetchFile( $path ) ];
120 }
121
122 // Remove files which were not found
123 return array_filter( $files );
124 }
125
126 public function execute(
127 Finder $finder,
128 ReaderFactory $readerFactory,
129 FetcherFactory $fetcherFactory,
130 array $repos,
131 $logger
132 ) {
133 $components = $finder->getComponents();
134
135 $updatedMessages = [];
136
137 foreach ( $components as $key => $info ) {
138 $logger->logInfo( "Updating component $key" );
139
140 $originFiles = $this->fetchFiles( $fetcherFactory, $info['orig'] );
141 $remotePath = $this->expandRemotePath( $info, $repos );
142 try {
143 $remoteFiles = $this->fetchFiles( $fetcherFactory, $remotePath );
144 } catch ( \Exception $e ) {
145 $logger->logError( __METHOD__ . ": Unable to fetch messages from $remotePath" );
146 continue;
147 }
148
149 if ( $remoteFiles === [] ) {
150 // Small optimization: if nothing to compare with, skip
151 continue;
152 }
153
154 $originMessages = $this->readMessages( $readerFactory, $originFiles );
155 $remoteMessages = $this->readMessages( $readerFactory, $remoteFiles );
156
157 if ( !isset( $remoteMessages['en'] ) ) {
158 // Could not find remote messages
159 continue;
160 }
161
162 // If remote translation in English is not present or differs, we do not want
163 // translations for other languages for those messages, as they are either not
164 // used in this version of code or can be incompatible.
165 $forbiddenKeys = $this->findChangedTranslations(
166 $originMessages['en'],
167 $remoteMessages['en']
168 );
169
170 // We never accept updates for English strings
171 unset( $originMessages['en'], $remoteMessages['en'] );
172
173 // message: string in all languages; translation: string in one language.
174 foreach ( $remoteMessages as $language => $remoteTranslations ) {
175 // Check for completely new languages
176 $originTranslations = [];
177 if ( isset( $originMessages[$language] ) ) {
178 $originTranslations = $originMessages[$language];
179 }
180
181 $updatedTranslations = $this->findChangedTranslations(
182 $originTranslations,
183 $remoteTranslations,
184 $forbiddenKeys
185 );
186
187 // Avoid empty arrays
188 if ( $updatedTranslations === [] ) {
189 continue;
190 }
191
192 if ( !isset( $updatedMessages[$language] ) ) {
193 $updatedMessages[$language] = [];
194 }
195
196 // In case of conflicts, which should not exist, this prefers the
197 // first translation seen.
198 $updatedMessages[$language] += $updatedTranslations;
199 }
200 }
201
202 return $updatedMessages;
203 }
204}
$messages
Constructs fetchers based on the repository urls.
Interface for classes which provide list of components, which should be included for l10n updates.
Definition Finder.php:14
Constructs readers for files based on the names.
Executes the localisation update.
Definition Updater.php:13
fetchFiles(FetcherFactory $factory, $path)
Fetches files from given Url pattern.
Definition Updater.php:113
execute(Finder $finder, ReaderFactory $readerFactory, FetcherFactory $fetcherFactory, array $repos, $logger)
Definition Updater.php:126
expandRemotePath( $info, $repos)
Expands repository relative path to full url with the given repository patterns.
Definition Updater.php:35
findChangedTranslations( $origin, $remote, $blacklist=[])
Find new and changed translations in $remote and returns them.
Definition Updater.php:92
readMessages(ReaderFactory $readerFactory, array $files)
Parses translations from given list of files.
Definition Updater.php:57
isDirectory( $path)
Whether the path is a pattern and thus we need to use appropriate code for fetching directories.
Definition Updater.php:21
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition hooks.txt:865
returning false will NOT prevent logging $e
Definition hooks.txt:2176