Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 153
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
DisplayGroupSynchronizationInfo
0.00% covered (danger)
0.00%
0 / 153
0.00% covered (danger)
0.00%
0 / 9
462
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupsInSyncHtml
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 getHtmlForGroupsWithError
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 addGroupSyncHelp
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupSyncInfoHtml
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getHtmlForGroupErrors
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
6
 getErrorMessageHtml
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
6
 getMessageInfoHtml
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
42
 getMessagePropHtml
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Synchronization;
5
6use Language;
7use MediaWiki\Html\Html;
8use MediaWiki\Linker\LinkRenderer;
9use MediaWiki\Title\Title;
10use MessageLocalizer;
11
12/**
13 * Display Group synchronization related information
14 * @author Abijeet Patro
15 * @license GPL-2.0-or-later
16 * @since 2021.02
17 */
18class DisplayGroupSynchronizationInfo {
19    /** @var MessageLocalizer */
20    private $localizer;
21    /** @var LinkRenderer */
22    private $linkRenderer;
23
24    public function __construct( MessageLocalizer $localizer, LinkRenderer $linkRenderer ) {
25        $this->localizer = $localizer;
26        $this->linkRenderer = $linkRenderer;
27    }
28
29    /** @param string[] $groupsInSync */
30    public function getGroupsInSyncHtml( array $groupsInSync, string $wrapperClass ): string {
31        sort( $groupsInSync );
32
33        if ( !$groupsInSync ) {
34            return Html::rawElement(
35                'p',
36                [ 'class' => $wrapperClass ],
37                $this->localizer->msg( 'translate-smg-no-groups-in-sync' )->escaped()
38                    . $this->addGroupSyncHelp( $wrapperClass )
39            );
40        }
41
42        $htmlGroupItems = [];
43        foreach ( $groupsInSync as $groupId ) {
44            $htmlGroupItems[] = Html::element( 'li', [], $groupId );
45        }
46
47        return $this->getGroupSyncInfoHtml(
48            $wrapperClass,
49            'translate-smg-groups-in-sync',
50            'translate-smg-groups-in-sync-list',
51            Html::rawElement( 'ul', [], implode( '', $htmlGroupItems ) ),
52            $this->addGroupSyncHelp( $wrapperClass )
53        );
54    }
55
56    public function getHtmlForGroupsWithError(
57        GroupSynchronizationCache $groupSynchronizationCache,
58        string $wrapperClass,
59        Language $currentLang
60    ): string {
61        $groupsWithErrors = $groupSynchronizationCache->getGroupsWithErrors();
62        if ( !$groupsWithErrors ) {
63            return '';
64        }
65
66        $htmlGroupItems = [];
67        foreach ( $groupsWithErrors as $groupId ) {
68            $groupErrorResponse = $groupSynchronizationCache->getGroupErrorInfo( $groupId );
69            $htmlGroupItems[] = $this->getHtmlForGroupErrors( $groupErrorResponse, $currentLang, $wrapperClass );
70        }
71
72        return $this->getGroupSyncInfoHtml(
73            $wrapperClass . ' js-group-sync-groups-with-error',
74            'translate-smg-groups-with-error-title',
75            'translate-smg-groups-with-error-desc',
76            implode( '', $htmlGroupItems )
77        );
78    }
79
80    private function addGroupSyncHelp( string $wrapperClass ): string {
81        return Html::element(
82            'a',
83            [
84                'href' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Extension:Translate/' .
85                    'Group_management#Strong_synchronization',
86                'target' => '_blank',
87                'class' => "{$wrapperClass}__help",
88            ],
89            '[' . $this->localizer->msg( 'translate-smg-strong-sync-help' )->text() . ']'
90        );
91    }
92
93    private function getGroupSyncInfoHtml(
94        string $className,
95        string $summaryMsgKey,
96        string $descriptionMsgKey,
97        string $htmlContent,
98        string $preHtmlContent = null
99    ): string {
100        $output = Html::openElement( 'div', [ 'class' => $className ] );
101        if ( $preHtmlContent ) {
102            $output .= $preHtmlContent;
103        }
104
105        $output .= Html::openElement( 'details' );
106        $output .= Html::element( 'summary', [], $this->localizer->msg( $summaryMsgKey )->text() );
107        $output .= Html::element( 'p', [], $this->localizer->msg( $descriptionMsgKey )->text() );
108        $output .= $htmlContent;
109        $output .= Html::closeElement( 'details' );
110        $output .= Html::closeElement( 'div' );
111
112        return $output;
113    }
114
115    private function getHtmlForGroupErrors(
116        GroupSynchronizationResponse $groupErrorResponse,
117        Language $language,
118        string $wrapperClass
119    ): string {
120        $groupId = $groupErrorResponse->getGroupId();
121        $output = Html::openElement(
122            'details',
123            [ 'class' => "{$wrapperClass}__group_errors js-group-sync-group-errors" ]
124        );
125
126        $groupResolveAction = Html::linkButton(
127            $this->localizer->msg( 'translate-smg-group-action-resolve' )->text(),
128            [
129                'class' => "{$wrapperClass}__resolve-action js-group-sync-group-resolve",
130                'href' => '#',
131                'data-group-id' => $groupId,
132            ]
133        );
134
135        $output .= Html::rawElement(
136            'summary',
137            [],
138            $groupId . ' ' .
139            Html::rawElement(
140                'span',
141                [ 'class' => "{$wrapperClass}__sync-actions" ],
142                $this->localizer->msg( 'parentheses' )
143                    ->rawParams( $groupResolveAction )->escaped()
144
145            )
146        );
147
148        $errorMessages = $groupErrorResponse->getRemainingMessages();
149
150        $output .= Html::openElement( 'ol' );
151        foreach ( $errorMessages as $message ) {
152            $output .= Html::rawElement(
153                'li',
154                [ 'class' => "{$wrapperClass}__message-error js-group-sync-message-error" ],
155                $this->getErrorMessageHtml( $groupId, $message, $language, $wrapperClass )
156            );
157        }
158        $output .= Html::closeElement( 'ol' );
159
160        $output .= Html::closeElement( 'details' );
161
162        return $output;
163    }
164
165    private function getErrorMessageHtml(
166        string $groupId,
167        MessageUpdateParameter $message,
168        Language $language,
169        string $wrapperClass
170    ): string {
171        $messageTitle = Title::newFromText( $message->getPageName() );
172        $actions = [];
173        if ( $messageTitle->exists() ) {
174            $output = $this->linkRenderer->makeLink( $messageTitle, $message->getPageName() );
175            $actions[] = $this->linkRenderer->makeLink(
176                $messageTitle,
177                $this->localizer->msg( 'translate-smg-group-message-action-history' )->text(),
178                [],
179                [ 'action' => 'history' ]
180            );
181        } else {
182            $output = $this->linkRenderer->makeBrokenLink( $messageTitle, $message->getPageName() );
183        }
184
185        $actions[] = Html::linkButton(
186            $this->localizer->msg( 'translate-smg-group-action-resolve' )->text(),
187            [
188                'class' => "{$wrapperClass}__resolve-action js-group-sync-message-resolve",
189                'href' => '#',
190                'data-group-id' => $groupId,
191                'data-msg-title' => $message->getPageName(),
192            ]
193        );
194
195        $output .= ' ' . Html::rawElement(
196            'span',
197            [ 'class' => "{$wrapperClass}__sync-actions" ],
198            $this->localizer->msg( 'parentheses' )
199                ->rawParams( $language->pipeList( $actions ) )->escaped()
200        );
201
202        $output .= $this->getMessageInfoHtml( $message, $language );
203
204        return $output;
205    }
206
207    private function getMessageInfoHtml( MessageUpdateParameter $message, Language $language ): string {
208        $output = Html::openElement( 'dl' );
209
210        $tags = [];
211        if ( $message->isFuzzy() ) {
212            $tags[] = $this->localizer->msg( 'translate-smg-group-message-tag-outdated' )->text();
213        }
214
215        if ( $message->isRename() ) {
216            $tags[] = $this->localizer->msg( 'translate-smg-group-message-tag-rename' )->text();
217        }
218
219        if ( $tags ) {
220            $output .= $this->getMessagePropHtml(
221                $this->localizer->msg( 'translate-smg-group-message-tag-label' )
222                    ->numParams( count( $tags ) )->text(),
223                implode( $this->localizer->msg( 'pipe-separator' )->text(), $tags )
224            );
225        }
226
227        $output .= $this->getMessagePropHtml(
228            $this->localizer->msg( 'translate-smg-group-message-message-content' )->text(),
229            $message->getContent()
230        );
231
232        if ( $message->isRename() ) {
233            $output .= $this->getMessagePropHtml(
234                $this->localizer->msg( 'translate-smg-group-message-message-target' )->text(),
235                $message->getTargetValue()
236            );
237
238            $output .= $this->getMessagePropHtml(
239                $this->localizer->msg( 'translate-smg-group-message-message-replacement' )->text(),
240                $message->getReplacementValue()
241            );
242
243            $otherLangs = $message->getOtherLangs();
244            if ( $otherLangs ) {
245                $output .= $this->getMessagePropHtml(
246                    $this->localizer->msg( 'translate-smg-group-message-message-other-langs' )->text(),
247                    implode(
248                        $this->localizer->msg( 'comma-separator' )->text(),
249                        array_keys( $otherLangs )
250                    )
251                );
252            }
253        }
254
255        $output .= Html::closeElement( 'dl' );
256        return $output;
257    }
258
259    private function getMessagePropHtml( string $label, string $value ): string {
260        return Html::element( 'dt', [], $label ) . Html::element( 'dd', [], $value );
261    }
262}