Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / specials / SpecialMyLanguage.php
blob1d5696adcf156069f78ed5034a30e0db5de49fa5
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
18 * @file
21 namespace MediaWiki\Specials;
23 use MediaWiki\Languages\LanguageNameUtils;
24 use MediaWiki\Page\RedirectLookup;
25 use MediaWiki\SpecialPage\RedirectSpecialArticle;
26 use MediaWiki\Title\Title;
28 /**
29 * Redirect to the appropriate translated version of a page if it exists.
31 * Usage: [[Special:MyLanguage/Page name|link text]]
33 * @since 1.24
34 * @ingroup SpecialPage
35 * @author Niklas Laxström
36 * @author Siebrand Mazeland
37 * @copyright Copyright © 2010-2013 Niklas Laxström, Siebrand Mazeland
39 class SpecialMyLanguage extends RedirectSpecialArticle {
41 private LanguageNameUtils $languageNameUtils;
42 private RedirectLookup $redirectLookup;
44 /**
45 * @param LanguageNameUtils $languageNameUtils
46 * @param RedirectLookup $redirectLookup
48 public function __construct(
49 LanguageNameUtils $languageNameUtils,
50 RedirectLookup $redirectLookup
51 ) {
52 parent::__construct( 'MyLanguage' );
53 $this->languageNameUtils = $languageNameUtils;
54 $this->redirectLookup = $redirectLookup;
57 /**
58 * If the special page is a redirect, then get the Title object it redirects to.
59 * False otherwise.
61 * @param string|null $subpage
62 * @return Title
64 public function getRedirect( $subpage ) {
65 $title = $this->findTitle( $subpage );
66 // Go to the main page if given invalid title.
67 if ( !$title ) {
68 $title = Title::newMainPage();
70 return $title;
73 /**
74 * Find a title.
76 * This may return the base page, e.g. if the UI and
77 * content language are the same.
79 * Examples, assuming the UI language is fi and the content language
80 * is en:
81 * - input Page: returns Page/fi if it exists, otherwise Page
82 * - input Page/de: returns Page/fi if it exists, otherwise Page/de
83 * if it exists, otherwise Page
85 * @param string|null $subpage
86 * @return Title|null
88 public function findTitle( $subpage ) {
89 return $this->findTitleInternal( $subpage, false );
92 /**
93 * Find a title for transclusion. This avoids returning the base
94 * page if a suitable alternative exists.
96 * Examples, assuming the UI language is fi and the content language
97 * is en:
98 * - input Page: returns Page/fi if it exists, otherwise Page/en if
99 * it exists, otherwise Page
100 * - input Page/de: returns Page/fi if it exists, otherwise Page/de
101 * if it exists, otherwise Page/en if it exists, otherwise Page
103 * @param string|null $subpage
104 * @return Title|null
106 public function findTitleForTransclusion( $subpage ) {
107 return $this->findTitleInternal( $subpage, true );
111 * Find a title, depending on the content language and the user's
112 * interface language.
114 * @param string|null $subpage
115 * @param bool $forTransclusion
116 * @return Title|null
118 private function findTitleInternal( $subpage, $forTransclusion ) {
119 // base = title without the language code suffix
120 // provided = the title as it was given
121 $base = $provided = null;
122 if ( $subpage !== null ) {
123 $provided = Title::newFromText( $subpage );
124 $base = $provided;
126 if ( $provided && str_contains( $subpage, '/' ) ) {
127 $pos = strrpos( $subpage, '/' );
128 $basepage = substr( $subpage, 0, $pos );
129 $code = substr( $subpage, $pos + 1 );
130 if ( strlen( $code ) && $this->languageNameUtils->isKnownLanguageTag( $code ) ) {
131 $base = Title::newFromText( $basepage );
136 if ( !$base || !$base->canExist() ) {
137 // No subpage provided or base page does not exist
138 return null;
141 $fragment = '';
142 if ( $base->isRedirect() ) {
143 $target = $this->redirectLookup->getRedirectTarget( $base );
144 if ( $target !== null ) {
145 $base = Title::newFromLinkTarget( $target );
146 // Preserve the fragment from the redirect target
147 $fragment = $base->getFragment();
151 $uiLang = $this->getLanguage();
152 $baseLang = $base->getPageLanguage();
154 // T309329: Always use subpages for transclusion
155 if ( !$forTransclusion && $baseLang->equals( $uiLang ) ) {
156 // Short circuit when the current UI language is the
157 // page's content language to avoid unnecessary page lookups.
158 return $base;
161 // Check for a subpage in the current UI language
162 $proposed = $base->getSubpage( $uiLang->getCode() );
163 if ( $proposed && $proposed->exists() ) {
164 if ( $fragment !== '' ) {
165 $proposed->setFragment( $fragment );
167 return $proposed;
170 // Explicit language code given and the page exists
171 if ( $provided !== $base && $provided->exists() ) {
172 // Not based on the redirect target, don't need the fragment
173 return $provided;
176 // Check for fallback languages specified by the UI language
177 $possibilities = $uiLang->getFallbackLanguages();
178 foreach ( $possibilities as $lang ) {
179 // $base already include fragments
180 // T309329: Always use subpages for transclusion
181 // T333187: Do not ignore base language page if matched
182 if ( !$forTransclusion && $lang === $baseLang->getCode() ) {
183 return $base;
185 // Look for subpages if is for transclusion or didn't match base page language
186 $proposed = $base->getSubpage( $lang );
187 if ( $proposed && $proposed->exists() ) {
188 if ( $fragment !== '' ) {
189 $proposed->setFragment( $fragment );
191 return $proposed;
195 // When all else has failed, return the base page
196 return $base;
200 * Target can identify a specific user's language preference.
202 * @see T109724
203 * @since 1.27
204 * @return bool
206 public function personallyIdentifiableTarget() {
207 return true;
212 * Retain the old class name for backwards compatibility.
213 * @deprecated since 1.41
215 class_alias( SpecialMyLanguage::class, 'SpecialMyLanguage' );