Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/Language.tar

Associations.php000064400000011213151157062550007721 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;

/**
 * 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 = array())
	{
		// To avoid doing duplicate database queries.
		static $multilanguageAssociations = array();

		// 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(array($extension, $tablename,
$context, $id), $advClause)));

		if (!isset($multilanguageAssociations[$queryKey]))
		{
			$multilanguageAssociations[$queryKey] = array();

			$db = \JFactory::getDbo();
			$categoriesExtraSql = (($tablename === '#__categories') ?
' AND c2.extension = ' . $db->quote($extension) :
'');
			$query = $db->getQuery(true)
				->select($db->quoteName('c2.language'))
				->from($db->quoteName($tablename, 'c'))
				->join('INNER',
$db->quoteName('#__associations', 'a') . ' ON
a.id = c.' . $db->quoteName($pk) . ' AND a.context=' .
$db->quote($context))
				->join('INNER',
$db->quoteName('#__associations', 'a2') . ' ON
' . $db->quoteName('a.key') . ' = ' .
$db->quoteName('a2.key'))
				->join('INNER', $db->quoteName($tablename,
'c2') . ' ON a2.id = c2.' . $db->quoteName($pk) .
$categoriesExtraSql);

			// Use alias field ?
			if (!empty($aliasField))
			{
				$query->select(
					$query->concatenate(
						array(
							$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') . '
ON ' . $db->quoteName('c2.' . $catField) . ' = ca.id
AND ca.extension = ' . $db->quote($extension)
					)
					->select(
						$query->concatenate(
							array('ca.id', 'ca.alias'),
							':'
						) . ' AS ' . $db->quoteName($catField)
					);
			}

			$query->where('c.' . $pk . ' = ' . (int) $id);

			if ($tablename === '#__categories')
			{
				$query->where('c.extension = ' .
$db->quote($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 = \JPluginHelper::getPlugin('system',
'languagefilter');

				if (!empty($plugin))
				{
					$params = new Registry($plugin->params);
					$enabled  = (boolean) $params->get('item_associations',
true);
				}

				$tested = true;
			}
		}

		return $enabled;
	}
}
Language.php000064400000072536151157062550007024 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

use Joomla\String\StringHelper;

/**
 * Languages/translation handler class
 *
 * @since  1.7.0
 */
class Language
{
	/**
	 * Array of Language objects
	 *
	 * @var    Language[]
	 * @since  1.7.0
	 */
	protected static $languages = array();

	/**
	 * Debug language, If true, highlights if string isn't found.
	 *
	 * @var    boolean
	 * @since  1.7.0
	 */
	protected $debug = false;

	/**
	 * The default language, used when a language file in the requested
language does not exist.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $default = 'en-GB';

	/**
	 * An array of orphaned text.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $orphans = array();

	/**
	 * Array holding the language metadata.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $metadata = null;

	/**
	 * Array holding the language locale or boolean null if none.
	 *
	 * @var    array|boolean
	 * @since  1.7.0
	 */
	protected $locale = null;

	/**
	 * The language to load.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $lang = null;

	/**
	 * A nested array of language files that have been loaded
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $paths = array();

	/**
	 * List of language files that are in error state
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $errorfiles = array();

	/**
	 * Translations
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $strings = array();

	/**
	 * An array of used text, used during debugging.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $used = array();

	/**
	 * Counter for number of loads.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	protected $counter = 0;

	/**
	 * An array used to store overrides.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $override = array();

	/**
	 * Name of the transliterator function for this language.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $transliterator = null;

	/**
	 * Name of the pluralSuffixesCallback function for this language.
	 *
	 * @var    callable
	 * @since  1.7.0
	 */
	protected $pluralSuffixesCallback = null;

	/**
	 * Name of the ignoredSearchWordsCallback function for this language.
	 *
	 * @var    callable
	 * @since  1.7.0
	 */
	protected $ignoredSearchWordsCallback = null;

	/**
	 * Name of the lowerLimitSearchWordCallback function for this language.
	 *
	 * @var    callable
	 * @since  1.7.0
	 */
	protected $lowerLimitSearchWordCallback = null;

	/**
	 * Name of the upperLimitSearchWordCallback function for this language.
	 *
	 * @var    callable
	 * @since  1.7.0
	 */
	protected $upperLimitSearchWordCallback = null;

	/**
	 * Name of the searchDisplayedCharactersNumberCallback function for this
language.
	 *
	 * @var    callable
	 * @since  1.7.0
	 */
	protected $searchDisplayedCharactersNumberCallback = null;

	/**
	 * Constructor activating the default information of the language.
	 *
	 * @param   string   $lang   The language
	 * @param   boolean  $debug  Indicates if language debugging is enabled.
	 *
	 * @since   1.7.0
	 */
	public function __construct($lang = null, $debug = false)
	{
		$this->strings = array();

		if ($lang == null)
		{
			$lang = $this->default;
		}

		$this->lang = $lang;
		$this->metadata = LanguageHelper::getMetadata($this->lang);
		$this->setDebug($debug);

		$this->override = $this->parse(JPATH_BASE .
'/language/overrides/' . $lang . '.override.ini');

		// Look for a language specific localise class
		$class = str_replace('-', '_', $lang .
'Localise');
		$paths = array();

		if (defined('JPATH_SITE'))
		{
			// Note: Manual indexing to enforce load order.
			$paths[0] = JPATH_SITE .
"/language/overrides/$lang.localise.php";
			$paths[2] = JPATH_SITE . "/language/$lang/$lang.localise.php";
		}

		if (defined('JPATH_ADMINISTRATOR'))
		{
			// Note: Manual indexing to enforce load order.
			$paths[1] = JPATH_ADMINISTRATOR .
"/language/overrides/$lang.localise.php";
			$paths[3] = JPATH_ADMINISTRATOR .
"/language/$lang/$lang.localise.php";
		}

		ksort($paths);
		$path = reset($paths);

		while (!class_exists($class) && $path)
		{
			if (file_exists($path))
			{
				require_once $path;
			}

			$path = next($paths);
		}

		if (class_exists($class))
		{
			/**
			 * Class exists. Try to find
			 * -a transliterate method,
			 * -a getPluralSuffixes method,
			 * -a getIgnoredSearchWords method
			 * -a getLowerLimitSearchWord method
			 * -a getUpperLimitSearchWord method
			 * -a getSearchDisplayCharactersNumber method
			 */
			if (method_exists($class, 'transliterate'))
			{
				$this->transliterator = array($class, 'transliterate');
			}

			if (method_exists($class, 'getPluralSuffixes'))
			{
				$this->pluralSuffixesCallback = array($class,
'getPluralSuffixes');
			}

			if (method_exists($class, 'getIgnoredSearchWords'))
			{
				$this->ignoredSearchWordsCallback = array($class,
'getIgnoredSearchWords');
			}

			if (method_exists($class, 'getLowerLimitSearchWord'))
			{
				$this->lowerLimitSearchWordCallback = array($class,
'getLowerLimitSearchWord');
			}

			if (method_exists($class, 'getUpperLimitSearchWord'))
			{
				$this->upperLimitSearchWordCallback = array($class,
'getUpperLimitSearchWord');
			}

			if (method_exists($class,
'getSearchDisplayedCharactersNumber'))
			{
				$this->searchDisplayedCharactersNumberCallback = array($class,
'getSearchDisplayedCharactersNumber');
			}
		}

		$this->load();
	}

	/**
	 * Returns a language object.
	 *
	 * @param   string   $lang   The language to use.
	 * @param   boolean  $debug  The debug mode.
	 *
	 * @return  Language  The Language object.
	 *
	 * @since   1.7.0
	 */
	public static function getInstance($lang, $debug = false)
	{
		if (!isset(self::$languages[$lang . $debug]))
		{
			self::$languages[$lang . $debug] = new Language($lang, $debug);
		}

		return self::$languages[$lang . $debug];
	}

	/**
	 * Translate function, mimics the php gettext (alias _) function.
	 *
	 * The function checks if $jsSafe is true, then if $interpretBackslashes
is true.
	 *
	 * @param   string   $string                The string to translate
	 * @param   boolean  $jsSafe                Make the result javascript
safe
	 * @param   boolean  $interpretBackSlashes  Interpret \t and \n
	 *
	 * @return  string  The translation of the string
	 *
	 * @since   1.7.0
	 */
	public function _($string, $jsSafe = false, $interpretBackSlashes = true)
	{
		// Detect empty string
		if ($string == '')
		{
			return '';
		}

		$key = strtoupper($string);

		if (isset($this->strings[$key]))
		{
			$string = $this->strings[$key];

			// Store debug information
			if ($this->debug)
			{
				$value =
\JFactory::getApplication()->get('debug_lang_const', 1) == 0 ?
$key : $string;
				$string = '**' . $value . '**';

				$caller = $this->getCallerInfo();

				if (!array_key_exists($key, $this->used))
				{
					$this->used[$key] = array();
				}

				$this->used[$key][] = $caller;
			}
		}
		else
		{
			if ($this->debug)
			{
				$caller = $this->getCallerInfo();
				$caller['string'] = $string;

				if (!array_key_exists($key, $this->orphans))
				{
					$this->orphans[$key] = array();
				}

				$this->orphans[$key][] = $caller;

				$string = '??' . $string . '??';
			}
		}

		if ($jsSafe)
		{
			// Javascript filter
			$string = addslashes($string);
		}
		elseif ($interpretBackSlashes)
		{
			if (strpos($string, '\\') !== false)
			{
				// Interpret \n and \t characters
				$string = str_replace(array('\\\\', '\t',
'\n'), array("\\", "\t", "\n"),
$string);
			}
		}

		return $string;
	}

	/**
	 * Transliterate function
	 *
	 * This method processes a string and replaces all accented UTF-8
characters by unaccented
	 * ASCII-7 "equivalents".
	 *
	 * @param   string  $string  The string to transliterate.
	 *
	 * @return  string  The transliteration of the string.
	 *
	 * @since   1.7.0
	 */
	public function transliterate($string)
	{
		if ($this->transliterator !== null)
		{
			return call_user_func($this->transliterator, $string);
		}

		$string = Transliterate::utf8_latin_to_ascii($string);
		$string = StringHelper::strtolower($string);

		return $string;
	}

	/**
	 * Getter for transliteration function
	 *
	 * @return  callable  The transliterator function
	 *
	 * @since   1.7.0
	 */
	public function getTransliterator()
	{
		return $this->transliterator;
	}

	/**
	 * Set the transliteration function.
	 *
	 * @param   callable  $function  Function name or the actual function.
	 *
	 * @return  callable  The previous function.
	 *
	 * @since   1.7.0
	 */
	public function setTransliterator($function)
	{
		$previous = $this->transliterator;
		$this->transliterator = $function;

		return $previous;
	}

	/**
	 * Returns an array of suffixes for plural rules.
	 *
	 * @param   integer  $count  The count number the rule is for.
	 *
	 * @return  array    The array of suffixes.
	 *
	 * @since   1.7.0
	 */
	public function getPluralSuffixes($count)
	{
		if ($this->pluralSuffixesCallback !== null)
		{
			return call_user_func($this->pluralSuffixesCallback, $count);
		}
		else
		{
			return array((string) $count);
		}
	}

	/**
	 * Getter for pluralSuffixesCallback function.
	 *
	 * @return  callable  Function name or the actual function.
	 *
	 * @since   1.7.0
	 */
	public function getPluralSuffixesCallback()
	{
		return $this->pluralSuffixesCallback;
	}

	/**
	 * Set the pluralSuffixes function.
	 *
	 * @param   callable  $function  Function name or actual function.
	 *
	 * @return  callable  The previous function.
	 *
	 * @since   1.7.0
	 */
	public function setPluralSuffixesCallback($function)
	{
		$previous = $this->pluralSuffixesCallback;
		$this->pluralSuffixesCallback = $function;

		return $previous;
	}

	/**
	 * Returns an array of ignored search words
	 *
	 * @return  array  The array of ignored search words.
	 *
	 * @since   1.7.0
	 */
	public function getIgnoredSearchWords()
	{
		if ($this->ignoredSearchWordsCallback !== null)
		{
			return call_user_func($this->ignoredSearchWordsCallback);
		}
		else
		{
			return array();
		}
	}

	/**
	 * Getter for ignoredSearchWordsCallback function.
	 *
	 * @return  callable  Function name or the actual function.
	 *
	 * @since   1.7.0
	 */
	public function getIgnoredSearchWordsCallback()
	{
		return $this->ignoredSearchWordsCallback;
	}

	/**
	 * Setter for the ignoredSearchWordsCallback function
	 *
	 * @param   callable  $function  Function name or actual function.
	 *
	 * @return  callable  The previous function.
	 *
	 * @since   1.7.0
	 */
	public function setIgnoredSearchWordsCallback($function)
	{
		$previous = $this->ignoredSearchWordsCallback;
		$this->ignoredSearchWordsCallback = $function;

		return $previous;
	}

	/**
	 * Returns a lower limit integer for length of search words
	 *
	 * @return  integer  The lower limit integer for length of search words (3
if no value was set for a specific language).
	 *
	 * @since   1.7.0
	 */
	public function getLowerLimitSearchWord()
	{
		if ($this->lowerLimitSearchWordCallback !== null)
		{
			return call_user_func($this->lowerLimitSearchWordCallback);
		}
		else
		{
			return 3;
		}
	}

	/**
	 * Getter for lowerLimitSearchWordCallback function
	 *
	 * @return  callable  Function name or the actual function.
	 *
	 * @since   1.7.0
	 */
	public function getLowerLimitSearchWordCallback()
	{
		return $this->lowerLimitSearchWordCallback;
	}

	/**
	 * Setter for the lowerLimitSearchWordCallback function.
	 *
	 * @param   callable  $function  Function name or actual function.
	 *
	 * @return  callable  The previous function.
	 *
	 * @since   1.7.0
	 */
	public function setLowerLimitSearchWordCallback($function)
	{
		$previous = $this->lowerLimitSearchWordCallback;
		$this->lowerLimitSearchWordCallback = $function;

		return $previous;
	}

	/**
	 * Returns an upper limit integer for length of search words
	 *
	 * @return  integer  The upper limit integer for length of search words
(200 if no value was set or if default value is < 200).
	 *
	 * @since   1.7.0
	 */
	public function getUpperLimitSearchWord()
	{
		if ($this->upperLimitSearchWordCallback !== null &&
call_user_func($this->upperLimitSearchWordCallback) > 200)
		{
			return call_user_func($this->upperLimitSearchWordCallback);
		}

		return 200;
	}

	/**
	 * Getter for upperLimitSearchWordCallback function
	 *
	 * @return  callable  Function name or the actual function.
	 *
	 * @since   1.7.0
	 */
	public function getUpperLimitSearchWordCallback()
	{
		return $this->upperLimitSearchWordCallback;
	}

	/**
	 * Setter for the upperLimitSearchWordCallback function
	 *
	 * @param   callable  $function  Function name or the actual function.
	 *
	 * @return  callable  The previous function.
	 *
	 * @since   1.7.0
	 */
	public function setUpperLimitSearchWordCallback($function)
	{
		$previous = $this->upperLimitSearchWordCallback;
		$this->upperLimitSearchWordCallback = $function;

		return $previous;
	}

	/**
	 * Returns the number of characters displayed in search results.
	 *
	 * @return  integer  The number of characters displayed (200 if no value
was set for a specific language).
	 *
	 * @since   1.7.0
	 */
	public function getSearchDisplayedCharactersNumber()
	{
		if ($this->searchDisplayedCharactersNumberCallback !== null)
		{
			return
call_user_func($this->searchDisplayedCharactersNumberCallback);
		}
		else
		{
			return 200;
		}
	}

	/**
	 * Getter for searchDisplayedCharactersNumberCallback function
	 *
	 * @return  callable  Function name or the actual function.
	 *
	 * @since   1.7.0
	 */
	public function getSearchDisplayedCharactersNumberCallback()
	{
		return $this->searchDisplayedCharactersNumberCallback;
	}

	/**
	 * Setter for the searchDisplayedCharactersNumberCallback function.
	 *
	 * @param   callable  $function  Function name or the actual function.
	 *
	 * @return  callable  The previous function.
	 *
	 * @since   1.7.0
	 */
	public function setSearchDisplayedCharactersNumberCallback($function)
	{
		$previous = $this->searchDisplayedCharactersNumberCallback;
		$this->searchDisplayedCharactersNumberCallback = $function;

		return $previous;
	}

	/**
	 * 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   1.7.0
	 * @deprecated   3.7.0, use LanguageHelper::exists() instead.
	 */
	public static function exists($lang, $basePath = JPATH_BASE)
	{
		\JLog::add(__METHOD__ . '() is deprecated, use
LanguageHelper::exists() instead.', \JLog::WARNING,
'deprecated');

		return LanguageHelper::exists($lang, $basePath);
	}

	/**
	 * Loads a single language file and appends the results to the existing
strings
	 *
	 * @param   string   $extension  The extension for which a language file
should be loaded.
	 * @param   string   $basePath   The basepath to use.
	 * @param   string   $lang       The language to load, default null for
the current language.
	 * @param   boolean  $reload     Flag that will force a language to be
reloaded if set to true.
	 * @param   boolean  $default    Flag that force the default language to
be loaded if the current does not exist.
	 *
	 * @return  boolean  True if the file has successfully loaded.
	 *
	 * @since   1.7.0
	 */
	public function load($extension = 'joomla', $basePath =
JPATH_BASE, $lang = null, $reload = false, $default = true)
	{
		// If language is null set as the current language.
		if (!$lang)
		{
			$lang = $this->lang;
		}

		// Load the default language first if we're not debugging and a
non-default language is requested to be loaded
		// with $default set to true
		if (!$this->debug && ($lang != $this->default) &&
$default)
		{
			$this->load($extension, $basePath, $this->default, false, true);
		}

		$path = LanguageHelper::getLanguagePath($basePath, $lang);

		$internal = $extension == 'joomla' || $extension ==
'';
		$filename = $internal ? $lang : $lang . '.' . $extension;
		$filename = "$path/$filename.ini";

		if (isset($this->paths[$extension][$filename]) && !$reload)
		{
			// This file has already been tested for loading.
			$result = $this->paths[$extension][$filename];
		}
		else
		{
			// Load the language file
			$result = $this->loadLanguage($filename, $extension);

			// Check whether there was a problem with loading the file
			if ($result === false && $default)
			{
				// No strings, so either file doesn't exist or the file is invalid
				$oldFilename = $filename;

				// Check the standard file name
				if (!$this->debug)
				{
					$path = LanguageHelper::getLanguagePath($basePath, $this->default);

					$filename = $internal ? $this->default : $this->default .
'.' . $extension;
					$filename = "$path/$filename.ini";

					// If the one we tried is different than the new name, try again
					if ($oldFilename != $filename)
					{
						$result = $this->loadLanguage($filename, $extension, false);
					}
				}
			}
		}

		return $result;
	}

	/**
	 * Loads a language file.
	 *
	 * This method will not note the successful loading of a file - use load()
instead.
	 *
	 * @param   string  $fileName   The name of the file.
	 * @param   string  $extension  The name of the extension.
	 *
	 * @return  boolean  True if new strings have been added to the language
	 *
	 * @see     Language::load()
	 * @since   1.7.0
	 */
	protected function loadLanguage($fileName, $extension =
'unknown')
	{
		$this->counter++;

		$result  = false;
		$strings = $this->parse($fileName);

		if ($strings !== array())
		{
			$this->strings = array_replace($this->strings, $strings,
$this->override);
			$result = true;
		}

		// Record the result of loading the extension's file.
		if (!isset($this->paths[$extension]))
		{
			$this->paths[$extension] = array();
		}

		$this->paths[$extension][$fileName] = $result;

		return $result;
	}

	/**
	 * Parses a language file.
	 *
	 * @param   string  $fileName  The name of the file.
	 *
	 * @return  array  The array of parsed strings.
	 *
	 * @since   1.7.0
	 */
	protected function parse($fileName)
	{
		$strings = \JLanguageHelper::parseIniFile($fileName, $this->debug);

		// Debug the ini file if needed.
		if ($this->debug === true && file_exists($fileName))
		{
			$this->debugFile($fileName);
		}

		return $strings;
	}

	/**
	 * Debugs a language file
	 *
	 * @param   string  $filename  Absolute path to the file to debug
	 *
	 * @return  integer  A count of the number of parsing errors
	 *
	 * @since   3.6.3
	 * @throws  \InvalidArgumentException
	 */
	public function debugFile($filename)
	{
		// Make sure our file actually exists
		if (!file_exists($filename))
		{
			throw new \InvalidArgumentException(
				sprintf('Unable to locate file "%s" for debugging',
$filename)
			);
		}

		// Initialise variables for manually parsing the file for common errors.
		$blacklist = array('YES', 'NO', 'NULL',
'FALSE', 'ON', 'OFF', 'NONE',
'TRUE');
		$debug = $this->getDebug();
		$this->debug = false;
		$errors = array();
		$php_errormsg = null;

		// Open the file as a stream.
		$file = new \SplFileObject($filename);

		foreach ($file as $lineNumber => $line)
		{
			// Avoid BOM error as BOM is OK when using parse_ini.
			if ($lineNumber == 0)
			{
				$line = str_replace("\xEF\xBB\xBF", '', $line);
			}

			$line = trim($line);

			// Ignore comment lines.
			if (!strlen($line) || $line['0'] == ';')
			{
				continue;
			}

			// Ignore grouping tag lines, like: [group]
			if (preg_match('#^\[[^\]]*\](\s*;.*)?$#', $line))
			{
				continue;
			}

			// Remove the "_QQ_" from the equation
			$line = str_replace('"_QQ_"', '', $line);

			// Remove any escaped double quotes \" from the equation
			$line = str_replace('\"', '', $line);

			$realNumber = $lineNumber + 1;

			// Check for any incorrect uses of _QQ_.
			if (strpos($line, '_QQ_') !== false)
			{
				$errors[] = $realNumber;
				continue;
			}

			// Check for odd number of double quotes.
			if (substr_count($line, '"') % 2 != 0)
			{
				$errors[] = $realNumber;
				continue;
			}

			// Check that the line passes the necessary format.
			if
(!preg_match('#^[A-Z][A-Z0-9_\*\-\.]*\s*=\s*".*"(\s*;.*)?$#',
$line))
			{
				$errors[] = $realNumber;
				continue;
			}

			// Check that the key is not in the blacklist.
			$key = strtoupper(trim(substr($line, 0, strpos($line, '='))));

			if (in_array($key, $blacklist))
			{
				$errors[] = $realNumber;
			}
		}

		// Check if we encountered any errors.
		if (count($errors))
		{
			$this->errorfiles[$filename] = $filename . ' : error(s) in
line(s) ' . implode(', ', $errors);
		}
		elseif ($php_errormsg)
		{
			// We didn't find any errors but there's probably a parse
notice.
			$this->errorfiles['PHP' . $filename] = 'PHP parser
errors :' . $php_errormsg;
		}

		$this->debug = $debug;

		return count($errors);
	}

	/**
	 * Get a metadata language property.
	 *
	 * @param   string  $property  The name of the property.
	 * @param   mixed   $default   The default value.
	 *
	 * @return  mixed  The value of the property.
	 *
	 * @since   1.7.0
	 */
	public function get($property, $default = null)
	{
		if (isset($this->metadata[$property]))
		{
			return $this->metadata[$property];
		}

		return $default;
	}

	/**
	 * Determine who called Language or JText.
	 *
	 * @return  array  Caller information.
	 *
	 * @since   1.7.0
	 */
	protected function getCallerInfo()
	{
		// Try to determine the source if none was provided
		if (!function_exists('debug_backtrace'))
		{
			return;
		}

		$backtrace = debug_backtrace();
		$info = array();

		// Search through the backtrace to our caller
		$continue = true;

		while ($continue && next($backtrace))
		{
			$step = current($backtrace);
			$class = @ $step['class'];

			// We're looking for something outside of language.php
			if ($class != '\\Joomla\\CMS\\Language\\Language' &&
$class != 'JText')
			{
				$info['function'] = @ $step['function'];
				$info['class'] = $class;
				$info['step'] = prev($backtrace);

				// Determine the file and name of the file
				$info['file'] = @ $step['file'];
				$info['line'] = @ $step['line'];

				$continue = false;
			}
		}

		return $info;
	}

	/**
	 * Getter for Name.
	 *
	 * @return  string  Official name element of the language.
	 *
	 * @since   1.7.0
	 */
	public function getName()
	{
		return $this->metadata['name'];
	}

	/**
	 * Get a list of language files that have been loaded.
	 *
	 * @param   string  $extension  An optional extension name.
	 *
	 * @return  array
	 *
	 * @since   1.7.0
	 */
	public function getPaths($extension = null)
	{
		if (isset($extension))
		{
			if (isset($this->paths[$extension]))
			{
				return $this->paths[$extension];
			}

			return;
		}
		else
		{
			return $this->paths;
		}
	}

	/**
	 * Get a list of language files that are in error state.
	 *
	 * @return  array
	 *
	 * @since   1.7.0
	 */
	public function getErrorFiles()
	{
		return $this->errorfiles;
	}

	/**
	 * Getter for the language tag (as defined in RFC 3066)
	 *
	 * @return  string  The language tag.
	 *
	 * @since   1.7.0
	 */
	public function getTag()
	{
		return $this->metadata['tag'];
	}

	/**
	 * Getter for the calendar type
	 *
	 * @return  string  The calendar type.
	 *
	 * @since   3.7.0
	 */
	public function getCalendar()
	{
		if (isset($this->metadata['calendar']))
		{
			return $this->metadata['calendar'];
		}
		else
		{
			return 'gregorian';
		}
	}

	/**
	 * Get the RTL property.
	 *
	 * @return  boolean  True is it an RTL language.
	 *
	 * @since   1.7.0
	 */
	public function isRtl()
	{
		return (bool) $this->metadata['rtl'];
	}

	/**
	 * Set the Debug property.
	 *
	 * @param   boolean  $debug  The debug setting.
	 *
	 * @return  boolean  Previous value.
	 *
	 * @since   1.7.0
	 */
	public function setDebug($debug)
	{
		$previous = $this->debug;
		$this->debug = (boolean) $debug;

		return $previous;
	}

	/**
	 * Get the Debug property.
	 *
	 * @return  boolean  True is in debug mode.
	 *
	 * @since   1.7.0
	 */
	public function getDebug()
	{
		return $this->debug;
	}

	/**
	 * Get the default language code.
	 *
	 * @return  string  Language code.
	 *
	 * @since   1.7.0
	 */
	public function getDefault()
	{
		return $this->default;
	}

	/**
	 * Set the default language code.
	 *
	 * @param   string  $lang  The language code.
	 *
	 * @return  string  Previous value.
	 *
	 * @since   1.7.0
	 */
	public function setDefault($lang)
	{
		$previous = $this->default;
		$this->default = $lang;

		return $previous;
	}

	/**
	 * Get the list of orphaned strings if being tracked.
	 *
	 * @return  array  Orphaned text.
	 *
	 * @since   1.7.0
	 */
	public function getOrphans()
	{
		return $this->orphans;
	}

	/**
	 * Get the list of used strings.
	 *
	 * Used strings are those strings requested and found either as a string
or a constant.
	 *
	 * @return  array  Used strings.
	 *
	 * @since   1.7.0
	 */
	public function getUsed()
	{
		return $this->used;
	}

	/**
	 * Determines is a key exists.
	 *
	 * @param   string  $string  The key to check.
	 *
	 * @return  boolean  True, if the key exists.
	 *
	 * @since   1.7.0
	 */
	public function hasKey($string)
	{
		$key = strtoupper($string);

		return isset($this->strings[$key]);
	}

	/**
	 * 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   1.7.0
	 * @deprecated   3.7.0, use LanguageHelper::getMetadata() instead.
	 */
	public static function getMetadata($lang)
	{
		\JLog::add(__METHOD__ . '() is deprecated, use
LanguageHelper::getMetadata() instead.', \JLog::WARNING,
'deprecated');

		return LanguageHelper::getMetadata($lang);
	}

	/**
	 * 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   1.7.0
	 * @deprecated   3.7.0, use LanguageHelper::getKnownLanguages() instead.
	 */
	public static function getKnownLanguages($basePath = JPATH_BASE)
	{
		\JLog::add(__METHOD__ . '() is deprecated, use
LanguageHelper::getKnownLanguages() instead.', \JLog::WARNING,
'deprecated');

		return LanguageHelper::getKnownLanguages($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   1.7.0
	 * @deprecated   3.7.0, use LanguageHelper::getLanguagePath() instead.
	 */
	public static function getLanguagePath($basePath = JPATH_BASE, $language =
null)
	{
		\JLog::add(__METHOD__ . '() is deprecated, use
LanguageHelper::getLanguagePath() instead.', \JLog::WARNING,
'deprecated');

		return LanguageHelper::getLanguagePath($basePath, $language);
	}

	/**
	 * Set the language attributes to the given language.
	 *
	 * Once called, the language still needs to be loaded using
Language::load().
	 *
	 * @param   string  $lang  Language code.
	 *
	 * @return  string  Previous value.
	 *
	 * @since   1.7.0
	 * @deprecated  4.0 (CMS) - Instantiate a new Language object instead
	 */
	public function setLanguage($lang)
	{
		\JLog::add(__METHOD__ . ' is deprecated. Instantiate a new Language
object instead.', \JLog::WARNING, 'deprecated');

		$previous = $this->lang;
		$this->lang = $lang;
		$this->metadata = LanguageHelper::getMetadata($this->lang);

		return $previous;
	}

	/**
	 * Get the language locale based on current language.
	 *
	 * @return  array  The locale according to the language.
	 *
	 * @since   1.7.0
	 */
	public function getLocale()
	{
		if (!isset($this->locale))
		{
			$locale = str_replace(' ', '',
isset($this->metadata['locale']) ?
$this->metadata['locale'] : '');

			if ($locale)
			{
				$this->locale = explode(',', $locale);
			}
			else
			{
				$this->locale = false;
			}
		}

		return $this->locale;
	}

	/**
	 * Get the first day of the week for this language.
	 *
	 * @return  integer  The first day of the week according to the language
	 *
	 * @since   1.7.0
	 */
	public function getFirstDay()
	{
		return (int) (isset($this->metadata['firstDay']) ?
$this->metadata['firstDay'] : 0);
	}

	/**
	 * Get the weekends days for this language.
	 *
	 * @return  string  The weekend days of the week separated by a comma
according to the language
	 *
	 * @since   3.2
	 */
	public function getWeekEnd()
	{
		return (isset($this->metadata['weekEnd']) &&
$this->metadata['weekEnd']) ?
$this->metadata['weekEnd'] : '0,6';
	}

	/**
	 * 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   1.7.0
	 * @deprecated   3.7.0, use LanguageHelper::parseLanguageFiles() instead.
	 */
	public static function parseLanguageFiles($dir = null)
	{
		\JLog::add(__METHOD__ . '() is deprecated, use
LanguageHelper::parseLanguageFiles() instead.', \JLog::WARNING,
'deprecated');

		return LanguageHelper::parseLanguageFiles($dir);
	}

	/**
	 * 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   1.7.0
	 * @throws  \RuntimeException
	 * @deprecated   3.7.0, use LanguageHelper::parseXMLLanguageFile()
instead.
	 */
	public static function parseXMLLanguageFile($path)
	{
		\JLog::add(__METHOD__ . '() is deprecated, use
LanguageHelper::parseXMLLanguageFile() instead.', \JLog::WARNING,
'deprecated');

		return LanguageHelper::parseXMLLanguageFile($path);
	}
}
LanguageHelper.php000064400000042022151157062550010147 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;
use Joomla\Utilities\ArrayHelper;

/**
 * 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      = array();
		$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[] = array(
				'text'     => isset($metadata['nativeName']) ?
$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;
						}
						elseif ($primary_browserLang == substr($systemLang->lang_code, 0,
2))
						{
							$primaryDetectedLang = $systemLang->lang_code;
						}
					}
				}

				if (isset($primaryDetectedLang))
				{
					return $primaryDetectedLang;
				}
			}
		}

		return;
	}

	/**
	 * 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 (empty($languages))
		{
			// Installation uses available languages
			if (\JFactory::getApplication()->getClientId() == 2)
			{
				$languages[$key] = array();
				$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
			{
				$cache = \JFactory::getCache('com_languages', '');

				if ($cache->contains('languages'))
				{
					$languages = $cache->get('languages');
				}
				else
				{
					$db = \JFactory::getDbo();
					$query = $db->getQuery(true)
						->select('*')
						->from('#__languages')
						->where('published=1')
						->order('ordering ASC');
					$db->setQuery($query);

					$languages['default'] = $db->loadObjectList();
					$languages['sef'] = array();
					$languages['lang_code'] = array();

					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.
	 *
	 * @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)
	{
		static $installedLanguages = null;

		if ($installedLanguages === null)
		{
			$cache = \JFactory::getCache('com_languages', '');

			if ($cache->contains('installedlanguages'))
			{
				$installedLanguages = $cache->get('installedlanguages');
			}
			else
			{
				$db = \JFactory::getDbo();

				$query = $db->getQuery(true)
					->select($db->quoteName(array('element',
'name', 'client_id', 'extension_id')))
					->from($db->quoteName('#__extensions'))
					->where($db->quoteName('type') . ' = ' .
$db->quote('language'))
					->where($db->quoteName('state') . ' = 0')
					->where($db->quoteName('enabled') . ' = 1');

				$installedLanguages = $db->setQuery($query)->loadObjectList();

				$cache->store($installedLanguages, 'installedlanguages');
			}
		}

		$clients   = $clientId === null ? array(0, 1) : array((int) $clientId);
		$languages = array(
			0 => array(),
			1 => array(),
		);

		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)
. '/' . $language->element . '.xml';

				// Process the language metadata.
				if ($processMetaData)
				{
					try
					{
						$lang->metadata = self::parseXMLLanguageFile($metafile);
					}

					// Not able to process xml language file. Fail silently.
					catch (\Exception $e)
					{
						\JLog::add(\JText::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METAFILE',
$language->element, $metafile), \JLog::WARNING, 'language');

						continue;
					}

					// No metadata found, not a valid language. Fail silently.
					if (!is_array($lang->metadata))
					{
						\JLog::add(\JText::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METADATA',
$language->element, $metafile), \JLog::WARNING, 'language');

						continue;
					}
				}

				// Process the language manifest.
				if ($processManifest)
				{
					try
					{
						$lang->manifest = \JInstaller::parseXMLInstallFile($metafile);
					}

					// Not able to process xml language file. Fail silently.
					catch (\Exception $e)
					{
						\JLog::add(\JText::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METAFILE',
$language->element, $metafile), \JLog::WARNING, 'language');

						continue;
					}

					// No metadata found, not a valid language. Fail silently.
					if (!is_array($lang->manifest))
					{
						\JLog::add(\JText::sprintf('JLIB_LANGUAGE_ERROR_CANNOT_LOAD_METADATA',
$language->element, $metafile), \JLog::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($languages[$cId],
$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($languages[$cId], $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 = array(1),
$checkInstalled = true, $pivot = 'lang_code', $orderField = null,
		$orderDirection = null)
	{
		static $contentLanguages = null;

		if ($contentLanguages === null)
		{
			$cache = \JFactory::getCache('com_languages', '');

			if ($cache->contains('contentlanguages'))
			{
				$contentLanguages = $cache->get('contentlanguages');
			}
			else
			{
				$db = \JFactory::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 = array(1);
		}
		elseif ($publishedStates === false)
		{
			$publishedStates = array();
		}

		// 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
	 *
	 * @since   3.9.0
	 */
	public static function parseIniFile($fileName, $debug = false)
	{
		// Check if file exists.
		if (!file_exists($fileName))
		{
			return array();
		}

		// @deprecated 3.9.0 Usage of "_QQ_" is deprecated. Use escaped
double quotes (\") instead.
		if (!defined('_QQ_'))
		{
			/**
			 * Defines a placeholder for a double quote character (") in a
language file
			 *
			 * @var    string
			 * @since  1.6
			 * @deprecated  4.0 Use escaped double quotes (\") instead.
			 */
			define('_QQ_', '"');
		}

		// Capture hidden PHP errors from the parsing.
		if ($debug === true)
		{
			// See https://www.php.net/manual/en/reserved.variables.phperrormsg.php
			$php_errormsg = null;

			$trackErrors = ini_get('track_errors');
			ini_set('track_errors', true);
		}

		// 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));

		if (!function_exists('parse_ini_file') ||
$isParseIniFileDisabled)
		{
			$contents = file_get_contents($fileName);
			$contents = str_replace('_QQ_',
'"\""', $contents);
			$strings = @parse_ini_string($contents);
		}
		else
		{
			$strings = @parse_ini_file($fileName);
		}

		// Restore error tracking to what it was before.
		if ($debug === true)
		{
			ini_set('track_errors', $trackErrors);
		}

		return is_array($strings) ? $strings : array();
	}

	/**
	 * 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)
	{
		\JLoader::register('\JFile', JPATH_LIBRARIES .
'/joomla/filesystem/file.php');

		// Escape double quotes.
		foreach ($strings as $key => $string)
		{
			$strings[$key] = addcslashes($string, '"');
		}

		// Write override.ini file with the strings.
		$registry = new Registry($strings);

		return \JFile::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 = array();

		// 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) . '/' .
$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 = array();

		// 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 . '/' .
$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,
array($dirPathParts['filename'] => $metadata));
					}
				}
				catch (\RuntimeException $e)
				{
				}
			}
		}

		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 = array();

		foreach ($xml->metadata->children() as $child)
		{
			$metadata[$child->getName()] = (string) $child;
		}

		return $metadata;
	}
}
LanguageStemmer.php000064400000003410151157062550010342 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

/**
 * Stemmer base class.
 *
 * @since       3.0.0
 * @deprecated  4.0 Use wamania/php-stemmer
 */
abstract class LanguageStemmer
{
	/**
	 * An internal cache of stemmed tokens.
	 *
	 * @var    array
	 * @since  3.0.0
	 */
	protected $cache = array();

	/**
	 * @var    array  LanguageStemmer instances.
	 * @since  3.0.0
	 */
	protected static $instances = array();

	/**
	 * Method to get a stemmer, creating it if necessary.
	 *
	 * @param   string  $adapter  The type of stemmer to load.
	 *
	 * @return  LanguageStemmer  A LanguageStemmer instance.
	 *
	 * @since   3.0.0
	 * @throws  \RuntimeException on invalid stemmer.
	 */
	public static function getInstance($adapter)
	{
		// Only create one stemmer for each adapter.
		if (isset(self::$instances[$adapter]))
		{
			return self::$instances[$adapter];
		}

		// Setup the adapter for the stemmer.
		$class = 'Joomla\\CMS\\Language\\Stemmer\\' .
ucfirst(trim($adapter));

		// Check if a stemmer exists for the adapter.
		if (!class_exists($class))
		{
			// Throw invalid adapter exception.
			throw new
\RuntimeException(\JText::sprintf('JLIB_STEMMER_INVALID_STEMMER',
$adapter));
		}

		self::$instances[$adapter] = new $class;

		return self::$instances[$adapter];
	}

	/**
	 * Method to stem a token and return the root.
	 *
	 * @param   string  $token  The token to stem.
	 * @param   string  $lang   The language of the token.
	 *
	 * @return  string  The root token.
	 *
	 * @since   3.0.0
	 */
	abstract public function stem($token, $lang);
}
Multilanguage.php000064400000005321151157062550010063 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

/**
 * Utility class for multilang
 *
 * @since  2.5.4
 */
class Multilanguage
{
	/**
	 * Method to determine if the language filter plugin is enabled.
	 * This works for both site and administrator.
	 *
	 * @return  boolean  True if site is supporting multiple languages; false
otherwise.
	 *
	 * @since   2.5.4
	 */
	public static function isEnabled()
	{
		// Flag to avoid doing multiple database queries.
		static $tested = false;

		// Status of language filter plugin.
		static $enabled = false;

		// Get application object.
		$app = \JFactory::getApplication();

		// If being called from the frontend, we can avoid the database query.
		if ($app->isClient('site'))
		{
			$enabled = $app->getLanguageFilter();

			return $enabled;
		}

		// If already tested, don't test again.
		if (!$tested)
		{
			// Determine status of language filter plugin.
			$db = \JFactory::getDbo();
			$query = $db->getQuery(true)
				->select('enabled')
				->from($db->quoteName('#__extensions'))
				->where($db->quoteName('type') . ' = ' .
$db->quote('plugin'))
				->where($db->quoteName('folder') . ' = ' .
$db->quote('system'))
				->where($db->quoteName('element') . ' = ' .
$db->quote('languagefilter'));
			$db->setQuery($query);

			$enabled = $db->loadResult();
			$tested = true;
		}

		return (bool) $enabled;
	}

	/**
	 * Method to return a list of published site languages.
	 *
	 * @return  array of language extension objects.
	 *
	 * @since   3.5
	 * @deprecated   3.7.0  Use \JLanguageHelper::getInstalledLanguages(0)
instead.
	 */
	public static function getSiteLangs()
	{
		\JLog::add(__METHOD__ . ' is deprecated. Use
\JLanguageHelper::getInstalledLanguages(0) instead.', \JLog::WARNING,
'deprecated');

		return \JLanguageHelper::getInstalledLanguages(0);
	}

	/**
	 * Method to return a list of language home page menu items.
	 *
	 * @return  array of menu objects.
	 *
	 * @since   3.5
	 */
	public static function getSiteHomePages()
	{
		// To avoid doing duplicate database queries.
		static $multilangSiteHomePages = null;

		if (!isset($multilangSiteHomePages))
		{
			// Check for Home pages languages.
			$db = \JFactory::getDbo();
			$query = $db->getQuery(true)
				->select('language')
				->select('id')
				->from($db->quoteName('#__menu'))
				->where('home = 1')
				->where('published = 1')
				->where('client_id = 0');
			$db->setQuery($query);

			$multilangSiteHomePages = $db->loadObjectList('language');
		}

		return $multilangSiteHomePages;
	}
}
Stemmer/Porteren.php000064400000023641151157062550010504 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @copyright  Copyright (C) 2005 Richard Heyes (http://www.phpguru.org/).
All rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language\Stemmer;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Language\LanguageStemmer;

/**
 * Porter English stemmer class.
 *
 * This class was adapted from one written by Richard Heyes.
 * See copyright and link information above.
 *
 * @since       3.0.0
 * @deprecated  4.0 Use wamania/php-stemmer
 */
class Porteren extends LanguageStemmer
{
	/**
	 * Regex for matching a consonant.
	 *
	 * @var    string
	 * @since  3.0.0
	 */
	private static $_regex_consonant =
'(?:[bcdfghjklmnpqrstvwxz]|(?<=[aeiou])y|^y)';

	/**
	 * Regex for matching a vowel
	 * @var    string
	 * @since  3.0.0
	 */
	private static $_regex_vowel = '(?:[aeiou]|(?<![aeiou])y)';

	/**
	 * Method to stem a token and return the root.
	 *
	 * @param   string  $token  The token to stem.
	 * @param   string  $lang   The language of the token.
	 *
	 * @return  string  The root token.
	 *
	 * @since   3.0.0
	 */
	public function stem($token, $lang)
	{
		// Check if the token is long enough to merit stemming.
		if (strlen($token) <= 2)
		{
			return $token;
		}

		// Check if the language is English or All.
		if ($lang !== 'en')
		{
			return $token;
		}

		// Stem the token if it is not in the cache.
		if (!isset($this->cache[$lang][$token]))
		{
			// Stem the token.
			$result = $token;
			$result = self::_step1ab($result);
			$result = self::_step1c($result);
			$result = self::_step2($result);
			$result = self::_step3($result);
			$result = self::_step4($result);
			$result = self::_step5($result);

			// Add the token to the cache.
			$this->cache[$lang][$token] = $result;
		}

		return $this->cache[$lang][$token];
	}

	/**
	 * Step 1
	 *
	 * @param   string  $word  The token to stem.
	 *
	 * @return  string
	 *
	 * @since   3.0.0
	 */
	private static function _step1ab($word)
	{
		// Part a
		if (substr($word, -1) == 's')
		{
				self::_replace($word, 'sses', 'ss')
			|| self::_replace($word, 'ies', 'i')
			|| self::_replace($word, 'ss', 'ss')
			|| self::_replace($word, 's', '');
		}

		// Part b
		if (substr($word, -2, 1) != 'e' || !self::_replace($word,
'eed', 'ee', 0))
		{
			// First rule
			$v = self::$_regex_vowel;

			// Check ing and ed
			// Note use of && and OR, for precedence reasons
			if (preg_match("#$v+#", substr($word, 0, -3)) &&
self::_replace($word, 'ing', '')
				|| preg_match("#$v+#", substr($word, 0, -2)) &&
self::_replace($word, 'ed', ''))
			{
				// If one of above two test successful
				if (!self::_replace($word, 'at', 'ate') &&
!self::_replace($word, 'bl', 'ble') &&
!self::_replace($word, 'iz', 'ize'))
				{
					// Double consonant ending
					if (self::_doubleConsonant($word) && substr($word, -2) !=
'll' && substr($word, -2) != 'ss' &&
substr($word, -2) != 'zz')
					{
						$word = substr($word, 0, -1);
					}
					elseif (self::_m($word) == 1 && self::_cvc($word))
					{
						$word .= 'e';
					}
				}
			}
		}

		return $word;
	}

	/**
	 * Step 1c
	 *
	 * @param   string  $word  The token to stem.
	 *
	 * @return  string
	 *
	 * @since   3.0.0
	 */
	private static function _step1c($word)
	{
		$v = self::$_regex_vowel;

		if (substr($word, -1) == 'y' &&
preg_match("#$v+#", substr($word, 0, -1)))
		{
			self::_replace($word, 'y', 'i');
		}

		return $word;
	}

	/**
	 * Step 2
	 *
	 * @param   string  $word  The token to stem.
	 *
	 * @return  string
	 *
	 * @since   3.0.0
	 */
	private static function _step2($word)
	{
		switch (substr($word, -2, 1))
		{
			case 'a':
					self::_replace($word, 'ational', 'ate', 0)
				|| self::_replace($word, 'tional', 'tion', 0);
				break;
			case 'c':
					self::_replace($word, 'enci', 'ence', 0)
				|| self::_replace($word, 'anci', 'ance', 0);
				break;
			case 'e':
				self::_replace($word, 'izer', 'ize', 0);
				break;
			case 'g':
				self::_replace($word, 'logi', 'log', 0);
				break;
			case 'l':
					self::_replace($word, 'entli', 'ent', 0)
				|| self::_replace($word, 'ousli', 'ous', 0)
				|| self::_replace($word, 'alli', 'al', 0)
				|| self::_replace($word, 'bli', 'ble', 0)
				|| self::_replace($word, 'eli', 'e', 0);
				break;
			case 'o':
					self::_replace($word, 'ization', 'ize', 0)
				|| self::_replace($word, 'ation', 'ate', 0)
				|| self::_replace($word, 'ator', 'ate', 0);
				break;
			case 's':
					self::_replace($word, 'iveness', 'ive', 0)
				|| self::_replace($word, 'fulness', 'ful', 0)
				|| self::_replace($word, 'ousness', 'ous', 0)
				|| self::_replace($word, 'alism', 'al', 0);
				break;
			case 't':
					self::_replace($word, 'biliti', 'ble', 0)
				|| self::_replace($word, 'aliti', 'al', 0)
				|| self::_replace($word, 'iviti', 'ive', 0);
				break;
		}

		return $word;
	}

	/**
	 * Step 3
	 *
	 * @param   string  $word  The token to stem.
	 *
	 * @return  string
	 *
	 * @since   3.0.0
	 */
	private static function _step3($word)
	{
		switch (substr($word, -2, 1))
		{
			case 'a':
				self::_replace($word, 'ical', 'ic', 0);
				break;
			case 's':
				self::_replace($word, 'ness', '', 0);
				break;
			case 't':
					self::_replace($word, 'icate', 'ic', 0)
				|| self::_replace($word, 'iciti', 'ic', 0);
				break;
			case 'u':
				self::_replace($word, 'ful', '', 0);
				break;
			case 'v':
				self::_replace($word, 'ative', '', 0);
				break;
			case 'z':
				self::_replace($word, 'alize', 'al', 0);
				break;
		}

		return $word;
	}

	/**
	 * Step 4
	 *
	 * @param   string  $word  The token to stem.
	 *
	 * @return  string
	 *
	 * @since   3.0.0
	 */
	private static function _step4($word)
	{
		switch (substr($word, -2, 1))
		{
			case 'a':
				self::_replace($word, 'al', '', 1);
				break;
			case 'c':
					self::_replace($word, 'ance', '', 1)
				|| self::_replace($word, 'ence', '', 1);
				break;
			case 'e':
				self::_replace($word, 'er', '', 1);
				break;
			case 'i':
				self::_replace($word, 'ic', '', 1);
				break;
			case 'l':
					self::_replace($word, 'able', '', 1)
				|| self::_replace($word, 'ible', '', 1);
				break;
			case 'n':
					self::_replace($word, 'ant', '', 1)
				|| self::_replace($word, 'ement', '', 1)
				|| self::_replace($word, 'ment', '', 1)
				|| self::_replace($word, 'ent', '', 1);
				break;
			case 'o':
				if (substr($word, -4) == 'tion' || substr($word, -4) ==
'sion')
				{
					self::_replace($word, 'ion', '', 1);
				}
				else
				{
					self::_replace($word, 'ou', '', 1);
				}
				break;
			case 's':
				self::_replace($word, 'ism', '', 1);
				break;
			case 't':
					self::_replace($word, 'ate', '', 1)
				|| self::_replace($word, 'iti', '', 1);
				break;
			case 'u':
				self::_replace($word, 'ous', '', 1);
				break;
			case 'v':
				self::_replace($word, 'ive', '', 1);
				break;
			case 'z':
				self::_replace($word, 'ize', '', 1);
				break;
		}

		return $word;
	}

	/**
	 * Step 5
	 *
	 * @param   string  $word  The token to stem.
	 *
	 * @return  string
	 *
	 * @since   3.0.0
	 */
	private static function _step5($word)
	{
		// Part a
		if (substr($word, -1) == 'e')
		{
			if (self::_m(substr($word, 0, -1)) > 1)
			{
				self::_replace($word, 'e', '');
			}
			elseif (self::_m(substr($word, 0, -1)) == 1)
			{
				if (!self::_cvc(substr($word, 0, -1)))
				{
					self::_replace($word, 'e', '');
				}
			}
		}

		// Part b
		if (self::_m($word) > 1 && self::_doubleConsonant($word)
&& substr($word, -1) == 'l')
		{
			$word = substr($word, 0, -1);
		}

		return $word;
	}

	/**
	 * Replaces the first string with the second, at the end of the string. If
third
	 * arg is given, then the preceding string must match that m count at
least.
	 *
	 * @param   string   &$str   String to check
	 * @param   string   $check  Ending to check for
	 * @param   string   $repl   Replacement string
	 * @param   integer  $m      Optional minimum number of m() to meet
	 *
	 * @return  boolean  Whether the $check string was at the end
	 *                   of the $str string. True does not necessarily mean
	 *                   that it was replaced.
	 *
	 * @since   3.0.0
	 */
	private static function _replace(&$str, $check, $repl, $m = null)
	{
		$len = 0 - strlen($check);

		if (substr($str, $len) == $check)
		{
			$substr = substr($str, 0, $len);

			if (is_null($m) || self::_m($substr) > $m)
			{
				$str = $substr . $repl;
			}

			return true;
		}

		return false;
	}

	/**
	 * m() measures the number of consonant sequences in $str. if c is
	 * a consonant sequence and v a vowel sequence, and <..> indicates
arbitrary
	 * presence,
	 *
	 * <c><v>       gives 0
	 * <c>vc<v>     gives 1
	 * <c>vcvc<v>   gives 2
	 * <c>vcvcvc<v> gives 3
	 *
	 * @param   string  $str  The string to return the m count for
	 *
	 * @return  integer  The m count
	 *
	 * @since   3.0.0
	 */
	private static function _m($str)
	{
		$c = self::$_regex_consonant;
		$v = self::$_regex_vowel;

		$str = preg_replace("#^$c+#", '', $str);
		$str = preg_replace("#$v+$#", '', $str);

		preg_match_all("#($v+$c+)#", $str, $matches);

		return count($matches[1]);
	}

	/**
	 * Returns true/false as to whether the given string contains two
	 * of the same consonant next to each other at the end of the string.
	 *
	 * @param   string  $str  String to check
	 *
	 * @return  boolean  Result
	 *
	 * @since   3.0.0
	 */
	private static function _doubleConsonant($str)
	{
		$c = self::$_regex_consonant;

		return preg_match("#$c{2}$#", $str, $matches) &&
$matches[0][0] == $matches[0][1];
	}

	/**
	 * Checks for ending CVC sequence where second C is not W, X or Y
	 *
	 * @param   string  $str  String to check
	 *
	 * @return  boolean  Result
	 *
	 * @since   3.0.0
	 */
	private static function _cvc($str)
	{
		$c = self::$_regex_consonant;
		$v = self::$_regex_vowel;

		$result = preg_match("#($c$v$c)$#", $str, $matches)
			&& strlen($matches[1]) == 3
			&& $matches[1][2] != 'w'
			&& $matches[1][2] != 'x'
			&& $matches[1][2] != 'y';

		return $result;
	}
}
Text.php000064400000027370151157062550006221 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Log\Log;

/**
 * Text handling class.
 *
 * @since  1.7.0
 */
class Text
{
	/**
	 * JavaScript strings
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected static $strings = array();

	/**
	 * Translates a string into the current language.
	 *
	 * Examples:
	 * `<script>alert(Joomla.JText._('<?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 = (boolean)
$jsSafe['interpretBackSlashes'];
			}

			if (array_key_exists('script', $jsSafe))
			{
				$script = (boolean) $jsSafe['script'];
			}

			$jsSafe = array_key_exists('jsSafe', $jsSafe) ? (boolean)
$jsSafe['jsSafe'] : false;
		}

		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 (strpos($string, ',') === false)
		{
			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 sprinftf 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 $i => $str)
			{
				static::$strings[$str] = $string_parts[$i];
			}
		}

		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.JText._('<?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);

		if ($count < 1)
		{
			return '';
		}

		if ($count == 1)
		{
			// Default to the normal sprintf handling.
			$args[0] = $lang->_($string);

			return call_user_func_array('sprintf', $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;
			}
		}

		if (!$found)
		{
			// Not found so revert to the original.
			$key = $string;
		}

		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 ($count < 1)
		{
			return '';
		}

		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 thru an 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 ($count < 1)
		{
			return '';
		}

		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                Ensure the output is
JavaScript safe.
	 * @param   boolean  $interpretBackSlashes  Interpret \t and \n.
	 *
	 * @return  string
	 *
	 * @since   1.7.0
	 */
	public static function script($string = null, $jsSafe = false,
$interpretBackSlashes = true)
	{
		if ($string === null)
		{
			Log::add(
				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__
				),
				Log::WARNING,
				'deprecated'
			);
		}

		if (is_array($jsSafe))
		{
			if (array_key_exists('interpretBackSlashes', $jsSafe))
			{
				$interpretBackSlashes = (boolean)
$jsSafe['interpretBackSlashes'];
			}

			if (array_key_exists('jsSafe', $jsSafe))
			{
				$jsSafe = (boolean) $jsSafe['jsSafe'];
			}
			else
			{
				$jsSafe = false;
			}
		}

		// Add the string to the array if not null.
		if ($string !== null)
		{
			// Normalize the key and translate the string.
			static::$strings[strtoupper($string)] =
Factory::getLanguage()->_($string, $jsSafe, $interpretBackSlashes);

			// Load core.js dependency
			HTMLHelper::_('behavior.core');

			// Update Joomla.JText script options
			Factory::getDocument()->addScriptOptions('joomla.jtext',
static::$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;
	}
}
Transliterate.php000064400000011741151157062550010111 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language;

defined('JPATH_PLATFORM') or die;

/**
 * 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 = array(
					'à' => '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 = array(
					'À' => '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;
	}
}
Wrapper/JTextWrapper.php000064400000007160151157062550011307
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language\Wrapper;

defined('JPATH_PLATFORM') or die;

/**
 * Wrapper class for JText
 *
 * @since       3.4
 * @deprecated  4.0  Use `JText` directly
 */
class JTextWrapper
{
	/**
	 * Helper wrapper method for _
	 *
	 * @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.
	 *
	 * @see     \JText::_
	 * @since   3.4
	 * @deprecated  4.0  Use `JText` directly
	 */
	public function _($string, $jsSafe = false, $interpretBackSlashes = true,
$script = false)
	{
		return \JText::_($string, $jsSafe, $interpretBackSlashes, $script);
	}

	/**
	 * Helper wrapper method for alt
	 *
	 * @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.
	 *
	 * @see     \JText::alt
	 * @since   3.4
	 * @deprecated  4.0  Use `JText` directly
	 */
	public function alt($string, $alt, $jsSafe = false, $interpretBackSlashes
= true, $script = false)
	{
		return \JText::alt($string, $alt, $jsSafe, $interpretBackSlashes,
$script);
	}

	/**
	 * Helper wrapper method for plural
	 *
	 * @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.
	 *
	 * @see     \JText::plural
	 * @since   3.4
	 * @deprecated  4.0  Use `JText` directly
	 */
	public function plural($string, $n)
	{
		return \JText::plural($string, $n);
	}

	/**
	 * Helper wrapper method for sprintf
	 *
	 * @param   string  $string  The format string.
	 *
	 * @return  string  The translated strings or the key if
'script' is true in the array of options.
	 *
	 * @see     \JText::sprintf
	 * @since   3.4
	 * @deprecated  4.0  Use `JText` directly
	 */
	public function sprintf($string)
	{
		return \JText::sprintf($string);
	}

	/**
	 * Helper wrapper method for printf
	 *
	 * @param   string  $string  The format string.
	 *
	 * @return  mixed
	 *
	 * @see     \JText::printf
	 * @since   3.4
	 * @deprecated  4.0  Use `JText` directly
	 */
	public function printf($string)
	{
		return \JText::printf($string);
	}

	/**
	 * Helper wrapper method for script
	 *
	 * @param   string   $string                The \JText key.
	 * @param   boolean  $jsSafe                Ensure the output is
JavaScript safe.
	 * @param   boolean  $interpretBackSlashes  Interpret \t and \n.
	 *
	 * @return  string
	 *
	 * @see     \JText::script
	 * @since   3.4
	 * @deprecated  4.0  Use `JText` directly
	 */
	public function script($string = null, $jsSafe = false,
$interpretBackSlashes = true)
	{
		return \JText::script($string, $jsSafe, $interpretBackSlashes);
	}
}
Wrapper/LanguageHelperWrapper.php000064400000003633151157062550013135
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language\Wrapper;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Language\LanguageHelper;

/**
 * Wrapper class for LanguageHelper
 *
 * @since       3.4
 * @deprecated  4.0  Use `Joomla\CMS\Language\LanguageHelper` directly
 */
class LanguageHelperWrapper
{
	/**
	 * Helper wrapper method for createLanguageList
	 *
	 * @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.
	 *
	 * @see     LanguageHelper::createLanguageList
	 * @since   3.4
	 * @deprecated  4.0  Use `Joomla\CMS\Language\LanguageHelper` directly
	 */
	public function createLanguageList($actualLanguage, $basePath =
JPATH_BASE, $caching = false, $installed = false)
	{
		return LanguageHelper::createLanguageList($actualLanguage, $basePath,
$caching, $installed);
	}

	/**
	 * Helper wrapper method for detectLanguage
	 *
	 * @return  string  locale or null if not found.
	 *
	 * @see     LanguageHelper::detectLanguage
	 * @since   3.4
	 * @deprecated  4.0  Use `Joomla\CMS\Language\LanguageHelper` directly
	 */
	public function detectLanguage()
	{
		return LanguageHelper::detectLanguage();
	}

	/**
	 * Helper wrapper method for getLanguages
	 *
	 * @param   string  $key  Array key
	 *
	 * @return  array  An array of published languages.
	 *
	 * @see     LanguageHelper::getLanguages
	 * @since   3.4
	 * @deprecated  4.0  Use `Joomla\CMS\Language\LanguageHelper` directly
	 */
	public function getLanguages($key = 'default')
	{
		return LanguageHelper::getLanguages($key);
	}
}
Wrapper/TransliterateWrapper.php000064400000002001151157062550013057
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Language\Wrapper;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Language\Transliterate;

/**
 * Wrapper class for Transliterate
 *
 * @since       3.4
 * @deprecated  4.0  Use `Joomla\CMS\Language\Transliterate` directly
 */
class TransliterateWrapper
{
	/**
	 * Helper wrapper method for utf8_latin_to_ascii
	 *
	 * @param   string   $string  String to transliterate.
	 * @param   integer  $case    Optionally specify upper or lower case.
Default to null.
	 *
	 * @return  string  Transliterated string.
	 *
	 * @see     Transliterate::utf8_latin_to_ascii()
	 * @since   3.4
	 * @deprecated  4.0  Use `Joomla\CMS\Language\Transliterate` directly
	 */
	public function utf8_latin_to_ascii($string, $case = 0)
	{
		return Transliterate::utf8_latin_to_ascii($string, $case);
	}
}