Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MessageGroupBase.php
Go to the documentation of this file.
1<?php
16use MediaWiki\MediaWikiServices;
17
27abstract class MessageGroupBase implements MessageGroup {
28 protected $conf;
29 protected $namespace;
31 protected $mangler;
32
33 protected function __construct() {
34 }
35
41 public static function factory( $conf ) {
42 $obj = new $conf['BASIC']['class']();
43 $obj->conf = $conf;
44 $obj->namespace = $obj->parseNamespace();
45
46 return $obj;
47 }
48
49 public function getConfiguration() {
50 return $this->conf;
51 }
52
53 public function getId() {
54 return $this->getFromConf( 'BASIC', 'id' );
55 }
56
57 public function getLabel( IContextSource $context = null ) {
58 return $this->getFromConf( 'BASIC', 'label' );
59 }
60
61 public function getDescription( IContextSource $context = null ) {
62 return $this->getFromConf( 'BASIC', 'description' );
63 }
64
65 public function getIcon() {
66 return $this->getFromConf( 'BASIC', 'icon' );
67 }
68
69 public function getNamespace() {
70 return $this->namespace;
71 }
72
73 public function isMeta() {
74 return $this->getFromConf( 'BASIC', 'meta' );
75 }
76
77 public function getSourceLanguage() {
78 $conf = $this->getFromConf( 'BASIC', 'sourcelanguage' );
79
80 return $conf ?? 'en';
81 }
82
83 public function getDefinitions() {
84 $defs = $this->load( $this->getSourceLanguage() );
85
86 return $defs;
87 }
88
89 protected function getFromConf( $section, $key = null ) {
90 if ( $key === null ) {
91 return $this->conf[$section] ?? null;
92 }
93 return $this->conf[$section][$key] ?? null;
94 }
95
96 public function getValidator() {
97 $validatorConfigs = $this->getFromConf( 'VALIDATORS' );
98 if ( $validatorConfigs === null ) {
99 return null;
100 }
101
102 $msgValidator = new ValidationRunner( $this->getId() );
103
104 foreach ( $validatorConfigs as $config ) {
105 try {
106 $msgValidator->addValidator( $config );
107 } catch ( Exception $e ) {
108 $id = $this->getId();
109 throw new InvalidArgumentException(
110 "Unable to construct validator for message group $id: " . $e->getMessage(),
111 0,
112 $e
113 );
114 }
115 }
116
117 return $msgValidator;
118 }
119
120 public function getMangler() {
121 if ( !isset( $this->mangler ) ) {
122 $class = $this->getFromConf( 'MANGLER', 'class' ) ?? StringMatcher::class;
123
124 if ( $class === 'StringMatcher' || $class === StringMatcher::class ) {
125 $this->mangler = new StringMatcher();
126 $manglerConfig = $this->conf['MANGLER'] ?? null;
127 if ( $manglerConfig ) {
128 $this->mangler->setConf( $manglerConfig );
129 }
130
131 return $this->mangler;
132 }
133
134 throw new InvalidArgumentException(
135 'Unable to create StringMangler for group ' . $this->getId() . ': ' .
136 "Custom StringManglers ($class) are currently not supported."
137 );
138 }
139
140 return $this->mangler;
141 }
142
148 public function getInsertablesSuggester() {
149 $suggesters = [];
150 $insertableConf = $this->getFromConf( 'INSERTABLES' ) ?? [];
151
152 foreach ( $insertableConf as $config ) {
153 if ( !isset( $config['class'] ) ) {
154 throw new InvalidArgumentException(
155 'Insertable configuration for group: ' . $this->getId() .
156 ' does not provide a class.'
157 );
158 }
159
160 if ( !is_string( $config['class'] ) ) {
161 throw new InvalidArgumentException(
162 'Expected Insertable class to be string, got: ' . gettype( $config['class'] ) .
163 ' for group: ' . $this->getId()
164 );
165 }
166
167 $suggesters[] = InsertableFactory::make( $config['class'], $config['params'] ?? [] );
168 }
169
170 // Get validators marked as insertable
171 $messageValidator = $this->getValidator();
172 if ( $messageValidator ) {
173 $suggesters = array_merge( $suggesters, $messageValidator->getInsertableValidators() );
174 }
175
176 return new CombinedInsertablesSuggester( $suggesters );
177 }
178
180 public function getKeys() {
181 return array_keys( $this->getDefinitions() );
182 }
183
184 public function getTags( $type = null ) {
185 if ( $type === null ) {
186 $taglist = [];
187
188 foreach ( $this->getRawTags() as $type => $patterns ) {
189 $taglist[$type] = $this->parseTags( $patterns );
190 }
191
192 return $taglist;
193 } else {
194 return $this->parseTags( $this->getRawTags( $type ) );
195 }
196 }
197
198 protected function parseTags( $patterns ) {
199 $messageKeys = $this->getKeys();
200
201 $matches = [];
202
206 foreach ( $patterns as $index => $pattern ) {
207 if ( strpos( $pattern, '*' ) === false ) {
208 $matches[] = $pattern;
209 unset( $patterns[$index] );
210 }
211 }
212
213 if ( count( $patterns ) ) {
217 $mangler = new StringMatcher( '', $patterns );
218
222 foreach ( $messageKeys as $key ) {
223 if ( $mangler->matches( $key ) ) {
224 $matches[] = $key;
225 }
226 }
227 }
228
229 return $matches;
230 }
231
232 protected function getRawTags( $type = null ) {
233 if ( !isset( $this->conf['TAGS'] ) ) {
234 return [];
235 }
236
237 $tags = $this->conf['TAGS'];
238 if ( !$type ) {
239 return $tags;
240 }
241
242 return $tags[$type] ?? [];
243 }
244
245 protected function setTags( MessageCollection $collection ) {
246 foreach ( $this->getTags() as $type => $tags ) {
247 $collection->setTags( $type, $tags );
248 }
249 }
250
251 protected function parseNamespace() {
252 $ns = $this->getFromConf( 'BASIC', 'namespace' );
253
254 if ( is_int( $ns ) ) {
255 return $ns;
256 }
257
258 if ( defined( $ns ) ) {
259 return constant( $ns );
260 }
261
262 $index = MediaWikiServices::getInstance()->getContentLanguage()
263 ->getNsIndex( $ns );
264
265 if ( !$index ) {
266 throw new MWException( "No valid namespace defined, got $ns." );
267 }
268
269 return $index;
270 }
271
272 protected function isSourceLanguage( $code ) {
273 return $code === $this->getSourceLanguage();
274 }
275
280 public function getMessageGroupStates() {
281 global $wgTranslateWorkflowStates;
282 $conf = $wgTranslateWorkflowStates ?: [];
283
284 Hooks::run( 'Translate:modifyMessageGroupStates', [ $this->getId(), &$conf ] );
285
286 return new MessageGroupStates( $conf );
287 }
288
290 public function getTranslatableLanguages() {
291 $groupConfiguration = $this->getConfiguration();
292 if ( !isset( $groupConfiguration['LANGUAGES'] ) ) {
293 // No LANGUAGES section in the configuration.
294 return null;
295 }
296
297 $codes = array_flip( array_keys( TranslateUtils::getLanguageNames( null ) ) );
298
299 $lists = $groupConfiguration['LANGUAGES'];
300 $exclusionList = $lists['exclude'] ?? null;
301 if ( $exclusionList !== null ) {
302 if ( $exclusionList === '*' ) {
303 // All excluded languages
304 $codes = [];
305 } elseif ( is_array( $exclusionList ) ) {
306 foreach ( $exclusionList as $code ) {
307 unset( $codes[$code] );
308 }
309 }
310 } else {
311 // Treat lack of explicit exclusion list the same as excluding everything. This way,
312 // when one defines only inclusions, it means that only those languages are allowed.
313 $codes = [];
314 }
315
316 $disabledLanguages = Services::getInstance()->getConfigHelper()->getDisabledTargetLanguages();
317 // DWIM with $wgTranslateDisabledTargetLanguages, e.g. languages in that list should not unexpectedly
318 // be enabled when an inclusion list is used to include any language.
319 $checks = [ $this->getId(), strtok( $this->getId(), '-' ), '*' ];
320 foreach ( $checks as $check ) {
321 if ( isset( $disabledLanguages[ $check ] ) ) {
322 foreach ( array_keys( $disabledLanguages[ $check ] ) as $excludedCode ) {
323 unset( $codes[ $excludedCode ] );
324 }
325 }
326 }
327
328 $inclusionList = $lists['include'] ?? null;
329 if ( $inclusionList !== null ) {
330 if ( $inclusionList === '*' ) {
331 // All languages included (except $wgTranslateDisabledTargetLanguages)
332 return null;
333 } elseif ( is_array( $inclusionList ) ) {
334 foreach ( $inclusionList as $code ) {
335 $codes[$code] = true;
336 }
337 }
338 }
339
340 return $codes;
341 }
342
343 public function getSupportConfig(): ?array {
344 return $this->getFromConf( 'BASIC', 'support' );
345 }
346}
return[ 'Translate:ConfigHelper'=> static function():ConfigHelper { return new ConfigHelper();}, 'Translate:CsvTranslationImporter'=> static function(MediaWikiServices $services):CsvTranslationImporter { return new CsvTranslationImporter( $services->getWikiPageFactory());}, 'Translate:EntitySearch'=> static function(MediaWikiServices $services):EntitySearch { return new EntitySearch($services->getMainWANObjectCache(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), MessageGroups::singleton(), $services->getNamespaceInfo(), $services->get( 'Translate:MessageIndex'), $services->getTitleParser(), $services->getTitleFormatter());}, 'Translate:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->getMainConfig(), $services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance( 'Translate.GroupSynchronization'), MessageIndex::singleton());}, 'Translate:GroupSynchronizationCache'=> static function(MediaWikiServices $services):GroupSynchronizationCache { return new GroupSynchronizationCache( $services->get( 'Translate:PersistentCache'));}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore(new RevTagStore(), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'));}, 'Translate:MessageGroupReview'=> static function(MediaWikiServices $services):MessageGroupReview { return new MessageGroupReview($services->getDBLoadBalancer(), $services->getHookContainer());}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=$services->getMainConfig() ->get( 'TranslateMessageIndex');if(is_string( $params)) { $params=(array) $params;} $class=array_shift( $params);return new $class( $params);}, 'Translate:ParsingPlaceholderFactory'=> static function():ParsingPlaceholderFactory { return new ParsingPlaceholderFactory();}, 'Translate:PersistentCache'=> static function(MediaWikiServices $services):PersistentCache { return new PersistentDatabaseCache($services->getDBLoadBalancer(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'));}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleFactory'=> static function(MediaWikiServices $services):TranslatableBundleFactory { return new TranslatableBundleFactory($services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:MessageBundleStore'));}, 'Translate:TranslatableBundleMover'=> static function(MediaWikiServices $services):TranslatableBundleMover { return new TranslatableBundleMover($services->getMovePageFactory(), $services->getJobQueueGroup(), $services->getLinkBatchFactory(), $services->get( 'Translate:TranslatableBundleFactory'), $services->get( 'Translate:SubpageListBuilder'), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), new RevTagStore(), $services->getDBLoadBalancer());}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { $db=$services->getDBLoadBalancer() ->getConnectionRef(DB_REPLICA);return new TranslationStashStorage( $db);}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory());}, 'Translate:TranslationUnitStoreFactory'=> static function(MediaWikiServices $services):TranslationUnitStoreFactory { return new TranslationUnitStoreFactory( $services->getDBLoadBalancer());}, 'Translate:TranslatorActivity'=> static function(MediaWikiServices $services):TranslatorActivity { $query=new TranslatorActivityQuery($services->getMainConfig(), $services->getDBLoadBalancer());return new TranslatorActivity($services->getMainObjectStash(), $query, $services->getJobQueueGroup());}, 'Translate:TtmServerFactory'=> static function(MediaWikiServices $services):TtmServerFactory { $config=$services->getMainConfig();$default=$config->get( 'TranslateTranslationDefaultService');if( $default===false) { $default=null;} return new TtmServerFactory( $config->get( 'TranslateTranslationServices'), $default);}]
@phpcs-require-sorted-array
The versatile default implementation of StringMangler interface.
Minimal service container.
Definition Services.php:38
A factory class used to instantiate instances of Insertables.
Message validator is used to run validators to find common mistakes so that translators can fix them ...
Core message collection class.
setTags( $type, array $keys)
Set message tags.
This class implements some basic functions that wrap around the YAML message group configurations.
getTranslatableLanguages()
@inheritDoc
getDefinitions()
Shortcut for load( getSourceLanguage() ).
getDescription(IContextSource $context=null)
Returns a longer description about the group.
getTags( $type=null)
Returns message tags.
getSourceLanguage()
Returns language code depicting the language of source text.
getNamespace()
Returns the namespace where messages are placed.
getSupportConfig()
Gets support URL defined for the group if any.
getLabel(IContextSource $context=null)
Returns the human readable label (as plain text).
getMessageGroupStates()
Get the message group workflow state configuration.
getMangler()
Return a message mangler or null.
getId()
Returns the unique identifier for this group.
getInsertablesSuggester()
Returns the configured InsertablesSuggester if any.
getValidator()
Returns a message validator object or null.
static factory( $conf)
getIcon()
Returns an icon for this message group if any.
Class for making the use of message group state easier.
Interface for message groups.
load( $code)
Returns a list of messages in a given language code.