ef034fb4d4b7e3e38c273990968a08a0922d3851
[lhc/web/wiklou.git] / includes / specials / SpecialPageLanguage.php
1 <?php
2 /**
3 * Implements Special:PageLanguage
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup SpecialPage
22 * @author Kunal Grover
23 * @since 1.24
24 */
25
26 /**
27 * Special page for changing the content language of a page
28 *
29 * @ingroup SpecialPage
30 */
31 class SpecialPageLanguage extends FormSpecialPage {
32 /**
33 * @var string URL to go to if language change successful
34 */
35 private $goToUrl;
36
37 public function __construct() {
38 parent::__construct( 'PageLanguage', 'pagelang' );
39 }
40
41 public function doesWrites() {
42 return true;
43 }
44
45 protected function preText() {
46 $this->getOutput()->addModules( 'mediawiki.special.pageLanguage' );
47 }
48
49 protected function getFormFields() {
50 // Get default from the subpage of Special page
51 $defaultName = $this->par;
52
53 $page = [];
54 $page['pagename'] = [
55 'type' => 'title',
56 'label-message' => 'pagelang-name',
57 'default' => $defaultName,
58 'autofocus' => $defaultName === null,
59 'exists' => true,
60 ];
61
62 // Options for whether to use the default language or select language
63 $selectoptions = [
64 (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
65 (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
66 ];
67 $page['selectoptions'] = [
68 'id' => 'mw-pl-options',
69 'type' => 'radio',
70 'options' => $selectoptions,
71 'default' => 1
72 ];
73
74 // Building a language selector
75 $userLang = $this->getLanguage()->getCode();
76 $languages = Language::fetchLanguageNames( $userLang, 'mwfile' );
77 ksort( $languages );
78 $options = [];
79 foreach ( $languages as $code => $name ) {
80 $options["$code - $name"] = $code;
81 }
82
83 $page['language'] = [
84 'id' => 'mw-pl-languageselector',
85 'cssclass' => 'mw-languageselector',
86 'type' => 'select',
87 'options' => $options,
88 'label-message' => 'pagelang-language',
89 'default' => $this->getConfig()->get( 'LanguageCode' ),
90 ];
91
92 // Allow user to enter a comment explaining the change
93 $page['reason'] = [
94 'type' => 'text',
95 'label-message' => 'pagelang-reason'
96 ];
97
98 return $page;
99 }
100
101 protected function postText() {
102 if ( $this->par ) {
103 return $this->showLogFragment( $this->par );
104 }
105 return '';
106 }
107
108 protected function getDisplayFormat() {
109 return 'ooui';
110 }
111
112 public function alterForm( HTMLForm $form ) {
113 Hooks::run( 'LanguageSelector', [ $this->getOutput(), 'mw-languageselector' ] );
114 $form->setSubmitTextMsg( 'pagelang-submit' );
115 }
116
117 /**
118 *
119 * @param array $data
120 * @return Status
121 */
122 public function onSubmit( array $data ) {
123 $pageName = $data['pagename'];
124
125 // Check if user wants to use default language
126 if ( $data['selectoptions'] == 1 ) {
127 $newLanguage = 'default';
128 } else {
129 $newLanguage = $data['language'];
130 }
131
132 try {
133 $title = Title::newFromTextThrow( $pageName );
134 } catch ( MalformedTitleException $ex ) {
135 return Status::newFatal( $ex->getMessageObject() );
136 }
137
138 // Check permissions and make sure the user has permission to edit the page
139 $errors = $title->getUserPermissionsErrors( 'edit', $this->getUser() );
140
141 if ( $errors ) {
142 $out = $this->getOutput();
143 $wikitext = $out->formatPermissionsErrorMessage( $errors );
144 // Hack to get our wikitext parsed
145 return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
146 }
147
148 // Url to redirect to after the operation
149 $this->goToUrl = $title->getFullURL(
150 $title->isRedirect() ? [ 'redirect' => 'no' ] : []
151 );
152
153 return self::changePageLanguage(
154 $this->getContext(),
155 $title,
156 $newLanguage,
157 $data['reason'] === null ? '' : $data['reason']
158 );
159 }
160
161 /**
162 * @param IContextSource $context
163 * @param Title $title
164 * @param string $newLanguage Language code
165 * @param string $reason Reason for the change
166 * @param array $tags Change tags to apply to the log entry
167 * @return Status
168 */
169 public static function changePageLanguage( IContextSource $context, Title $title,
170 $newLanguage, $reason, array $tags = [] ) {
171 // Get the default language for the wiki
172 $defLang = $context->getConfig()->get( 'LanguageCode' );
173
174 $pageId = $title->getArticleID();
175
176 // Check if article exists
177 if ( !$pageId ) {
178 return Status::newFatal(
179 'pagelang-nonexistent-page',
180 wfEscapeWikiText( $title->getPrefixedText() )
181 );
182 }
183
184 // Load the page language from DB
185 $dbw = wfGetDB( DB_MASTER );
186 $oldLanguage = $dbw->selectField(
187 'page',
188 'page_lang',
189 [ 'page_id' => $pageId ],
190 __METHOD__
191 );
192
193 // Check if user wants to use the default language
194 if ( $newLanguage === 'default' ) {
195 $newLanguage = null;
196 }
197
198 // No change in language
199 if ( $newLanguage === $oldLanguage ) {
200 // Check if old language does not exist
201 if ( !$oldLanguage ) {
202 return Status::newFatal( ApiMessage::create(
203 [
204 'pagelang-unchanged-language-default',
205 wfEscapeWikiText( $title->getPrefixedText() )
206 ],
207 'pagelang-unchanged-language'
208 ) );
209 }
210 return Status::newFatal(
211 'pagelang-unchanged-language',
212 wfEscapeWikiText( $title->getPrefixedText() ),
213 $oldLanguage
214 );
215 }
216
217 // Hardcoded [def] if the language is set to null
218 $logOld = $oldLanguage ? $oldLanguage : $defLang . '[def]';
219 $logNew = $newLanguage ? $newLanguage : $defLang . '[def]';
220
221 // Writing new page language to database
222 $dbw->update(
223 'page',
224 [ 'page_lang' => $newLanguage ],
225 [
226 'page_id' => $pageId,
227 'page_lang' => $oldLanguage
228 ],
229 __METHOD__
230 );
231
232 if ( !$dbw->affectedRows() ) {
233 return Status::newFatal( 'pagelang-db-failed' );
234 }
235
236 // Logging change of language
237 $logParams = [
238 '4::oldlanguage' => $logOld,
239 '5::newlanguage' => $logNew
240 ];
241 $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
242 $entry->setPerformer( $context->getUser() );
243 $entry->setTarget( $title );
244 $entry->setParameters( $logParams );
245 $entry->setComment( $reason );
246 $entry->setTags( $tags );
247
248 $logid = $entry->insert();
249 $entry->publish( $logid );
250
251 // Force re-render so that language-based content (parser functions etc.) gets updated
252 $title->invalidateCache();
253
254 return Status::newGood( (object)[
255 'oldLanguage' => $logOld,
256 'newLanguage' => $logNew,
257 'logId' => $logid,
258 ] );
259 }
260
261 public function onSuccess() {
262 // Success causes a redirect
263 $this->getOutput()->redirect( $this->goToUrl );
264 }
265
266 function showLogFragment( $title ) {
267 $moveLogPage = new LogPage( 'pagelang' );
268 $out1 = Xml::element( 'h2', null, $moveLogPage->getName()->text() );
269 $out2 = '';
270 LogEventsList::showLogExtract( $out2, 'pagelang', $title );
271 return $out1 . $out2;
272 }
273
274 /**
275 * Return an array of subpages beginning with $search that this special page will accept.
276 *
277 * @param string $search Prefix to search for
278 * @param int $limit Maximum number of results to return (usually 10)
279 * @param int $offset Number of results to skip (usually 0)
280 * @return string[] Matching subpages
281 */
282 public function prefixSearchSubpages( $search, $limit, $offset ) {
283 return $this->prefixSearchString( $search, $limit, $offset );
284 }
285
286 protected function getGroupName() {
287 return 'pagetools';
288 }
289 }