SpecialPageLanguage.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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. * Special page for changing the content language of a page
  27. *
  28. * @ingroup SpecialPage
  29. */
  30. class SpecialPageLanguage extends FormSpecialPage {
  31. /**
  32. * @var string URL to go to if language change successful
  33. */
  34. private $goToUrl;
  35. public function __construct() {
  36. parent::__construct( 'PageLanguage', 'pagelang' );
  37. }
  38. public function doesWrites() {
  39. return true;
  40. }
  41. protected function preText() {
  42. $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
  43. return parent::preText();
  44. }
  45. protected function getFormFields() {
  46. // Get default from the subpage of Special page
  47. $defaultName = $this->par;
  48. $title = $defaultName ? Title::newFromText( $defaultName ) : null;
  49. if ( $title ) {
  50. $defaultPageLanguage =
  51. ContentHandler::getForTitle( $title )->getPageLanguage( $title );
  52. $hasCustomLanguageSet = !$defaultPageLanguage->equals( $title->getPageLanguage() );
  53. } else {
  54. $hasCustomLanguageSet = false;
  55. }
  56. $page = [];
  57. $page['pagename'] = [
  58. 'type' => 'title',
  59. 'label-message' => 'pagelang-name',
  60. 'default' => $title ? $title->getPrefixedText() : $defaultName,
  61. 'autofocus' => $defaultName === null,
  62. 'exists' => true,
  63. ];
  64. // Options for whether to use the default language or select language
  65. $selectoptions = [
  66. (string)$this->msg( 'pagelang-use-default' )->escaped() => 1,
  67. (string)$this->msg( 'pagelang-select-lang' )->escaped() => 2,
  68. ];
  69. $page['selectoptions'] = [
  70. 'id' => 'mw-pl-options',
  71. 'type' => 'radio',
  72. 'options' => $selectoptions,
  73. 'default' => $hasCustomLanguageSet ? 2 : 1
  74. ];
  75. // Building a language selector
  76. $userLang = $this->getLanguage()->getCode();
  77. $languages = Language::fetchLanguageNames( $userLang, 'mwfile' );
  78. $options = [];
  79. foreach ( $languages as $code => $name ) {
  80. $options["$code - $name"] = $code;
  81. }
  82. $page['language'] = [
  83. 'id' => 'mw-pl-languageselector',
  84. 'cssclass' => 'mw-languageselector',
  85. 'type' => 'select',
  86. 'options' => $options,
  87. 'label-message' => 'pagelang-language',
  88. 'default' => $title ?
  89. $title->getPageLanguage()->getCode() :
  90. $this->getConfig()->get( 'LanguageCode' ),
  91. ];
  92. // Allow user to enter a comment explaining the change
  93. $page['reason'] = [
  94. 'type' => 'text',
  95. 'label-message' => 'pagelang-reason'
  96. ];
  97. return $page;
  98. }
  99. protected function postText() {
  100. if ( $this->par ) {
  101. return $this->showLogFragment( $this->par );
  102. }
  103. return '';
  104. }
  105. protected function getDisplayFormat() {
  106. return 'ooui';
  107. }
  108. public function alterForm( HTMLForm $form ) {
  109. Hooks::run( 'LanguageSelector', [ $this->getOutput(), 'mw-languageselector' ] );
  110. $form->setSubmitTextMsg( 'pagelang-submit' );
  111. }
  112. /**
  113. *
  114. * @param array $data
  115. * @return Status
  116. */
  117. public function onSubmit( array $data ) {
  118. $pageName = $data['pagename'];
  119. // Check if user wants to use default language
  120. if ( $data['selectoptions'] == 1 ) {
  121. $newLanguage = 'default';
  122. } else {
  123. $newLanguage = $data['language'];
  124. }
  125. try {
  126. $title = Title::newFromTextThrow( $pageName );
  127. } catch ( MalformedTitleException $ex ) {
  128. return Status::newFatal( $ex->getMessageObject() );
  129. }
  130. // Check permissions and make sure the user has permission to edit the page
  131. $errors = $title->getUserPermissionsErrors( 'edit', $this->getUser() );
  132. if ( $errors ) {
  133. $out = $this->getOutput();
  134. $wikitext = $out->formatPermissionsErrorMessage( $errors );
  135. // Hack to get our wikitext parsed
  136. return Status::newFatal( new RawMessage( '$1', [ $wikitext ] ) );
  137. }
  138. // Url to redirect to after the operation
  139. $this->goToUrl = $title->getFullUrlForRedirect(
  140. $title->isRedirect() ? [ 'redirect' => 'no' ] : []
  141. );
  142. return self::changePageLanguage(
  143. $this->getContext(),
  144. $title,
  145. $newLanguage,
  146. $data['reason'] ?? ''
  147. );
  148. }
  149. /**
  150. * @param IContextSource $context
  151. * @param Title $title
  152. * @param string $newLanguage Language code
  153. * @param string $reason Reason for the change
  154. * @param array $tags Change tags to apply to the log entry
  155. * @return Status
  156. */
  157. public static function changePageLanguage( IContextSource $context, Title $title,
  158. $newLanguage, $reason, array $tags = [] ) {
  159. // Get the default language for the wiki
  160. $defLang = $context->getConfig()->get( 'LanguageCode' );
  161. $pageId = $title->getArticleID();
  162. // Check if article exists
  163. if ( !$pageId ) {
  164. return Status::newFatal(
  165. 'pagelang-nonexistent-page',
  166. wfEscapeWikiText( $title->getPrefixedText() )
  167. );
  168. }
  169. // Load the page language from DB
  170. $dbw = wfGetDB( DB_MASTER );
  171. $oldLanguage = $dbw->selectField(
  172. 'page',
  173. 'page_lang',
  174. [ 'page_id' => $pageId ],
  175. __METHOD__
  176. );
  177. // Check if user wants to use the default language
  178. if ( $newLanguage === 'default' ) {
  179. $newLanguage = null;
  180. }
  181. // No change in language
  182. if ( $newLanguage === $oldLanguage ) {
  183. // Check if old language does not exist
  184. if ( !$oldLanguage ) {
  185. return Status::newFatal( ApiMessage::create(
  186. [
  187. 'pagelang-unchanged-language-default',
  188. wfEscapeWikiText( $title->getPrefixedText() )
  189. ],
  190. 'pagelang-unchanged-language'
  191. ) );
  192. }
  193. return Status::newFatal(
  194. 'pagelang-unchanged-language',
  195. wfEscapeWikiText( $title->getPrefixedText() ),
  196. $oldLanguage
  197. );
  198. }
  199. // Hardcoded [def] if the language is set to null
  200. $logOld = $oldLanguage ?: $defLang . '[def]';
  201. $logNew = $newLanguage ?: $defLang . '[def]';
  202. // Writing new page language to database
  203. $dbw->update(
  204. 'page',
  205. [ 'page_lang' => $newLanguage ],
  206. [
  207. 'page_id' => $pageId,
  208. 'page_lang' => $oldLanguage
  209. ],
  210. __METHOD__
  211. );
  212. if ( !$dbw->affectedRows() ) {
  213. return Status::newFatal( 'pagelang-db-failed' );
  214. }
  215. // Logging change of language
  216. $logParams = [
  217. '4::oldlanguage' => $logOld,
  218. '5::newlanguage' => $logNew
  219. ];
  220. $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
  221. $entry->setPerformer( $context->getUser() );
  222. $entry->setTarget( $title );
  223. $entry->setParameters( $logParams );
  224. $entry->setComment( $reason );
  225. $entry->addTags( $tags );
  226. $logid = $entry->insert();
  227. $entry->publish( $logid );
  228. // Force re-render so that language-based content (parser functions etc.) gets updated
  229. $title->invalidateCache();
  230. return Status::newGood( (object)[
  231. 'oldLanguage' => $logOld,
  232. 'newLanguage' => $logNew,
  233. 'logId' => $logid,
  234. ] );
  235. }
  236. public function onSuccess() {
  237. // Success causes a redirect
  238. $this->getOutput()->redirect( $this->goToUrl );
  239. }
  240. function showLogFragment( $title ) {
  241. $moveLogPage = new LogPage( 'pagelang' );
  242. $out1 = Xml::element( 'h2', null, $moveLogPage->getName()->text() );
  243. $out2 = '';
  244. LogEventsList::showLogExtract( $out2, 'pagelang', $title );
  245. return $out1 . $out2;
  246. }
  247. /**
  248. * Return an array of subpages beginning with $search that this special page will accept.
  249. *
  250. * @param string $search Prefix to search for
  251. * @param int $limit Maximum number of results to return (usually 10)
  252. * @param int $offset Number of results to skip (usually 0)
  253. * @return string[] Matching subpages
  254. */
  255. public function prefixSearchSubpages( $search, $limit, $offset ) {
  256. return $this->prefixSearchString( $search, $limit, $offset );
  257. }
  258. protected function getGroupName() {
  259. return 'pagetools';
  260. }
  261. }