"MDL-12304, fix double text"
[moodle-linuxchix.git] / lib / htmlpurifier / HTMLPurifier / LanguageFactory.php
blob715c3fee9adde5c1c28afab6f8fe082c6e39bde7
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
19 * @todo Serialized cache for languages
21 class HTMLPurifier_LanguageFactory
24 /**
25 * Cache of language code information used to load HTMLPurifier_Language objects
26 * Structure is: $factory->cache[$language_code][$key] = $value
27 * @value array map
29 var $cache;
31 /**
32 * Valid keys in the HTMLPurifier_Language object. Designates which
33 * variables to slurp out of a message file.
34 * @value array list
36 var $keys = array('fallback', 'messages', 'errorNames');
38 /**
39 * Instance of HTMLPurifier_AttrDef_Lang to validate language codes
40 * @value object HTMLPurifier_AttrDef_Lang
42 var $validator;
44 /**
45 * Cached copy of dirname(__FILE__), directory of current file without
46 * trailing slash
47 * @value string filename
49 var $dir;
51 /**
52 * Keys whose contents are a hash map and can be merged
53 * @value array lookup
55 var $mergeable_keys_map = array('messages' => true, 'errorNames' => true);
57 /**
58 * Keys whose contents are a list and can be merged
59 * @value array lookup
61 var $mergeable_keys_list = array();
63 /**
64 * Retrieve sole instance of the factory.
65 * @static
66 * @param $prototype Optional prototype to overload sole instance with,
67 * or bool true to reset to default factory.
69 function &instance($prototype = null) {
70 static $instance = null;
71 if ($prototype !== null) {
72 $instance = $prototype;
73 } elseif ($instance === null || $prototype == true) {
74 $instance = new HTMLPurifier_LanguageFactory();
75 $instance->setup();
77 return $instance;
80 /**
81 * Sets up the singleton, much like a constructor
82 * @note Prevents people from getting this outside of the singleton
84 function setup() {
85 $this->validator = new HTMLPurifier_AttrDef_Lang();
86 $this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier';
89 /**
90 * Creates a language object, handles class fallbacks
91 * @param $config Instance of HTMLPurifier_Config
92 * @param $context Instance of HTMLPurifier_Context
93 * @param $code Code to override configuration with. Private parameter.
95 function create($config, &$context, $code = false) {
97 // validate language code
98 if ($code === false) {
99 $code = $this->validator->validate(
100 $config->get('Core', 'Language'), $config, $context
102 } else {
103 $code = $this->validator->validate($code, $config, $context);
105 if ($code === false) $code = 'en'; // malformed code becomes English
107 $pcode = str_replace('-', '_', $code); // make valid PHP classname
108 static $depth = 0; // recursion protection
110 if ($code == 'en') {
111 $lang = new HTMLPurifier_Language($config, $context);
112 } else {
113 $class = 'HTMLPurifier_Language_' . $pcode;
114 $file = $this->dir . '/Language/classes/' . $code . '.php';
115 if (file_exists($file)) {
116 include $file;
117 $lang = new $class($config, $context);
118 } else {
119 // Go fallback
120 $raw_fallback = $this->getFallbackFor($code);
121 $fallback = $raw_fallback ? $raw_fallback : 'en';
122 $depth++;
123 $lang = $this->create($config, $context, $fallback);
124 if (!$raw_fallback) {
125 $lang->error = true;
127 $depth--;
130 $lang->code = $code;
132 return $lang;
137 * Returns the fallback language for language
138 * @note Loads the original language into cache
139 * @param $code string language code
141 function getFallbackFor($code) {
142 $this->loadLanguage($code);
143 return $this->cache[$code]['fallback'];
147 * Loads language into the cache, handles message file and fallbacks
148 * @param $code string language code
150 function loadLanguage($code) {
151 static $languages_seen = array(); // recursion guard
153 // abort if we've already loaded it
154 if (isset($this->cache[$code])) return;
156 // generate filename
157 $filename = $this->dir . '/Language/messages/' . $code . '.php';
159 // default fallback : may be overwritten by the ensuing include
160 $fallback = ($code != 'en') ? 'en' : false;
162 // load primary localisation
163 if (!file_exists($filename)) {
164 // skip the include: will rely solely on fallback
165 $filename = $this->dir . '/Language/messages/en.php';
166 $cache = array();
167 } else {
168 include $filename;
169 $cache = compact($this->keys);
172 // load fallback localisation
173 if (!empty($fallback)) {
175 // infinite recursion guard
176 if (isset($languages_seen[$code])) {
177 trigger_error('Circular fallback reference in language ' .
178 $code, E_USER_ERROR);
179 $fallback = 'en';
181 $language_seen[$code] = true;
183 // load the fallback recursively
184 $this->loadLanguage($fallback);
185 $fallback_cache = $this->cache[$fallback];
187 // merge fallback with current language
188 foreach ( $this->keys as $key ) {
189 if (isset($cache[$key]) && isset($fallback_cache[$key])) {
190 if (isset($this->mergeable_keys_map[$key])) {
191 $cache[$key] = $cache[$key] + $fallback_cache[$key];
192 } elseif (isset($this->mergeable_keys_list[$key])) {
193 $cache[$key] = array_merge( $fallback_cache[$key], $cache[$key] );
195 } else {
196 $cache[$key] = $fallback_cache[$key];
202 // save to cache for later retrieval
203 $this->cache[$code] = $cache;
205 return;