1<?php 2/** 3 * Implements Special:MyLanguage 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 * @author Niklas Laxström 22 * @author Siebrand Mazeland 23 * @copyright Copyright © 2010-2013 Niklas Laxström, Siebrand Mazeland 24 */ 25 26use MediaWiki\Languages\LanguageNameUtils; 27use MediaWiki\Page\WikiPageFactory; 28 29/** 30 * Unlisted special page just to redirect the user to the translated version of 31 * a page, if it exists. 32 * 33 * Usage: [[Special:MyLanguage/Page name|link text]] 34 * 35 * @since 1.24 36 * @ingroup SpecialPage 37 */ 38class SpecialMyLanguage extends RedirectSpecialArticle { 39 40 /** @var LanguageNameUtils */ 41 private $languageNameUtils; 42 43 /** @var WikiPageFactory */ 44 private $wikiPageFactory; 45 46 /** 47 * @param LanguageNameUtils $languageNameUtils 48 * @param WikiPageFactory $wikiPageFactory 49 */ 50 public function __construct( 51 LanguageNameUtils $languageNameUtils, 52 WikiPageFactory $wikiPageFactory 53 ) { 54 parent::__construct( 'MyLanguage' ); 55 $this->languageNameUtils = $languageNameUtils; 56 $this->wikiPageFactory = $wikiPageFactory; 57 } 58 59 /** 60 * If the special page is a redirect, then get the Title object it redirects to. 61 * False otherwise. 62 * 63 * @param string|null $subpage 64 * @return Title 65 */ 66 public function getRedirect( $subpage ) { 67 $title = $this->findTitle( $subpage ); 68 // Go to the main page if given invalid title. 69 if ( !$title ) { 70 $title = Title::newMainPage(); 71 } 72 return $title; 73 } 74 75 /** 76 * Assuming the user's interface language is fi. Given input Page, it 77 * returns Page/fi if it exists, otherwise Page. Given input Page/de, 78 * it returns Page/fi if it exists, otherwise Page/de if it exists, 79 * otherwise Page. 80 * 81 * @param string|null $subpage 82 * @return Title|null 83 */ 84 public function findTitle( $subpage ) { 85 // base = title without language code suffix 86 // provided = the title as it was given 87 $base = $provided = null; 88 if ( $subpage !== null ) { 89 $provided = Title::newFromText( $subpage ); 90 $base = $provided; 91 92 if ( $provided && strpos( $subpage, '/' ) !== false ) { 93 $pos = strrpos( $subpage, '/' ); 94 $basepage = substr( $subpage, 0, $pos ); 95 $code = substr( $subpage, $pos + 1 ); 96 if ( strlen( $code ) && $this->languageNameUtils->isKnownLanguageTag( $code ) ) { 97 $base = Title::newFromText( $basepage ); 98 } 99 } 100 } 101 102 if ( !$base || !$base->canExist() ) { 103 // No subpage provided or base page does not exist 104 return null; 105 } 106 107 if ( $base->isRedirect() ) { 108 $page = $this->wikiPageFactory->newFromTitle( $base ); 109 $base = $page->getRedirectTarget(); 110 } 111 112 $uiLang = $this->getLanguage(); 113 $contLang = $this->getContentLanguage(); 114 115 if ( $uiLang->equals( $contLang ) ) { 116 // Short circuit when the current UI language is the 117 // wiki's default language to avoid unnecessary page lookups. 118 return $base; 119 } 120 121 // Check for a subpage in current UI language 122 $proposed = $base->getSubpage( $uiLang->getCode() ); 123 if ( $proposed && $proposed->exists() ) { 124 return $proposed; 125 } 126 127 if ( $provided !== $base && $provided->exists() ) { 128 // Explicit language code given and the page exists 129 return $provided; 130 } 131 132 // Check for fallback languages specified by the UI language 133 $possibilities = $uiLang->getFallbackLanguages(); 134 foreach ( $possibilities as $lang ) { 135 if ( $lang !== $contLang->getCode() ) { 136 $proposed = $base->getSubpage( $lang ); 137 if ( $proposed && $proposed->exists() ) { 138 return $proposed; 139 } 140 } 141 } 142 143 // When all else has failed, return the base page 144 return $base; 145 } 146 147 /** 148 * Target can identify a specific user's language preference. 149 * 150 * @see T109724 151 * @since 1.27 152 * @return bool 153 */ 154 public function personallyIdentifiableTarget() { 155 return true; 156 } 157} 158