Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 182 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
TranslatePage | |
0.00% |
0 / 182 |
|
0.00% |
0 / 5 |
552 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 114 |
|
0.00% |
0 / 1 |
272 | |||
getTitle | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
showLanguageSelector | |
0.00% |
0 / 47 |
|
0.00% |
0 / 1 |
6 | |||
doSubmit | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\SecurePoll\Pages; |
4 | |
5 | use MediaWiki\Extension\SecurePoll\Exceptions\InvalidDataException; |
6 | use MediaWiki\Extension\SecurePoll\SpecialSecurePoll; |
7 | use MediaWiki\Extension\SecurePoll\TranslationRepo; |
8 | use MediaWiki\Languages\LanguageNameUtils; |
9 | use MediaWiki\Linker\Linker; |
10 | use MediaWiki\MediaWikiServices; |
11 | use MediaWiki\Message\Message; |
12 | use MediaWiki\Title\Title; |
13 | use MediaWiki\WikiMap\WikiMap; |
14 | use OOUI\ButtonInputWidget; |
15 | use OOUI\DropdownInputWidget; |
16 | use OOUI\Element; |
17 | use OOUI\FieldLayout; |
18 | use OOUI\FieldsetLayout; |
19 | use OOUI\FormLayout; |
20 | use OOUI\HorizontalLayout; |
21 | use OOUI\HtmlSnippet; |
22 | use OOUI\LabelWidget; |
23 | use OOUI\MultilineTextInputWidget; |
24 | use OOUI\Tag; |
25 | use OOUI\TextInputWidget; |
26 | |
27 | /** |
28 | * A SecurePoll subpage for translating election messages. |
29 | */ |
30 | class TranslatePage extends ActionPage { |
31 | |
32 | /** @var bool|null */ |
33 | public $isAdmin; |
34 | |
35 | /** @var LanguageNameUtils */ |
36 | private $languageNameUtils; |
37 | |
38 | /** @var TranslationRepo */ |
39 | private $translationRepo; |
40 | |
41 | /** |
42 | * @param SpecialSecurePoll $specialPage |
43 | * @param LanguageNameUtils $languageNameUtils |
44 | * @param TranslationRepo $translationRepo |
45 | */ |
46 | public function __construct( |
47 | SpecialSecurePoll $specialPage, |
48 | LanguageNameUtils $languageNameUtils, |
49 | TranslationRepo $translationRepo |
50 | ) { |
51 | parent::__construct( $specialPage ); |
52 | $this->languageNameUtils = $languageNameUtils; |
53 | $this->translationRepo = $translationRepo; |
54 | } |
55 | |
56 | /** |
57 | * Execute the subpage. |
58 | * @param array $params Array of subpage parameters. |
59 | */ |
60 | public function execute( $params ) { |
61 | $out = $this->specialPage->getOutput(); |
62 | $request = $this->specialPage->getRequest(); |
63 | $out->enableOOUI(); |
64 | |
65 | if ( !count( $params ) ) { |
66 | $out->addWikiMsg( 'securepoll-too-few-params' ); |
67 | |
68 | return; |
69 | } |
70 | |
71 | $electionId = intval( $params[0] ); |
72 | $this->election = $this->context->getElection( $electionId ); |
73 | if ( !$this->election ) { |
74 | $out->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
75 | |
76 | return; |
77 | } |
78 | $this->initLanguage( $this->specialPage->getUser(), $this->election ); |
79 | $out->setPageTitleMsg( $this->msg( 'securepoll-translate-title', $this->election->getMessage( 'title' ) ) ); |
80 | |
81 | $jumpUrl = $this->election->getProperty( 'jump-url' ); |
82 | if ( $jumpUrl ) { |
83 | $jumpId = $this->election->getProperty( 'jump-id' ); |
84 | if ( !$jumpId ) { |
85 | throw new InvalidDataException( 'Configuration error: no jump-id' ); |
86 | } |
87 | $jumpUrl .= "/edit/$jumpId"; |
88 | if ( count( $params ) > 1 ) { |
89 | $jumpUrl .= '/' . implode( '/', array_slice( $params, 1 ) ); |
90 | } |
91 | |
92 | $wiki = $this->election->getProperty( 'main-wiki' ); |
93 | if ( $wiki ) { |
94 | $wiki = WikiMap::getWikiName( $wiki ); |
95 | } else { |
96 | $wiki = $this->msg( 'securepoll-edit-redirect-otherwiki' )->text(); |
97 | } |
98 | |
99 | $out->addWikiMsg( |
100 | 'securepoll-edit-redirect', |
101 | Message::rawParam( Linker::makeExternalLink( $jumpUrl, $wiki ) ) |
102 | ); |
103 | |
104 | return; |
105 | } |
106 | |
107 | $this->isAdmin = $this->election->isAdmin( $this->specialPage->getUser() ); |
108 | |
109 | $primary = $this->election->getLanguage(); |
110 | $secondary = $request->getVal( 'secondary_lang' ); |
111 | if ( $secondary !== null ) { |
112 | # Language selector submitted: redirect to the subpage |
113 | $out->redirect( $this->getTitle( $secondary )->getFullURL() ); |
114 | |
115 | return; |
116 | } |
117 | |
118 | if ( !isset( $params[1] ) ) { |
119 | # No language selected, show the selector |
120 | $this->showLanguageSelector( $primary ); |
121 | $sourceConfig = MediaWikiServices::getInstance()->getMainConfig() |
122 | ->get( 'SecurePollTranslationImportSourceUrl' ); |
123 | $out->addJsConfigVars( 'SecurePollTranslationImportSourceUrl', $sourceConfig ); |
124 | |
125 | $out->addJsConfigVars( 'SecurePollSubPage', 'translate' ); |
126 | $out->addModules( 'ext.securepoll.htmlform' ); |
127 | return; |
128 | } |
129 | |
130 | $secondary = $params[1]; |
131 | $inLanguage = $this->specialPage->getLanguage()->getCode(); |
132 | $primaryName = $this->languageNameUtils->getLanguageName( $primary, $inLanguage ); |
133 | $secondaryName = $this->languageNameUtils->getLanguageName( $secondary, $inLanguage ); |
134 | if ( $secondaryName === '' ) { |
135 | $out->addWikiMsg( 'securepoll-invalid-language', $secondary ); |
136 | $this->showLanguageSelector( $primary ); |
137 | return; |
138 | } |
139 | |
140 | # Set a subtitle to return to the language selector |
141 | $this->specialPage->setSubtitle( |
142 | [ |
143 | $this->getTitle(), |
144 | $this->msg( |
145 | 'securepoll-translate-title', |
146 | $this->election->getMessage( 'title' ) |
147 | )->text() |
148 | ] |
149 | ); |
150 | |
151 | # If the request was posted, do the submission |
152 | if ( $request->wasPosted() && $request->getVal( 'action' ) == 'submit' ) { |
153 | $this->doSubmit( $secondary ); |
154 | return; |
155 | } |
156 | |
157 | # Show the form |
158 | $action = $this->getTitle( $secondary )->getLocalURL( 'action=submit' ); |
159 | $form = new FormLayout( [ 'method' => 'post', 'action' => $action ] ); |
160 | |
161 | $table = new Tag( 'table' ); |
162 | $table->addClasses( [ 'mw-datatable', 'TablePager', 'securepoll-trans-table' ] )->appendContent( |
163 | ( new Tag( 'thead' ) )->appendContent( ( new Tag( 'tr' ) )->appendContent( |
164 | ( new Tag( 'th' ) )->appendContent( $this->msg( 'securepoll-header-trans-id' ) ), |
165 | ( new Tag( 'th' ) )->appendContent( $primaryName ), |
166 | ( new Tag( 'th' ) )->appendContent( $secondaryName ) |
167 | ) ) |
168 | ); |
169 | $tbody = new Tag( 'tbody' ); |
170 | $table->appendContent( $tbody ); |
171 | |
172 | $entities = array_merge( [ $this->election ], $this->election->getDescendants() ); |
173 | foreach ( $entities as $entity ) { |
174 | $entityName = $entity->getType() . '(' . $entity->getId() . ')'; |
175 | foreach ( $entity->getMessageNames() as $messageName ) { |
176 | $tbody->appendContent( ( new Tag( 'tr' ) )->appendContent( |
177 | ( new Tag( 'td' ) )->addClasses( [ 'trans-id' ] ) |
178 | ->appendContent( "$entityName/$messageName" ), |
179 | ( new Tag( 'td' ) )->addClasses( [ 'trans-origin' ] )->appendContent( new HtmlSnippet( |
180 | nl2br( htmlspecialchars( $entity->getRawMessage( $messageName, $primary ) ) ) |
181 | ) ), |
182 | ( new Tag( 'td' ) )->addClasses( [ 'trans-lang' ] )->appendContent( |
183 | new MultilineTextInputWidget( [ |
184 | 'name' => 'trans_' . $entity->getId() . '_' . $messageName, |
185 | 'value' => $entity->getRawMessage( $messageName, $secondary ), |
186 | 'classes' => [ 'securepoll-translate-box' ], |
187 | 'readonly' => !$this->isAdmin, |
188 | 'autosize' => true |
189 | ] ) |
190 | ) ) |
191 | ); |
192 | } |
193 | } |
194 | |
195 | $fields = new FieldsetLayout(); |
196 | |
197 | $fields->addItems( [ new Element( [ 'content' => [ $table ] ] ) ] ); |
198 | |
199 | if ( $this->isAdmin && $this->specialPage->getConfig()->get( 'SecurePollUseNamespace' ) ) { |
200 | $fields->addItems( [ new FieldLayout( new TextInputWidget( [ |
201 | 'name' => 'comment', |
202 | 'maxlength' => 250, |
203 | ] ), [ |
204 | 'label' => $this->msg( 'securepoll-translate-label-comment' ), |
205 | 'align' => 'top', |
206 | ] ) ] ); |
207 | } |
208 | |
209 | $fields->addItems( [ new FieldLayout( new ButtonInputWidget( [ |
210 | 'label' => $this->msg( 'securepoll-submit-translate' )->text(), |
211 | 'flags' => [ 'primary', 'progressive' ], |
212 | 'type' => 'submit', |
213 | 'disabled' => !$this->isAdmin, |
214 | ] ) ) ] ); |
215 | |
216 | $form->appendContent( $fields ); |
217 | |
218 | $out->addHTML( $form ); |
219 | } |
220 | |
221 | /** |
222 | * @param string|false $lang |
223 | * @return Title |
224 | */ |
225 | public function getTitle( $lang = false ) { |
226 | $subpage = 'translate/' . $this->election->getId(); |
227 | if ( $lang !== false ) { |
228 | $subpage .= '/' . $lang; |
229 | } |
230 | |
231 | return $this->specialPage->getPageTitle( $subpage ); |
232 | } |
233 | |
234 | /** |
235 | * Show a language selector to allow the user to choose the language to |
236 | * translate. |
237 | * @param string $selectedCode |
238 | */ |
239 | public function showLanguageSelector( $selectedCode ) { |
240 | $languages = $this->languageNameUtils->getLanguageNames(); |
241 | ksort( $languages ); |
242 | |
243 | $apiEndpoint = $this->specialPage->getConfig()->get( 'SecurePollTranslationImportSourceUrl' ); |
244 | |
245 | $form = new FormLayout( [ |
246 | 'action' => $this->getTitle( false )->getLocalURL(), |
247 | 'method' => 'get', |
248 | 'items' => [ new FieldsetLayout( [ 'items' => [ |
249 | new HorizontalLayout( [ |
250 | 'id' => 'sp-translation-selection', |
251 | 'items' => [ |
252 | new DropdownInputWidget( [ |
253 | 'name' => 'secondary_lang', |
254 | 'value' => $selectedCode, |
255 | 'options' => array_map( static function ( $code, $name ) { |
256 | return [ |
257 | 'label' => "$code - $name", |
258 | 'data' => $code, |
259 | ]; |
260 | }, array_keys( $languages ), $languages ) |
261 | ] ), |
262 | new ButtonInputWidget( [ |
263 | 'label' => $this->msg( 'securepoll-submit-select-lang' )->text(), |
264 | 'flags' => [ 'primary' ], |
265 | 'type' => 'submit', |
266 | ] ) |
267 | ] |
268 | ] ) |
269 | ] ] ) ] |
270 | ] ); |
271 | |
272 | if ( $apiEndpoint !== '' ) { |
273 | $form->addItems( [ |
274 | new FieldLayout( |
275 | new LabelWidget( [ |
276 | 'label' => $this->msg( 'securepoll-subpage-translate-info', $apiEndpoint )->text() |
277 | ] ) |
278 | ), |
279 | new FieldLayout( |
280 | new ButtonInputWidget( [ |
281 | 'id' => 'import-trans-btn', |
282 | 'infusable' => true, |
283 | 'label' => $this->msg( 'securepoll-translate-import-button-label' )->text(), |
284 | 'flags' => [ 'primary', 'progressive' ], |
285 | 'disabled' => !$this->isAdmin |
286 | ] ) |
287 | ) |
288 | ], 0 ); |
289 | } |
290 | $this->specialPage->getOutput()->addHTML( $form ); |
291 | } |
292 | |
293 | /** |
294 | * Submit message text changes. |
295 | * @param string $secondary |
296 | */ |
297 | public function doSubmit( $secondary ) { |
298 | $out = $this->specialPage->getOutput(); |
299 | |
300 | if ( !$this->isAdmin ) { |
301 | $out->addWikiMsg( 'securepoll-need-admin' ); |
302 | return; |
303 | } |
304 | |
305 | $request = $this->specialPage->getRequest(); |
306 | $data = $request->getValues(); |
307 | |
308 | $this->translationRepo->setTranslation( |
309 | $this->election, |
310 | $data, |
311 | $secondary, |
312 | $this->specialPage->getContext()->getUser(), |
313 | $this->specialPage->getContext()->getRequest()->getText( 'comment' ) |
314 | ); |
315 | |
316 | $out->redirect( $this->getTitle( $secondary )->getFullURL() ); |
317 | } |
318 | } |