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