Файловый менеджер - Редактировать - /var/www/html/Language.zip
Ðазад
PK ! ���l l Language.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; /** * Base class for Language objects. */ class Language { /** @var LanguageConverter|null */ private $converter; public function getConverter(): ?LanguageConverter { return $this->converter; } public function setConverter( LanguageConverter $converter ): void { $this->converter = $converter; } /** * Returns true if a language code string is of a valid form, whether or not it exists. * This includes codes which are used solely for customisation via the MediaWiki namespace. * @param string $code a MediaWiki-internal code * @return bool */ public static function isValidInternalCode( string $code ): bool { static $validityCache = []; if ( !isset( $validityCache[$code] ) ) { $validityCache[$code] = strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code ) && // XXX Core's version also checks against // !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code ) && strlen( $code ) <= 128; } return $validityCache[$code]; } /** * Get an array of language names, indexed by code. * @param string $inLanguage Code of language in which to return the names. * Use null for autonyms (native names) * @param string $include One of: * * `all` all available languages * * `mw` only if the language is defined in MediaWiki or `wgExtraLanguageNames` (default) * * `mwfile` only if the language is in `mw` *and* has a message file * @return array * @deprecated Appears to be unused */ public function fetchLanguageNames( string $inLanguage, string $include ): array { return []; } } PK ! wp�u LanguageFactoryInterface.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface defining a factory which can create language objects * * @since 4.0.0 */ interface LanguageFactoryInterface { /** * Method to get an instance of a language. * * @param string $lang The language to use * @param boolean $debug The debug mode * * @return Language * * @since 4.0.0 */ public function createLanguage($lang, $debug = false): Language; } PK ! �>>5L L LanguageFactory.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Default factory for creating language objects * * @since 4.0.0 */ class LanguageFactory implements LanguageFactoryInterface { /** * Method to get an instance of a language. * * @param string $lang The language to use * @param boolean $debug The debug mode * * @return Language * * @since 4.0.0 */ public function createLanguage($lang, $debug = false): Language { return new Language($lang, $debug); } } PK ! 7���\ �\ LanguageHelper.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; use Joomla\CMS\Cache\CacheControllerFactoryInterface; use Joomla\CMS\Cache\Controller\OutputController; use Joomla\CMS\Factory; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Log\Log; use Joomla\Database\DatabaseInterface; use Joomla\Filesystem\File; use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Language helper class * * @since 1.5 */ class LanguageHelper { /** * Builds a list of the system languages which can be used in a select option * * @param string $actualLanguage Client key for the area * @param string $basePath Base path to use * @param boolean $caching True if caching is used * @param boolean $installed Get only installed languages * * @return array List of system languages * * @since 1.5 */ public static function createLanguageList($actualLanguage, $basePath = JPATH_BASE, $caching = false, $installed = false) { $list = []; $clientId = $basePath === JPATH_ADMINISTRATOR ? 1 : 0; $languages = $installed ? static::getInstalledLanguages($clientId, true) : self::getKnownLanguages($basePath); foreach ($languages as $languageCode => $language) { $metadata = $installed ? $language->metadata : $language; $list[] = [ 'text' => $metadata['nativeName'] ?? $metadata['name'], 'value' => $languageCode, 'selected' => $languageCode === $actualLanguage ? 'selected="selected"' : null, ]; } return $list; } /** * Builds a list of the system languages which can be used in a select option * with both the native name and the english name * * @param string $actualLanguage Client key for the area * @param string $basePath Base path to use * @param boolean $caching True if caching is used * @param boolean $installed Get only installed languages * * @return array List of system languages * * @since 5.1.0 */ public static function createLanguageListInstall($actualLanguage, $basePath = JPATH_BASE, $caching = false, $installed = false) { $list = []; $clientId = $basePath === JPATH_ADMINISTRATOR ? 1 : 0; $languages = $installed ? static::getInstalledLanguages($clientId, true) : self::getKnownLanguages($basePath); foreach ($languages as $languageCode => $language) { $metadata = $installed ? $language->metadata : $language; $list[] = [ 'text' => $metadata['name'] . ' | ' . $metadata['nativeName'] ?? $metadata['name'], 'value' => $languageCode, 'selected' => $languageCode === $actualLanguage ? 'selected="selected"' : null, ]; } return $list; } /** * Tries to detect the language. * * @return string locale or null if not found * * @since 1.5 */ public static function detectLanguage() { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $browserLangs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); $systemLangs = self::getLanguages(); foreach ($browserLangs as $browserLang) { // Slice out the part before ; on first step, the part before - on second, place into array $browserLang = substr($browserLang, 0, strcspn($browserLang, ';')); $primary_browserLang = substr($browserLang, 0, 2); foreach ($systemLangs as $systemLang) { // Take off 3 letters iso code languages as they can't match browsers' languages and default them to en $Jinstall_lang = $systemLang->lang_code; if (\strlen($Jinstall_lang) < 6) { if (strtolower($browserLang) == strtolower(substr($systemLang->lang_code, 0, \strlen($browserLang)))) { return $systemLang->lang_code; } if ($primary_browserLang == substr($systemLang->lang_code, 0, 2)) { $primaryDetectedLang = $systemLang->lang_code; } } } if (isset($primaryDetectedLang)) { return $primaryDetectedLang; } } } return null; } /** * Get available languages * * @param string $key Array key * * @return array An array of published languages * * @since 1.6 */ public static function getLanguages($key = 'default') { static $languages = []; if (!\count($languages)) { // Installation uses available languages if (Factory::getApplication()->isClient('installation')) { $languages[$key] = []; $knownLangs = self::getKnownLanguages(JPATH_BASE); foreach ($knownLangs as $metadata) { // Take off 3 letters iso code languages as they can't match browsers' languages and default them to en $obj = new \stdClass(); $obj->lang_code = $metadata['tag']; $languages[$key][] = $obj; } } else { /** @var OutputController $cache */ $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) ->createCacheController('output', ['defaultgroup' => 'com_languages']); if ($cache->contains('languages')) { $languages = $cache->get('languages'); } else { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__languages')) ->where($db->quoteName('published') . ' = 1') ->order($db->quoteName('ordering') . ' ASC'); $db->setQuery($query); $languages['default'] = $db->loadObjectList(); $languages['sef'] = []; $languages['lang_code'] = []; if (isset($languages['default'][0])) { foreach ($languages['default'] as $lang) { $languages['sef'][$lang->sef] = $lang; $languages['lang_code'][$lang->lang_code] = $lang; } } $cache->store($languages, 'languages'); } } } return $languages[$key]; } /** * Get a list of installed languages. * * @param integer $clientId The client app id. * @param boolean $processMetaData Fetch Language metadata. * @param boolean $processManifest Fetch Language manifest. * @param string $pivot The pivot of the returning array. * @param string $orderField Field to order the results. * @param string $orderDirection Direction to order the results. * @param ?DatabaseInterface $db Database object to use database queries * * @return array Array with the installed languages. * * @since 3.7.0 */ public static function getInstalledLanguages( $clientId = null, $processMetaData = false, $processManifest = false, $pivot = 'element', $orderField = null, $orderDirection = null, ?DatabaseInterface $db = null ) { static $installedLanguages = null; if ($installedLanguages === null) { /** @var OutputController $cache */ $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) ->createCacheController('output', ['defaultgroup' => 'com_languages']); if ($cache->contains('installedlanguages')) { $installedLanguages = $cache->get('installedlanguages'); } else { $db ??= Factory::getContainer()->get(DatabaseInterface::class); $query = $db->getQuery(true) ->select( [ $db->quoteName('element'), $db->quoteName('name'), $db->quoteName('client_id'), $db->quoteName('extension_id'), ] ) ->from($db->quoteName('#__extensions')) ->where( [ $db->quoteName('type') . ' = ' . $db->quote('language'), $db->quoteName('state') . ' = 0', $db->quoteName('enabled') . ' = 1', ] ); $installedLanguages = $db->setQuery($query)->loadObjectList(); $cache->store($installedLanguages, 'installedlanguages'); } } $clients = $clientId === null ? [0, 1] : [(int) $clientId]; $languages = [ 0 => [], 1 => [], ]; foreach ($installedLanguages as $language) { // If the language client is not needed continue cycle. Drop for performance. if (!\in_array((int) $language->client_id, $clients)) { continue; } $lang = $language; if ($processMetaData || $processManifest) { $clientPath = (int) $language->client_id === 0 ? JPATH_SITE : JPATH_ADMINISTRATOR; $metafile = self::getLanguagePath($clientPath, $language->element) . '/langmetadata.xml'; if (!is_file($metafile)) { $metafile = self::getLanguagePath($clientPath, $language->element) . '/' . $language->element . '.xml'; } // Process the language metadata. if ($processMetaData) { try { $lang->metadata = self::parseXMLLanguageFile($metafile); } catch (\Exception) { // Not able to process xml language file. Fail silently. Log::add(Text::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METAFILE', $language->element, $metafile), Log::WARNING, 'language'); continue; } // No metadata found, not a valid language. Fail silently. if (!\is_array($lang->metadata)) { Log::add(Text::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METADATA', $language->element, $metafile), Log::WARNING, 'language'); continue; } } // Process the language manifest. if ($processManifest) { try { $lang->manifest = Installer::parseXMLInstallFile($metafile); } catch (\Exception) { // Not able to process xml language file. Fail silently. Log::add(Text::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METAFILE', $language->element, $metafile), Log::WARNING, 'language'); continue; } // No metadata found, not a valid language. Fail silently. if (!\is_array($lang->manifest)) { Log::add(Text::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METADATA', $language->element, $metafile), Log::WARNING, 'language'); continue; } } } $languages[$language->client_id][] = $lang; } // Order the list, if needed. if ($orderField !== null && $orderDirection !== null) { $orderDirection = strtolower($orderDirection) === 'desc' ? -1 : 1; foreach ($languages as $cId => $language) { // If the language client is not needed continue cycle. Drop for performance. if (!\in_array($cId, $clients)) { continue; } $languages[$cId] = ArrayHelper::sortObjects($language, $orderField, $orderDirection, true, true); } } // Add the pivot, if needed. if ($pivot !== null) { foreach ($languages as $cId => $language) { // If the language client is not needed continue cycle. Drop for performance. if (!\in_array($cId, $clients)) { continue; } $languages[$cId] = ArrayHelper::pivot($language, $pivot); } } return $clientId !== null ? $languages[$clientId] : $languages; } /** * Get a list of content languages. * * @param array $publishedStates Array with the content language published states. Empty array for all. * @param boolean $checkInstalled Check if the content language is installed. * @param string $pivot The pivot of the returning array. * @param string $orderField Field to order the results. * @param string $orderDirection Direction to order the results. * * @return array Array of the content languages. * * @since 3.7.0 */ public static function getContentLanguages( $publishedStates = [1], $checkInstalled = true, $pivot = 'lang_code', $orderField = null, $orderDirection = null ) { static $contentLanguages = null; if ($contentLanguages === null) { /** @var OutputController $cache */ $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) ->createCacheController('output', ['defaultgroup' => 'com_languages']); if ($cache->contains('contentlanguages')) { $contentLanguages = $cache->get('contentlanguages'); } else { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__languages')); $contentLanguages = $db->setQuery($query)->loadObjectList(); $cache->store($contentLanguages, 'contentlanguages'); } } $languages = $contentLanguages; // B/C layer. Before 3.8.3. if ($publishedStates === true) { $publishedStates = [1]; } elseif ($publishedStates === false) { $publishedStates = []; } // Check the language published state, if needed. if (\count($publishedStates) > 0) { foreach ($languages as $key => $language) { if (!\in_array((int) $language->published, $publishedStates, true)) { unset($languages[$key]); } } } // Check if the language is installed, if needed. if ($checkInstalled) { $languages = array_values(array_intersect_key(ArrayHelper::pivot($languages, 'lang_code'), static::getInstalledLanguages(0))); } // Order the list, if needed. if ($orderField !== null && $orderDirection !== null) { $languages = ArrayHelper::sortObjects($languages, $orderField, strtolower($orderDirection) === 'desc' ? -1 : 1, true, true); } // Add the pivot, if needed. if ($pivot !== null) { $languages = ArrayHelper::pivot($languages, $pivot); } return $languages; } /** * Parse strings from a language file. * * @param string $fileName The language ini file path. * @param boolean $debug If set to true debug language ini file. * * @return array The strings parsed. * * @since 3.9.0 * @throws \RuntimeException On debug */ public static function parseIniFile($fileName, $debug = false) { // Check if file exists. if (!is_file($fileName)) { return []; } // This was required for https://github.com/joomla/joomla-cms/issues/17198 but not sure what server setup // issue it is solving $disabledFunctions = explode(',', \ini_get('disable_functions')); $isParseIniFileDisabled = \in_array('parse_ini_file', array_map('trim', $disabledFunctions)); // Capture hidden PHP errors from the parsing. set_error_handler(static function ($errno, $err) { throw new \Exception($err); }, \E_WARNING); try { if (!\function_exists('parse_ini_file') || $isParseIniFileDisabled) { $contents = file_get_contents($fileName); $strings = parse_ini_string($contents, false, INI_SCANNER_RAW); } else { $strings = parse_ini_file($fileName, false, INI_SCANNER_RAW); } } catch (\Exception $e) { if ($debug) { throw new \RuntimeException($e->getMessage()); } return []; } finally { restore_error_handler(); } // Ini files are processed in the "RAW" mode of parse_ini_string, leaving escaped quotes untouched - lets postprocess them $strings = str_replace('\"', '"', $strings); return \is_array($strings) ? $strings : []; } /** * Save strings to a language file. * * @param string $fileName The language ini file path. * @param array $strings The array of strings. * * @return boolean True if saved, false otherwise. * * @since 3.7.0 */ public static function saveToIniFile($fileName, array $strings) { // Escape double quotes. foreach ($strings as $key => $string) { $strings[$key] = addcslashes($string, '"'); } // Write override.ini file with the strings. $registry = new Registry($strings); return File::write($fileName, $registry->toString('INI')); } /** * Checks if a language exists. * * This is a simple, quick check for the directory that should contain language files for the given user. * * @param string $lang Language to check. * @param string $basePath Optional path to check. * * @return boolean True if the language exists. * * @since 3.7.0 */ public static function exists($lang, $basePath = JPATH_BASE) { static $paths = []; // Return false if no language was specified if (!$lang) { return false; } $path = $basePath . '/language/' . $lang; // Return previous check results if it exists if (isset($paths[$path])) { return $paths[$path]; } // Check if the language exists $paths[$path] = is_dir($path); return $paths[$path]; } /** * Returns an associative array holding the metadata. * * @param string $lang The name of the language. * * @return mixed If $lang exists return key/value pair with the language metadata, otherwise return NULL. * * @since 3.7.0 */ public static function getMetadata($lang) { $file = self::getLanguagePath(JPATH_BASE, $lang) . '/langmetadata.xml'; if (!is_file($file)) { $file = self::getLanguagePath(JPATH_BASE, $lang) . '/' . $lang . '.xml'; } $result = null; if (is_file($file)) { $result = self::parseXMLLanguageFile($file); } if (empty($result)) { return; } return $result; } /** * Returns a list of known languages for an area * * @param string $basePath The basepath to use * * @return array key/value pair with the language file and real name. * * @since 3.7.0 */ public static function getKnownLanguages($basePath = JPATH_BASE) { return self::parseLanguageFiles(self::getLanguagePath($basePath)); } /** * Get the path to a language * * @param string $basePath The basepath to use. * @param string $language The language tag. * * @return string language related path or null. * * @since 3.7.0 */ public static function getLanguagePath($basePath = JPATH_BASE, $language = null) { return $basePath . '/language' . (!empty($language) ? '/' . $language : ''); } /** * Searches for language directories within a certain base dir. * * @param string $dir directory of files. * * @return array Array holding the found languages as filename => real name pairs. * * @since 3.7.0 */ public static function parseLanguageFiles($dir = null) { $languages = []; // Search main language directory for subdirectories foreach (glob($dir . '/*', GLOB_NOSORT | GLOB_ONLYDIR) as $directory) { // But only directories with lang code format if (preg_match('#/[a-z]{2,3}-[A-Z]{2}$#', $directory)) { $dirPathParts = pathinfo($directory); $file = $directory . '/langmetadata.xml'; if (!is_file($file)) { $file = $directory . '/' . $dirPathParts['filename'] . '.xml'; } if (!is_file($file)) { continue; } try { // Get installed language metadata from xml file and merge it with lang array if ($metadata = self::parseXMLLanguageFile($file)) { $languages = array_replace($languages, [$dirPathParts['filename'] => $metadata]); } } catch (\RuntimeException) { // Ignore it } } } return $languages; } /** * Parse XML file for language information. * * @param string $path Path to the XML files. * * @return array Array holding the found metadata as a key => value pair. * * @since 3.7.0 * @throws \RuntimeException */ public static function parseXMLLanguageFile($path) { if (!is_readable($path)) { throw new \RuntimeException('File not found or not readable'); } // Try to load the file $xml = simplexml_load_file($path); if (!$xml) { return; } // Check that it's a metadata file if ((string) $xml->getName() !== 'metafile') { return; } $metadata = []; foreach ($xml->metadata->children() as $child) { $metadata[$child->getName()] = (string) $child; } return $metadata; } } PK ! n++� � Multilanguage.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Factory; use Joomla\Database\DatabaseInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Utility class for multilang * * @since 2.5.4 */ class Multilanguage { /** * Flag indicating multilanguage functionality is enabled. * * @var boolean * @since 4.0.0 */ public static $enabled = false; /** * Method to determine if the language filter plugin is enabled. * This works for both site and administrator. * * @param ?CMSApplication $app The application * @param ?DatabaseInterface $db The database * * @return boolean True if site is supporting multiple languages; false otherwise. * * @since 2.5.4 */ public static function isEnabled(?CMSApplication $app = null, ?DatabaseInterface $db = null) { // Flag to avoid doing multiple database queries. static $tested = false; // Do not proceed with testing if the flag is true if (static::$enabled) { return true; } // Get application object. $app = $app ?: Factory::getApplication(); // If being called from the frontend, we can avoid the database query. if ($app->isClient('site')) { static::$enabled = $app->getLanguageFilter(); return static::$enabled; } // If already tested, don't test again. if (!$tested) { // Determine status of language filter plugin. $db = $db ?: Factory::getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('enabled')) ->from($db->quoteName('#__extensions')) ->where( [ $db->quoteName('type') . ' = ' . $db->quote('plugin'), $db->quoteName('folder') . ' = ' . $db->quote('system'), $db->quoteName('element') . ' = ' . $db->quote('languagefilter'), ] ); $db->setQuery($query); static::$enabled = (bool) $db->loadResult(); $tested = true; } return static::$enabled; } /** * Method to return a list of language home page menu items. * * @param ?DatabaseInterface $db The database * * @return array of menu objects. * * @since 3.5 */ public static function getSiteHomePages(?DatabaseInterface $db = null) { // To avoid doing duplicate database queries. static $multilangSiteHomePages = null; if (!isset($multilangSiteHomePages)) { // Check for Home pages languages. $db = $db ?: Factory::getDbo(); $query = $db->getQuery(true) ->select( [ $db->quoteName('language'), $db->quoteName('id'), ] ) ->from($db->quoteName('#__menu')) ->where( [ $db->quoteName('home') . ' = ' . $db->quote('1'), $db->quoteName('published') . ' = 1', $db->quoteName('client_id') . ' = 0', ] ); $db->setQuery($query); $multilangSiteHomePages = $db->loadObjectList('language'); } return $multilangSiteHomePages; } } PK ! 7�#�� � Transliterate.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Class to transliterate strings * * @since 1.7.0 * @note Port of phputf8's utf8_accents_to_ascii() */ class Transliterate { /** * Returns strings transliterated from UTF-8 to Latin * * @param string $string String to transliterate * @param integer $case Optionally specify upper or lower case. Default to null. * * @return string Transliterated string * * @since 1.7.0 */ public static function utf8_latin_to_ascii($string, $case = 0) { static $UTF8_LOWER_ACCENTS = null; static $UTF8_UPPER_ACCENTS = null; if ($case <= 0) { if (\is_null($UTF8_LOWER_ACCENTS)) { $UTF8_LOWER_ACCENTS = [ 'à' => 'a', 'ô' => 'o', 'ď' => 'd', 'ḟ' => 'f', 'ë' => 'e', 'š' => 's', 'ơ' => 'o', 'ß' => 'ss', 'ă' => 'a', 'ř' => 'r', 'ț' => 't', 'ň' => 'n', 'ā' => 'a', 'ķ' => 'k', 'ŝ' => 's', 'ỳ' => 'y', 'ņ' => 'n', 'ĺ' => 'l', 'ħ' => 'h', 'ṗ' => 'p', 'ó' => 'o', 'ú' => 'u', 'ě' => 'e', 'é' => 'e', 'ç' => 'c', 'ẁ' => 'w', 'ċ' => 'c', 'õ' => 'o', 'ṡ' => 's', 'ø' => 'o', 'ģ' => 'g', 'ŧ' => 't', 'ș' => 's', 'ė' => 'e', 'ĉ' => 'c', 'ś' => 's', 'î' => 'i', 'ű' => 'u', 'ć' => 'c', 'ę' => 'e', 'ŵ' => 'w', 'ṫ' => 't', 'ū' => 'u', 'č' => 'c', 'ö' => 'oe', 'è' => 'e', 'ŷ' => 'y', 'ą' => 'a', 'ł' => 'l', 'ų' => 'u', 'ů' => 'u', 'ş' => 's', 'ğ' => 'g', 'ļ' => 'l', 'ƒ' => 'f', 'ž' => 'z', 'ẃ' => 'w', 'ḃ' => 'b', 'å' => 'a', 'ì' => 'i', 'ï' => 'i', 'ḋ' => 'd', 'ť' => 't', 'ŗ' => 'r', 'ä' => 'ae', 'í' => 'i', 'ŕ' => 'r', 'ê' => 'e', 'ü' => 'ue', 'ò' => 'o', 'ē' => 'e', 'ñ' => 'n', 'ń' => 'n', 'ĥ' => 'h', 'ĝ' => 'g', 'đ' => 'd', 'ĵ' => 'j', 'ÿ' => 'y', 'ũ' => 'u', 'ŭ' => 'u', 'ư' => 'u', 'ţ' => 't', 'ý' => 'y', 'ő' => 'o', 'â' => 'a', 'ľ' => 'l', 'ẅ' => 'w', 'ż' => 'z', 'ī' => 'i', 'ã' => 'a', 'ġ' => 'g', 'ṁ' => 'm', 'ō' => 'o', 'ĩ' => 'i', 'ù' => 'u', 'į' => 'i', 'ź' => 'z', 'á' => 'a', 'û' => 'u', 'þ' => 'th', 'ð' => 'dh', 'æ' => 'ae', 'µ' => 'u', 'ĕ' => 'e', 'œ' => 'oe', ]; } $string = str_replace(array_keys($UTF8_LOWER_ACCENTS), array_values($UTF8_LOWER_ACCENTS), $string); } if ($case >= 0) { if (\is_null($UTF8_UPPER_ACCENTS)) { $UTF8_UPPER_ACCENTS = [ 'À' => 'A', 'Ô' => 'O', 'Ď' => 'D', 'Ḟ' => 'F', 'Ë' => 'E', 'Š' => 'S', 'Ơ' => 'O', 'Ă' => 'A', 'Ř' => 'R', 'Ț' => 'T', 'Ň' => 'N', 'Ā' => 'A', 'Ķ' => 'K', 'Ŝ' => 'S', 'Ỳ' => 'Y', 'Ņ' => 'N', 'Ĺ' => 'L', 'Ħ' => 'H', 'Ṗ' => 'P', 'Ó' => 'O', 'Ú' => 'U', 'Ě' => 'E', 'É' => 'E', 'Ç' => 'C', 'Ẁ' => 'W', 'Ċ' => 'C', 'Õ' => 'O', 'Ṡ' => 'S', 'Ø' => 'O', 'Ģ' => 'G', 'Ŧ' => 'T', 'Ș' => 'S', 'Ė' => 'E', 'Ĉ' => 'C', 'Ś' => 'S', 'Î' => 'I', 'Ű' => 'U', 'Ć' => 'C', 'Ę' => 'E', 'Ŵ' => 'W', 'Ṫ' => 'T', 'Ū' => 'U', 'Č' => 'C', 'Ö' => 'Oe', 'È' => 'E', 'Ŷ' => 'Y', 'Ą' => 'A', 'Ł' => 'L', 'Ų' => 'U', 'Ů' => 'U', 'Ş' => 'S', 'Ğ' => 'G', 'Ļ' => 'L', 'Ƒ' => 'F', 'Ž' => 'Z', 'Ẃ' => 'W', 'Ḃ' => 'B', 'Å' => 'A', 'Ì' => 'I', 'Ï' => 'I', 'Ḋ' => 'D', 'Ť' => 'T', 'Ŗ' => 'R', 'Ä' => 'Ae', 'Í' => 'I', 'Ŕ' => 'R', 'Ê' => 'E', 'Ü' => 'Ue', 'Ò' => 'O', 'Ē' => 'E', 'Ñ' => 'N', 'Ń' => 'N', 'Ĥ' => 'H', 'Ĝ' => 'G', 'Đ' => 'D', 'Ĵ' => 'J', 'Ÿ' => 'Y', 'Ũ' => 'U', 'Ŭ' => 'U', 'Ư' => 'U', 'Ţ' => 'T', 'Ý' => 'Y', 'Ő' => 'O', 'Â' => 'A', 'Ľ' => 'L', 'Ẅ' => 'W', 'Ż' => 'Z', 'Ī' => 'I', 'Ã' => 'A', 'Ġ' => 'G', 'Ṁ' => 'M', 'Ō' => 'O', 'Ĩ' => 'I', 'Ù' => 'U', 'Į' => 'I', 'Ź' => 'Z', 'Á' => 'A', 'Û' => 'U', 'Þ' => 'Th', 'Ð' => 'Dh', 'Æ' => 'Ae', 'Ĕ' => 'E', 'Œ' => 'Oe', ]; } $string = str_replace(array_keys($UTF8_UPPER_ACCENTS), array_values($UTF8_UPPER_ACCENTS), $string); } return $string; } } PK ! !�X X Associations.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Utility class for associations in multilang * * @since 3.1 */ class Associations { /** * Get the associations. * * @param string $extension The name of the component. * @param string $tablename The name of the table. * @param string $context The context * @param integer $id The primary key value. * @param string $pk The name of the primary key in the given $table. * @param string $aliasField If the table has an alias field set it here. Null to not use it * @param string $catField If the table has a catid field set it here. Null to not use it * @param array $advClause Additional advanced 'where' clause; use c as parent column key, c2 as associations column key * * @return array The associated items * * @since 3.1 * * @throws \Exception */ public static function getAssociations( $extension, $tablename, $context, $id, $pk = 'id', $aliasField = 'alias', $catField = 'catid', $advClause = [] ) { // To avoid doing duplicate database queries. static $multilanguageAssociations = []; // Cast before creating cache key. $id = (int) $id; // Multilanguage association array key. If the key is already in the array we don't need to run the query again, just return it. $queryKey = md5(serialize(array_merge([$extension, $tablename, $context, $id], $advClause))); if (!isset($multilanguageAssociations[$queryKey])) { $multilanguageAssociations[$queryKey] = []; $db = Factory::getDbo(); $query = $db->getQuery(true); $categoriesExtraSql = ''; if ($tablename === '#__categories') { $categoriesExtraSql = ' AND c2.extension = :extension1'; $query->bind(':extension1', $extension); } $query->select($db->quoteName('c2.language')) ->from($db->quoteName($tablename, 'c')) ->join( 'INNER', $db->quoteName('#__associations', 'a'), $db->quoteName('a.id') . ' = ' . $db->quoteName('c.' . $pk) . ' AND ' . $db->quoteName('a.context') . ' = :context' ) ->bind(':context', $context) ->join('INNER', $db->quoteName('#__associations', 'a2'), $db->quoteName('a.key') . ' = ' . $db->quoteName('a2.key')) ->join( 'INNER', $db->quoteName($tablename, 'c2'), $db->quoteName('a2.id') . ' = ' . $db->quoteName('c2.' . $pk) . $categoriesExtraSql ); // Use alias field ? if (!empty($aliasField)) { $query->select( $query->concatenate( [ $db->quoteName('c2.' . $pk), $db->quoteName('c2.' . $aliasField), ], ':' ) . ' AS ' . $db->quoteName($pk) ); } else { $query->select($db->quoteName('c2.' . $pk)); } // Use catid field ? if (!empty($catField)) { $query->join( 'INNER', $db->quoteName('#__categories', 'ca'), $db->quoteName('c2.' . $catField) . ' = ' . $db->quoteName('ca.id') . ' AND ' . $db->quoteName('ca.extension') . ' = :extension2' ) ->bind(':extension2', $extension) ->select( $query->concatenate( [ $db->quoteName('ca.id'), $db->quoteName('ca.alias'), ], ':' ) . ' AS ' . $db->quoteName($catField) ); } $query->where($db->quoteName('c.' . $pk) . ' = :id') ->bind(':id', $id, ParameterType::INTEGER); if ($tablename === '#__categories') { $query->where($db->quoteName('c.extension') . ' = :extension3') ->bind(':extension3', $extension); } // Advanced where clause if (!empty($advClause)) { foreach ($advClause as $clause) { $query->where($clause); } } $db->setQuery($query); try { $items = $db->loadObjectList('language'); } catch (\RuntimeException $e) { throw new \Exception($e->getMessage(), 500, $e); } if ($items) { foreach ($items as $tag => $item) { // Do not return itself as result if ((int) $item->{$pk} !== $id) { $multilanguageAssociations[$queryKey][$tag] = $item; } } } } return $multilanguageAssociations[$queryKey]; } /** * Method to determine if the language filter Associations parameter is enabled. * This works for both site and administrator. * * @return boolean True if the parameter is implemented; false otherwise. * * @since 3.2 */ public static function isEnabled() { // Flag to avoid doing multiple database queries. static $tested = false; // Status of language filter parameter. static $enabled = false; if (Multilanguage::isEnabled()) { // If already tested, don't test again. if (!$tested) { $plugin = PluginHelper::getPlugin('system', 'languagefilter'); if (!empty($plugin)) { $params = new Registry($plugin->params); $enabled = (bool) $params->get('item_associations', true); } $tested = true; } } return $enabled; } } PK ! S�fH� � LanguageAwareTrait.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Defines the trait for a language aware class. * * @since 4.4.0 */ trait LanguageAwareTrait { /** * Language * * @var Language * @since 4.4.0 */ private $language; /** * Get the Language. * * @return Language * * @since 4.4.0 * @throws \UnexpectedValueException May be thrown if the language has not been set. */ protected function getLanguage(): Language { if ($this->language) { return $this->language; } throw new \UnexpectedValueException('Language not set in ' . __CLASS__); } /** * Set the language to use. * * @param Language $language The language to use * * @return void * * @since 4.4.0 */ public function setLanguage(Language $language): void { $this->language = $language; } } PK ! ��ѣ � CachingLanguageFactory.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Caching factory for creating language objects. The requested languages are * cached in memory. * * @since 4.0.0 */ class CachingLanguageFactory extends LanguageFactory { /** * Array of Language objects * * @var Language[] * @since 4.0.0 */ private static $languages = []; /** * Method to get an instance of a language. * * @param string $lang The language to use * @param boolean $debug The debug mode * * @return Language * * @since 4.0.0 */ public function createLanguage($lang, $debug = false): Language { if (!isset(self::$languages[$lang . $debug])) { self::$languages[$lang . $debug] = parent::createLanguage($lang, $debug); } return self::$languages[$lang . $debug]; } } PK ! y���5 �5 Text.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Text handling class. * * @since 1.7.0 */ class Text { /** * JavaScript strings * * @var array * @since 1.7.0 */ protected static $strings = []; /** * Translates a string into the current language. * * Examples: * `<script>alert(Joomla.Text._('<?php echo Text::_("JDEFAULT", array("script"=>true)); ?>'));</script>` * will generate an alert message containing 'Default' * `<?php echo Text::_("JDEFAULT"); ?>` will generate a 'Default' string * * @param string $string The string to translate. * @param mixed $jsSafe Boolean: Make the result javascript safe. * @param boolean $interpretBackSlashes To interpret backslashes (\\=\, \n=carriage return, \t=tabulation) * @param boolean $script To indicate that the string will be push in the javascript language store * * @return string The translated string or the key if $script is true * * @since 1.7.0 */ public static function _($string, $jsSafe = false, $interpretBackSlashes = true, $script = false) { if (\is_array($jsSafe)) { if (\array_key_exists('interpretBackSlashes', $jsSafe)) { $interpretBackSlashes = (bool) $jsSafe['interpretBackSlashes']; } if (\array_key_exists('script', $jsSafe)) { $script = (bool) $jsSafe['script']; } $jsSafe = !empty($jsSafe['jsSafe']); } if (self::passSprintf($string, $jsSafe, $interpretBackSlashes, $script)) { return $string; } $lang = Factory::getLanguage(); if ($script) { static::$strings[$string] = $lang->_($string, $jsSafe, $interpretBackSlashes); return $string; } return $lang->_($string, $jsSafe, $interpretBackSlashes); } /** * Checks the string if it should be interpreted as sprintf and runs sprintf over it. * * @param string &$string The string to translate. * @param mixed $jsSafe Boolean: Make the result javascript safe. * @param boolean $interpretBackSlashes To interpret backslashes (\\=\, \n=carriage return, \t=tabulation) * @param boolean $script To indicate that the string will be push in the javascript language store * * @return boolean Whether the string be interpreted as sprintf * * @since 3.4.4 */ private static function passSprintf(&$string, $jsSafe = false, $interpretBackSlashes = true, $script = false) { // Check if string contains a comma if (empty($string) || !str_contains($string, ',')) { return false; } $lang = Factory::getLanguage(); $string_parts = explode(',', $string); // Pass all parts through the Text translator foreach ($string_parts as $i => $str) { $string_parts[$i] = $lang->_($str, $jsSafe, $interpretBackSlashes); } $first_part = array_shift($string_parts); // Replace custom named placeholders with sprintf style placeholders $first_part = preg_replace('/\[\[%([0-9]+):[^\]]*\]\]/', '%\1$s', $first_part); // Check if string contains sprintf placeholders if (!preg_match('/%([0-9]+\$)?s/', $first_part)) { return false; } $final_string = vsprintf($first_part, $string_parts); // Return false if string hasn't changed if ($first_part === $final_string) { return false; } $string = $final_string; if ($script) { foreach ($string_parts as $str) { static::$strings[$str] = $str; } } return true; } /** * Translates a string into the current language. * * Examples: * `<?php echo Text::alt('JALL', 'language'); ?>` will generate a 'All' string in English but a "Toutes" string in French * `<?php echo Text::alt('JALL', 'module'); ?>` will generate a 'All' string in English but a "Tous" string in French * * @param string $string The string to translate. * @param string $alt The alternate option for global string * @param mixed $jsSafe Boolean: Make the result javascript safe. * @param boolean $interpretBackSlashes To interpret backslashes (\\=\, \n=carriage return, \t=tabulation) * @param boolean $script To indicate that the string will be pushed in the javascript language store * * @return string The translated string or the key if $script is true * * @since 1.7.0 */ public static function alt($string, $alt, $jsSafe = false, $interpretBackSlashes = true, $script = false) { if (Factory::getLanguage()->hasKey($string . '_' . $alt)) { $string .= '_' . $alt; } return static::_($string, $jsSafe, $interpretBackSlashes, $script); } /** * Like Text::sprintf but tries to pluralise the string. * * Note that this method can take a mixed number of arguments as for the sprintf function. * * The last argument can take an array of options: * * array('jsSafe'=>boolean, 'interpretBackSlashes'=>boolean, 'script'=>boolean) * * where: * * jsSafe is a boolean to generate a javascript safe strings. * interpretBackSlashes is a boolean to interpret backslashes \\->\, \n->new line, \t->tabulation. * script is a boolean to indicate that the string will be push in the javascript language store. * * Examples: * `<script>alert(Joomla.Text._('<?php echo Text::plural("COM_PLUGINS_N_ITEMS_UNPUBLISHED", 1, array("script"=>true)); ?>'));</script>` * will generate an alert message containing '1 plugin successfully disabled' * `<?php echo Text::plural('COM_PLUGINS_N_ITEMS_UNPUBLISHED', 1); ?>` will generate a '1 plugin successfully disabled' string * * @param string $string The format string. * @param integer $n The number of items * * @return string The translated strings or the key if 'script' is true in the array of options * * @since 1.7.0 */ public static function plural($string, $n) { $lang = Factory::getLanguage(); $args = \func_get_args(); $count = \count($args); // Try the key from the language plural potential suffixes $found = false; $suffixes = $lang->getPluralSuffixes((int) $n); // Add the count as possible suffix to allow for eg "a dozen" with suffix _12. // Only do that if it is a real plural (more than one) to avoid issues with languages. See https://github.com/joomla/joomla-cms/pull/29029 if ($n != 1) { array_unshift($suffixes, (int) $n); } foreach ($suffixes as $suffix) { $key = $string . '_' . $suffix; if ($lang->hasKey($key)) { $found = true; break; } } // Not found so revert to the original. $key = !$found ? $string : $key; if (\is_array($args[$count - 1])) { $args[0] = $lang->_( $key, \array_key_exists('jsSafe', $args[$count - 1]) ? $args[$count - 1]['jsSafe'] : false, \array_key_exists('interpretBackSlashes', $args[$count - 1]) ? $args[$count - 1]['interpretBackSlashes'] : true ); if (\array_key_exists('script', $args[$count - 1]) && $args[$count - 1]['script']) { static::$strings[$key] = \call_user_func_array('sprintf', $args); return $key; } } else { $args[0] = $lang->_($key); } return \call_user_func_array('sprintf', $args); } /** * Passes a string thru a sprintf. * * Note that this method can take a mixed number of arguments as for the sprintf function. * * The last argument can take an array of options: * * array('jsSafe'=>boolean, 'interpretBackSlashes'=>boolean, 'script'=>boolean) * * where: * * jsSafe is a boolean to generate a javascript safe strings. * interpretBackSlashes is a boolean to interpret backslashes \\->\, \n->new line, \t->tabulation. * script is a boolean to indicate that the string will be push in the javascript language store. * * @param string $string The format string. * * @return string The translated strings or the key if 'script' is true in the array of options. * * @since 1.7.0 */ public static function sprintf($string) { $lang = Factory::getLanguage(); $args = \func_get_args(); $count = \count($args); if (\is_array($args[$count - 1])) { $args[0] = $lang->_( $string, \array_key_exists('jsSafe', $args[$count - 1]) ? $args[$count - 1]['jsSafe'] : false, \array_key_exists('interpretBackSlashes', $args[$count - 1]) ? $args[$count - 1]['interpretBackSlashes'] : true ); if (\array_key_exists('script', $args[$count - 1]) && $args[$count - 1]['script']) { static::$strings[$string] = \call_user_func_array('sprintf', $args); return $string; } } else { $args[0] = $lang->_($string); } // Replace custom named placeholders with sprintf style placeholders $args[0] = preg_replace('/\[\[%([0-9]+):[^\]]*\]\]/', '%\1$s', $args[0]); return \call_user_func_array('sprintf', $args); } /** * Passes a string through a printf. * * Note that this method can take a mixed number of arguments as for the sprintf function. * * @param string $string The format string. * * @return mixed * * @since 1.7.0 */ public static function printf($string) { $lang = Factory::getLanguage(); $args = \func_get_args(); $count = \count($args); if (\is_array($args[$count - 1])) { $args[0] = $lang->_( $string, \array_key_exists('jsSafe', $args[$count - 1]) ? $args[$count - 1]['jsSafe'] : false, \array_key_exists('interpretBackSlashes', $args[$count - 1]) ? $args[$count - 1]['interpretBackSlashes'] : true ); } else { $args[0] = $lang->_($string); } return \call_user_func_array('printf', $args); } /** * Translate a string into the current language and stores it in the JavaScript language store. * * @param string $string The Text key. * @param boolean $jsSafe Legacy parameter to add slashes to the string. * Set it as "false" because the method encodes the string as JSON with json_encode(). * @param boolean $interpretBackSlashes Interpret \t and \n. * * @return array * * @since 1.7.0 */ public static function script($string = null, $jsSafe = false, $interpretBackSlashes = true) { if ($string === null) { @trigger_error( \sprintf( 'As of 3.7.0, passing a null value for the first argument of %1$s() is deprecated and will not be supported in 4.0.' . ' Use the %2$s::getScriptStrings() method to get the strings from the JavaScript language store instead.', __METHOD__, __CLASS__ ), E_USER_DEPRECATED ); } if (\is_array($jsSafe)) { if (\array_key_exists('interpretBackSlashes', $jsSafe)) { $interpretBackSlashes = (bool) $jsSafe['interpretBackSlashes']; } if (\array_key_exists('jsSafe', $jsSafe)) { $jsSafe = (bool) $jsSafe['jsSafe']; } else { $jsSafe = false; } } // Add the string to the array if not null. if ($string !== null) { $doc = Factory::getDocument(); // Get previously added strings $strings = $doc->getScriptOptions('joomla.jtext'); // Normalize the key and translate the string. $key = strtoupper($string); $strings[$key] = Factory::getLanguage()->_($string, $jsSafe, $interpretBackSlashes); static::$strings[$key] = $strings[$key]; // Load core.js dependency HTMLHelper::_('behavior.core'); // Update Joomla.Text script options $doc->addScriptOptions('joomla.jtext', $strings, false); } return static::getScriptStrings(); } /** * Get the strings that have been loaded to the JavaScript language store. * * @return array * * @since 3.7.0 */ public static function getScriptStrings() { return static::$strings; } } PK ! � �� � LanguageAwareInterface.phpnu �[��� <?php /** * Joomla! Content Management System * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Language; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface to be implemented by classes depending on a language. * * @since 4.4.0 */ interface LanguageAwareInterface { /** * Set the language to use. * * @param Language $language The language to use * * @return void * * @since 4.4.0 */ public function setLanguage(Language $language): void; } PK ! #u�2 2 LanguageEn.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; /** English ( / Pig Latin) conversion code */ class LanguageEn extends Language { public function __construct() { $variants = [ 'en', 'en-x-piglatin' ]; $this->setConverter( new EnConverter( $this, 'en', $variants ) ); } } PK ! �e� ZhConverter.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\LangConv\ZhReplacementMachine; /* @note: Use of this class is currently disabled in production, see T346657 */ class ZhConverter extends LanguageConverter { public function loadDefaultTables() { $this->setMachine( new ZhReplacementMachine() ); } // phpcs:ignore MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic public function findVariantLink( $link, $nt, $ignoreOtherCond ) { $ns = $nt->getNamespace(); // do not try to find variants for usernames if ( $ns->isUser() || $ns->isUserTalk ) { return [ 'nt' => $nt, 'link' => $link ]; } // FIXME check whether selected language is 'zh' return parent::findVariantLink( $link, $nt, $ignoreOtherCond ); } } PK ! ��;� SrConverter.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\Bcp47Code\Bcp47Code; use Wikimedia\LangConv\FstReplacementMachine; use Wikimedia\Parsoid\Utils\Utils; class SrConverter extends LanguageConverter { public function loadDefaultTables() { # T320662: should be converted from mediawiki-internal codes $this->setMachine( new FstReplacementMachine( 'sr', [ 'sr-ec', 'sr-el' ] ) ); } // phpcs:ignore MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic public function findVariantLink( $link, $nt, $ignoreOtherCond ) { $ns = $nt->getNamespace(); // do not try to find variants for usernames if ( $ns->isUser() || $ns->isUserTalk ) { return [ 'nt' => $nt, 'link' => $link ]; } // FIXME check whether selected language is 'sr' return parent::findVariantLink( $link, $nt, $ignoreOtherCond ); } /** * Variant based on the ReplacementMachine's bracketing abilities * @param string $text * @param Bcp47Code $variant a language code * @return bool */ public function guessVariant( $text, $variant ) { # T320662 This code is implemented using MW-internal codes $variant = Utils::bcp47ToMwCode( $variant ); $r = []; $machine = $this->getMachine(); '@phan-var FstReplacementMachine $machine'; /* @var FstReplacementMachine $machine */ foreach ( $machine->getCodes() as $code => $ignore1 ) { foreach ( $machine->getCodes() as $othercode => $ignore2 ) { if ( $code === $othercode ) { return false; } $r[] = [ 'code' => $code, 'othercode' => $othercode, 'stats' => $machine->countBrackets( $text, $code, $othercode ) ]; } } uasort( $r, static function ( $a, $b ) { return $a['stats']->unsafe - $b['stats']->unsafe; } ); return $r[0]['othercode'] === $variant; } } PK ! �2h LanguageGuesser.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\Bcp47Code\Bcp47Code; use Wikimedia\Parsoid\DOM\Element; /** * An oracle that gives you a predicted "source language" for every node in a DOM, which is used * when converting the result back to the source language during round-tripping. */ abstract class LanguageGuesser { /** * @param Element $node * @return Bcp47Code predicted source language */ abstract public function guessLang( Element $node ): Bcp47Code; } PK ! e��w)9 )9 LanguageConverter.phpnu �Iw�� <?php declare( strict_types = 1 ); /** * A bidirectional Language Converter, capable of round-tripping variant * conversion. * * Language conversion is as DOMPostProcessor pass, run over the * Parsoid-format HTML output, which may have embedded language converter * rules. We first assign a (guessed) wikitext variant to each DOM node, * the variant we expect the original wikitext was written in, * which will be used when round-tripping the result back to the original * wikitext variant. Then for each applicable text node in the DOM, we * first "bracket" the text, splitting it into cleanly round-trippable * segments and lossy/unclean segments. For the lossy segments we add * additional metadata to the output to record the original text used in * the wikitext to allow round-tripping (and variant-aware editing). * * Note that different wikis have different policies for wikitext variant: * in some wikis all articles are authored in one particular variant, by * convention. In others, it's a "first author gets to choose the variant" * situation. In both cases, a constant/per-article "wikitext variant" may * be specified via some as-of-yet-unimplemented mechanism; either part of * the site configuration, or per-article metadata like pageLanguage. * In other wikis (like zhwiki) the text is a random mix of variants; in * these cases the "wikitext variant" will be null/unspecified, and we'll * dynamically pick the most likely wikitext variant for each subtree. * * Each individual language has a dynamically-loaded subclass of `Language`, * which may also have a `LanguageConverter` subclass to load appropriate * `ReplacementMachine`s and do other language-specific customizations. */ namespace Wikimedia\Parsoid\Language; use DOMDocument; use Wikimedia\Bcp47Code\Bcp47Code; use Wikimedia\LangConv\ReplacementMachine; use Wikimedia\Parsoid\Config\Env; use Wikimedia\Parsoid\Core\ClientError; use Wikimedia\Parsoid\DOM\Document; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\NodeData\TempData; use Wikimedia\Parsoid\Utils\DOMCompat; use Wikimedia\Parsoid\Utils\DOMDataUtils; use Wikimedia\Parsoid\Utils\DOMUtils; use Wikimedia\Parsoid\Utils\Timing; use Wikimedia\Parsoid\Utils\Utils; /** * Base class for language variant conversion. */ class LanguageConverter { /** @var Language */ private $language; /** @var string */ private $langCode; /** @var string[] */ private $variants; /** @var ?array */ private $variantFallbacks; /** @var ?ReplacementMachine */ private $machine; /** * @param Language $language * @param string $langCode The main language code of this language * @param string[] $variants The supported variants of this language * @param ?array $variantfallbacks The fallback language of each variant * @param ?array $flags Defining the custom strings that maps to the flags * @param ?array $manualLevel Limit for supported variants */ public function __construct( Language $language, string $langCode, array $variants, ?array $variantfallbacks = null, ?array $flags = null, ?array $manualLevel = null ) { $this->language = $language; $this->langCode = $langCode; $this->variants = $variants; // XXX subtract disabled variants $this->variantFallbacks = $variantfallbacks; // this.mVariantNames = Language.// XXX // Eagerly load conversion tables. // XXX we could defer loading in the future, or cache more // aggressively $this->loadDefaultTables(); } public function loadDefaultTables() { } /** * Return the {@link ReplacementMachine} powering this conversion. * @return ?ReplacementMachine */ public function getMachine(): ?ReplacementMachine { return $this->machine; } public function setMachine( ReplacementMachine $machine ): void { $this->machine = $machine; } /** * Try to return a classname from a given code. * @param string $code * @param bool $fallback Whether we're going through language fallback * @return class-string Name of the language class (if one were to exist) */ public static function classFromCode( string $code, bool $fallback ): string { if ( $fallback && $code === 'en' ) { return '\Wikimedia\Parsoid\Language\Language'; } else { $code = ucfirst( $code ); $code = str_replace( '-', '_', $code ); $code = preg_replace( '#/|^\.+#', '', $code ); // avoid path attacks return "\Wikimedia\Parsoid\Language\Language{$code}"; } } /** * @param Env $env * @param Bcp47Code $lang a language code * @param bool $fallback * @return Language */ public static function loadLanguage( Env $env, Bcp47Code $lang, bool $fallback = false ): Language { // Our internal language classes still use MW-internal names. $lang = Utils::bcp47ToMwCode( $lang ); try { if ( Language::isValidInternalCode( $lang ) ) { $languageClass = self::classFromCode( $lang, $fallback ); return new $languageClass(); } } catch ( \Error $e ) { /* fall through */ } $fallback = (string)$fallback; $env->log( 'info', "Couldn't load language: {$lang} fallback={$fallback}" ); return new Language(); } // phpcs:ignore MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic public function findVariantLink( $link, $nt, $ignoreOtherCond ) { // XXX unimplemented return [ 'nt' => $nt, 'link' => $link ]; } /** * @param string $fromVariant * @param string $text * @param string $toVariant * @suppress PhanEmptyPublicMethod */ public function translate( $fromVariant, $text, $toVariant ) { // XXX unimplemented } /** * @param string $text * @param Bcp47Code $variant a language code * @return bool * @deprecated Appears to be unused */ public function guessVariant( $text, $variant ) { return false; } /** * Convert the given document into $htmlVariantLanguage, if: * 1) language converter is enabled on this wiki, and * 2) the htmlVariantLanguage is specified, and it is a known variant (not a * base language code) * * The `$wtVariantLanguage`, if provided is expected to be per-wiki or * per-article metadata which specifies a standard "authoring variant" * for this article or wiki. For example, all articles are authored in * Cyrillic by convention. It should be left blank if there is no * consistent convention on the wiki (as for zhwiki, for instance). * * @param Env $env * @param Document $doc The input document. * @param ?Bcp47Code $htmlVariantLanguage The desired output variant. * @param ?Bcp47Code $wtVariantLanguage The variant used by convention when * authoring pages, if there is one; otherwise left null. */ public static function maybeConvert( Env $env, Document $doc, ?Bcp47Code $htmlVariantLanguage, ?Bcp47Code $wtVariantLanguage ): void { // language converter must be enabled for the pagelanguage if ( !$env->langConverterEnabled() ) { return; } // htmlVariantLanguage must be specified, and a language-with-variants if ( $htmlVariantLanguage === null ) { return; } $variants = $env->getSiteConfig()->variantsFor( $htmlVariantLanguage ); if ( $variants === null ) { return; } // htmlVariantLanguage must not be a base language code if ( Utils::isBcp47CodeEqual( $htmlVariantLanguage, $variants['base'] ) ) { // XXX in the future we probably want to go ahead and expand // empty <span>s left by -{...}- constructs, etc. return; } // Record the fact that we've done conversion to htmlVariantLanguage $env->getPageConfig()->setVariantBcp47( $htmlVariantLanguage ); // But don't actually do the conversion if __NOCONTENTCONVERT__ if ( DOMCompat::querySelector( $doc, 'meta[property="mw:PageProp/nocontentconvert"]' ) ) { return; } // OK, convert! self::baseToVariant( $env, DOMCompat::getBody( $doc ), $htmlVariantLanguage, $wtVariantLanguage ); } /** * Convert a text in the "base variant" to a specific variant, given by `htmlVariantLanguage`. If * `wtVariantLanguage` is given, assume that the input wikitext is in `wtVariantLanguage` to * construct round-trip metadata, instead of using a heuristic to guess the best variant * for each DOM subtree of wikitext. * @param Env $env * @param Node $rootNode The root node of a fragment to convert. * @param string|Bcp47Code $htmlVariantLanguage The variant to be used for the output DOM. * This is a mediawiki-internal language code string (T320662, deprecated), * or a BCP 47 language object (preferred). * @param string|Bcp47Code|null $wtVariantLanguage An optional variant assumed for the * input DOM in order to create roundtrip metadata. * This is a mediawiki-internal language code (T320662, deprecated), * or a BCP 47 language object (preferred), or null. */ public static function baseToVariant( Env $env, Node $rootNode, $htmlVariantLanguage, $wtVariantLanguage ): void { // Back-compat w/ old string-passing parameter convention if ( is_string( $htmlVariantLanguage ) ) { $htmlVariantLanguage = Utils::mwCodeToBcp47( $htmlVariantLanguage, true, $env->getSiteConfig()->getLogger() ); } if ( is_string( $wtVariantLanguage ) ) { $wtVariantLanguage = Utils::mwCodeToBcp47( $wtVariantLanguage, true, $env->getSiteConfig()->getLogger() ); } // PageConfig guarantees getPageLanguage() never returns null. $pageLangCode = $env->getPageConfig()->getPageLanguageBcp47(); $guesser = null; $metrics = $env->getSiteConfig()->metrics(); $loadTiming = Timing::start( $metrics ); $languageClass = self::loadLanguage( $env, $pageLangCode ); $lang = new $languageClass(); $langconv = $lang->getConverter(); $htmlVariantLanguageMw = Utils::bcp47ToMwCode( $htmlVariantLanguage ); // XXX we might want to lazily-load conversion tables here. $loadTiming->end( "langconv.{$htmlVariantLanguageMw}.init" ); $loadTiming->end( 'langconv.init' ); // Check the html variant is valid (and implemented!) $validTarget = $langconv !== null && $langconv->getMachine() !== null && array_key_exists( $htmlVariantLanguageMw, $langconv->getMachine()->getCodes() ); if ( !$validTarget ) { // XXX create a warning header? (T197949) $env->log( 'info', "Unimplemented variant: {$htmlVariantLanguageMw}" ); return; /* no conversion */ } // Check that the wikitext variant is valid. $wtVariantLanguageMw = $wtVariantLanguage ? Utils::bcp47ToMwCode( $wtVariantLanguage ) : null; $validSource = $wtVariantLanguage === null || array_key_exists( $wtVariantLanguageMw, $langconv->getMachine()->getCodes() ); if ( !$validSource ) { throw new ClientError( "Invalid wikitext variant: $wtVariantLanguageMw for target $htmlVariantLanguageMw" ); } $timing = Timing::start( $metrics ); if ( $metrics ) { $metrics->increment( 'langconv.count' ); $metrics->increment( "langconv." . $htmlVariantLanguageMw . ".count" ); $env->getSiteConfig()->incrementCounter( 'langconv_count_total', [ 'variant' => $htmlVariantLanguageMw ] ); } // XXX Eventually we'll want to consult some wiki configuration to // decide whether a ConstantLanguageGuesser is more appropriate. if ( $wtVariantLanguage ) { $guesser = new ConstantLanguageGuesser( $wtVariantLanguage ); } else { $guesser = new MachineLanguageGuesser( // @phan-suppress-next-line PhanTypeMismatchArgumentSuperType $langconv->getMachine(), $rootNode, $htmlVariantLanguage ); } $ct = new ConversionTraverser( $env, $htmlVariantLanguage, $guesser, $langconv->getMachine() ); $ct->traverse( null, $rootNode ); // HACK: to avoid data-parsoid="{}" in the output, set the isNew flag // on synthetic spans DOMUtils::assertElt( $rootNode ); foreach ( DOMCompat::querySelectorAll( $rootNode, 'span[typeof="mw:LanguageVariant"][data-mw-variant]' ) as $span ) { $dmwv = DOMDataUtils::getJSONAttribute( $span, 'data-mw-variant', null ); if ( $dmwv->rt ?? false ) { $dp = DOMDataUtils::getDataParsoid( $span ); $dp->setTempFlag( TempData::IS_NEW ); } } $timing->end( 'langconv.total' ); $timing->end( "langconv.{$htmlVariantLanguageMw}.total" ); $loadTiming->end( 'langconv.totalWithInit' ); } /** * Check if support for html variant conversion is implemented * @internal FIXME: Remove once Parsoid's language variant work is completed * @param Env $env * @param Bcp47Code $htmlVariantLanguage The variant to be checked for implementation * @return bool */ public static function implementsLanguageConversionBcp47( Env $env, Bcp47Code $htmlVariantLanguage ): bool { $htmlVariantLanguageMw = Utils::bcp47ToMwCode( $htmlVariantLanguage ); $pageLangCode = $env->getPageConfig()->getPageLanguageBcp47(); $lang = self::loadLanguage( $env, $pageLangCode ); $langconv = $lang->getConverter(); $validTarget = $langconv !== null && $langconv->getMachine() !== null && array_key_exists( $htmlVariantLanguageMw, $langconv->getMachine()->getCodes() ); return $validTarget; } /** * Convert a string in an unknown variant of the page language to all its possible variants. * * @param Env $env * @param DOMDocument $doc * @param string $text * @return string[] map of converted variants keyed by variant language */ public static function autoConvertToAllVariants( Env $env, DOMDocument $doc, string $text ): array { $pageLangCode = $env->getPageConfig()->getPageLanguageBcp47(); // Parsoid's Chinese language converter implementation is not performant enough, // so disable it explicitly (T346657). if ( $pageLangCode->toBcp47Code() === 'zh' ) { return []; } if ( $env->getSiteConfig()->variantsFor( $pageLangCode ) === null ) { // Optimize for the common case where the page language has no variants. return []; } $languageClass = self::loadLanguage( $env, $pageLangCode ); $lang = new $languageClass(); $langconv = $lang->getConverter(); if ( $langconv === null || $langconv->getMachine() === null ) { return []; } $machine = $langconv->getMachine(); $codes = $machine->getCodes(); $textByVariant = []; foreach ( $codes as $destCode ) { foreach ( $codes as $invertCode ) { if ( !$machine->isValidCodePair( $destCode, $invertCode ) ) { continue; } $fragment = $machine->convert( $doc, $text, $destCode, $invertCode ); $converted = $fragment->textContent; if ( $converted !== $text ) { $textByVariant[$destCode] = $converted; // Move on to the next code once we found a candidate conversion, // to match behavior with the old LanguageConverter. break; } } } return $textByVariant; } } PK ! Ml�w w LanguageSr.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; /** Serbian (Српски / Srpski) specific code. */ class LanguageSr extends Language { public function __construct() { $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', ]; $converter = new SrConverter( $this, 'sr', $variants, $variantfallbacks, $flags ); $this->setConverter( $converter ); } } PK ! )��� � LanguageZh.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; /* @note: Use of this class is currently disabled in production, see T346657 */ /** Chinese conversion code. */ class LanguageZh extends Language { public function __construct() { $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' ], ]; $manualLevel = [ 'zh' => 'disable', 'zh-hans' => 'unidirectional', 'zh-hant' => 'unidirectional', ]; $converter = new ZhConverter( $this, 'zh', $variants, $variantfallbacks, [], $manualLevel ); $this->setConverter( $converter ); } } PK ! 8V��d! d! ConversionTraverser.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\Assert\Assert; use Wikimedia\Bcp47Code\Bcp47Code; use Wikimedia\LangConv\ReplacementMachine; use Wikimedia\Parsoid\Config\Env; use Wikimedia\Parsoid\DOM\DocumentFragment; use Wikimedia\Parsoid\DOM\Element; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\DOM\Text; use Wikimedia\Parsoid\Utils\DOMCompat; use Wikimedia\Parsoid\Utils\DOMDataUtils; use Wikimedia\Parsoid\Utils\DOMTraverser; use Wikimedia\Parsoid\Utils\DOMUtils; use Wikimedia\Parsoid\Utils\Utils; class ConversionTraverser extends DOMTraverser { /** @var Bcp47Code a language code */ private $toLang; /** @var Bcp47Code a language code */ private $fromLang; /** @var LanguageGuesser */ private $guesser; /** @var ReplacementMachine (uses MW-internal codes) */ private $machine; /** * @param Env $env * @param Bcp47Code $toLang target language for conversion * @param LanguageGuesser $guesser oracle to determine "original language" for round-tripping * @param ReplacementMachine $machine machine to do actual conversion */ public function __construct( Env $env, Bcp47Code $toLang, LanguageGuesser $guesser, ReplacementMachine $machine ) { parent::__construct(); $this->toLang = $toLang; $this->guesser = $guesser; $this->machine = $machine; // No conversion inside <code>, <script>, <pre>, <cite> // (See adhoc regexps inside LanguageConverter.php::autoConvert) // XXX: <cite> ought to probably be handled more generically // as extension output, not special-cased as a HTML tag. foreach ( [ 'code', 'script', 'pre', 'cite' ] as $el ) { $this->addHandler( $el, function ( Element $el ) { return $this->noConvertHandler( $el ); } ); } // Setting/saving the language context $this->addHandler( null, function ( Node $node ) { return $this->anyHandler( $node ); } ); $this->addHandler( 'p', function ( Element $el ) { return $this->langContextHandler( $el ); } ); $this->addHandler( 'body', function ( Element $el ) { return $this->langContextHandler( $el ); } ); // Converting #text, <a> nodes, and title/alt attributes $this->addHandler( '#text', function ( Node $node ) { return $this->textHandler( $node ); } ); $this->addHandler( 'a', function ( Element $el ) use ( $env ){ return $this->aHandler( $el, $env ); } ); $this->addHandler( null, function ( Node $node ) { return $this->attrHandler( $node ); } ); // LanguageConverter markup foreach ( [ 'meta', 'div', 'span' ] as $el ) { $this->addHandler( $el, function ( Element $el ) { return $this->lcHandler( $el ); } ); } } /** * @param Element $el * @return ?Node|bool */ private function noConvertHandler( Element $el ) { // Don't touch the inside of this node! return $el->nextSibling; } /** * @param Node $node * @return ?Node|bool */ private function anyHandler( Node $node ) { /* Look for `lang` attributes */ if ( $node instanceof Element ) { if ( $node->hasAttribute( 'lang' ) ) { $lang = DOMCompat::getAttribute( $node, 'lang' ); // XXX validate lang! override fromLang? // $this->>fromLang = $lang; } } return true; // Continue with other handlers } /** * @param Element $el * @return ?Node|bool */ private function langContextHandler( Element $el ) { $this->fromLang = $this->guesser->guessLang( $el ); // T320662: use internal MW language names for now :( $fromLangMw = Utils::bcp47ToMwCode( $this->fromLang ); $el->setAttribute( 'data-mw-variant-lang', $fromLangMw ); return true; // Continue with other handlers } /** * @param Node $node * @return ?Node|bool */ private function textHandler( Node $node ) { Assert::invariant( $this->fromLang !== null, 'Text w/o a context' ); $toLangMw = Utils::bcp47ToMwCode( $this->toLang ); $fromLangMw = Utils::bcp47ToMwCode( $this->fromLang ); // @phan-suppress-next-line PhanTypeMismatchArgument,PhanTypeMismatchReturn both declared as DOMNode return $this->machine->replace( $node, $toLangMw, $fromLangMw ); } /** * @param Element $el * @param Env $env * @return ?Node|bool */ private function aHandler( Element $el, Env $env ) { // Is this a wikilink? If so, extract title & convert it if ( DOMUtils::hasRel( $el, 'mw:WikiLink' ) ) { $href = preg_replace( '#^(\.\.?/)+#', '', DOMCompat::getAttribute( $el, 'href' ) ?? '', 1 ); $fromPage = Utils::decodeURI( $href ); $toPageFrag = $this->machine->convert( $el->ownerDocument, $fromPage, Utils::bcp47ToMwCode( $this->toLang ), Utils::bcp47ToMwCode( $this->fromLang ) ); '@phan-var DocumentFragment $toPageFrag'; // @var DocumentFragment $toPageFrag $toPage = $this->docFragToString( $toPageFrag ); if ( $toPage === null ) { // Non-reversible transform (sigh); mark this for rt. $el->setAttribute( 'data-mw-variant-orig', $fromPage ); $toPage = $this->docFragToString( $toPageFrag, true/* force */ ); } if ( $el->hasAttribute( 'title' ) ) { $el->setAttribute( 'title', str_replace( '_', ' ', $toPage ) ); } $el->setAttribute( 'href', "./{$toPage}" ); } elseif ( DOMUtils::hasRel( $el, 'mw:WikiLink/Interwiki' ) ) { // Don't convert title or children of interwiki links return $el->nextSibling; } elseif ( DOMUtils::hasRel( $el, 'mw:ExtLink' ) ) { // WTUtils.usesURLLinkSyntax uses data-parsoid, so don't use it, // but syntactic free links should also have class="external free" if ( DOMUtils::hasClass( $el, 'free' ) ) { // Don't convert children of syntactic "free links" return $el->nextSibling; } // Other external link text is protected from conversion iff // (a) it doesn't starts/end with -{ ... }- if ( $el->firstChild && DOMUtils::hasTypeOf( $el->firstChild, 'mw:LanguageVariant' ) ) { return true; } // (b) it looks like a URL (protocol-relative links excluded) $linkText = $el->textContent; // XXX: this could be expensive if ( Utils::isProtocolValid( $linkText, $env ) && substr( $linkText, 0, 2 ) !== '//' ) { return $el->nextSibling; } } return true; } /** * @param Node $node * @return ?Node|bool */ private function attrHandler( Node $node ) { // Convert `alt` and `title` attributes on elements // (Called before aHandler, so the `title` might get overwritten there) if ( !( $node instanceof Element ) ) { return true; } DOMUtils::assertElt( $node ); foreach ( [ 'title', 'alt' ] as $attr ) { $orig = DOMCompat::getAttribute( $node, $attr ); if ( $orig === null ) { continue; } if ( $attr === 'title' && DOMUtils::hasRel( $node, 'mw:WikiLink' ) ) { // We've already converted the title in aHandler above. continue; } if ( str_contains( $orig, '://' ) ) { continue; /* Don't convert URLs */ } $toFrag = $this->machine->convert( $node->ownerDocument, $orig, Utils::bcp47ToMwCode( $this->toLang ), Utils::bcp47ToMwCode( $this->fromLang ) ); '@phan-var DocumentFragment $toFrag'; // @var DocumentFragment $toFrag $to = $this->docFragToString( $toFrag ); if ( $to === null ) { // Non-reversible transform (sigh); mark for rt. $node->setAttribute( "data-mw-variant-{$attr}", $orig ); $to = $this->docFragToString( $toFrag, true/* force */ ); } $node->setAttribute( $attr, $to ); } return true; } /** * Handler for LanguageConverter markup * * @param Element $el * @return ?Node|bool */ private function lcHandler( Element $el ) { if ( !DOMUtils::hasTypeOf( $el, 'mw:LanguageVariant' ) ) { return true; /* not language converter markup */ } $dmv = DOMDataUtils::getJSONAttribute( $el, 'data-mw-variant', [] ); if ( isset( $dmv->disabled ) ) { DOMCompat::setInnerHTML( $el, $dmv->disabled->t ); // XXX check handling of embedded data-parsoid // XXX check handling of nested constructs return $el->nextSibling; } elseif ( isset( $dmv->twoway ) ) { // FIXME } elseif ( isset( $dmv->oneway ) ) { // FIXME } elseif ( isset( $dmv->name ) ) { // FIXME } elseif ( isset( $dmv->filter ) ) { // FIXME } elseif ( isset( $dmv->describe ) ) { // FIXME } return true; } private function docFragToString( DocumentFragment $docFrag, bool $force = false ): ?string { if ( !$force ) { for ( $child = $docFrag->firstChild; $child; $child = $child->nextSibling ) { if ( !( $child instanceof Text ) ) { return null; /* unsafe */ } } } return $docFrag->textContent; } } PK ! P��� � ConstantLanguageGuesser.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\Bcp47Code\Bcp47Code; use Wikimedia\Parsoid\DOM\Element; /** * A simple {@link LanguageGuesser} that returns the same "source language" for every node. * Appropriate for wikis which by convention are written in a single variant. */ class ConstantLanguageGuesser extends LanguageGuesser { /** @var Bcp47Code */ private $langCode; /** * @param Bcp47Code $langCode a language code */ public function __construct( Bcp47Code $langCode ) { $this->langCode = $langCode; } /** @inheritDoc */ public function guessLang( Element $node ): Bcp47Code { return $this->langCode; } } PK ! �u�� � LanguageKu.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; /** Kurdish conversion code. */ class LanguageKu extends Language { public function __construct() { $variants = [ 'ku', 'ku-arab', 'ku-latn' ]; $variantfallbacks = [ 'ku' => 'ku-latn', 'ku-arab' => 'ku-latn', 'ku-latn' => 'ku-arab', ]; $this->setConverter( new KuConverter( $this, 'ku', $variants, $variantfallbacks ) ); } } PK ! /{�J� � MachineLanguageGuesser.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use stdClass; use Wikimedia\Bcp47Code\Bcp47Code; use Wikimedia\LangConv\FstReplacementMachine; use Wikimedia\Parsoid\DOM\Element; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\DOM\Text; use Wikimedia\Parsoid\Utils\DOMDataUtils; use Wikimedia\Parsoid\Utils\DOMPostOrder; use Wikimedia\Parsoid\Utils\Utils; /** * Use a {@Link ReplacementMachine} to predict the best "source language" for every node in a DOM. * Appropriate for wikis which are written in a mix of variants. */ class MachineLanguageGuesser extends LanguageGuesser { /** * MachineLanguageGuesser constructor. * @param FstReplacementMachine $machine * @param Node $root * @param Bcp47Code $destCode a language code */ public function __construct( FstReplacementMachine $machine, Node $root, $destCode ) { # T320662 This code uses MW-internal codes internally $destCode = Utils::bcp47ToMwCode( $destCode ); $codes = []; foreach ( $machine->getCodes() as $invertCode => $ignore ) { if ( $machine->isValidCodePair( $destCode, $invertCode ) ) { $codes[] = $invertCode; } } $zeroCounts = []; foreach ( $codes as $invertCode ) { $zeroCounts[$invertCode] = 0; } DOMPostOrder::traverse( $root, function ( Node &$node ) use ( $machine, $codes, $destCode, $zeroCounts ) { if ( !( $node instanceof Element ) ) { // Elements only! return; } // XXX look at `lang` attribute and use it to inform guess? $nodeData = self::getNodeData( $node ); $first = true; // Iterate over child *nodes* (not just elements) for ( $child = $node->firstChild; $child; $child = $child->nextSibling ) { if ( $child instanceof Text ) { $countMap = []; foreach ( $codes as $invertCode ) { $countMap[$invertCode] = $machine->countBrackets( $child->textContent, $destCode, $invertCode )->safe; } } elseif ( $child instanceof Element ) { $countMap = self::getNodeData( $child )->countMap; } else { continue; // skip this non-element non-text node } if ( $first ) { $nodeData->countMap = $countMap; $first = false; } else { // accumulate child counts! foreach ( $codes as $c ) { $nodeData->countMap[$c] += $countMap[$c]; } } } if ( $first ) { $nodeData->countMap = $zeroCounts; } // Compute best guess for language $safe = []; foreach ( $codes as $code ) { $safe[$code] = $nodeData->countMap[$code]; } arsort( $safe ); $nodeData->guessLang = array_keys( $safe )[0]; } ); } /** * Helper function that namespaces all of our node data used in * this class into the top-level `mw_variant` key. * * @param Element $node * @return stdClass */ private static function getNodeData( Element $node ): stdClass { $nodeData = DOMDataUtils::getNodeData( $node ); if ( !isset( $nodeData->mw_variant ) ) { $nodeData->mw_variant = new stdClass; } return $nodeData->mw_variant; } /** @inheritDoc */ public function guessLang( Element $node ): Bcp47Code { return Utils::mwCodeToBcp47( self::getNodeData( $node )->guessLang ); } } PK ! Ls�� � CrhConverter.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\LangConv\FstReplacementMachine; class CrhConverter extends LanguageConverter { public function loadDefaultTables() { $this->setMachine( new FstReplacementMachine( 'crh', [ 'crh-latn', 'crh-cyrl' ] ) ); } // phpcs:ignore MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic public function findVariantLink( $link, $nt, $ignoreOtherCond ) { $ns = $nt->getNamespace(); // do not try to find variants for usernames if ( $ns->isUser() || $ns->isUserTalk ) { return [ 'nt' => $nt, 'link' => $link ]; } // FIXME check whether selected language is 'crh' return parent::findVariantLink( $link, $nt, $ignoreOtherCond ); } } PK ! �,(>� � LanguageCrh.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; /** Crimean Tatar (Qırımtatarca) conversion code */ class LanguageCrh extends Language { public function __construct() { $variants = [ 'crh', 'crh-cyrl', 'crh-latn' ]; $variantfallbacks = [ 'crh' => 'crh-latn', 'crh-cyrl' => 'crh-latn', 'crh-latn' => 'crh-cyrl', ]; $converter = new CrhConverter( $this, 'crh', $variants, $variantfallbacks ); $this->setConverter( $converter ); } } PK ! ���� � KuConverter.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\LangConv\FstReplacementMachine; class KuConverter extends LanguageConverter { public function loadDefaultTables() { $this->setMachine( new FstReplacementMachine( 'ku', [ 'ku-arab', 'ku-latn' ] ) ); } // phpcs:ignore MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic public function findVariantLink( $link, $nt, $ignoreOtherCond ) { $ns = $nt->getNamespace(); // do not try to find variants for usernames if ( $ns->isUser() || $ns->isUserTalk ) { return [ 'nt' => $nt, 'link' => $link ]; } // FIXME check whether selected language is 'ku' return parent::findVariantLink( $link, $nt, $ignoreOtherCond ); } } PK ! �4�!� � EnConverter.phpnu �Iw�� <?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Language; use Wikimedia\LangConv\FstReplacementMachine; class EnConverter extends LanguageConverter { public function loadDefaultTables() { $this->setMachine( new FstReplacementMachine( 'en', [ 'en', 'en-x-piglatin' ] ) ); } // phpcs:ignore MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic public function findVariantLink( $link, $nt, $ignoreOtherCond ) { $ns = $nt->getNamespace(); // do not try to find variants for usernames if ( $ns->isUser() || $ns->isUserTalk ) { return [ 'nt' => $nt, 'link' => $link ]; } // FIXME check whether selected language is 'en' return parent::findVariantLink( $link, $nt, $ignoreOtherCond ); } } PK ! ���l l Language.phpnu �Iw�� PK ! wp�u � LanguageFactoryInterface.phpnu �[��� PK ! �>>5L L LanguageFactory.phpnu �[��� PK ! 7���\ �\ � LanguageHelper.phpnu �[��� PK ! n++� � qj Multilanguage.phpnu �[��� PK ! 7�#�� � �y Transliterate.phpnu �[��� PK ! !�X X ښ Associations.phpnu �[��� PK ! S�fH� � r� LanguageAwareTrait.phpnu �[��� PK ! ��ѣ � �� CachingLanguageFactory.phpnu �[��� PK ! y���5 �5 �� Text.phpnu �[��� PK ! � �� � J� LanguageAwareInterface.phpnu �[��� PK ! #u�2 2 X� LanguageEn.phpnu �Iw�� PK ! �e� � ZhConverter.phpnu �Iw�� PK ! ��;� � SrConverter.phpnu �Iw�� PK ! �2h Z LanguageGuesser.phpnu �Iw�� PK ! e��w)9 )9 � LanguageConverter.phpnu �Iw�� PK ! Ml�w w @ LanguageSr.phpnu �Iw�� PK ! )��� � �B LanguageZh.phpnu �Iw�� PK ! 8V��d! d! �G ConversionTraverser.phpnu �Iw�� PK ! P��� � 0i ConstantLanguageGuesser.phpnu �Iw�� PK ! �u�� � #l LanguageKu.phpnu �Iw�� PK ! /{�J� � n MachineLanguageGuesser.phpnu �Iw�� PK ! Ls�� � { CrhConverter.phpnu �Iw�� PK ! �,(>� � ,~ LanguageCrh.phpnu �Iw�� PK ! ���� � M� KuConverter.phpnu �Iw�� PK ! �4�!� � j� EnConverter.phpnu �Iw�� PK X ��
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0.02 |
proxy
|
phpinfo
|
ÐаÑтройка