PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/moodle/lib/htmlpurifier/HTMLPurifier/LanguageFactory.php

https://bitbucket.org/geek745/moodle-db2
PHP | 209 lines | 106 code | 32 blank | 71 comment | 22 complexity | 43774682a6dc207c22acaa7fd7ba6332 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause, LGPL-2.0
  1. <?php
  2. require_once 'HTMLPurifier/Language.php';
  3. require_once 'HTMLPurifier/AttrDef/Lang.php';
  4. HTMLPurifier_ConfigSchema::define(
  5. 'Core', 'Language', 'en', 'string', '
  6. ISO 639 language code for localizable things in HTML Purifier to use,
  7. which is mainly error reporting. There is currently only an English (en)
  8. translation, so this directive is currently useless.
  9. This directive has been available since 2.0.0.
  10. ');
  11. /**
  12. * Class responsible for generating HTMLPurifier_Language objects, managing
  13. * caching and fallbacks.
  14. * @note Thanks to MediaWiki for the general logic, although this version
  15. * has been entirely rewritten
  16. * @todo Serialized cache for languages
  17. */
  18. class HTMLPurifier_LanguageFactory
  19. {
  20. /**
  21. * Cache of language code information used to load HTMLPurifier_Language objects
  22. * Structure is: $factory->cache[$language_code][$key] = $value
  23. * @value array map
  24. */
  25. var $cache;
  26. /**
  27. * Valid keys in the HTMLPurifier_Language object. Designates which
  28. * variables to slurp out of a message file.
  29. * @value array list
  30. */
  31. var $keys = array('fallback', 'messages', 'errorNames');
  32. /**
  33. * Instance of HTMLPurifier_AttrDef_Lang to validate language codes
  34. * @value object HTMLPurifier_AttrDef_Lang
  35. */
  36. var $validator;
  37. /**
  38. * Cached copy of dirname(__FILE__), directory of current file without
  39. * trailing slash
  40. * @value string filename
  41. */
  42. var $dir;
  43. /**
  44. * Keys whose contents are a hash map and can be merged
  45. * @value array lookup
  46. */
  47. var $mergeable_keys_map = array('messages' => true, 'errorNames' => true);
  48. /**
  49. * Keys whose contents are a list and can be merged
  50. * @value array lookup
  51. */
  52. var $mergeable_keys_list = array();
  53. /**
  54. * Retrieve sole instance of the factory.
  55. * @static
  56. * @param $prototype Optional prototype to overload sole instance with,
  57. * or bool true to reset to default factory.
  58. */
  59. function &instance($prototype = null) {
  60. static $instance = null;
  61. if ($prototype !== null) {
  62. $instance = $prototype;
  63. } elseif ($instance === null || $prototype == true) {
  64. $instance = new HTMLPurifier_LanguageFactory();
  65. $instance->setup();
  66. }
  67. return $instance;
  68. }
  69. /**
  70. * Sets up the singleton, much like a constructor
  71. * @note Prevents people from getting this outside of the singleton
  72. */
  73. function setup() {
  74. $this->validator = new HTMLPurifier_AttrDef_Lang();
  75. $this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier';
  76. }
  77. /**
  78. * Creates a language object, handles class fallbacks
  79. * @param $config Instance of HTMLPurifier_Config
  80. * @param $context Instance of HTMLPurifier_Context
  81. * @param $code Code to override configuration with. Private parameter.
  82. */
  83. function create($config, &$context, $code = false) {
  84. // validate language code
  85. if ($code === false) {
  86. $code = $this->validator->validate(
  87. $config->get('Core', 'Language'), $config, $context
  88. );
  89. } else {
  90. $code = $this->validator->validate($code, $config, $context);
  91. }
  92. if ($code === false) $code = 'en'; // malformed code becomes English
  93. $pcode = str_replace('-', '_', $code); // make valid PHP classname
  94. static $depth = 0; // recursion protection
  95. if ($code == 'en') {
  96. $lang = new HTMLPurifier_Language($config, $context);
  97. } else {
  98. $class = 'HTMLPurifier_Language_' . $pcode;
  99. $file = $this->dir . '/Language/classes/' . $code . '.php';
  100. if (file_exists($file)) {
  101. include $file;
  102. $lang = new $class($config, $context);
  103. } else {
  104. // Go fallback
  105. $raw_fallback = $this->getFallbackFor($code);
  106. $fallback = $raw_fallback ? $raw_fallback : 'en';
  107. $depth++;
  108. $lang = $this->create($config, $context, $fallback);
  109. if (!$raw_fallback) {
  110. $lang->error = true;
  111. }
  112. $depth--;
  113. }
  114. }
  115. $lang->code = $code;
  116. return $lang;
  117. }
  118. /**
  119. * Returns the fallback language for language
  120. * @note Loads the original language into cache
  121. * @param $code string language code
  122. */
  123. function getFallbackFor($code) {
  124. $this->loadLanguage($code);
  125. return $this->cache[$code]['fallback'];
  126. }
  127. /**
  128. * Loads language into the cache, handles message file and fallbacks
  129. * @param $code string language code
  130. */
  131. function loadLanguage($code) {
  132. static $languages_seen = array(); // recursion guard
  133. // abort if we've already loaded it
  134. if (isset($this->cache[$code])) return;
  135. // generate filename
  136. $filename = $this->dir . '/Language/messages/' . $code . '.php';
  137. // default fallback : may be overwritten by the ensuing include
  138. $fallback = ($code != 'en') ? 'en' : false;
  139. // load primary localisation
  140. if (!file_exists($filename)) {
  141. // skip the include: will rely solely on fallback
  142. $filename = $this->dir . '/Language/messages/en.php';
  143. $cache = array();
  144. } else {
  145. include $filename;
  146. $cache = compact($this->keys);
  147. }
  148. // load fallback localisation
  149. if (!empty($fallback)) {
  150. // infinite recursion guard
  151. if (isset($languages_seen[$code])) {
  152. trigger_error('Circular fallback reference in language ' .
  153. $code, E_USER_ERROR);
  154. $fallback = 'en';
  155. }
  156. $language_seen[$code] = true;
  157. // load the fallback recursively
  158. $this->loadLanguage($fallback);
  159. $fallback_cache = $this->cache[$fallback];
  160. // merge fallback with current language
  161. foreach ( $this->keys as $key ) {
  162. if (isset($cache[$key]) && isset($fallback_cache[$key])) {
  163. if (isset($this->mergeable_keys_map[$key])) {
  164. $cache[$key] = $cache[$key] + $fallback_cache[$key];
  165. } elseif (isset($this->mergeable_keys_list[$key])) {
  166. $cache[$key] = array_merge( $fallback_cache[$key], $cache[$key] );
  167. }
  168. } else {
  169. $cache[$key] = $fallback_cache[$key];
  170. }
  171. }
  172. }
  173. // save to cache for later retrieval
  174. $this->cache[$code] = $cache;
  175. return;
  176. }
  177. }