diff --git a/autoload.php b/autoload.php index b0a66c86296..a489389df0a 100644 --- a/autoload.php +++ b/autoload.php @@ -494,7 +494,7 @@ $wgAutoloadLocalClasses = [ 'FSFileBackendList' => __DIR__ . '/includes/libs/filebackend/fileiteration/FSFileBackendList.php', 'FSFileOpHandle' => __DIR__ . '/includes/libs/filebackend/fileophandle/FSFileOpHandle.php', 'FSLockManager' => __DIR__ . '/includes/libs/lockmanager/FSLockManager.php', - 'FakeConverter' => __DIR__ . '/languages/FakeConverter.php', + 'FakeConverter' => __DIR__ . '/languages/TrivialLanguageConverter.php', 'FakeMaintenance' => __DIR__ . '/maintenance/Maintenance.php', 'FakeResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/FakeResultWrapper.php', 'FatalError' => __DIR__ . '/includes/exception/FatalError.php', @@ -647,6 +647,7 @@ $wgAutoloadLocalClasses = [ 'IEContentAnalyzer' => __DIR__ . '/includes/libs/mime/IEContentAnalyzer.php', 'IExpiringStore' => __DIR__ . '/includes/libs/objectcache/IExpiringStore.php', 'IJobSpecification' => __DIR__ . '/includes/jobqueue/IJobSpecification.php', + 'ILanguageConverter' => __DIR__ . '/languages/ILanguageConverter.php', 'ILocalizedException' => __DIR__ . '/includes/exception/ILocalizedException.php', 'IMaintainableDatabase' => __DIR__ . '/includes/libs/rdbms/database/IMaintainableDatabase.php', 'IP' => __DIR__ . '/includes/compat/IP.php', @@ -736,7 +737,6 @@ $wgAutoloadLocalClasses = [ 'LanguageBs' => __DIR__ . '/languages/classes/LanguageBs.php', 'LanguageCode' => __DIR__ . '/includes/language/LanguageCode.php', 'LanguageConverter' => __DIR__ . '/languages/LanguageConverter.php', - 'LanguageCrh' => __DIR__ . '/languages/classes/LanguageCrh.php', 'LanguageCu' => __DIR__ . '/languages/classes/LanguageCu.php', 'LanguageDsb' => __DIR__ . '/languages/classes/LanguageDsb.php', 'LanguageEn' => __DIR__ . '/languages/classes/LanguageEn.php', @@ -746,26 +746,20 @@ $wgAutoloadLocalClasses = [ 'LanguageHsb' => __DIR__ . '/languages/classes/LanguageHsb.php', 'LanguageHu' => __DIR__ . '/languages/classes/LanguageHu.php', 'LanguageHy' => __DIR__ . '/languages/classes/LanguageHy.php', - 'LanguageIu' => __DIR__ . '/languages/classes/LanguageIu.php', 'LanguageJa' => __DIR__ . '/languages/classes/LanguageJa.php', 'LanguageKaa' => __DIR__ . '/languages/classes/LanguageKaa.php', 'LanguageKk' => __DIR__ . '/languages/classes/LanguageKk.php', 'LanguageKk_cyrl' => __DIR__ . '/languages/classes/LanguageKk_cyrl.php', 'LanguageKm' => __DIR__ . '/languages/classes/LanguageKm.php', 'LanguageKsh' => __DIR__ . '/languages/classes/LanguageKsh.php', - 'LanguageKu' => __DIR__ . '/languages/classes/LanguageKu.php', 'LanguageLa' => __DIR__ . '/languages/classes/LanguageLa.php', 'LanguageMl' => __DIR__ . '/languages/classes/LanguageMl.php', 'LanguageMy' => __DIR__ . '/languages/classes/LanguageMy.php', 'LanguageOs' => __DIR__ . '/languages/classes/LanguageOs.php', 'LanguageQqx' => __DIR__ . '/languages/classes/LanguageQqx.php', - 'LanguageShi' => __DIR__ . '/languages/classes/LanguageShi.php', 'LanguageSl' => __DIR__ . '/languages/classes/LanguageSl.php', - 'LanguageSr' => __DIR__ . '/languages/classes/LanguageSr.php', - 'LanguageTg' => __DIR__ . '/languages/classes/LanguageTg.php', 'LanguageTr' => __DIR__ . '/languages/classes/LanguageTr.php', 'LanguageTyv' => __DIR__ . '/languages/classes/LanguageTyv.php', - 'LanguageUz' => __DIR__ . '/languages/classes/LanguageUz.php', 'LanguageWa' => __DIR__ . '/languages/classes/LanguageWa.php', 'LanguageYue' => __DIR__ . '/languages/classes/LanguageYue.php', 'LanguageZh' => __DIR__ . '/languages/classes/LanguageZh.php', @@ -883,6 +877,7 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Languages\\Data\\CrhExceptions' => __DIR__ . '/languages/data/CrhExceptions.php', 'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php', 'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php', + 'MediaWiki\\Languages\\LanguageConverterFactory' => __DIR__ . '/languages/LanguageConverterFactory.php', 'MediaWiki\\Languages\\LanguageFactory' => __DIR__ . '/includes/language/LanguageFactory.php', 'MediaWiki\\Languages\\LanguageFallback' => __DIR__ . '/includes/language/LanguageFallback.php', 'MediaWiki\\Languages\\LanguageNameUtils' => __DIR__ . '/includes/language/LanguageNameUtils.php', @@ -1523,6 +1518,7 @@ $wgAutoloadLocalClasses = [ 'TransformParameterError' => __DIR__ . '/includes/media/TransformParameterError.php', 'TransformTooBigImageAreaError' => __DIR__ . '/includes/media/TransformTooBigImageAreaError.php', 'TransformationalImageHandler' => __DIR__ . '/includes/media/TransformationalImageHandler.php', + 'TrivialLanguageConverter' => __DIR__ . '/languages/TrivialLanguageConverter.php', 'UDPRCFeedEngine' => __DIR__ . '/includes/rcfeed/UDPRCFeedEngine.php', 'UDPTransport' => __DIR__ . '/includes/libs/UDPTransport.php', 'UIDGenerator' => __DIR__ . '/includes/utils/UIDGenerator.php', diff --git a/includes/Html.php b/includes/Html.php index 0d301b68cce..62bd921d5bf 100644 --- a/includes/Html.php +++ b/includes/Html.php @@ -865,7 +865,9 @@ class Html { // main we don't use "" but the user message describing it (e.g. "(Main)" or "(Article)") $nsName = wfMessage( 'blanknamespace' )->text(); } elseif ( is_int( $nsId ) ) { - $nsName = $lang->convertNamespace( $nsId ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $lang ); + $nsName = $converter->convertNamespace( $nsId ); } $optionsOut[$nsId] = $nsName; } diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index 5e857be8e1f..75a10e628c9 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -33,6 +33,7 @@ use MediaWiki\FileBackend\FSFile\TempFSFileFactory; use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory; use MediaWiki\Http\HttpRequestFactory; use MediaWiki\Interwiki\InterwikiLookup; +use MediaWiki\Languages\LanguageConverterFactory; use MediaWiki\Languages\LanguageFactory; use MediaWiki\Languages\LanguageFallback; use MediaWiki\Languages\LanguageNameUtils; @@ -667,6 +668,14 @@ class MediaWikiServices extends ServiceContainer { return $this->getService( 'InterwikiLookup' ); } + /** + * @since 1.35 + * @return LanguageConverterFactory + */ + public function getLanguageConverterFactory() : LanguageConverterFactory { + return $this->getService( 'LanguageConverterFactory' ); + } + /** * @since 1.35 * @return LanguageFactory diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 78a476f892e..6eeffc0802e 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -58,6 +58,7 @@ use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory; use MediaWiki\Http\HttpRequestFactory; use MediaWiki\Interwiki\ClassicInterwikiLookup; use MediaWiki\Interwiki\InterwikiLookup; +use MediaWiki\Languages\LanguageConverterFactory; use MediaWiki\Languages\LanguageFactory; use MediaWiki\Languages\LanguageFallback; use MediaWiki\Languages\LanguageNameUtils; @@ -303,12 +304,20 @@ return [ ); }, + 'LanguageConverterFactory' => function ( MediaWikiServices $services ) : LanguageConverterFactory { + $usePigLatinVariant = $services->getMainConfig()->get( 'UsePigLatinVariant' ); + return new LanguageConverterFactory( $usePigLatinVariant, function () use ( $services ) { + return $services->getContentLanguage(); + } ); + }, + 'LanguageFactory' => function ( MediaWikiServices $services ) : LanguageFactory { return new LanguageFactory( new ServiceOptions( LanguageFactory::CONSTRUCTOR_OPTIONS, $services->getMainConfig() ), $services->getLocalisationCache(), $services->getLanguageNameUtils(), - $services->getLanguageFallback() + $services->getLanguageFallback(), + $services->getLanguageConverterFactory() ); }, @@ -508,6 +517,7 @@ return [ $clusterCache, $srvCache, $services->getContentLanguage(), + $services->getLanguageConverterFactory()->getLanguageConverter(), $logger, [ 'useDB' => $mainConfig->get( 'UseDatabaseMessages' ) ], $services->getLanguageFactory(), diff --git a/includes/Title.php b/includes/Title.php index 0c7dc557fa8..a364f2224d3 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -189,6 +189,24 @@ class Title implements LinkTarget, IDBAccessObject { private $mIsValid = null; // @} + /** + * Shorthand for getting a Language Converter for specific language + * @param Language $language Language of converter + * @return ILanguageConverter + */ + private function getLanguageConverter( Language $language ) : ILanguageConverter { + return MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $language ); + } + + /** + * Shorthand for getting a Language Converter for page's language + * @return ILanguageConverter + */ + private function getPageLanguageConverter() : ILanguageConverter { + return $this->getLanguageConverter( $this->getPageLanguage() ); + } + /** * B/C kludge: provide a TitleParser for use by Title. * Ideally, Title would have no methods that need this. @@ -2219,10 +2237,10 @@ class Title implements LinkTarget, IDBAccessObject { && preg_match( '/^variant=([^&]*)$/', $query, $matches ) && $this->getPageLanguage()->equals( MediaWikiServices::getInstance()->getContentLanguage() ) - && $this->getPageLanguage()->hasVariants() + && $this->getPageLanguageConverter()->hasVariants() ) { $variant = urldecode( $matches[1] ); - if ( $this->getPageLanguage()->hasVariant( $variant ) ) { + if ( $this->getPageLanguageConverter()->hasVariant( $variant ) ) { // Only do the variant replacement if the given variant is a valid // variant for the page's language. $url = str_replace( '$2', urlencode( $variant ), $wgVariantArticlePath ); @@ -3547,9 +3565,8 @@ class Title implements LinkTarget, IDBAccessObject { $this->getInternalURL( 'action=history' ) ]; - $pageLang = $this->getPageLanguage(); - if ( $pageLang->hasVariants() ) { - $variants = $pageLang->getVariants(); + if ( $this->getPageLanguageConverter()->hasVariants() ) { + $variants = $this->getPageLanguageConverter()->getVariants(); foreach ( $variants as $vCode ) { $urls[] = $this->getInternalURL( $vCode ); } @@ -4069,7 +4086,7 @@ class Title implements LinkTarget, IDBAccessObject { return $user->getName(); }, $users ); } catch ( InvalidArgumentException $e ) { - return null; // b/c + return null; // b/c } } @@ -4621,7 +4638,7 @@ class Title implements LinkTarget, IDBAccessObject { if ( $this->isSpecialPage() ) { // If the user chooses a variant, the content is actually // in a language whose code is the variant code. - $variant = $wgLang->getPreferredVariant(); + $variant = $this->getLanguageConverter( $wgLang )->getPreferredVariant(); if ( $wgLang->getCode() !== $variant ) { return MediaWikiServices::getInstance()->getLanguageFactory() ->getLanguage( $variant ); @@ -4634,7 +4651,7 @@ class Title implements LinkTarget, IDBAccessObject { $dbPageLanguage = $this->getDbPageLanguageCode(); if ( $dbPageLanguage ) { $pageLang = wfGetLangObj( $dbPageLanguage ); - $variant = $pageLang->getPreferredVariant(); + $variant = $this->getLanguageConverter( $pageLang )->getPreferredVariant(); if ( $pageLang->getCode() !== $variant ) { $pageLang = MediaWikiServices::getInstance()->getLanguageFactory() ->getLanguage( $variant ); diff --git a/includes/api/ApiQueryLanguageinfo.php b/includes/api/ApiQueryLanguageinfo.php index af55877d025..5f85041620e 100644 --- a/includes/api/ApiQueryLanguageinfo.php +++ b/includes/api/ApiQueryLanguageinfo.php @@ -184,8 +184,11 @@ class ApiQueryLanguageinfo extends ApiQueryBase { } if ( $includeVariants ) { - $variants = MediaWikiServices::getInstance()->getLanguageFactory() - ->getLanguage( $languageCode )->getVariants(); + $language = MediaWikiServices::getInstance()->getLanguageFactory() + ->getLanguage( $languageCode ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $language ); + $variants = $converter->getVariants(); ApiResult::setIndexedTagName( $variants, 'var' ); $info['variants'] = $variants; } diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php index 49f4658ea2f..ef0833bc668 100644 --- a/includes/api/ApiQuerySiteinfo.php +++ b/includes/api/ApiQuerySiteinfo.php @@ -161,6 +161,8 @@ class ApiQuerySiteinfo extends ApiQueryBase { $data['titleconversion'] = !$config->get( 'DisableTitleConversion' ); $contLang = MediaWikiServices::getInstance()->getContentLanguage(); + $contLangConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $contLang ); if ( $contLang->linkPrefixExtension() ) { $linkPrefixCharset = $contLang->linkPrefixCharset(); $data['linkprefixcharset'] = $linkPrefixCharset; @@ -200,9 +202,9 @@ class ApiQuerySiteinfo extends ApiQueryBase { $data['fallback'] = $fallbacks; ApiResult::setIndexedTagName( $data['fallback'], 'lang' ); - if ( $contLang->hasVariants() ) { + if ( $contLangConverter->hasVariants() ) { $variants = []; - foreach ( $contLang->getVariants() as $code ) { + foreach ( $contLangConverter->getVariants() as $code ) { $variants[] = [ 'code' => $code, 'name' => $contLang->getVariantname( $code ), @@ -739,9 +741,10 @@ class ApiQuerySiteinfo extends ApiQueryBase { foreach ( $langNames as $langCode ) { $lang = MediaWikiServices::getInstance()->getLanguageFactory() ->getLanguage( $langCode ); - if ( $lang->getConverter() instanceof FakeConverter ) { - // Only languages which do not return instances of - // FakeConverter implement language conversion. + $langConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $lang ); + if ( !$langConverter->hasVariants() ) { + // Only languages which has conversions can be processed continue; } $data[$langCode] = []; @@ -751,7 +754,7 @@ class ApiQuerySiteinfo extends ApiQueryBase { $variants = $lang->getVariants(); sort( $variants ); foreach ( $variants as $v ) { - $fallbacks = $lang->getConverter()->getVariantFallbacks( $v ); + $fallbacks = $langConverter->getVariantFallbacks( $v ); if ( !is_array( $fallbacks ) ) { $fallbacks = [ $fallbacks ]; } diff --git a/includes/auth/AuthManager.php b/includes/auth/AuthManager.php index 7cfbaf4d590..d9c40a2d94e 100644 --- a/includes/auth/AuthManager.php +++ b/includes/auth/AuthManager.php @@ -2421,8 +2421,10 @@ class AuthManager implements LoggerAwareInterface { $lang = $useContextLang ? \RequestContext::getMain()->getLanguage() : $contLang; $user->setOption( 'language', $lang->getPreferredVariant() ); - if ( $contLang->hasVariants() ) { - $user->setOption( 'variant', $contLang->getPreferredVariant() ); + $contLangConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + if ( $contLangConverter->hasVariants() ) { + $user->setOption( 'variant', $contLangConverter->getPreferredVariant() ); } } diff --git a/includes/cache/MessageCache.php b/includes/cache/MessageCache.php index 4e093fd4677..f3c6729d2b7 100644 --- a/includes/cache/MessageCache.php +++ b/includes/cache/MessageCache.php @@ -103,6 +103,8 @@ class MessageCache implements LoggerAwareInterface { protected $srvCache; /** @var Language */ protected $contLang; + /** @var ILanguageConverter */ + protected $contLangConverter; /** @var LanguageFactory */ protected $langFactory; /** @var LocalisationCache */ @@ -142,6 +144,7 @@ class MessageCache implements LoggerAwareInterface { * @param BagOStuff $clusterCache * @param BagOStuff $serverCache * @param Language $contLang Content language of site + * @param ILanguageConverter $contLangConverter Content language converter for site * @param LoggerInterface $logger * @param array $options * - useDB (bool): Whether to allow message overrides from "MediaWiki:" pages. @@ -154,6 +157,7 @@ class MessageCache implements LoggerAwareInterface { BagOStuff $clusterCache, BagOStuff $serverCache, Language $contLang, + ILanguageConverter $contLangConverter, LoggerInterface $logger, array $options, LanguageFactory $langFactory, @@ -163,6 +167,7 @@ class MessageCache implements LoggerAwareInterface { $this->clusterCache = $clusterCache; $this->srvCache = $serverCache; $this->contLang = $contLang; + $this->contLangConverter = $contLangConverter; $this->logger = $logger; $this->langFactory = $langFactory; $this->localisationCache = $localisationCache; @@ -1383,8 +1388,8 @@ class MessageCache implements LoggerAwareInterface { $this->replace( $title->getDBkey(), $msgText ); - if ( $this->contLang->hasVariants() ) { - $this->contLang->updateConversionTable( $title ); + if ( $this->contLangConverter->hasVariants() ) { + $this->contLangConverter->updateConversionTable( $title ); } } diff --git a/includes/content/ContentHandler.php b/includes/content/ContentHandler.php index 59719d1d851..f718731ad23 100644 --- a/includes/content/ContentHandler.php +++ b/includes/content/ContentHandler.php @@ -753,7 +753,7 @@ abstract class ContentHandler { if ( $title->getNamespace() !== NS_MEDIAWIKI ) { // If the user chooses a variant, the content is actually // in a language whose code is the variant code. - $variant = $pageLang->getPreferredVariant(); + $variant = $this->getLanguageConverter( $pageLang )->getPreferredVariant(); if ( $pageLang->getCode() !== $variant ) { $pageLang = MediaWikiServices::getInstance()->getLanguageFactory() ->getLanguage( $variant ); @@ -818,6 +818,16 @@ abstract class ContentHandler { return false; } + /** + * Shorthand for getting a Language Converter for specific language + * @param Language $language Language of converter + * @return ILanguageConverter + */ + private function getLanguageConverter( Language $language ) : ILanguageConverter { + return MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $language ); + } + /** * Return type of change if one exists for the given edit. * diff --git a/includes/deferred/LinksUpdate.php b/includes/deferred/LinksUpdate.php index 35b5c513b23..f0c2e298af0 100644 --- a/includes/deferred/LinksUpdate.php +++ b/includes/deferred/LinksUpdate.php @@ -621,11 +621,14 @@ class LinksUpdate extends DataUpdate { global $wgCategoryCollation; $diffs = array_diff_assoc( $this->mCategories, $existing ); $arr = []; - $contLang = MediaWikiServices::getInstance()->getContentLanguage(); + + $languageConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + $collation = Collation::singleton(); foreach ( $diffs as $name => $prefix ) { $nt = Title::makeTitleSafe( NS_CATEGORY, $name ); - $contLang->findVariantLink( $name, $nt, true ); + $languageConverter->findVariantLink( $name, $nt, true ); $type = MediaWikiServices::getInstance()->getNamespaceInfo()-> getCategoryLinkType( $this->mTitle->getNamespace() ); diff --git a/includes/language/ConverterRule.php b/includes/language/ConverterRule.php index 4a330ad6acd..70ca8f1c13d 100644 --- a/includes/language/ConverterRule.php +++ b/includes/language/ConverterRule.php @@ -26,6 +26,9 @@ */ class ConverterRule { public $mText; // original text in -{text}- + /** + * @var LanguageConverter + */ public $mConverter; // LanguageConverter object public $mRuleDisplay = ''; public $mRuleTitle = false; @@ -41,7 +44,7 @@ class ConverterRule { * @param string $text The text between -{ and }- * @param LanguageConverter $converter */ - public function __construct( $text, $converter ) { + public function __construct( $text, LanguageConverter $converter ) { $this->mText = $text; $this->mConverter = $converter; } @@ -117,7 +120,7 @@ class ConverterRule { } // try to find flags like "zh-hans", "zh-hant" // allow syntaxes like "-{zh-hans;zh-hant|XXXX}-" - $variantFlags = array_intersect( array_keys( $flags ), $this->mConverter->mVariants ); + $variantFlags = array_intersect( array_keys( $flags ), $this->mConverter->getVariants() ); if ( $variantFlags ) { $variantFlags = array_flip( $variantFlags ); $flags = []; @@ -136,7 +139,7 @@ class ConverterRule { $rules = $this->mRules; $bidtable = []; $unidtable = []; - $variants = $this->mConverter->mVariants; + $variants = $this->mConverter->getVariants(); $varsep_pattern = $this->mConverter->getVarSeparatorPattern(); // Split according to $varsep_pattern, but ignore semicolons from HTML entities diff --git a/includes/language/LanguageFactory.php b/includes/language/LanguageFactory.php index 4c9289d13c9..21d96a22d10 100644 --- a/includes/language/LanguageFactory.php +++ b/includes/language/LanguageFactory.php @@ -53,6 +53,9 @@ class LanguageFactory { /** @var LanguageFallback */ private $langFallback; + /** @var LanguageConverterFactory */ + private $langConverterFactory; + /** @var array */ private $langObjCache = []; @@ -73,12 +76,14 @@ class LanguageFactory { * @param LocalisationCache $localisationCache * @param LanguageNameUtils $langNameUtils * @param LanguageFallback $langFallback + * @param LanguageConverterFactory $langConverterFactory */ public function __construct( ServiceOptions $options, LocalisationCache $localisationCache, LanguageNameUtils $langNameUtils, - LanguageFallback $langFallback + LanguageFallback $langFallback, + LanguageConverterFactory $langConverterFactory ) { $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); @@ -86,6 +91,7 @@ class LanguageFactory { $this->localisationCache = $localisationCache; $this->langNameUtils = $langNameUtils; $this->langFallback = $langFallback; + $this->langConverterFactory = $langConverterFactory; } /** @@ -142,7 +148,8 @@ class LanguageFactory { $code, $this->localisationCache, $this->langNameUtils, - $this->langFallback + $this->langFallback, + $this->langConverterFactory, ]; if ( !$this->langNameUtils->isValidBuiltInCode( $code ) ) { @@ -202,7 +209,8 @@ class LanguageFactory { } $lang = $this->getLanguage( $codeBase ); - if ( !$lang->hasVariant( $code ) ) { + $converter = $this->langConverterFactory->getLanguageConverter( $lang ); + if ( !$converter->hasVariant( $code ) ) { $this->parentLangCache[$code] = null; return null; } diff --git a/includes/parser/CoreParserFunctions.php b/includes/parser/CoreParserFunctions.php index 784ca5d5740..3515d11fa2a 100644 --- a/includes/parser/CoreParserFunctions.php +++ b/includes/parser/CoreParserFunctions.php @@ -368,6 +368,16 @@ class CoreParserFunctions { return $parser->getFunctionLang()->embedBidi( $text ); } + /** + * Shorthand for getting a Language Converter for Target language + * @param Parser $parser Parent parser + * @return ILanguageConverter + */ + private static function getTargetLanguageConverter( Parser $parser ) : ILanguageConverter { + return MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $parser->getTargetLanguage() ); + } + /** * Override the title of the page when viewed, provided we've been given a * title which will normalise to the canonical title @@ -441,7 +451,8 @@ class CoreParserFunctions { $parser->mOutput->setDisplayTitle( $text ); } if ( $old !== false && $old !== $text && !$arg ) { - $converter = $parser->getTargetLanguage()->getConverter(); + + $converter = self::getTargetLanguageConverter( $parser ); return '' . wfMessage( 'duplicate-displaytitle', // Message should be parsed, but these params should only be escaped. diff --git a/includes/parser/LinkHolderArray.php b/includes/parser/LinkHolderArray.php index 61ba809d832..a4346c55e0c 100644 --- a/includes/parser/LinkHolderArray.php +++ b/includes/parser/LinkHolderArray.php @@ -41,10 +41,18 @@ class LinkHolderArray { protected $tempIdOffset; /** - * @param Parser $parent + * Current language converter + * @var ILanguageConverter */ - public function __construct( $parent ) { + private $languageConverter; + + /** + * @param Parser $parent + * @param ILanguageConverter $languageConverter + */ + public function __construct( $parent, ILanguageConverter $languageConverter ) { $this->parent = $parent; + $this->languageConverter = $languageConverter; } /** @@ -238,7 +246,7 @@ class LinkHolderArray { } # Do a second query for different language variants of links and categories - if ( $this->parent->getContentLanguage()->hasVariants() ) { + if ( $this->languageConverter->hasVariants() ) { $this->doVariants( $colours ); } @@ -354,7 +362,7 @@ class LinkHolderArray { } // Now do the conversion and explode string to text of titles - $titlesAllVariants = $this->parent->getContentLanguage()-> + $titlesAllVariants = $this->languageConverter-> autoConvertToAllVariants( rtrim( $titlesToBeConverted, "\0" ) ); $allVariantsName = array_keys( $titlesAllVariants ); foreach ( $titlesAllVariants as &$titlesVariant ) { @@ -396,7 +404,7 @@ class LinkHolderArray { foreach ( $output->getCategoryLinks() as $category ) { $categoryTitle = Title::makeTitleSafe( NS_CATEGORY, $category ); $linkBatch->addObj( $categoryTitle ); - $variants = $this->parent->getContentLanguage()->autoConvertToAllVariants( $category ); + $variants = $this->languageConverter->autoConvertToAllVariants( $category ); foreach ( $variants as $variant ) { if ( $variant !== $category ) { $variantTitle = Title::makeTitleSafe( NS_CATEGORY, $variant ); diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index 2f7cc63ec98..a1dfa81a392 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -481,7 +481,7 @@ class Parser { $this->resetOutput(); $this->mAutonumber = 0; $this->mIncludeCount = []; - $this->mLinkHolders = new LinkHolderArray( $this ); + $this->mLinkHolders = new LinkHolderArray( $this, $this->getContentLanguageConverter() ); $this->mLinkID = 0; $this->mRevisionObject = $this->mRevisionTimestamp = $this->mRevisionId = $this->mRevisionUser = $this->mRevisionSize = null; @@ -602,11 +602,11 @@ class Parser { || isset( $this->mDoubleUnderscores['notitleconvert'] ) || $this->mOutput->getDisplayTitle() !== false ) ) { - $convruletitle = $this->getTargetLanguage()->getConvRuleTitle(); + $convruletitle = $this->getTargetLanguageConverter()->getConvRuleTitle(); if ( $convruletitle ) { $this->mOutput->setTitleText( $convruletitle ); } else { - $titleText = $this->getTargetLanguage()->convertTitle( $title ); + $titleText = $this->getTargetLanguageConverter()->convertTitle( $title ); $this->mOutput->setTitleText( $titleText ); } } @@ -1514,6 +1514,26 @@ class Parser { return $text; } + /** + * Shorthand for getting a Language Converter for Target language + * + * @return ILanguageConverter + */ + private function getTargetLanguageConverter() : ILanguageConverter { + return MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $this->getTargetLanguage() ); + } + + /** + * Shorthand for getting a Language Converter for Content language + * + * @return ILanguageConverter + */ + private function getContentLanguageConverter() : ILanguageConverter { + return MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $this->getContentLanguage() ); + } + /** * Helper function for parse() that transforms half-parsed HTML into fully * parsed HTML. @@ -1550,7 +1570,7 @@ class Parser { # The position of the convert() call should not be changed. it # assumes that the links are all replaced and the only thing left # is the mark. - $text = $this->getTargetLanguage()->convert( $text ); + $text = $this->getTargetLanguageConverter()->convert( $text ); } $text = $this->mStripState->unstripNoWiki( $text ); @@ -1781,7 +1801,7 @@ class Parser { if ( $text === false ) { # Not an image, make a link $text = Linker::makeExternalLink( $url, - $this->getTargetLanguage()->getConverter()->markNoConversion( $url ), + $this->getTargetLanguageConverter()->markNoConversion( $url ), true, 'free', $this->getExternalLinkAttribs( $url ), $this->getTitle() ); # Register it in the output object... @@ -2065,7 +2085,7 @@ class Parser { // Excluding protocol-relative URLs may avoid many false positives. if ( preg_match( '/^(?:' . wfUrlProtocolsWithoutProtRel() . ')/', $text ) ) { - $text = $this->getTargetLanguage()->getConverter()->markNoConversion( $text ); + $text = $this->getTargetLanguageConverter()->markNoConversion( $text ); } $url = Sanitizer::cleanUrl( $url ); @@ -2306,7 +2326,7 @@ class Parser { $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; } - $holders = new LinkHolderArray( $this ); + $holders = new LinkHolderArray( $this, $this->getContentLanguageConverter() ); # split the entire text string on occurrences of [[ $a = StringUtils::explode( '[[', ' ' . $s ); @@ -2547,7 +2567,7 @@ class Parser { } $sortkey = Sanitizer::decodeCharReferences( $sortkey ); $sortkey = str_replace( "\n", '', $sortkey ); - $sortkey = $this->getTargetLanguage()->convertCategoryKey( $sortkey ); + $sortkey = $this->getTargetLanguageConverter()->convertCategoryKey( $sortkey ); $this->mOutput->addCategory( $nt->getDBkey(), $sortkey ); continue; @@ -3316,8 +3336,8 @@ class Parser { if ( $title ) { $titleText = $title->getPrefixedText(); # Check for language variants if the template is not found - if ( $this->getTargetLanguage()->hasVariants() && $title->getArticleID() == 0 ) { - $this->getTargetLanguage()->findVariantLink( $part1, $title, true ); + if ( $this->getTargetLanguageConverter()->hasVariants() && $title->getArticleID() == 0 ) { + $this->getTargetLanguageConverter()->findVariantLink( $part1, $title, true ); } # Do recursion depth check $limit = $this->mOptions->getMaxTemplateDepth(); diff --git a/includes/parser/ParserOptions.php b/includes/parser/ParserOptions.php index e36eab12522..4a6654a227b 100644 --- a/includes/parser/ParserOptions.php +++ b/includes/parser/ParserOptions.php @@ -1348,12 +1348,12 @@ class ParserOptions { // add in language specific options, if any // @todo FIXME: This is just a way of retrieving the url/user preferred variant - if ( $title !== null ) { - $confstr .= $title->getPageLanguage()->getExtraHashOptions(); - } else { - $confstr .= - MediaWikiServices::getInstance()->getContentLanguage()->getExtraHashOptions(); - } + + $lang = $title ? $title->getPageLanguage() : + MediaWikiServices::getInstance()->getContentLanguage(); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $lang ); + $confstr .= $converter->getExtraHashOptions(); $confstr .= $wgRenderHashAppend; diff --git a/includes/preferences/DefaultPreferencesFactory.php b/includes/preferences/DefaultPreferencesFactory.php index 40d4d4396ca..364b5a95e85 100644 --- a/includes/preferences/DefaultPreferencesFactory.php +++ b/includes/preferences/DefaultPreferencesFactory.php @@ -469,13 +469,17 @@ class DefaultPreferencesFactory implements PreferencesFactory { // see if there are multiple language variants to choose from if ( !$this->options->get( 'DisableLangConversion' ) ) { + + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $this->contLang ); + foreach ( LanguageConverter::$languagesWithVariants as $langCode ) { if ( $langCode == $this->contLang->getCode() ) { - if ( !$this->contLang->hasVariants() ) { + if ( !$converter->hasVariants() ) { continue; } - $variants = $this->contLang->getVariants(); + $variants = $converter->getVariants(); $variantArray = []; foreach ( $variants as $v ) { $v = str_replace( '_', '-', strtolower( $v ) ); diff --git a/includes/search/SearchNearMatcher.php b/includes/search/SearchNearMatcher.php index cbdad3339b9..3f6d2f6e50d 100644 --- a/includes/search/SearchNearMatcher.php +++ b/includes/search/SearchNearMatcher.php @@ -18,9 +18,17 @@ class SearchNearMatcher { */ private $language; + /** + * Current language converter + * @var ILanguageConverter + */ + private $languageConverter; + public function __construct( Config $config, Language $lang ) { $this->config = $config; $this->language = $lang; + $this->languageConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $lang ); } /** @@ -57,10 +65,10 @@ class SearchNearMatcher { $lang = $this->language; $allSearchTerms = [ $searchterm ]; - if ( $lang->hasVariants() ) { + if ( $this->languageConverter->hasVariants() ) { $allSearchTerms = array_unique( array_merge( $allSearchTerms, - $lang->autoConvertToAllVariants( $searchterm ) + $this->languageConverter->autoConvertToAllVariants( $searchterm ) ) ); } diff --git a/includes/search/SearchSqlite.php b/includes/search/SearchSqlite.php index 45a849f3eb4..45bc6ca0034 100644 --- a/includes/search/SearchSqlite.php +++ b/includes/search/SearchSqlite.php @@ -79,8 +79,10 @@ class SearchSqlite extends SearchDatabase { // Some languages such as Serbian store the input form in the search index, // so we may need to search for matches in multiple writing system variants. - $convertedVariants = MediaWikiServices::getInstance()->getContentLanguage()-> - autoConvertToAllVariants( $term ); + + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + $convertedVariants = $converter->autoConvertToAllVariants( $term ); if ( is_array( $convertedVariants ) ) { $variants = array_unique( array_values( $convertedVariants ) ); } else { diff --git a/includes/skins/SkinTemplate.php b/includes/skins/SkinTemplate.php index 18a01ffbdee..601133341ff 100644 --- a/includes/skins/SkinTemplate.php +++ b/includes/skins/SkinTemplate.php @@ -860,6 +860,16 @@ class SkinTemplate extends Skin { ]; } + /** + * Shorthand for getting a Language Converter for specific language + * @param Language $language Language of converter + * @return ILanguageConverter + */ + private function getLanguageConverter( Language $language ) : ILanguageConverter { + return MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $language ); + } + /** * a structured array of links usually used for the tabs in a skin * @@ -1143,14 +1153,15 @@ class SkinTemplate extends Skin { if ( $userCanRead && !$wgDisableLangConversion ) { $pageLang = $title->getPageLanguage(); + $converter = $this->getLanguageConverter( $pageLang ); // Checks that language conversion is enabled and variants exist // And if it is not in the special namespace - if ( $pageLang->hasVariants() ) { + if ( $converter->hasVariants() ) { // Gets list of language variants - $variants = $pageLang->getVariants(); + $variants = $converter->getVariants(); // Gets preferred variant (note that user preference is // only possible for wiki content language variant) - $preferred = $pageLang->getPreferredVariant(); + $preferred = $converter->getPreferredVariant(); if ( Action::getActionName( $this ) === 'view' ) { $params = $request->getQueryValues(); unset( $params['title'] ); diff --git a/includes/specialpage/PageQueryPage.php b/includes/specialpage/PageQueryPage.php index c9cf8d72feb..acbbfeb657c 100644 --- a/includes/specialpage/PageQueryPage.php +++ b/includes/specialpage/PageQueryPage.php @@ -52,10 +52,10 @@ abstract class PageQueryPage extends QueryPage { */ public function formatResult( $skin, $row ) { $title = Title::makeTitleSafe( $row->namespace, $row->title ); - if ( $title instanceof Title ) { - $text = MediaWikiServices::getInstance()->getContentLanguage()-> - convert( htmlspecialchars( $title->getPrefixedText() ) ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + $text = $converter->convertHtml( $title->getPrefixedText() ); return $this->getLinkRenderer()->makeLink( $title, new HtmlArmor( $text ) ); } else { return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ], diff --git a/includes/specials/SpecialAncientPages.php b/includes/specials/SpecialAncientPages.php index a17c1219ec8..8cda8326d98 100644 --- a/includes/specials/SpecialAncientPages.php +++ b/includes/specials/SpecialAncientPages.php @@ -93,10 +93,13 @@ class SpecialAncientPages extends QueryPage { $d = $this->getLanguage()->userTimeAndDate( $result->value, $this->getUser() ); $title = Title::makeTitle( $result->namespace, $result->title ); $linkRenderer = $this->getLinkRenderer(); + + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + $link = $linkRenderer->makeKnownLink( $title, - new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()-> - convert( htmlspecialchars( $title->getPrefixedText() ) ) ) + new HtmlArmor( $converter->convertHtml( $title->getPrefixedText() ) ) ); return $this->getLanguage()->specialList( $link, htmlspecialchars( $d ) ); diff --git a/includes/specials/SpecialFewestRevisions.php b/includes/specials/SpecialFewestRevisions.php index 204d73a625d..08280f8d526 100644 --- a/includes/specials/SpecialFewestRevisions.php +++ b/includes/specials/SpecialFewestRevisions.php @@ -85,8 +85,11 @@ class SpecialFewestRevisions extends QueryPage { ); } $linkRenderer = $this->getLinkRenderer(); - $text = MediaWikiServices::getInstance()->getContentLanguage()-> - convert( htmlspecialchars( $nt->getPrefixedText() ) ); + + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + + $text = $converter->convertHtml( $nt->getPrefixedText() ); $plink = $linkRenderer->makeLink( $nt, new HtmlArmor( $text ) ); $nl = $this->msg( 'nrevisions' )->numParams( $result->value )->text(); diff --git a/includes/specials/SpecialMIMESearch.php b/includes/specials/SpecialMIMESearch.php index eac14256064..9348d2ebceb 100644 --- a/includes/specials/SpecialMIMESearch.php +++ b/includes/specials/SpecialMIMESearch.php @@ -189,8 +189,9 @@ class SpecialMIMESearch extends QueryPage { function formatResult( $skin, $result ) { $linkRenderer = $this->getLinkRenderer(); $nt = Title::makeTitle( $result->namespace, $result->title ); - $text = MediaWikiServices::getInstance()->getContentLanguage() - ->convert( htmlspecialchars( $nt->getText() ) ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + $text = $converter->convertHtml( $nt->getText() ); $plink = $linkRenderer->makeLink( Title::newFromText( $nt->getPrefixedText() ), new HtmlArmor( $text ) diff --git a/includes/specials/SpecialMostLinkedCategories.php b/includes/specials/SpecialMostLinkedCategories.php index 470a34b87a5..89d5a922f04 100644 --- a/includes/specials/SpecialMostLinkedCategories.php +++ b/includes/specials/SpecialMostLinkedCategories.php @@ -84,8 +84,11 @@ class SpecialMostLinkedCategories extends QueryPage { ); } - $text = MediaWikiServices::getInstance()->getContentLanguage() - ->convert( htmlspecialchars( $nt->getText() ) ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + + $text = $converter->convertHtml( $nt->getText() ); + $plink = $this->getLinkRenderer()->makeLink( $nt, new HtmlArmor( $text ) ); $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped(); diff --git a/includes/specials/SpecialUnwatchedPages.php b/includes/specials/SpecialUnwatchedPages.php index b50d1bdf2a5..f620e97fceb 100644 --- a/includes/specials/SpecialUnwatchedPages.php +++ b/includes/specials/SpecialUnwatchedPages.php @@ -117,8 +117,10 @@ class SpecialUnwatchedPages extends QueryPage { Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); } - $text = MediaWikiServices::getInstance()->getContentLanguage()-> - convert( htmlspecialchars( $nt->getPrefixedText() ) ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + + $text = $converter->convertHtml( $nt->getPrefixedText() ); $linkRenderer = $this->getLinkRenderer(); diff --git a/includes/specials/SpecialWantedCategories.php b/includes/specials/SpecialWantedCategories.php index 659650c6ab8..9cd21ce7421 100644 --- a/includes/specials/SpecialWantedCategories.php +++ b/includes/specials/SpecialWantedCategories.php @@ -91,8 +91,9 @@ class SpecialWantedCategories extends WantedQueryPage { */ function formatResult( $skin, $result ) { $nt = Title::makeTitle( $result->namespace, $result->title ); - $text = new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage() - ->convert( htmlspecialchars( $nt->getText() ) ) ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + $text = new HtmlArmor( $converter->convertHtml( $nt->getText() ) ); if ( !$this->isCached() ) { // We can assume the freshest data diff --git a/includes/user/User.php b/includes/user/User.php index 9d7830921df..a4d948575d0 100644 --- a/includes/user/User.php +++ b/includes/user/User.php @@ -5157,7 +5157,8 @@ class User implements IDBAccessObject, UserIdentity { // There's no need to do it for logged-in users: they can set preferences, // and handling of page content is done by $pageLang->getPreferredVariant() and such, // so don't override user's choice (especially when the user chooses site default). - $variant = MediaWikiServices::getInstance()->getContentLanguage()->getDefaultVariant(); + $factory = MediaWikiServices::getInstance()->getLanguageConverterFactory(); + $variant = $factory->getLanguageConverter()->getDefaultVariant(); $this->mOptions['variant'] = $variant; $this->mOptions['language'] = $variant; $this->mOptionsLoaded = true; diff --git a/includes/widget/search/BasicSearchResultSetWidget.php b/includes/widget/search/BasicSearchResultSetWidget.php index 698d22315b2..d90c39b5889 100644 --- a/includes/widget/search/BasicSearchResultSetWidget.php +++ b/includes/widget/search/BasicSearchResultSetWidget.php @@ -94,7 +94,9 @@ class BasicSearchResultSetWidget { // Convert the whole thing to desired language variant // TODO: Move this up to Special:Search? - return MediaWikiServices::getInstance()->getContentLanguage()->convert( $out ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter(); + return $converter->convert( $out ); } /** diff --git a/languages/ILanguageConverter.php b/languages/ILanguageConverter.php new file mode 100644 index 00000000000..c7843c3efd7 --- /dev/null +++ b/languages/ILanguageConverter.php @@ -0,0 +1,239 @@ +mVariants directly. + * @return string[] Contains all valid variants + */ + public function getVariants(); + + /** + * In case some variant is not defined in the markup, we need + * to have some fallback. For example, in zh, normally people + * will define zh-hans and zh-hant, but less so for zh-sg or zh-hk. + * when zh-sg is preferred but not defined, we will pick zh-hans + * in this case. Right now this is only used by zh. + * + * @param string $variant The language code of the variant + * @return string|array The code of the fallback language or the + * main code if there is no fallback + */ + public function getVariantFallbacks( $variant ); + + /** + * Get the title produced by the conversion rule. + * @return string The converted title text + */ + public function getConvRuleTitle(); + + /** + * Get preferred language variant. + * @return string The preferred language code + */ + public function getPreferredVariant(); + + /** + * Get default variant. + * This function would not be affected by user's settings + * @return string The default variant code + */ + public function getDefaultVariant(); + + /** + * Validate the variant and return an appropriate strict internal + * variant code if one exists. Compare to Language::hasVariant() + * which does a strict test. + * + * @param string|null $variant The variant to validate + * @return mixed Returns an equivalent valid variant code if possible, + * null otherwise + */ + public function validateVariant( $variant = null ); + + /** + * Get the variant specified in the URL + * + * @return mixed Variant if one found, null otherwise + */ + public function getURLVariant(); + + /** + * Dictionary-based conversion. + * This function would not parse the conversion rules. + * If you want to parse rules, try to use convert() or + * convertTo(). + * + * @param string $text The text to be converted + * @param bool|string $toVariant The target language code + * @return string The converted text + */ + public function autoConvert( $text, $toVariant = false ); + + /** + * Translate a string to a variant. + * Doesn't parse rules or do any of that other stuff, for that use + * convert() or convertTo(). + * + * @param string $text Text to convert + * @param string $variant Variant language code + * @return string Translated text + */ + public function translate( $text, $variant ); + + /** + * Call translate() to convert text to all valid variants. + * + * @param string $text The text to be converted + * @return array Variant => converted text + */ + public function autoConvertToAllVariants( $text ); + + /** + * Auto convert a Title object to a readable string in the + * preferred variant. + * + * @param Title $title A object of Title + * @return string Converted title text + */ + public function convertTitle( $title ); + + /** + * Get the namespace display name in the preferred variant. + * + * @param int $index Namespace id + * @param string|null $variant Variant code or null for preferred variant + * @return string Namespace name for display + */ + public function convertNamespace( $index, $variant = null ); + + /** + * Convert text to different variants of a language. The automatic + * conversion is done in autoConvert(). Here we parse the text + * marked with -{}-, which specifies special conversions of the + * text that can not be accomplished in autoConvert(). + * + * Syntax of the markup: + * -{code1:text1;code2:text2;...}- or + * -{flags|code1:text1;code2:text2;...}- or + * -{text}- in which case no conversion should take place for text + * + * @warning Glossary state is maintained between calls. Never feed this + * method input that hasn't properly been escaped as it may result in + * an XSS in subsequent calls, even if those subsequent calls properly + * escape things. + * @param string $text Text to be converted, already html escaped. + * @return string Converted text (html) + */ + public function convert( $text ); + + /** + * Same as convert() except a extra parameter to custom variant. + * + * @param string $text Text to be converted, already html escaped + * @param-taint $text exec_html + * @param string $variant The target variant code + * @return string Converted text + * @return-taint escaped + */ + public function convertTo( $text, $variant ); + + /** + * If a language supports multiple variants, it is possible that + * non-existing link in one variant actually exists in another variant. + * This function tries to find it. See e.g. LanguageZh.php + * The input parameters may be modified upon return + * + * @param string &$link The name of the link + * @param Title &$nt The title object of the link + * @param bool $ignoreOtherCond To disable other conditions when + * we need to transclude a template or update a category's link + */ + public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ); + + /** + * Returns language specific hash options. + * + * @return string + */ + public function getExtraHashOptions(); + + /** + * Guess if a text is written in a variant. This should be implemented in subclasses. + * + * @param string $text The text to be checked + * @param string $variant Language code of the variant to be checked for + * @return bool True if $text appears to be written in $variant, false if not + * + * @author Nikola Smolenski + * @since 1.19 + */ + public function guessVariant( $text, $variant ); + + /** + * Enclose a string with the "no conversion" tag. This is used by + * various functions in the Parser. + * + * @param string $text Text to be tagged for no conversion + * @param bool $noParse Unused + * @return string The tagged text + */ + public function markNoConversion( $text, $noParse = false ); + + /** + * Convert the sorting key for category links. This should make different + * keys that are variants of each other map to the same key. + * + * @param string $key + * + * @return string + */ + public function convertCategoryKey( $key ); + + /** + * Refresh the cache of conversion tables when + * MediaWiki:Conversiontable* is updated. + * + * @param Title $title The Title of the page being updated + */ + public function updateConversionTable( Title $title ); + + /** + * Check if this is a language with variants + * + * @since 1.35 + * + * @return bool + */ + public function hasVariants(); + + /** + * Strict check if the language has the specific variant. + * + * Compare to LanguageConverter::validateVariant() which does a more + * lenient check and attempts to coerce the given code to a valid one. + * + * @since 1.35 + * @param string $variant + * @return bool + */ + public function hasVariant( $variant ); + + /** + * Perform output conversion on a string, and encode for safe HTML output. + * + * @since 1.35 + * + * @param string $text Text to be converted + * @return string string converted to be safely used in HTML + */ + public function convertHtml( $text ); +} diff --git a/languages/Language.php b/languages/Language.php index 29ff9e41598..9331a1902e6 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -27,6 +27,7 @@ */ use CLDRPluralRuleParser\Evaluator; +use MediaWiki\Languages\LanguageConverterFactory; use MediaWiki\Languages\LanguageFallback; use MediaWiki\Languages\LanguageNameUtils; use MediaWiki\MediaWikiServices; @@ -60,9 +61,19 @@ class Language { const SUPPORTED = LanguageNameUtils::SUPPORTED; /** - * @var LanguageConverter|FakeConverter + * Use PHP's magic __get handler to handle lazy accessing to + * deprecated mConverter. + * + * @param string $name Field name + * @return mixed */ - public $mConverter; + public function __get( string $name ) { + if ( $name == "mConverter" ) { + wfDeprecated( 'Language::mConverter', '1.35' ); + return $this->getConverter(); + } + throw new RuntimeException( "Cannot get '$name' property." ); + } public $mVariants, $mCode, $mLoaded = false; public $mMagicExtensions = []; @@ -94,6 +105,11 @@ class Language { /** @var array[]|null */ private $grammarTransformCache; + /** + * @var LanguageConverterFactory + */ + private $converterFactory; + /** * @deprecated since 1.35, use LanguageFactory * @var array @@ -454,14 +470,15 @@ class Language { * @param LocalisationCache|null $localisationCache * @param LanguageNameUtils|null $langNameUtils * @param LanguageFallback|null $langFallback + * @param LanguageConverterFactory|null $converterFactory */ public function __construct( $code = null, LocalisationCache $localisationCache = null, LanguageNameUtils $langNameUtils = null, - LanguageFallback $langFallback = null + LanguageFallback $langFallback = null, + LanguageConverterFactory $converterFactory = null ) { - $this->mConverter = $this->newConverter(); if ( !func_num_args() ) { // Old calling convention, deprecated if ( static::class === 'Language' ) { @@ -469,10 +486,12 @@ class Language { } else { $this->mCode = str_replace( '_', '-', strtolower( substr( static::class, 8 ) ) ); } + $services = MediaWikiServices::getInstance(); $this->localisationCache = $services->getLocalisationCache(); $this->langNameUtils = $services->getLanguageNameUtils(); $this->langFallback = $services->getLanguageFallback(); + $this->converterFactory = $services->getLanguageConverterFactory(); return; } @@ -484,11 +503,14 @@ class Language { 'Parameters cannot be null unless all are omitted' ); Assert::parameter( $langFallback !== null, '$langFallback', 'Parameters cannot be null unless all are omitted' ); + Assert::parameter( $converterFactory !== null, '$converterFactory', + 'Parameters cannot be null unless all are omitted' ); $this->mCode = $code; $this->localisationCache = $localisationCache; $this->langNameUtils = $langNameUtils; $this->langFallback = $langFallback; + $this->converterFactory = $converterFactory; } /** @@ -708,7 +730,7 @@ class Language { # Also add converted namespace names as aliases, to avoid confusion. $convertedNames = []; - foreach ( $this->getVariants() as $variant ) { + foreach ( $this->getConverter()->getVariants() as $variant ) { if ( $variant === $this->mCode ) { continue; } @@ -4015,46 +4037,43 @@ class Language { return $text; } - /** - * Construct a new LanguageConverter suitable for this language. Languages that support variants - * need to override this method appropriately. - * - * @return LanguageConverter|FakeConverter - */ - protected function newConverter() { - return new FakeConverter( $this ); - } - /** * Return the LanguageConverter used in the Language * * @since 1.19 - * @return LanguageConverter + * @deprecated since 1.35 Use MediaWikiServices::getInstance()->getLanguageConverterFactory() + * ->getLanguageConverter( $language ) instead + * + * @return ILanguageConverter */ - public function getConverter() { - return $this->mConverter; + public function getConverter() : ILanguageConverter { + return $this->converterFactory->getLanguageConverter( $this ); } /** * convert text to a variant * + * @deprecated since 1.35 use LanguageConverter::autoConvert + * * @param string $text text to convert * @param string|bool $variant variant to convert to, or false to use the user's preferred * variant (if logged in), or the project default variant * @return string the converted string */ public function autoConvert( $text, $variant = false ) { - return $this->mConverter->autoConvert( $text, $variant ); + return $this->getConverter()->autoConvert( $text, $variant ); } /** * convert text to all supported variants * + * @deprecated since 1.35 use LanguageConverter::autoConvertToAllVariants + * * @param string $text * @return array */ public function autoConvertToAllVariants( $text ) { - return $this->mConverter->autoConvertToAllVariants( $text ); + return $this->getConverter()->autoConvertToAllVariants( $text ); } /** @@ -4065,38 +4084,47 @@ class Language { * in later calls to this method, even if the later calls have properly * escaped the input. Never feed this method user controlled text that * is not properly escaped! + * + * @deprecated since 1.35 use LanguageConverter::convert + * * @param string $text Content that has been already escaped for use in HTML * @return string HTML */ public function convert( $text ) { - return $this->mConverter->convert( $text ); + return $this->getConverter()->convert( $text ); } /** * Convert a Title object to a string in the preferred variant * + * @deprecated since 1.35 use LanguageConverter::convertTitle + * * @param Title $title * @return string */ public function convertTitle( $title ) { - return $this->mConverter->convertTitle( $title ); + return $this->getConverter()->convertTitle( $title ); } /** * Convert a namespace index to a string in the preferred variant * + * @deprecated since 1.35 use LanguageConverter::convertNamespace instead + * * @param int $ns namespace index (https://www.mediawiki.org/wiki/Manual:Namespace) * @param string|null $variant variant to convert to, or null to use the user's preferred * variant (if logged in), or the project default variant * @return string a string representation of the namespace */ public function convertNamespace( $ns, $variant = null ) { - return $this->mConverter->convertNamespace( $ns, $variant ); + return $this->getConverter()->convertNamespace( $ns, $variant ); } /** * Check if this is a language with variants * + * @deprecated since 1.35 use LanguageConverter::hasVariants instead + * * @return bool */ public function hasVariants() { @@ -4109,16 +4137,21 @@ class Language { * Compare to LanguageConverter::validateVariant() which does a more * lenient check and attempts to coerce the given code to a valid one. * + * @deprecated since 1.35 use LanguageConverter::hasVariant instead + * * @since 1.19 * @param string $variant * @return bool */ public function hasVariant( $variant ) { - return $variant && ( $variant === $this->mConverter->validateVariant( $variant ) ); + return $this->getConverter()->hasVariant( $variant ); } /** * Perform output conversion on a string, and encode for safe HTML output. + * + * @deprecated since 1.35 use LanguageConverter::convertHtml instead + * * @param string $text Text to be converted * @return string * @todo this should get integrated somewhere sane @@ -4128,42 +4161,49 @@ class Language { } /** + * @deprecated since 1.35 use LanguageConverter::convertCategoryKey instead + * * @param string $key * @return string */ public function convertCategoryKey( $key ) { - return $this->mConverter->convertCategoryKey( $key ); + return $this->getConverter()->convertCategoryKey( $key ); } /** * Get the list of variants supported by this language * see sample implementation in LanguageZh.php * + * @deprecated since 1.35 use LanguageConverter::getVariants instead + * * @return string[] An array of language codes */ public function getVariants() { - return $this->mConverter->getVariants(); + return $this->getConverter()->getVariants(); } /** + * @deprecated since 1.35 use LanguageConverter::getPreferredVariant instead * @return string */ public function getPreferredVariant() { - return $this->mConverter->getPreferredVariant(); + return $this->getConverter()->getPreferredVariant(); } /** + * @deprecated since 1.35 use LanguageConverter::getDefaultVariant instead * @return string */ public function getDefaultVariant() { - return $this->mConverter->getDefaultVariant(); + return $this->getConverter()->getDefaultVariant(); } /** + * @deprecated since 1.35 use LanguageConverter::getURLVariant instead * @return string */ public function getURLVariant() { - return $this->mConverter->getURLVariant(); + return $this->getConverter()->getURLVariant(); } /** @@ -4173,33 +4213,39 @@ class Language { * tries to find it. See e.g. LanguageZh.php * The input parameters may be modified upon return * + * @deprecated since 1.35 use LanguageConverter::findVariantLink instead + * * @param string &$link The name of the link * @param Title &$nt The title object of the link * @param bool $ignoreOtherCond To disable other conditions when * we need to transclude a template or update a category's link */ public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) { - $this->mConverter->findVariantLink( $link, $nt, $ignoreOtherCond ); + $this->getConverter()->findVariantLink( $link, $nt, $ignoreOtherCond ); } /** * returns language specific options used by User::getPageRenderHash() * for example, the preferred language variant * + * @deprecated since 1.35 use LanguageConverter::getExtraHashOptions instead + * * @return string */ public function getExtraHashOptions() { - return $this->mConverter->getExtraHashOptions(); + return $this->getConverter()->getExtraHashOptions(); } /** * Refresh the cache of conversion tables when * MediaWiki:Conversiontable* is updated. * + * @deprecated since 1.35 use LanguageConverter::updateConversionTable instead + * * @param Title $title The Title of the page being updated */ public function updateConversionTable( Title $title ) { - $this->mConverter->updateConversionTable( $title ); + $this->getConverter()->updateConversionTable( $title ); } /** @@ -4754,10 +4800,12 @@ class Language { /** * Get the conversion rule title, if any. * + * @deprecated since 1.35 use LanguageConverter::getConvRuleTitle instead + * * @return string */ public function getConvRuleTitle() { - return $this->mConverter->getConvRuleTitle(); + return $this->getConverter()->getConvRuleTitle(); } /** diff --git a/languages/LanguageConverter.php b/languages/LanguageConverter.php index 9aa5fe98436..9b9e11b7aa5 100644 --- a/languages/LanguageConverter.php +++ b/languages/LanguageConverter.php @@ -23,7 +23,7 @@ use MediaWiki\MediaWikiServices; use MediaWiki\Revision\RevisionRecord; /** - * Base class for language conversion. + * Base class for multi-variant language conversion. * @ingroup Language * * @author Zhengzhu Feng @@ -31,7 +31,7 @@ use MediaWiki\Revision\RevisionRecord; * @author shinjiman * @author PhiLiP */ -class LanguageConverter { +abstract class LanguageConverter implements ILanguageConverter { /** * languages supporting variants * @since 1.20 @@ -69,7 +69,11 @@ class LanguageConverter { // 'bidirectional' 'unidirectional' 'disable' for each variant public $mManualLevel; + /** + * @var Language + */ public $mLangObj; + public $mFlags; public $mDescCodeSep = ':', $mDescVarSep = ';'; public $mUcfirst = false; @@ -561,7 +565,7 @@ class LanguageConverter { * * @param ConverterRule $convRule */ - protected function applyManualConv( $convRule ) { + protected function applyManualConv( ConverterRule $convRule ) { // Use syntax -{T|zh-cn:TitleCN; zh-tw:TitleTw}- to custom // title conversion. // T26072: $mConvRuleTitle was overwritten by other manual @@ -651,8 +655,8 @@ class LanguageConverter { if ( $nsVariantText === false ) { // No message exists, retrieve it from the target variant's namespace names. - $langObj = $this->mLangObj->factory( $variant ); - $nsVariantText = $langObj->getFormattedNsText( $index ); + $mLangObj = $this->mLangObj->factory( $variant ); // TODO: create from services + $nsVariantText = $mLangObj->getFormattedNsText( $index ); } $cache->set( $key, $nsVariantText, 60 ); @@ -1213,4 +1217,41 @@ class LanguageConverter { } return $this->mVarSeparatorPattern; } + + /** + * Check if this is a language with variants + * + * @since 1.35 + * + * @return bool + */ + public function hasVariants() { + return count( $this->getVariants() ) > 1; + } + + /** + * Strict check if the language has the specific variant. + * + * Compare to LanguageConverter::validateVariant() which does a more + * lenient check and attempts to coerce the given code to a valid one. + * + * @since 1.35 + * @param string $variant + * @return bool + */ + public function hasVariant( $variant ) { + return $variant && ( $variant === $this->validateVariant( $variant ) ); + } + + /** + * Perform output conversion on a string, and encode for safe HTML output. + * + * @since 1.35 + * + * @param string $text Text to be converted + * @return string + */ + public function convertHtml( $text ) { + return htmlspecialchars( $this->convert( $text ) ); + } } diff --git a/languages/LanguageConverterFactory.php b/languages/LanguageConverterFactory.php new file mode 100644 index 00000000000..f2598a81d62 --- /dev/null +++ b/languages/LanguageConverterFactory.php @@ -0,0 +1,89 @@ + CrhConverter::class, + 'gan' => GanConverter::class, + 'iu' => IuConverter::class, + 'kk' => KkConverter::class, + 'ku' => KuConverter::class, + 'shi' => ShiConverter::class, + 'sr' => SrConverter::class, + 'tg' => TgConverter::class, + 'uz' => UzConverter::class, + 'zh' => ZhConverter::class, + ]; + + private $defaultConverterClass = TrivialLanguageConverter::class; + + /** + * @var callable callback of () : Language + */ + private $defaultLanguage; + + /** + * @param bool $usePigLatinVariant should pig variant of English be used + * @param callable $defaultLanguage - callback of () : Language, should return + * default language. Used in getLanguageConverter when $language is null. + */ + public function __construct( $usePigLatinVariant, callable $defaultLanguage ) { + if ( $usePigLatinVariant ) { + $this->converterClasses['en'] = EnConverter::class; + } + $this->defaultLanguage = $defaultLanguage; + } + + /** + * Returns Converter's class name for given language code + * + * @param string $code code for which class name should be provided + * @return string + */ + private function classFromCode( string $code ) : string { + $code = mb_strtolower( $code ); + return $this->converterClasses[$code] ?? $this->defaultConverterClass; + } + + /** + * Provide a LanguageConverter for given language + * + * @param Language|null $language for which a LanguageConverter should be provided. + * If null then LanguageConverter provided for current content language as returned + * by the callback provided to the constructor.. + * + * @return ILanguageConverter + */ + public function getLanguageConverter( Language $language = null ) : ILanguageConverter { + $lang = $language ?? ( $this->defaultLanguage )(); + if ( isset( $this->cache[$lang->getCode()] ) ) { + return $this->cache[$lang->getCode()]; + } + $class = $this->classFromCode( $lang->getCode() ); + + $converter = new $class( $lang ); + $this->cache[$lang->getCode()] = $converter; + return $converter; + } +} diff --git a/languages/FakeConverter.php b/languages/TrivialLanguageConverter.php similarity index 57% rename from languages/FakeConverter.php rename to languages/TrivialLanguageConverter.php index c32e2908aa1..43db15ae6f8 100644 --- a/languages/FakeConverter.php +++ b/languages/TrivialLanguageConverter.php @@ -22,23 +22,26 @@ */ /** - * A fake language variant converter. Languages which do not implement variant - * conversion, for example, English, should return a FakeConverter rather than a - * LanguageConverter when asked for their converter. The fake converter just + * A trivial language converter. + * + * For Languages which do not implement variant + * conversion, for example, German, TrivialLanguageConverter is provided rather than a + * LanguageConverter when asked for their converter. The TrivialLanguageConverter just * returns text unchanged, i.e. it doesn't do any conversion. * * See https://www.mediawiki.org/wiki/Writing_systems#LanguageConverter. * * @ingroup Language */ -class FakeConverter { + +class TrivialLanguageConverter implements ILanguageConverter { /** * @var Language */ - public $mLang; + protected $language; public function __construct( Language $langobj ) { - $this->mLang = $langobj; + $this->language = $langobj; } public function autoConvert( $text, $variant = false ) { @@ -46,7 +49,7 @@ class FakeConverter { } public function autoConvertToAllVariants( $text ) { - return [ $this->mLang->getCode() => $text ]; + return [ $this->language->getCode() => $text ]; } public function convert( $t ) { @@ -65,27 +68,27 @@ class FakeConverter { return $t->getPrefixedText(); } - public function convertNamespace( $ns ) { - return $this->mLang->getFormattedNsText( $ns ); + public function convertNamespace( $index, $variant = null ) { + return $this->language->getFormattedNsText( $index ); } /** * @return string[] */ public function getVariants() { - return [ $this->mLang->getCode() ]; + return [ $this->language->getCode() ]; } public function getVariantFallbacks( $variant ) { - return $this->mLang->getCode(); + return $this->language->getCode(); } public function getPreferredVariant() { - return $this->mLang->getCode(); + return $this->language->getCode(); } public function getDefaultVariant() { - return $this->mLang->getCode(); + return $this->language->getCode(); } public function getURLVariant() { @@ -103,6 +106,10 @@ class FakeConverter { return ''; } + public function guessVariant( $text, $variant ) { + return false; + } + public function markNoConversion( $text, $noParse = false ) { return $text; } @@ -116,7 +123,7 @@ class FakeConverter { return null; } $variant = strtolower( $variant ); - return $variant === $this->mLang->getCode() ? $variant : null; + return $variant === $this->language->getCode() ? $variant : null; } public function translate( $text, $variant ) { @@ -133,4 +140,46 @@ class FakeConverter { */ private function reloadTables() { } + + /** + * Check if this is a language with variants + * + * @since 1.35 + * + * @return bool + */ + public function hasVariants() { + return count( $this->getVariants() ) > 1; + } + + /** + * Strict check if the language has the specific variant. + * + * Compare to LanguageConverter::validateVariant() which does a more + * lenient check and attempts to coerce the given code to a valid one. + * + * @since 1.35 + * @param string $variant + * @return bool + */ + public function hasVariant( $variant ) { + return $variant && ( $variant === $this->validateVariant( $variant ) ); + } + + /** + * Perform output conversion on a string, and encode for safe HTML output. + * + * @since 1.35 + * + * @param string $text Text to be converted + * @return string + */ + public function convertHtml( $text ) { + return htmlspecialchars( $this->convert( $text ) ); + } } + +/** + * @deprecated since 1.35 use TrivialLanguageConverter instead + */ +class_alias( TrivialLanguageConverter::class, 'FakeConverter' ); diff --git a/languages/classes/LanguageCrh.php b/languages/classes/LanguageCrh.php index 0fb1694ed44..0f1050559ba 100644 --- a/languages/classes/LanguageCrh.php +++ b/languages/classes/LanguageCrh.php @@ -58,18 +58,17 @@ class CrhConverter extends LanguageConverter { /** * @param Language $langobj - * @param string $maincode - * @param array $variants - * @param array $variantfallbacks - * @param array $flags */ - public function __construct( Language $langobj, $maincode, - $variants = [], - $variantfallbacks = [], - $flags = [] - ) { - parent::__construct( $langobj, $maincode, - $variants, $variantfallbacks, $flags ); + public function __construct( Language $langobj ) { + $variants = [ 'crh', 'crh-cyrl', 'crh-latn' ]; + $variantfallbacks = [ + 'crh' => 'crh-latn', + 'crh-cyrl' => 'crh-latn', + 'crh-latn' => 'crh-cyrl', + ]; + + parent::__construct( $langobj, 'crh', + $variants, $variantfallbacks, [] ); // No point delaying this since they're in code. // Waiting until loadDefaultTables() means they never get loaded @@ -283,21 +282,3 @@ class CrhConverter extends LanguageConverter { } } - -/** - * Crimean Tatar (Qırımtatarca) - * - * @ingroup Language - */ -class LanguageCrh extends Language { - protected function newConverter() : CrhConverter { - $variants = [ 'crh', 'crh-cyrl', 'crh-latn' ]; - $variantfallbacks = [ - 'crh' => 'crh-latn', - 'crh-cyrl' => 'crh-latn', - 'crh-latn' => 'crh-cyrl', - ]; - - return new CrhConverter( $this, 'crh', $variants, $variantfallbacks ); - } -} diff --git a/languages/classes/LanguageEn.php b/languages/classes/LanguageEn.php index e1019269269..0ea06f58be8 100644 --- a/languages/classes/LanguageEn.php +++ b/languages/classes/LanguageEn.php @@ -24,6 +24,14 @@ * @ingroup Language */ class EnConverter extends LanguageConverter { + + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + parent::__construct( $langobj, 'en', [ 'en', 'en-x-piglatin' ] ); + } + /** * Dummy methods required by base class. */ @@ -74,12 +82,4 @@ class EnConverter extends LanguageConverter { * @ingroup Language */ class LanguageEn extends Language { - protected function newConverter() { - global $wgUsePigLatinVariant; - - if ( $wgUsePigLatinVariant ) { - return new EnConverter( $this, 'en', [ 'en', 'en-x-piglatin' ] ); - } - return parent::newConverter(); - } } diff --git a/languages/classes/LanguageGan.php b/languages/classes/LanguageGan.php index 9563a394f6a..42d36c39759 100644 --- a/languages/classes/LanguageGan.php +++ b/languages/classes/LanguageGan.php @@ -26,26 +26,28 @@ class GanConverter extends LanguageConverter { /** * @param Language $langobj - * @param string $maincode - * @param array $variants - * @param array $variantfallbacks - * @param array $flags - * @param array $manualLevel */ - public function __construct( Language $langobj, $maincode, - $variants = [], - $variantfallbacks = [], - $flags = [], - $manualLevel = [] - ) { + public function __construct( Language $langobj ) { $this->mDescCodeSep = ':'; $this->mDescVarSep = ';'; - parent::__construct( $langobj, $maincode, + + $variants = [ 'gan', 'gan-hans', 'gan-hant' ]; + $variantfallbacks = [ + 'gan' => [ 'gan-hans', 'gan-hant' ], + 'gan-hans' => [ 'gan' ], + 'gan-hant' => [ 'gan' ], + ]; + $ml = [ + 'gan' => 'disable', + ]; + + parent::__construct( $langobj, 'gan', $variants, $variantfallbacks, - $flags, - $manualLevel + [], + $ml ); + $names = [ 'gan' => '原文', 'gan-hans' => '简体', @@ -80,24 +82,6 @@ class GanConverter extends LanguageConverter { * @ingroup Language */ class LanguageGan extends LanguageZh { - protected function newConverter() : LanguageConverter { - $variants = [ 'gan', 'gan-hans', 'gan-hant' ]; - $variantfallbacks = [ - 'gan' => [ 'gan-hans', 'gan-hant' ], - 'gan-hans' => [ 'gan' ], - 'gan-hant' => [ 'gan' ], - ]; - $ml = [ - 'gan' => 'disable', - ]; - - return new GanConverter( $this, 'gan', - $variants, $variantfallbacks, - [], - $ml - ); - } - /** * word segmentation * diff --git a/languages/classes/LanguageIu.php b/languages/classes/LanguageIu.php index ad4d94ac9d7..209c145ebf3 100644 --- a/languages/classes/LanguageIu.php +++ b/languages/classes/LanguageIu.php @@ -87,6 +87,21 @@ class IuConverter extends LanguageConverter { 'ɫii' => 'ᖡ', 'ɫu' => 'ᖢ', 'ɫuu' => 'ᖣ', 'ɫa' => 'ᖤ', 'ɫaa' => 'ᖥ', ]; + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + $variants = [ 'iu', 'ike-cans', 'ike-latn' ]; + $variantfallbacks = [ + 'iu' => 'ike-cans', + 'ike-cans' => 'iu', + 'ike-latn' => 'iu', + ]; + $flags = []; + + parent::__construct( $langobj, 'iu', $variants, $variantfallbacks, $flags ); + } + protected function loadDefaultTables() { $this->mTables = [ 'lowercase' => new ReplacementArray( $this->mUpperToLowerCaseLatin ), @@ -144,22 +159,3 @@ class IuConverter extends LanguageConverter { return $text; } } - -/** - * Inuktitut - * - * @ingroup Language - */ -class LanguageIu extends Language { - protected function newConverter() : IuConverter { - $variants = [ 'iu', 'ike-cans', 'ike-latn' ]; - $variantfallbacks = [ - 'iu' => 'ike-cans', - 'ike-cans' => 'iu', - 'ike-latn' => 'iu', - ]; - - $flags = []; - return new IuConverter( $this, 'iu', $variants, $variantfallbacks, $flags ); - } -} diff --git a/languages/classes/LanguageKk.php b/languages/classes/LanguageKk.php index 82fa6f82ca3..d2467ef3a11 100644 --- a/languages/classes/LanguageKk.php +++ b/languages/classes/LanguageKk.php @@ -39,18 +39,21 @@ class KkConverter extends LanguageConverter { /** * @param Language $langobj - * @param string $maincode - * @param array $variants - * @param array $variantfallbacks - * @param array $flags */ - public function __construct( Language $langobj, $maincode, - $variants = [], - $variantfallbacks = [], - $flags = [] - ) { - parent::__construct( $langobj, $maincode, - $variants, $variantfallbacks, $flags ); + public function __construct( Language $langobj ) { + $variants = [ 'kk', 'kk-cyrl', 'kk-latn', 'kk-arab', 'kk-kz', 'kk-tr', 'kk-cn' ]; + $variantfallbacks = [ + 'kk' => 'kk-cyrl', + 'kk-cyrl' => 'kk', + 'kk-latn' => 'kk', + 'kk-arab' => 'kk', + 'kk-kz' => 'kk-cyrl', + 'kk-tr' => 'kk-latn', + 'kk-cn' => 'kk-arab' + ]; + + parent::__construct( $langobj, 'kk', + $variants, $variantfallbacks, [] ); // No point delaying this since they're in code. // Waiting until loadDefaultTables() means they never get loaded @@ -363,21 +366,6 @@ class KkConverter extends LanguageConverter { * @ingroup Language */ class LanguageKk extends LanguageKk_cyrl { - protected function newConverter() : KKConverter { - $variants = [ 'kk', 'kk-cyrl', 'kk-latn', 'kk-arab', 'kk-kz', 'kk-tr', 'kk-cn' ]; - $variantfallbacks = [ - 'kk' => 'kk-cyrl', - 'kk-cyrl' => 'kk', - 'kk-latn' => 'kk', - 'kk-arab' => 'kk', - 'kk-kz' => 'kk-cyrl', - 'kk-tr' => 'kk-latn', - 'kk-cn' => 'kk-arab' - ]; - - return new KkConverter( $this, 'kk', $variants, $variantfallbacks ); - } - /** * It fixes issue with ucfirst for transforming 'i' to 'İ' * diff --git a/languages/classes/LanguageKu.php b/languages/classes/LanguageKu.php index 98091062e31..bf357548398 100644 --- a/languages/classes/LanguageKu.php +++ b/languages/classes/LanguageKu.php @@ -143,6 +143,20 @@ class KuConverter extends LanguageConverter { */ ]; + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + $variants = [ 'ku', 'ku-arab', 'ku-latn' ]; + $variantfallbacks = [ + 'ku' => 'ku-latn', + 'ku-arab' => 'ku-latn', + 'ku-latn' => 'ku-arab', + ]; + + parent::__construct( $langobj, 'ku', $variants, $variantfallbacks ); + } + protected function loadDefaultTables() { $this->mTables = [ 'ku-latn' => new ReplacementArray( $this->mArabicToLatin ), @@ -222,22 +236,3 @@ class KuConverter extends LanguageConverter { return parent::translate( $text, $toVariant ); } } - -/** - * Kurdish (Kurdî / كوردی) - * - * @ingroup Language - */ -class LanguageKu extends Language { - - protected function newConverter() : KuConverter { - $variants = [ 'ku', 'ku-arab', 'ku-latn' ]; - $variantfallbacks = [ - 'ku' => 'ku-latn', - 'ku-arab' => 'ku-latn', - 'ku-latn' => 'ku-arab', - ]; - - return new KuConverter( $this, 'ku', $variants, $variantfallbacks ); - } -} diff --git a/languages/classes/LanguageShi.php b/languages/classes/LanguageShi.php index bc72d096e2d..6565b51a1f6 100644 --- a/languages/classes/LanguageShi.php +++ b/languages/classes/LanguageShi.php @@ -63,6 +63,21 @@ class ShiConverter extends LanguageConverter { 'ẓ' => 'ⵥ', 'ʷ' => 'ⵯ', 'ɣ' => 'ⵖ', 'v' => 'ⵠ', 'p' => 'ⵒ', ]; + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + $variants = [ 'shi', 'shi-tfng', 'shi-latn' ]; + $variantfallbacks = [ + 'shi' => 'shi-tfng', + 'shi-tfng' => 'shi', + 'shi-latn' => 'shi', + ]; + + $flags = []; + parent::__construct( $langobj, 'shi', $variants, $variantfallbacks, $flags ); + } + protected function loadDefaultTables() { $this->mTables = [ 'lowercase' => new ReplacementArray( $this->mUpperToLowerCaseLatin ), @@ -120,22 +135,3 @@ class ShiConverter extends LanguageConverter { return $text; } } - -/** - * Tachelhit - * - * @ingroup Language - */ -class LanguageShi extends Language { - protected function newConverter() : ShiConverter { - $variants = [ 'shi', 'shi-tfng', 'shi-latn' ]; - $variantfallbacks = [ - 'shi' => 'shi-tfng', - 'shi-tfng' => 'shi', - 'shi-latn' => 'shi', - ]; - - $flags = []; - return new ShiConverter( $this, 'shi', $variants, $variantfallbacks, $flags ); - } -} diff --git a/languages/classes/LanguageSr.php b/languages/classes/LanguageSr.php index 8a63bfda4a9..2672f1f0c63 100644 --- a/languages/classes/LanguageSr.php +++ b/languages/classes/LanguageSr.php @@ -67,6 +67,24 @@ class SrConverter extends LanguageConverter { 'Nj' => 'Њ', 'n!j' => 'нј', 'N!j' => 'Нј', 'N!J' => 'НЈ' ]; + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + $variants = [ 'sr', 'sr-ec', 'sr-el' ]; + $variantfallbacks = [ + 'sr' => 'sr-ec', + 'sr-ec' => 'sr', + 'sr-el' => 'sr', + ]; + + $flags = [ + 'S' => 'S', 'писмо' => 'S', 'pismo' => 'S', + 'W' => 'W', 'реч' => 'W', 'reč' => 'W', 'ријеч' => 'W', 'riječ' => 'W' + ]; + parent::__construct( $langobj, 'sr', $variants, $variantfallbacks, $flags ); + } + protected function loadDefaultTables() { $this->mTables = [ 'sr-ec' => new ReplacementArray( $this->mToCyrillics ), @@ -165,25 +183,3 @@ class SrConverter extends LanguageConverter { } } - -/** - * Serbian (Српски / Srpski) - * - * @ingroup Language - */ -class LanguageSr extends Language { - protected function newConverter() : SrConverter { - $variants = [ 'sr', 'sr-ec', 'sr-el' ]; - $variantfallbacks = [ - 'sr' => 'sr-ec', - 'sr-ec' => 'sr', - 'sr-el' => 'sr', - ]; - - $flags = [ - 'S' => 'S', 'писмо' => 'S', 'pismo' => 'S', - 'W' => 'W', 'реч' => 'W', 'reč' => 'W', 'ријеч' => 'W', 'riječ' => 'W' - ]; - return new SrConverter( $this, 'sr', $variants, $variantfallbacks, $flags ); - } -} diff --git a/languages/classes/LanguageTg.php b/languages/classes/LanguageTg.php index 684e70f7d9a..2cec7d031fe 100644 --- a/languages/classes/LanguageTg.php +++ b/languages/classes/LanguageTg.php @@ -103,23 +103,18 @@ class TgConverter extends LanguageConverter { 'Ц' => 'Ts', ]; + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + $variants = [ 'tg', 'tg-latn' ]; + parent::__construct( $langobj, 'tg', $variants ); + } + protected function loadDefaultTables() { $this->mTables = [ 'tg-latn' => new ReplacementArray( $this->table ), 'tg' => new ReplacementArray() ]; } - -} - -/** - * Tajik (Тоҷикӣ) - * - * @ingroup Language - */ -class LanguageTg extends Language { - protected function newConverter() : TgConverter { - $variants = [ 'tg', 'tg-latn' ]; - return new TgConverter( $this, 'tg', $variants ); - } } diff --git a/languages/classes/LanguageUz.php b/languages/classes/LanguageUz.php index 96e872964a6..ae822efd680 100644 --- a/languages/classes/LanguageUz.php +++ b/languages/classes/LanguageUz.php @@ -102,6 +102,19 @@ class UzConverter extends LanguageConverter { 'ʼ' => 'ъ', ]; + /** + * @param Language $langobj + */ + public function __construct( Language $langobj ) { + $variants = [ 'uz', 'uz-latn', 'uz-cyrl' ]; + $variantfallbacks = [ + 'uz' => 'uz-latn', + 'uz-cyrl' => 'uz', + 'uz-latn' => 'uz', + ]; + parent::__construct( $langobj, 'uz', $variants, $variantfallbacks ); + } + protected function loadDefaultTables() { $this->mTables = [ 'uz-cyrl' => new ReplacementArray( $this->toCyrillic ), @@ -123,21 +136,3 @@ class UzConverter extends LanguageConverter { } } - -/** - * Uzbek - * - * @ingroup Language - */ -class LanguageUz extends Language { - protected function newConverter() : UzConverter { - $variants = [ 'uz', 'uz-latn', 'uz-cyrl' ]; - $variantfallbacks = [ - 'uz' => 'uz-latn', - 'uz-cyrl' => 'uz', - 'uz-latn' => 'uz', - ]; - - return new UzConverter( $this, 'uz', $variants, $variantfallbacks ); - } -} diff --git a/languages/classes/LanguageZh.php b/languages/classes/LanguageZh.php index c32ae54f879..9adcb582eb3 100644 --- a/languages/classes/LanguageZh.php +++ b/languages/classes/LanguageZh.php @@ -27,26 +27,45 @@ class ZhConverter extends LanguageConverter { /** * @param Language $langobj - * @param string $maincode - * @param array $variants - * @param array $variantfallbacks - * @param array $flags - * @param array $manualLevel */ - public function __construct( Language $langobj, $maincode, - $variants = [], - $variantfallbacks = [], - $flags = [], - $manualLevel = [] - ) { + public function __construct( Language $langobj ) { $this->mDescCodeSep = ':'; $this->mDescVarSep = ';'; - parent::__construct( $langobj, $maincode, + + $variants = [ + 'zh', + 'zh-hans', + 'zh-hant', + 'zh-cn', + 'zh-hk', + 'zh-mo', + 'zh-my', + 'zh-sg', + 'zh-tw' + ]; + + $variantfallbacks = [ + 'zh' => [ 'zh-hans', 'zh-hant', 'zh-cn', 'zh-tw', 'zh-hk', 'zh-sg', 'zh-mo', 'zh-my' ], + 'zh-hans' => [ 'zh-cn', 'zh-sg', 'zh-my' ], + 'zh-hant' => [ 'zh-tw', 'zh-hk', 'zh-mo' ], + 'zh-cn' => [ 'zh-hans', 'zh-sg', 'zh-my' ], + 'zh-sg' => [ 'zh-hans', 'zh-cn', 'zh-my' ], + 'zh-my' => [ 'zh-hans', 'zh-sg', 'zh-cn' ], + 'zh-tw' => [ 'zh-hant', 'zh-hk', 'zh-mo' ], + 'zh-hk' => [ 'zh-hant', 'zh-mo', 'zh-tw' ], + 'zh-mo' => [ 'zh-hant', 'zh-hk', 'zh-tw' ], + ]; + $ml = [ + 'zh' => 'disable', + 'zh-hans' => 'unidirectional', + 'zh-hant' => 'unidirectional', + ]; + + parent::__construct( $langobj, 'zh', $variants, $variantfallbacks, - $flags, - $manualLevel - ); + [], + $ml ); $names = [ 'zh' => '原文', 'zh-hans' => '简体', @@ -112,43 +131,6 @@ class ZhConverter extends LanguageConverter { * @ingroup Language */ class LanguageZh extends LanguageZh_hans { - protected function newConverter() : LanguageConverter { - $variants = [ - 'zh', - 'zh-hans', - 'zh-hant', - 'zh-cn', - 'zh-hk', - 'zh-mo', - 'zh-my', - 'zh-sg', - 'zh-tw' - ]; - - $variantfallbacks = [ - 'zh' => [ 'zh-hans', 'zh-hant', 'zh-cn', 'zh-tw', 'zh-hk', 'zh-sg', 'zh-mo', 'zh-my' ], - 'zh-hans' => [ 'zh-cn', 'zh-sg', 'zh-my' ], - 'zh-hant' => [ 'zh-tw', 'zh-hk', 'zh-mo' ], - 'zh-cn' => [ 'zh-hans', 'zh-sg', 'zh-my' ], - 'zh-sg' => [ 'zh-hans', 'zh-cn', 'zh-my' ], - 'zh-my' => [ 'zh-hans', 'zh-sg', 'zh-cn' ], - 'zh-tw' => [ 'zh-hant', 'zh-hk', 'zh-mo' ], - 'zh-hk' => [ 'zh-hant', 'zh-mo', 'zh-tw' ], - 'zh-mo' => [ 'zh-hant', 'zh-hk', 'zh-tw' ], - ]; - $ml = [ - 'zh' => 'disable', - 'zh-hans' => 'unidirectional', - 'zh-hant' => 'unidirectional', - ]; - - return new ZhConverter( $this, 'zh', - $variants, $variantfallbacks, - [], - $ml - ); - } - /** * this should give much better diff info * @@ -179,7 +161,7 @@ class LanguageZh extends LanguageZh_hans { // better to use zh-hans for search, since conversion from // Traditional to Simplified is less ambiguous than the // other way around - $s = $this->mConverter->autoConvert( $string, $autoVariant ); + $s = $this->getConverter()->autoConvert( $string, $autoVariant ); // LanguageZh_hans::normalizeForSearch $s = parent::normalizeForSearch( $s ); return $s; diff --git a/tests/parser/ParserTestRunner.php b/tests/parser/ParserTestRunner.php index 0f981fb0259..6c2a9b1a414 100644 --- a/tests/parser/ParserTestRunner.php +++ b/tests/parser/ParserTestRunner.php @@ -1215,7 +1215,8 @@ class ParserTestRunner { $teardown[] = function () use ( $context, $oldSkin ) { // Clear language conversion tables $wrapper = TestingAccessWrapper::newFromObject( - $context->getLanguage()->getConverter() + MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $context->getLanguage() ) ); $wrapper->reloadTables(); // Reset context to the restored globals diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php index e3a55f83231..5a2ab8d0633 100644 --- a/tests/phpunit/includes/OutputPageTest.php +++ b/tests/phpunit/includes/OutputPageTest.php @@ -1189,11 +1189,16 @@ class OutputPageTest extends MediaWikiTestCase { if ( $variantLinkCallback ) { $mockContLang = $this->getMockBuilder( Language::class ) - ->setMethods( [ 'findVariantLink' ] ) + ->setMethods( [ 'findVariantLink', 'convertHtml' ] ) ->getMock(); $mockContLang->expects( $this->any() ) ->method( 'findVariantLink' ) ->will( $this->returnCallback( $variantLinkCallback ) ); + $mockContLang->expects( $this->any() ) + ->method( 'convertHtml' ) + ->will( $this->returnCallback( function ( $arg ) { + return $arg; + } ) ); $this->setContentLang( $mockContLang ); } diff --git a/tests/phpunit/includes/api/ApiQuerySiteinfoTest.php b/tests/phpunit/includes/api/ApiQuerySiteinfoTest.php index e492b25655e..99667567191 100644 --- a/tests/phpunit/includes/api/ApiQuerySiteinfoTest.php +++ b/tests/phpunit/includes/api/ApiQuerySiteinfoTest.php @@ -544,8 +544,11 @@ class ApiQuerySiteinfoTest extends ApiTestCase { public function testLanguageVariants() { $expectedKeys = array_filter( LanguageConverter::$languagesWithVariants, function ( $langCode ) { - return !MediaWikiServices::getInstance()->getLanguageFactory() - ->getLanguage( $langCode )->getConverter() instanceof FakeConverter; + $lang = MediaWikiServices::getInstance()->getLanguageFactory() + ->getLanguage( $langCode ); + $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory() + ->getLanguageConverter( $lang ); + return $converter->hasVariants(); } ); sort( $expectedKeys ); diff --git a/tests/phpunit/includes/language/ConverterRuleTest.php b/tests/phpunit/includes/language/ConverterRuleTest.php index 0aeac9b5387..2c7f3fc5e5b 100644 --- a/tests/phpunit/includes/language/ConverterRuleTest.php +++ b/tests/phpunit/includes/language/ConverterRuleTest.php @@ -11,7 +11,7 @@ class ConverterRuleTest extends MediaWikiTestCase { } public function testParseEmpty() { - $converter = new LanguageConverter( new Language(), 'en' ); + $converter = new EnConverter( new Language() ); $rule = new ConverterRule( '', $converter ); $rule->parse(); diff --git a/tests/phpunit/languages/LanguageConverterFactoryTest.php b/tests/phpunit/languages/LanguageConverterFactoryTest.php new file mode 100644 index 00000000000..d37f56100ee --- /dev/null +++ b/tests/phpunit/languages/LanguageConverterFactoryTest.php @@ -0,0 +1,760 @@ +getLanguageFactory()->getLanguage( $code ); + $factory = new LanguageConverterFactory( false, function () use ( $lang ) { + return $lang; + } ); + $converter = $factory->getLanguageConverter( $lang ); + $this->verifyConverter( + $converter, + $lang, + $code, + $type, + $variants, + $variantFallbacks, + $variantNames, + $flags, + $manualLevel + ); + } + + /** + * @covers ::__construct + * @covers ::classFromCode + * @covers ::getLanguageConverter + */ + public function testCreateFromCodeEnPigLatin() { + $lang = MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( 'en' ); + $factory = new LanguageConverterFactory( true, function () use ( $lang ) { + return $lang; + } ); + + $converter = $factory->getLanguageConverter( $lang ); + + $this->verifyConverter( + $converter, + $lang, + 'en', + 'EnConverter', + [ 'en', 'en-x-piglatin' ], + [], + [], + [], + [ 'en' => 'bidirectional', 'en-x-piglatin' => 'bidirectional' ] + ); + } + + /** + * @covers ::__construct + * @covers ::classFromCode + * @covers ::getLanguageConverter + */ + public function testDefaultConentLanguageFallback() { + $lang = MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( 'en' ); + $factory = new LanguageConverterFactory( false, function () use ( $lang ) { + return $lang; + } ); + + $converter = $factory->getLanguageConverter(); + + $this->verifyConverter( + $converter, + $lang, + 'en', + 'TrivialLanguageConverter', + [ 'en' ], + [], + [], + [], + [] + ); + } + + private function verifyConverter( + $converter, + $lang, + $code, + $type, + $variants, + $variantFallbacks, + $variantNames, + $flags, + $manualLevel + ) { + $this->assertEquals( $type, get_class( $converter ) ); + + if ( is_a( $converter, LanguageConverter::class ) ) { + $this->assertSame( $lang, $converter->mLangObj, "Language should be as provided" ); + $this->assertEquals( $code, $converter->mMainLanguageCode, + "mMainLanguageCode should be as $code" ); + $this->assertEquals( $manualLevel, $converter->mManualLevel, "Manual Level" ); + + $this->assertEquals( $variants, $converter->mVariants, "Variants" ); + $this->assertEquals( $variantFallbacks, $converter->mVariantFallbacks, "Variant Fallbacks" ); + // $this->assertEquals(Language::fetchLanguageNames(), + // $newConverter->mVariantNames, "Variant Names"); + $defaultFlags = [ + 'A' => 'A', + 'T' => 'T', + 'R' => 'R', + 'D' => 'D', + '-' => '-', + 'H' => 'H', + 'N' => 'N', + ]; + $this->assertArraySubset( array_merge( $defaultFlags, $flags ), + $converter->mFlags, false, "Flags" ); + } + } + + public function codeProvider() { + $zh_variants = [ + 'zh', + 'zh-hans', + 'zh-hant', + 'zh-cn', + 'zh-hk', + 'zh-mo', + 'zh-my', + 'zh-sg', + 'zh-tw' + ]; + + $zh_variantfallbacks = [ + 'zh' => [ 'zh-hans', 'zh-hant', 'zh-cn', 'zh-tw', 'zh-hk', 'zh-sg', 'zh-mo', 'zh-my' ], + 'zh-hans' => [ 'zh-cn', 'zh-sg', 'zh-my' ], + 'zh-hant' => [ 'zh-tw', 'zh-hk', 'zh-mo' ], + 'zh-cn' => [ 'zh-hans', 'zh-sg', 'zh-my' ], + 'zh-sg' => [ 'zh-hans', 'zh-cn', 'zh-my' ], + 'zh-my' => [ 'zh-hans', 'zh-sg', 'zh-cn' ], + 'zh-tw' => [ 'zh-hant', 'zh-hk', 'zh-mo' ], + 'zh-hk' => [ 'zh-hant', 'zh-mo', 'zh-tw' ], + 'zh-mo' => [ 'zh-hant', 'zh-hk', 'zh-tw' ], + ]; + $zh_ml = [ + 'zh' => 'disable', + 'zh-hans' => 'unidirectional', + 'zh-hant' => 'unidirectional', + 'zh-cn' => 'bidirectional', + 'zh-hk' => 'bidirectional', + 'zh-mo' => 'bidirectional', + 'zh-my' => 'bidirectional', + 'zh-sg' => 'bidirectional', + 'zh-tw' => 'bidirectional', + ]; + + $zh_flags = [ + 'A' => 'A', + 'T' => 'T', + 'R' => 'R', + 'D' => 'D', + '-' => '-', + 'H' => 'H', + 'N' => 'N', + 'zh' => 'zh', + 'zh-hans' => 'zh-hans', + 'zh-hant' => 'zh-hant', + 'zh-cn' => 'zh-cn', + 'zh-hk' => 'zh-hk', + 'zh-mo' => 'zh-mo', + 'zh-my' => 'zh-my', + 'zh-sg' => 'zh-sg', + 'zh-tw' => 'zh-tw' + ]; + + return [ + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'aa' => [ 'aa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ab' => [ 'ab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'abs' => [ 'abs', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ace' => [ 'ace', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ady' => [ 'ady', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ady-cyrl' => [ 'ady-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'aeb' => [ 'aeb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'aeb-arab' => [ 'aeb-arab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'aeb-latn' => [ 'aeb-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'af' => [ 'af', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ak' => [ 'ak', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'aln' => [ 'aln', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'als' => [ 'als', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'am' => [ 'am', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'an' => [ 'an', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ang' => [ 'ang', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'anp' => [ 'anp', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ar' => [ 'ar', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'arc' => [ 'arc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'arn' => [ 'arn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'arq' => [ 'arq', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ary' => [ 'ary', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'arz' => [ 'arz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'as' => [ 'as', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ase' => [ 'ase', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ast' => [ 'ast', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'atj' => [ 'atj', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'av' => [ 'av', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'avk' => [ 'avk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'awa' => [ 'awa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ay' => [ 'ay', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'az' => [ 'az', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'azb' => [ 'azb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ba' => [ 'ba', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ban' => [ 'ban', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bar' => [ 'bar', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bat-smg' => [ 'bat-smg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bbc' => [ 'bbc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bbc-latn' => [ 'bbc-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bcc' => [ 'bcc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bcl' => [ 'bcl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'be' => [ 'be', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'be-tarask' => [ 'be-tarask', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'be-x-old' => [ 'be-x-old', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bg' => [ 'bg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bgn' => [ 'bgn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bh' => [ 'bh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bho' => [ 'bho', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bi' => [ 'bi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bjn' => [ 'bjn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bm' => [ 'bm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bn' => [ 'bn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bo' => [ 'bo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bpy' => [ 'bpy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bqi' => [ 'bqi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'br' => [ 'br', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'brh' => [ 'brh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bs' => [ 'bs', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'btm' => [ 'btm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bto' => [ 'bto', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bug' => [ 'bug', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'bxr' => [ 'bxr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ca' => [ 'ca', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cbk-zam' => [ 'cbk-zam', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cdo' => [ 'cdo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ce' => [ 'ce', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ceb' => [ 'ceb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ch' => [ 'ch', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cho' => [ 'cho', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'chr' => [ 'chr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'chy' => [ 'chy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ckb' => [ 'ckb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'co' => [ 'co', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cps' => [ 'cps', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cr' => [ 'cr', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'crh' => [ 'crh', 'CrhConverter', [ 'crh', 'crh-cyrl', 'crh-latn' ], [ + 'crh' => 'crh-latn', + 'crh-cyrl' => 'crh-latn', + 'crh-latn' => 'crh-cyrl', + ], [], [], [ + 'crh' => 'bidirectional', + 'crh-cyrl' => 'bidirectional', + 'crh-latn' => 'bidirectional' + ] + ], + 'crh-latn' => [ 'crh-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'crh-cyrl' => [ 'crh-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cs' => [ 'cs', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'csb' => [ 'csb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cu' => [ 'cu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cv' => [ 'cv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'cy' => [ 'cy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'da' => [ 'da', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'de' => [ 'de', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'de-at' => [ 'de-at', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'de-ch' => [ 'de-ch', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'de-formal' => [ 'de-formal', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'din' => [ 'din', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'diq' => [ 'diq', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'dsb' => [ 'dsb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'dtp' => [ 'dtp', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'dty' => [ 'dty', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'dv' => [ 'dv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'dz' => [ 'dz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ee' => [ 'ee', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'egl' => [ 'egl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'el' => [ 'el', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'eml' => [ 'eml', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'en' => [ 'en', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'en-ca' => [ 'en-ca', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'en-gb' => [ 'en-gb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'eo' => [ 'eo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'es' => [ 'es', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'es-419' => [ 'es-419', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'es-formal' => [ 'es-formal', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'et' => [ 'et', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'eu' => [ 'eu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ext' => [ 'ext', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fa' => [ 'fa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ff' => [ 'ff', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fi' => [ 'fi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fit' => [ 'fit', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fiu-vro' => [ 'fiu-vro', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fj' => [ 'fj', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fo' => [ 'fo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fr' => [ 'fr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'frc' => [ 'frc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'frp' => [ 'frp', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'frr' => [ 'frr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fur' => [ 'fur', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'fy' => [ 'fy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ga' => [ 'ga', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gag' => [ 'gag', 'TrivialLanguageConverter', [], [], [], [], [] ], + + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'gan' => [ 'gan', 'GanConverter', [ 'gan', 'gan-hans', 'gan-hant' ], [ + 'gan' => [ 'gan-hans', 'gan-hant' ], + 'gan-hans' => [ 'gan' ], + 'gan-hant' => [ 'gan' ], + ], [], [], [ + 'gan' => 'disable', + 'gan-hans' => 'bidirectional', + 'gan-hant' => 'bidirectional' + ] + ], + 'gan-hans' => [ 'gan-hans', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gan-hant' => [ 'gan-hant', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gcr' => [ 'gcr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gd' => [ 'gd', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gl' => [ 'gl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'glk' => [ 'glk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gn' => [ 'gn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gom' => [ 'gom', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gom-deva' => [ 'gom-deva', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gom-latn' => [ 'gom-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gor' => [ 'gor', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'got' => [ 'got', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'grc' => [ 'grc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gsw' => [ 'gsw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gu' => [ 'gu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'gv' => [ 'gv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ha' => [ 'ha', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hak' => [ 'hak', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'haw' => [ 'haw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'he' => [ 'he', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hi' => [ 'hi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hif' => [ 'hif', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hif-latn' => [ 'hif-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hil' => [ 'hil', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ho' => [ 'ho', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hr' => [ 'hr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hrx' => [ 'hrx', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hsb' => [ 'hsb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ht' => [ 'ht', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hu' => [ 'hu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hu-formal' => [ 'hu-formal', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hy' => [ 'hy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hyw' => [ 'hyw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'hz' => [ 'hz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ia' => [ 'ia', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'id' => [ 'id', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ie' => [ 'ie', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ig' => [ 'ig', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ii' => [ 'ii', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ik' => [ 'ik', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ike-cans' => [ 'ike-cans', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ike-latn' => [ 'ike-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ilo' => [ 'ilo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'inh' => [ 'inh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'io' => [ 'io', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'is' => [ 'is', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'it' => [ 'it', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'iu' => [ 'iu', 'IuConverter', [ 'iu', 'ike-cans', 'ike-latn' ], [ + 'iu' => 'ike-cans', + 'ike-cans' => 'iu', + 'ike-latn' => 'iu', + ], [], [], [ + 'iu' => 'bidirectional', + 'ike-cans' => 'bidirectional', + 'ike-latn' => 'bidirectional' + ] + ], + 'ja' => [ 'ja', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'jam' => [ 'jam', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'jbo' => [ 'jbo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'jut' => [ 'jut', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'jv' => [ 'jv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ka' => [ 'ka', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kaa' => [ 'kaa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kab' => [ 'kab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kbd' => [ 'kbd', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kbd-cyrl' => [ 'kbd-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kbp' => [ 'kbp', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kg' => [ 'kg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'khw' => [ 'khw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ki' => [ 'ki', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kiu' => [ 'kiu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kj' => [ 'kj', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kjp' => [ 'kjp', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'kk' => [ 'kk', 'KkConverter', + [ 'kk', 'kk-cyrl', 'kk-latn', 'kk-arab', 'kk-kz', 'kk-tr', 'kk-cn' ], [ + 'kk' => 'kk-cyrl', + 'kk-cyrl' => 'kk', + 'kk-latn' => 'kk', + 'kk-arab' => 'kk', + 'kk-kz' => 'kk-cyrl', + 'kk-tr' => 'kk-latn', + 'kk-cn' => 'kk-arab' + ], [], [], [ + 'kk' => 'bidirectional', + 'kk-cyrl' => 'bidirectional', + 'kk-latn' => 'bidirectional', + 'kk-arab' => 'bidirectional', + 'kk-kz' => 'bidirectional', + 'kk-tr' => 'bidirectional', + 'kk-cn' => 'bidirectional' + ] + ], + 'kk-arab' => [ 'kk-arab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kk-cyrl' => [ 'kk-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kk-latn' => [ 'kk-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kk-cn' => [ 'kk-cn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kk-kz' => [ 'kk-kz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kk-tr' => [ 'kk-tr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kl' => [ 'kl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'km' => [ 'km', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kn' => [ 'kn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ko' => [ 'ko', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ko-kp' => [ 'ko-kp', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'koi' => [ 'koi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kr' => [ 'kr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'krc' => [ 'krc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kri' => [ 'kri', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'krj' => [ 'krj', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'krl' => [ 'krl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ks' => [ 'ks', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ks-arab' => [ 'ks-arab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ks-deva' => [ 'ks-deva', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ksh' => [ 'ksh', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'ku' => [ 'ku', 'KuConverter', [ + 'ku', + 'ku-arab', + 'ku-latn' + ], [ + 'ku' => 'ku-latn', + 'ku-arab' => 'ku-latn', + 'ku-latn' => 'ku-arab' + ], [], [], [ + 'ku' => 'bidirectional', + 'ku-arab' => 'bidirectional', + 'ku-latn' => 'bidirectional' + ] + ], + 'ku-latn' => [ 'ku-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ku-arab' => [ 'ku-arab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kum' => [ 'kum', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kv' => [ 'kv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'kw' => [ 'kw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ky' => [ 'ky', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'la' => [ 'la', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lad' => [ 'lad', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lb' => [ 'lb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lbe' => [ 'lbe', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lez' => [ 'lez', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lfn' => [ 'lfn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lg' => [ 'lg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'li' => [ 'li', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lij' => [ 'lij', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'liv' => [ 'liv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lki' => [ 'lki', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lmo' => [ 'lmo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ln' => [ 'ln', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lo' => [ 'lo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lrc' => [ 'lrc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'loz' => [ 'loz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lt' => [ 'lt', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ltg' => [ 'ltg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lus' => [ 'lus', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'luz' => [ 'luz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lv' => [ 'lv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lzh' => [ 'lzh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'lzz' => [ 'lzz', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mai' => [ 'mai', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'map-bms' => [ 'map-bms', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mdf' => [ 'mdf', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mg' => [ 'mg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mh' => [ 'mh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mhr' => [ 'mhr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mi' => [ 'mi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'min' => [ 'min', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mk' => [ 'mk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ml' => [ 'ml', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mn' => [ 'mn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mni' => [ 'mni', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mnw' => [ 'mnw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mo' => [ 'mo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mr' => [ 'mr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mrj' => [ 'mrj', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ms' => [ 'ms', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mt' => [ 'mt', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mus' => [ 'mus', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mwl' => [ 'mwl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'my' => [ 'my', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'myv' => [ 'myv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'mzn' => [ 'mzn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'na' => [ 'na', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nah' => [ 'nah', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nan' => [ 'nan', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nap' => [ 'nap', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nb' => [ 'nb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nds' => [ 'nds', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nds-nl' => [ 'nds-nl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ne' => [ 'ne', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'new' => [ 'new', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ng' => [ 'ng', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'niu' => [ 'niu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nl' => [ 'nl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nl-informal' => [ 'nl-informal', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nn' => [ 'nn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'no' => [ 'no', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nov' => [ 'nov', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nqo' => [ 'nqo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nrm' => [ 'nrm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nso' => [ 'nso', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nv' => [ 'nv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ny' => [ 'ny', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'nys' => [ 'nys', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'oc' => [ 'oc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'olo' => [ 'olo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'om' => [ 'om', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'or' => [ 'or', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'os' => [ 'os', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pa' => [ 'pa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pag' => [ 'pag', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pam' => [ 'pam', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pap' => [ 'pap', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pcd' => [ 'pcd', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pdc' => [ 'pdc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pdt' => [ 'pdt', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pfl' => [ 'pfl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pi' => [ 'pi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pih' => [ 'pih', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pl' => [ 'pl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pms' => [ 'pms', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pnb' => [ 'pnb', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pnt' => [ 'pnt', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'prg' => [ 'prg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ps' => [ 'ps', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pt' => [ 'pt', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'pt-br' => [ 'pt-br', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'qu' => [ 'qu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'qug' => [ 'qug', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rgn' => [ 'rgn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rif' => [ 'rif', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rm' => [ 'rm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rmy' => [ 'rmy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rn' => [ 'rn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ro' => [ 'ro', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'roa-rup' => [ 'roa-rup', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'roa-tara' => [ 'roa-tara', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ru' => [ 'ru', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rue' => [ 'rue', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rup' => [ 'rup', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ruq' => [ 'ruq', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ruq-cyrl' => [ 'ruq-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + # ['ruq-grek', 'TrivialLanguageConverter', [], [], [], [], []], + 'ruq-latn' => [ 'ruq-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'rw' => [ 'rw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sa' => [ 'sa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sah' => [ 'sah', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sat' => [ 'sat', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sc' => [ 'sc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'scn' => [ 'scn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sco' => [ 'sco', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sd' => [ 'sd', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sdc' => [ 'sdc', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sdh' => [ 'sdh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'se' => [ 'se', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sei' => [ 'sei', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ses' => [ 'ses', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sg' => [ 'sg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sgs' => [ 'sgs', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sh' => [ 'sh', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'shi' => [ 'shi', 'ShiConverter', [ 'shi', 'shi-tfng', 'shi-latn' ], + [ 'shi' => 'shi-tfng','shi-tfng' => 'shi','shi-latn' => 'shi' ], + [], [], [ + 'shi' => 'bidirectional', + 'shi-tfng' => 'bidirectional', + 'shi-latn' => 'bidirectional' + ] + ], + 'shi-tfng' => [ 'shi-tfng', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'shi-latn' => [ 'shi-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'shn' => [ 'shn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'shy-latn' => [ 'shy-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'si' => [ 'si', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'simple' => [ 'simple', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sk' => [ 'sk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'skr' => [ 'skr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'skr-arab' => [ 'skr-arab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sl' => [ 'sl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sli' => [ 'sli', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sm' => [ 'sm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sma' => [ 'sma', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sn' => [ 'sn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'so' => [ 'so', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sq' => [ 'sq', 'TrivialLanguageConverter', [], [], [], [], [] ], + + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + + 'sr' => [ 'sr', 'SrConverter', [ 'sr', 'sr-ec', 'sr-el' ], [ + 'sr' => 'sr-ec', + 'sr-ec' => 'sr', + 'sr-el' => 'sr' + ], [], [ + 'S' => 'S', + 'писмо' => 'S', + 'pismo' => 'S', + 'W' => 'W', + 'реч' => 'W', + 'reč' => 'W', + 'ријеч' => 'W', + 'riječ' => 'W' + ], [ + 'sr' => 'bidirectional', + 'sr-ec' => 'bidirectional', + 'sr-el' => 'bidirectional' + ] + ], + 'sr-ec' => [ 'sr-ec', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sr-el' => [ 'sr-el', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'srn' => [ 'srn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ss' => [ 'ss', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'st' => [ 'st', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sty' => [ 'sty', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'stq' => [ 'stq', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'su' => [ 'su', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sv' => [ 'sv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'sw' => [ 'sw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'szl' => [ 'szl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'szy' => [ 'szy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ta' => [ 'ta', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tay' => [ 'tay', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tcy' => [ 'tcy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'te' => [ 'te', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tet' => [ 'tet', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'tg' => [ 'tg', 'TgConverter', [ 'tg', 'tg-latn' ], [], [], [], [ + 'tg' => 'bidirectional', + 'tg-latn' => 'bidirectional' + ] + ], + 'tg-cyrl' => [ 'tg-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tg-latn' => [ 'tg-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'th' => [ 'th', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ti' => [ 'ti', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tk' => [ 'tk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tl' => [ 'tl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tly' => [ 'tly', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tn' => [ 'tn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'to' => [ 'to', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tpi' => [ 'tpi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tr' => [ 'tr', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tru' => [ 'tru', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ts' => [ 'ts', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tt' => [ 'tt', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tt-cyrl' => [ 'tt-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tt-latn' => [ 'tt-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tum' => [ 'tum', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tw' => [ 'tw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ty' => [ 'ty', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tyv' => [ 'tyv', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'tzm' => [ 'tzm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'udm' => [ 'udm', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ug' => [ 'ug', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ug-arab' => [ 'ug-arab', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ug-latn' => [ 'ug-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'uk' => [ 'uk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'ur' => [ 'ur', 'TrivialLanguageConverter', [], [], [], [], [] ], + + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'uz' => [ 'uz', 'UzConverter', [ 'uz', 'uz-latn', 'uz-cyrl' ], [ + 'uz' => 'uz-latn', + 'uz-cyrl' => 'uz', + 'uz-latn' => 'uz', + ], [], [ + 'uz' => 'uz', + 'uz-latn' => 'uz-latn', + 'uz-cyrl' => 'uz-cyrl' + ], [ + 'uz' => 'bidirectional', + 'uz-latn' => 'bidirectional', + 'uz-cyrl' => 'bidirectional', + ] + ], + 'uz-cyrl' => [ 'uz-cyrl', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'uz-latn' => [ 'uz-latn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 've' => [ 've', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vec' => [ 'vec', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vep' => [ 'vep', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vi' => [ 'vi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vls' => [ 'vls', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vmf' => [ 'vmf', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vo' => [ 'vo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vot' => [ 'vot', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'vro' => [ 'vro', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'wa' => [ 'wa', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'war' => [ 'war', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'wo' => [ 'wo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'wuu' => [ 'wuu', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'xal' => [ 'xal', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'xh' => [ 'xh', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'xmf' => [ 'xmf', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'xsy' => [ 'xsy', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'yi' => [ 'yi', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'yo' => [ 'yo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'yue' => [ 'yue', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'za' => [ 'za', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zea' => [ 'zea', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zgh' => [ 'zgh', 'TrivialLanguageConverter', [], [], [], [], [] ], + # $code, $type, $variants, $variantFallbacks, $variantNames, $flags, $manualLevel + 'zh' => [ 'zh', 'ZhConverter', $zh_variants, $zh_variantfallbacks,[], $zh_flags, $zh_ml ], + 'zh-classical' => [ 'zh-classical', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-cn' => [ 'zh-cn', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-hans' => [ 'zh-hans', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-hant' => [ 'zh-hant', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-hk' => [ 'zh-hk', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-min-nan' => [ 'zh-min-nan', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-mo' => [ 'zh-mo', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-my' => [ 'zh-my', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-sg' => [ 'zh-sg', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-tw' => [ 'zh-tw', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zh-yue' => [ 'zh-yue', 'TrivialLanguageConverter', [], [], [], [], [] ], + 'zu' => [ 'zu', 'TrivialLanguageConverter', [], [], [], [], [] ] + ]; + } +} diff --git a/tests/phpunit/languages/LanguageConverterIntegrationTest.php b/tests/phpunit/languages/LanguageConverterIntegrationTest.php new file mode 100644 index 00000000000..7284840feaa --- /dev/null +++ b/tests/phpunit/languages/LanguageConverterIntegrationTest.php @@ -0,0 +1,44 @@ +getLanguageFactory() + ->getLanguage( $code ); + return $this->factory->getLanguageConverter( $language ); + } + + public function setUp() : void { + $this->factory = new LanguageConverterFactory( false, function () { + $language = MediaWikiServices::getInstance()->getContentLanguage(); + } ); + parent::setUp(); + } + + /** + * @covers LanguageConverter::hasVariant + */ + public function testHasVariant() { + // See LanguageSrTest::testHasVariant() for additional tests + $converterEn = $this->getLanguageConverter( 'en' ); + $this->assertTrue( $converterEn->hasVariant( 'en' ), 'base is always a variant' ); + $this->assertFalse( $converterEn->hasVariant( 'en-bogus' ), 'bogus en variant' ); + + $converterBogus = $this->getLanguageConverter( 'bogus' ); + $this->assertTrue( $converterBogus->hasVariant( 'bogus' ), 'base is always a variant' ); + } +} diff --git a/tests/phpunit/languages/LanguageConverterTest.php b/tests/phpunit/languages/LanguageConverterTest.php index dca42d72e1f..a4887fccf27 100644 --- a/tests/phpunit/languages/LanguageConverterTest.php +++ b/tests/phpunit/languages/LanguageConverterTest.php @@ -1,5 +1,8 @@ createNoOpMock( LocalisationCache::class ), $this->createNoOpMock( LanguageNameUtils::class ), $this->createNoOpMock( LanguageFallback::class ), - $this->createNoOpMock( MapCacheLRU::class ) + $this->createNoOpMock( LanguageConverterFactory::class ) ); } @@ -1976,7 +1980,7 @@ class LanguageIntegrationTest extends LanguageClassesTestCase { MediaWikiServices::getInstance()->getLocalisationCache(), $this->createNoOpMock( LanguageNameUtils::class ), $this->createNoOpMock( LanguageFallback::class ), - $this->createNoOpMock( MapCacheLRU::class ) + $this->createNoOpMock( LanguageConverterFactory::class ) ); $config += [ 'wgMetaNamespace' => 'Project', diff --git a/tests/phpunit/languages/classes/LanguageCrhTest.php b/tests/phpunit/languages/classes/LanguageCrhTest.php index 84a4c467572..45b9d2db939 100644 --- a/tests/phpunit/languages/classes/LanguageCrhTest.php +++ b/tests/phpunit/languages/classes/LanguageCrhTest.php @@ -1,7 +1,6 @@ getParentLanguage( $l->getCode() ); $this->assertTrue( $p !== null, 'parent language exists' ); $this->assertEquals( 'sr', $p->getCode(), 'sr is parent language' ); - $this->assertTrue( $p instanceof LanguageSr, 'parent is LanguageSr' ); // This is a valid variant of the base $this->assertTrue( $p->hasVariant( $l->getCode() ) ); // This test should be tweaked if/when sr-ec is renamed (T117845) @@ -297,7 +295,7 @@ class LanguageSrTest extends LanguageClassesTestCase { /** Wrapper for converter::convertTo() method */ protected function convertTo( $text, $variant ) { return $this->getLang() - ->mConverter + ->getConverter() ->convertTo( $text, $variant ); diff --git a/tests/phpunit/languages/classes/LanguageTgTest.php b/tests/phpunit/languages/classes/LanguageTgTest.php index 89697675ab0..24ee19d8836 100644 --- a/tests/phpunit/languages/classes/LanguageTgTest.php +++ b/tests/phpunit/languages/classes/LanguageTgTest.php @@ -1,7 +1,6 @@ getLang()->mConverter->convertTo( $text, $variant ); + return $this->getLang()->getConverter()->convertTo( $text, $variant ); } protected function convertToCyrillic( $text ) { diff --git a/tests/phpunit/unit/languages/LanguageTest.php b/tests/phpunit/unit/languages/LanguageTest.php index 18261290cc9..4b6d1d4c067 100644 --- a/tests/phpunit/unit/languages/LanguageTest.php +++ b/tests/phpunit/unit/languages/LanguageTest.php @@ -1,5 +1,6 @@ createNoOpMock( LocalisationCache::class ), $this->createNoOpMock( LanguageNameUtils::class ), - $this->createNoOpMock( LanguageFallback::class ) + $this->createNoOpMock( LanguageFallback::class ), + $this->createNoOpMock( LanguageConverterFactory::class ) ); }