2declare( strict_types = 1 );
7use MediaWiki\Languages\LanguageConverterFactory;
8use MediaWiki\Languages\LanguageFactory;
18use Wikimedia\Bcp47Code\Bcp47Code;
19use Wikimedia\Bcp47Code\Bcp47CodeValue;
21use Wikimedia\Parsoid\Config\PageConfig;
22use Wikimedia\Parsoid\Config\SiteConfig;
23use Wikimedia\Parsoid\Core\HtmlPageBundle;
24use Wikimedia\Parsoid\DOM\Element;
25use Wikimedia\Parsoid\Parsoid;
26use Wikimedia\Parsoid\Utils\DOMCompat;
27use Wikimedia\Parsoid\Utils\DOMUtils;
34 private ?PageConfig $pageConfig =
null;
35 private readonly
Title $pageTitle;
39 private ?Bcp47Code $pageLanguageOverride =
null;
40 private bool $isFallbackLanguageConverterEnabled =
true;
48 private readonly Parsoid $parsoid,
49 private readonly SiteConfig $siteConfig,
51 private readonly LanguageConverterFactory $languageConverterFactory,
52 private readonly LanguageFactory $languageFactory
65 $this->pageConfig = $pageConfig;
75 $this->pageLanguageOverride = $language;
90 HtmlPageBundle $pageBundle,
91 Bcp47Code $targetVariant,
92 ?Bcp47Code $sourceVariant =
null
94 [ $pageLanguage, $sourceVariant ] =
95 $this->getBaseAndSourceLanguage( $pageBundle, $sourceVariant );
97 if ( !$this->siteConfig->langConverterEnabledBcp47( $pageLanguage ) ) {
102 $pageConfig = $this->getPageConfig( $pageLanguage, $sourceVariant );
104 if ( $this->parsoid->implementsLanguageConversionBcp47( $pageConfig, $targetVariant ) ) {
105 return $this->parsoid->pb2pb(
106 $pageConfig,
'variant', $pageBundle,
109 'source' => $sourceVariant,
110 'target' => $targetVariant,
115 if ( !$this->isFallbackLanguageConverterEnabled ) {
123 $baseLanguage = $this->languageFactory->getParentLanguage( $targetVariant );
124 $languageConverter = $this->languageConverterFactory->getLanguageConverter( $baseLanguage );
125 $targetVariantCode = $this->languageFactory->getLanguage( $targetVariant )->getCode();
126 if ( $languageConverter->hasVariant( $targetVariantCode ) ) {
130 $convertedHtml = $languageConverter->convertTo( $pageBundle->html, $targetVariantCode );
131 $pageVariant = $targetVariant;
134 $convertedHtml = $pageBundle->html;
135 $pageVariant = $pageConfig->getPageLanguageBcp47();
139 $msg =
"<!-- Variant conversion performed using the core LanguageConverter -->";
140 $convertedHtml = $msg . $convertedHtml;
145 'content-language' => $pageVariant->toBcp47Code(),
146 'vary' => [
'Accept',
'Accept-Language' ]
148 $doc = DOMUtils::parseHTML(
'<head></head><body></body>' );
149 DOMUtils::addHttpEquivHeaders( $doc, $headers );
150 $docElt = $doc->documentElement;
151 '@phan-var Element $docElt';
152 $docHtml = DOMCompat::getOuterHTML( $docElt );
153 $convertedHtml = preg_replace(
"#</body>#", $docHtml,
"$convertedHtml</body>" );
154 return new HtmlPageBundle(
155 html: $convertedHtml, parsoid: [], mw: [],
156 version: $pageBundle->version, headers: $headers
172 Bcp47Code $targetVariant,
173 ?Bcp47Code $sourceVariant =
null
176 $modifiedPageBundle = $this->convertPageBundleVariant( $pageBundle, $targetVariant, $sourceVariant );
185 $this->isFallbackLanguageConverterEnabled = false;
188 private function getPageConfig( Bcp47Code $pageLanguage, ?Bcp47Code $sourceVariant ): PageConfig {
189 if ( $this->pageConfig ) {
190 return $this->pageConfig;
194 $this->pageConfig = $this->pageConfigFactory->createFromParserOptions(
196 $this->parserOptionsForTest ?? ParserOptions::newFromAnon(),
202 if ( $sourceVariant ) {
203 $this->pageConfig->setVariantBcp47( $sourceVariant );
205 }
catch ( RevisionAccessException ) {
208 throw new LocalizedHttpException(
new MessageValue(
"rest-specified-revision-unavailable" ), 404 );
211 return $this->pageConfig;
240 private function getPageLanguage( HtmlPageBundle $pageBundle, ?Bcp47Code $default =
null ): Bcp47Code {
242 if ( $this->pageLanguageOverride ) {
243 return $this->pageLanguageOverride;
247 $pageBundleLanguage = $pageBundle->headers[
'content-language' ] ??
null;
248 if ( $pageBundleLanguage ) {
251 return new Bcp47CodeValue( $pageBundleLanguage );
262 if ( $this->pageConfig ) {
263 return $this->pageConfig->getPageLanguageBcp47();
268 return $this->pageTitle->getPageLanguage();
286 private function getBaseAndSourceLanguage( HtmlPageBundle $pageBundle, ?Bcp47Code $sourceLanguage ): array {
289 $baseLanguage = $this->getPageLanguage( $pageBundle, $sourceLanguage );
292 $parentLang = $this->languageFactory->getParentLanguage( $baseLanguage );
298 if ( $parentLang && strcasecmp( $parentLang->toBcp47Code(), $baseLanguage->toBcp47Code() ) !== 0 ) {
299 if ( !$sourceLanguage ) {
300 $sourceLanguage = $baseLanguage;
302 $baseLanguage = $parentLang;
305 if ( $sourceLanguage !==
null ) {
306 $parentConverter = $this->languageConverterFactory->getLanguageConverter( $parentLang );
309 strcasecmp( $parentLang->toBcp47Code(), $sourceLanguage->toBcp47Code() ) !== 0 &&
310 $parentConverter->hasVariant(
311 LanguageCode::bcp47ToInternal( $sourceLanguage->toBcp47Code() )
314 if ( !$sourceIsVariant ) {
315 $sourceLanguage =
null;
319 return [ $baseLanguage, $sourceLanguage ];
if(!defined('MW_SETUP_CALLBACK'))
Helper class used by MediaWiki to create Parsoid PageConfig objects.
Provides methods for conversion between HtmlPageBundle and ParserOutput TODO: Convert to a trait once...
static parserOutputFromPageBundle(HtmlPageBundle $pageBundle, ?ParserOutput $originalParserOutput=null)
Creates a ParserOutput object containing the relevant data from the given HtmlPageBundle object.
Interface for objects (potentially) representing an editable wiki page.