S2OJ/web/app/vendor/htmlpurifier/HTMLPurifier/LanguageFactory.php
Masco Skray 96d4a3ecf7 style(judger,web): move code out from subfolder "1"
Due to historical reasons, the code is in subfolder "1".
With SVN removal, we place the code back and remove the annoying "1" folder.
2019-06-14 23:34:41 +08:00

210 lines
6.5 KiB
PHP

<?php
/**
* Class responsible for generating HTMLPurifier_Language objects, managing
* caching and fallbacks.
* @note Thanks to MediaWiki for the general logic, although this version
* has been entirely rewritten
* @todo Serialized cache for languages
*/
class HTMLPurifier_LanguageFactory
{
/**
* Cache of language code information used to load HTMLPurifier_Language objects.
* Structure is: $factory->cache[$language_code][$key] = $value
* @type array
*/
public $cache;
/**
* Valid keys in the HTMLPurifier_Language object. Designates which
* variables to slurp out of a message file.
* @type array
*/
public $keys = array('fallback', 'messages', 'errorNames');
/**
* Instance to validate language codes.
* @type HTMLPurifier_AttrDef_Lang
*
*/
protected $validator;
/**
* Cached copy of dirname(__FILE__), directory of current file without
* trailing slash.
* @type string
*/
protected $dir;
/**
* Keys whose contents are a hash map and can be merged.
* @type array
*/
protected $mergeable_keys_map = array('messages' => true, 'errorNames' => true);
/**
* Keys whose contents are a list and can be merged.
* @value array lookup
*/
protected $mergeable_keys_list = array();
/**
* Retrieve sole instance of the factory.
* @param HTMLPurifier_LanguageFactory $prototype Optional prototype to overload sole instance with,
* or bool true to reset to default factory.
* @return HTMLPurifier_LanguageFactory
*/
public static function instance($prototype = null)
{
static $instance = null;
if ($prototype !== null) {
$instance = $prototype;
} elseif ($instance === null || $prototype == true) {
$instance = new HTMLPurifier_LanguageFactory();
$instance->setup();
}
return $instance;
}
/**
* Sets up the singleton, much like a constructor
* @note Prevents people from getting this outside of the singleton
*/
public function setup()
{
$this->validator = new HTMLPurifier_AttrDef_Lang();
$this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier';
}
/**
* Creates a language object, handles class fallbacks
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @param bool|string $code Code to override configuration with. Private parameter.
* @return HTMLPurifier_Language
*/
public function create($config, $context, $code = false)
{
// validate language code
if ($code === false) {
$code = $this->validator->validate(
$config->get('Core.Language'),
$config,
$context
);
} else {
$code = $this->validator->validate($code, $config, $context);
}
if ($code === false) {
$code = 'en'; // malformed code becomes English
}
$pcode = str_replace('-', '_', $code); // make valid PHP classname
static $depth = 0; // recursion protection
if ($code == 'en') {
$lang = new HTMLPurifier_Language($config, $context);
} else {
$class = 'HTMLPurifier_Language_' . $pcode;
$file = $this->dir . '/Language/classes/' . $code . '.php';
if (file_exists($file) || class_exists($class, false)) {
$lang = new $class($config, $context);
} else {
// Go fallback
$raw_fallback = $this->getFallbackFor($code);
$fallback = $raw_fallback ? $raw_fallback : 'en';
$depth++;
$lang = $this->create($config, $context, $fallback);
if (!$raw_fallback) {
$lang->error = true;
}
$depth--;
}
}
$lang->code = $code;
return $lang;
}
/**
* Returns the fallback language for language
* @note Loads the original language into cache
* @param string $code language code
* @return string|bool
*/
public function getFallbackFor($code)
{
$this->loadLanguage($code);
return $this->cache[$code]['fallback'];
}
/**
* Loads language into the cache, handles message file and fallbacks
* @param string $code language code
*/
public function loadLanguage($code)
{
static $languages_seen = array(); // recursion guard
// abort if we've already loaded it
if (isset($this->cache[$code])) {
return;
}
// generate filename
$filename = $this->dir . '/Language/messages/' . $code . '.php';
// default fallback : may be overwritten by the ensuing include
$fallback = ($code != 'en') ? 'en' : false;
// load primary localisation
if (!file_exists($filename)) {
// skip the include: will rely solely on fallback
$filename = $this->dir . '/Language/messages/en.php';
$cache = array();
} else {
include $filename;
$cache = compact($this->keys);
}
// load fallback localisation
if (!empty($fallback)) {
// infinite recursion guard
if (isset($languages_seen[$code])) {
trigger_error(
'Circular fallback reference in language ' .
$code,
E_USER_ERROR
);
$fallback = 'en';
}
$language_seen[$code] = true;
// load the fallback recursively
$this->loadLanguage($fallback);
$fallback_cache = $this->cache[$fallback];
// merge fallback with current language
foreach ($this->keys as $key) {
if (isset($cache[$key]) && isset($fallback_cache[$key])) {
if (isset($this->mergeable_keys_map[$key])) {
$cache[$key] = $cache[$key] + $fallback_cache[$key];
} elseif (isset($this->mergeable_keys_list[$key])) {
$cache[$key] = array_merge($fallback_cache[$key], $cache[$key]);
}
} else {
$cache[$key] = $fallback_cache[$key];
}
}
}
// save to cache for later retrieval
$this->cache[$code] = $cache;
return;
}
}
// vim: et sw=4 sts=4