Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MessageGroupConfigurationParser.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\MessageGroupConfiguration;
5
7use Exception;
9use RomaricDrigon\MetaYaml\MetaYaml;
11
18 private $baseSchema;
19
20 public function __construct() {
21 // Don't perform validations if library not available
22 if ( class_exists( MetaYaml::class ) ) {
23 $this->baseSchema = $this->getBaseSchema();
24 }
25 }
26
36 public function getHopefullyValidConfigurations( string $data, ?callable $callback = null ): array {
37 if ( !is_callable( $callback ) ) {
38 $callback = static function ( $unused1, $unused2, $unused3 ) {
39 /*noop*/
40 };
41 }
42
43 $documents = self::getDocumentsFromYaml( $data );
44 $configurations = self::parseDocuments( $documents );
45 $groups = [];
46
47 if ( is_array( $this->baseSchema ) ) {
48 foreach ( $configurations as $index => $config ) {
49 try {
50 $this->validate( $config );
51 $groups[$config['BASIC']['id']] = $config;
52 } catch ( Exception $e ) {
53 $callback( $index, $config, $e->getMessage() );
54 }
55 }
56 } else {
57 foreach ( $configurations as $index => $config ) {
58 if ( isset( $config['BASIC']['id'] ) ) {
59 $groups[$config['BASIC']['id']] = $config;
60 } else {
61 $callback( $index, $config, 'id is missing' );
62 }
63 }
64 }
65
66 return $groups;
67 }
68
73 public function getDocumentsFromYaml( string $data ): array {
74 return preg_split( "/^---$/m", $data, -1, PREG_SPLIT_NO_EMPTY );
75 }
76
83 public function parseDocuments( array $documents ): array {
84 $groups = [];
85 $template = [];
86
87 foreach ( $documents as $document ) {
88 $document = TranslateYaml::loadString( $document );
89
90 if ( isset( $document['TEMPLATE'] ) ) {
91 $template = $document['TEMPLATE'];
92 } else {
93 $groups[] = $document;
94 }
95 }
96
97 if ( $template ) {
98 foreach ( $groups as $i => $group ) {
99 $groups[$i] = self::mergeTemplate( $template, $group );
100 // Little hack to allow aggregate groups to be defined in same file with other groups.
101 if ( $groups[$i]['BASIC']['class'] === AggregateMessageGroup::class ) {
102 unset( $groups[$i]['FILES'] );
103 }
104 }
105 }
106
107 return $groups;
108 }
109
110 public function getBaseSchema(): array {
111 return TranslateYaml::load( __DIR__ . '/../../data/group-yaml-schema.yaml' );
112 }
113
118 public function validate( array $config ): void {
119 $schema = $this->baseSchema;
120
121 foreach ( $config as $section ) {
122 if ( !isset( $section['class'] ) ) {
123 continue;
124 }
125
126 $class = $section['class'];
127
128 // FIXME: UGLY HACK: StringMatcher is now under a namespace so use the fully prefixed
129 // class to check if it has the getExtraSchema method
130 if ( $class === 'StringMatcher' ) {
131 $class = StringMatcher::class;
132 }
133
134 // There is no sane way to check whether *class* implements interface in PHP
135 if ( !is_callable( [ $class, 'getExtraSchema' ] ) ) {
136 continue;
137 }
138
139 $extra = call_user_func( [ $class, 'getExtraSchema' ] );
140 $schema = array_replace_recursive( $schema, $extra );
141 }
142
143 $schema = new MetaYaml( $schema );
144 $schema->validate( $config );
145 }
146
148 public static function mergeTemplate( array $base, array $specific ): array {
149 foreach ( $specific as $key => $value ) {
150 if ( is_array( $value ) && isset( $base[$key] ) && is_array( $base[$key] ) ) {
151 $base[$key] = self::mergeTemplate( $base[$key], $value );
152 } else {
153 $base[$key] = $value;
154 }
155 }
156
157 return $base;
158 }
159}
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'), $services->get( 'Translate:MessageIndex'));}, '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:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getDBLoadBalancer(), $services->getLinkRenderer(), $services->getMainConfig() ->get( 'TranslateWorkflowStates') !==false);}, '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:MessagePrefixStats'=> static function(MediaWikiServices $services):MessagePrefixStats { return new MessagePrefixStats( $services->getTitleParser());}, '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:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getDBLoadBalancer() ->getConnection(DB_PRIMARY), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, '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(), $services->get( 'Translate:TranslatableBundleStatusStore'));}, '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
Groups multiple message groups together as one group.
getDocumentsFromYaml(string $data)
Given a Yaml string, returns the non-empty documents as an array.
static mergeTemplate(array $base, array $specific)
Merges a document template (base) to actual definition (specific)
getHopefullyValidConfigurations(string $data, ?callable $callback=null)
Easy to use function to get valid group configurations from YAML.
The versatile default implementation of StringMangler interface.
This class is a wrapper class to provide interface to parse and generate YAML files with phpyaml or s...