MDL-11517 reserved word MOD used in table alias in questions backup code
[moodle-pu.git] / lib / htmlpurifier / HTMLPurifier / LanguageFactory.php
blob9d26cd70375350f6a403a6e6052d0f532601b2fa
1 <?php
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.
12 ');
14 /**
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
23 /**
24 * Cache of language code information used to load HTMLPurifier_Language objects
25 * Structure is: $factory->cache[$language_code][$key] = $value
26 * @value array map
28 var $cache;
30 /**
31 * Valid keys in the HTMLPurifier_Language object. Designates which
32 * variables to slurp out of a message file.
33 * @value array list
35 var $keys = array('fallback', 'messages', 'errorNames');
37 /**
38 * Instance of HTMLPurifier_AttrDef_Lang to validate language codes
39 * @value object HTMLPurifier_AttrDef_Lang
41 var $validator;
43 /**
44 * Cached copy of dirname(__FILE__), directory of current file without
45 * trailing slash
46 * @value string filename
48 var $dir;
50 /**
51 * Keys whose contents are a hash map and can be merged
52 * @value array lookup
54 var $mergeable_keys_map = array('messages' => true, 'errorNames' => true);
56 /**
57 * Keys whose contents are a list and can be merged
58 * @value array lookup
60 var $mergeable_keys_list = array();
62 /**
63 * Retrieve sole instance of the factory.
64 * @static
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();
74 $instance->setup();
76 return $instance;
79 /**
80 * Sets up the singleton, much like a constructor
81 * @note Prevents people from getting this outside of the singleton
83 function setup() {
84 $this->validator = new HTMLPurifier_AttrDef_Lang();
85 $this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier';
88 /**
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
104 if ($code == 'en') {
105 $class = 'HTMLPurifier_Language';
106 $file = $this->dir . '/Language.php';
107 } else {
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
112 // file yourself
113 if (file_exists($file) && !class_exists($class)) {
114 include_once $file;
118 if (!class_exists($class)) {
119 // go fallback
120 $fallback = HTMLPurifier_LanguageFactory::getFallbackFor($code);
121 $depth++;
122 $lang = HTMLPurifier_LanguageFactory::factory( $fallback );
123 $depth--;
124 } else {
125 $lang = new $class($config, $context);
127 $lang->code = $code;
129 return $lang;
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;
153 // generate filename
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';
163 $cache = array();
164 } else {
165 include $filename;
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);
176 $fallback = 'en';
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] );
192 } else {
193 $cache[$key] = $fallback_cache[$key];
199 // save to cache for later retrieval
200 $this->cache[$code] = $cache;
202 return;