Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 24
CRAP
0.00% covered (danger)
0.00%
0 / 1
MessageBundleMessageGroup
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 24
1190
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBundlePageId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getData
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 makeGroupKeys
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLabel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getIcon
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getNamespace
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isMeta
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 exists
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getValidator
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMangler
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 initCollection
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 load
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefinitions
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getKeys
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMessage
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getSourceLanguage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMessageGroupStates
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getTranslatableLanguages
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSupportConfig
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare( strict_types = 1 );
4
5namespace MediaWiki\Extension\Translate\MessageBundleTranslation;
6
7use IContextSource;
8use LogicException;
9use MediaWiki\Extension\Translate\MessageGroupProcessing\MessageGroupStates;
10use MediaWiki\Extension\Translate\MessageLoading\MessageCollection;
11use MediaWiki\Extension\Translate\MessageLoading\MessageDefinitions;
12use MediaWiki\Extension\Translate\MessageProcessing\StringMatcher;
13use MediaWiki\Extension\Translate\Services;
14use MediaWiki\Extension\Translate\Validation\ValidationRunner;
15use MediaWiki\MediaWikiServices;
16use MediaWiki\Revision\SlotRecord;
17use MediaWiki\Title\Title;
18use MessageGroup;
19use const NS_TRANSLATIONS;
20
21/**
22 * @author Niklas Laxström
23 * @license GPL-2.0-or-later
24 * @since 2021.12
25 */
26class MessageBundleMessageGroup implements MessageGroup {
27    /** Name of the bundle (prefixed text of the bundle page) */
28    private string $name;
29    private string $groupId;
30    private int $pageId;
31    private int $revisionId;
32    private ?array $data = null;
33    private ?string $description;
34    private ?string $label;
35
36    public function __construct(
37        string $groupId,
38        string $name,
39        int $pageId,
40        int $revisionId,
41        ?string $description,
42        ?string $label
43    ) {
44        $this->groupId = $groupId;
45        $this->name = $name;
46        $this->pageId = $pageId;
47        $this->revisionId = $revisionId;
48        $this->description = $description;
49        $this->label = $label;
50    }
51
52    /** Suggested default naming pattern */
53    public static function getGroupId( string $name ): string {
54        return "messagebundle-$name";
55    }
56
57    public function getBundlePageId(): int {
58        return $this->pageId;
59    }
60
61    private function getData(): array {
62        if ( isset( $this->data ) ) {
63            return $this->data;
64        }
65
66        $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
67        $revision = $revisionStore->getRevisionById( $this->revisionId );
68
69        if ( $revision === null ) {
70            throw new LogicException( "Could not find revision id $this->revisionId" );
71        }
72
73        $content = $revision->getContent( SlotRecord::MAIN );
74        if ( !$content instanceof MessageBundleContent ) {
75            throw new LogicException(
76                "Content with revision id $this->revisionId has wrong content format"
77            );
78        }
79
80        $data = json_decode( $content->getText(), true );
81        if ( !$data ) {
82            throw new LogicException(
83                "Content with revision id $this->revisionId is not valid JSON"
84            );
85        }
86
87        $this->data = $data;
88        return $this->data;
89    }
90
91    private function makeGroupKeys( array $keys ): array {
92        $result = [];
93        foreach ( $keys as $key ) {
94            $result[] = str_replace( ' ', '_', "$this->name/$key" );
95        }
96        return $result;
97    }
98
99    /** @inheritDoc */
100    public function getId(): string {
101        return $this->groupId;
102    }
103
104    /** @inheritDoc */
105    public function getLabel( IContextSource $context = null ): string {
106        return $this->label ?? $this->name;
107    }
108
109    /** @inheritDoc */
110    public function getDescription( IContextSource $context = null ): string {
111        $titleText = Title::newFromID( $this->pageId )->getPrefixedText();
112        $linkTargetText = ":$titleText";
113        if ( $context ) {
114            $message = $context->msg( 'translate-messagebundle-group-description' );
115        } else {
116            $message = wfMessage( 'translate-messagebundle-group-description' )
117                ->inContentLanguage();
118        }
119
120        $plainMessage = $message->params( $titleText, $linkTargetText )->plain();
121
122        if ( $this->description === null ) {
123            return $plainMessage;
124        }
125
126        return $plainMessage . ' ' . $this->description;
127    }
128
129    /** @inheritDoc */
130    public function getIcon(): ?string {
131        return null;
132    }
133
134    /** @inheritDoc */
135    public function getNamespace(): int {
136        return NS_TRANSLATIONS;
137    }
138
139    /** @inheritDoc */
140    public function isMeta(): bool {
141        return false;
142    }
143
144    /** @inheritDoc */
145    public function exists(): bool {
146        return true;
147    }
148
149    /** @inheritDoc */
150    public function getValidator(): ?ValidationRunner {
151        return null;
152    }
153
154    /** @inheritDoc */
155    public function getMangler(): ?StringMatcher {
156        return null;
157    }
158
159    /** @inheritDoc */
160    public function initCollection( $code ): MessageCollection {
161        $defs = new MessageDefinitions( $this->getDefinitions(), $this->getNamespace() );
162        $collection = MessageCollection::newFromDefinitions( $defs, $code );
163
164        foreach ( $this->getTags() as $type => $tags ) {
165            $collection->setTags( $type, $tags );
166        }
167
168        return $collection;
169    }
170
171    /** @inheritDoc */
172    public function load( $code ): array {
173        return [];
174    }
175
176    /** @inheritDoc */
177    public function getDefinitions(): array {
178        $data = $this->getData();
179        unset( $data['@metadata'] );
180
181        return array_combine(
182            $this->makeGroupKeys( array_keys( $data ) ),
183            array_values( $data )
184        );
185    }
186
187    /** @inheritDoc */
188    public function getKeys(): array {
189        return array_keys( $this->getDefinitions() );
190    }
191
192    /** @inheritDoc */
193    public function getTags( $type = null ): array {
194        return [];
195    }
196
197    /** @inheritDoc */
198    public function getMessage( $key, $code ): ?string {
199        if ( $code === $this->getSourceLanguage() ) {
200            return $this->getDefinitions()[$key] ?? null;
201        }
202
203        return null;
204    }
205
206    /** @inheritDoc */
207    public function getSourceLanguage(): string {
208        return Title::newFromText( $this->name )->getPageLanguage()->getCode();
209    }
210
211    /** @inheritDoc */
212    public function getMessageGroupStates(): MessageGroupStates {
213        global $wgTranslateWorkflowStates;
214        $conf = $wgTranslateWorkflowStates ?: [];
215
216        Services::getInstance()->getHookRunner()
217            ->onTranslate_modifyMessageGroupStates( $this->getId(), $conf );
218
219        return new MessageGroupStates( $conf );
220    }
221
222    /** @inheritDoc */
223    public function getTranslatableLanguages(): ?array {
224        return null;
225    }
226
227    /** @inheritDoc */
228    public function getSupportConfig(): ?array {
229        return null;
230    }
231}