3 require_once 'HTMLPurifier/Language.php';
4 require_once 'HTMLPurifier/AttrDef/Lang.php';
6 HTMLPurifier_ConfigSchema
::define(
7 'Core', 'Language', 'en', 'string', '
8 ISO 639 language code for localizable things in HTML Purifier to use,
9 which is mainly error reporting. There is currently only an English (en)
10 translation, so this directive is currently useless.
11 This directive has been available since 2.0.0.
15 * Class responsible for generating HTMLPurifier_Language objects, managing
16 * caching and fallbacks.
17 * @note Thanks to MediaWiki for the general logic, although this version
18 * has been entirely rewritten
20 class HTMLPurifier_LanguageFactory
24 * Cache of language code information used to load HTMLPurifier_Language objects
25 * Structure is: $factory->cache[$language_code][$key] = $value
31 * Valid keys in the HTMLPurifier_Language object. Designates which
32 * variables to slurp out of a message file.
35 var $keys = array('fallback', 'messages', 'errorNames');
38 * Instance of HTMLPurifier_AttrDef_Lang to validate language codes
39 * @value object HTMLPurifier_AttrDef_Lang
44 * Cached copy of dirname(__FILE__), directory of current file without
46 * @value string filename
51 * Keys whose contents are a hash map and can be merged
54 var $mergeable_keys_map = array('messages' => true, 'errorNames' => true);
57 * Keys whose contents are a list and can be merged
60 var $mergeable_keys_list = array();
63 * Retrieve sole instance of the factory.
65 * @param $prototype Optional prototype to overload sole instance with,
66 * or bool true to reset to default factory.
68 function &instance($prototype = null) {
69 static $instance = null;
70 if ($prototype !== null) {
71 $instance = $prototype;
72 } elseif ($instance === null ||
$prototype == true) {
73 $instance = new HTMLPurifier_LanguageFactory();
80 * Sets up the singleton, much like a constructor
81 * @note Prevents people from getting this outside of the singleton
84 $this->validator
= new HTMLPurifier_AttrDef_Lang();
85 $this->dir
= HTMLPURIFIER_PREFIX
. '/HTMLPurifier';
89 * Creates a language object, handles class fallbacks
90 * @param $config Instance of HTMLPurifier_Config
91 * @param $context Instance of HTMLPurifier_Context
93 function create($config, &$context) {
95 // validate language code
96 $code = $this->validator
->validate(
97 $config->get('Core', 'Language'), $config, $context
99 if ($code === false) $code = 'en'; // malformed code becomes English
101 $pcode = str_replace('-', '_', $code); // make valid PHP classname
102 static $depth = 0; // recursion protection
105 $class = 'HTMLPurifier_Language';
106 $file = $this->dir
. '/Language.php';
108 $class = 'HTMLPurifier_Language_' . $pcode;
109 $file = $this->dir
. '/Language/classes/' . $code . '.php';
110 // PHP5/APC deps bug workaround can go here
111 // you can bypass the conditional include by loading the
113 if (file_exists($file) && !class_exists($class)) {
118 if (!class_exists($class)) {
120 $fallback = HTMLPurifier_LanguageFactory
::getFallbackFor($code);
122 $lang = HTMLPurifier_LanguageFactory
::factory( $fallback );
125 $lang = new $class($config, $context);
134 * Returns the fallback language for language
135 * @note Loads the original language into cache
136 * @param $code string language code
138 function getFallbackFor($code) {
139 $this->loadLanguage($code);
140 return $this->cache
[$code]['fallback'];
144 * Loads language into the cache, handles message file and fallbacks
145 * @param $code string language code
147 function loadLanguage($code) {
148 static $languages_seen = array(); // recursion guard
150 // abort if we've already loaded it
151 if (isset($this->cache
[$code])) return;
154 $filename = $this->dir
. '/Language/messages/' . $code . '.php';
156 // default fallback : may be overwritten by the ensuing include
157 $fallback = ($code != 'en') ?
'en' : false;
159 // load primary localisation
160 if (!file_exists($filename)) {
161 // skip the include: will rely solely on fallback
162 $filename = $this->dir
. '/Language/messages/en.php';
166 $cache = compact($this->keys
);
169 // load fallback localisation
170 if (!empty($fallback)) {
172 // infinite recursion guard
173 if (isset($languages_seen[$code])) {
174 trigger_error('Circular fallback reference in language ' .
175 $code, E_USER_ERROR
);
178 $language_seen[$code] = true;
180 // load the fallback recursively
181 $this->loadLanguage($fallback);
182 $fallback_cache = $this->cache
[$fallback];
184 // merge fallback with current language
185 foreach ( $this->keys
as $key ) {
186 if (isset($cache[$key]) && isset($fallback_cache[$key])) {
187 if (isset($this->mergeable_keys_map
[$key])) {
188 $cache[$key] = $cache[$key] +
$fallback_cache[$key];
189 } elseif (isset($this->mergeable_keys_list
[$key])) {
190 $cache[$key] = array_merge( $fallback_cache[$key], $cache[$key] );
193 $cache[$key] = $fallback_cache[$key];
199 // save to cache for later retrieval
200 $this->cache
[$code] = $cache;