Language.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. /**
  3. * Represents a language and defines localizable string formatting and
  4. * other functions, as well as the localized messages for HTML Purifier.
  5. */
  6. class HTMLPurifier_Language
  7. {
  8. /**
  9. * ISO 639 language code of language. Prefers shortest possible version.
  10. * @type string
  11. */
  12. public $code = 'en';
  13. /**
  14. * Fallback language code.
  15. * @type bool|string
  16. */
  17. public $fallback = false;
  18. /**
  19. * Array of localizable messages.
  20. * @type array
  21. */
  22. public $messages = array();
  23. /**
  24. * Array of localizable error codes.
  25. * @type array
  26. */
  27. public $errorNames = array();
  28. /**
  29. * True if no message file was found for this language, so English
  30. * is being used instead. Check this if you'd like to notify the
  31. * user that they've used a non-supported language.
  32. * @type bool
  33. */
  34. public $error = false;
  35. /**
  36. * Has the language object been loaded yet?
  37. * @type bool
  38. * @todo Make it private, fix usage in HTMLPurifier_LanguageTest
  39. */
  40. public $_loaded = false;
  41. /**
  42. * @type HTMLPurifier_Config
  43. */
  44. protected $config;
  45. /**
  46. * @type HTMLPurifier_Context
  47. */
  48. protected $context;
  49. /**
  50. * @param HTMLPurifier_Config $config
  51. * @param HTMLPurifier_Context $context
  52. */
  53. public function __construct($config, $context)
  54. {
  55. $this->config = $config;
  56. $this->context = $context;
  57. }
  58. /**
  59. * Loads language object with necessary info from factory cache
  60. * @note This is a lazy loader
  61. */
  62. public function load()
  63. {
  64. if ($this->_loaded) {
  65. return;
  66. }
  67. $factory = HTMLPurifier_LanguageFactory::instance();
  68. $factory->loadLanguage($this->code);
  69. foreach ($factory->keys as $key) {
  70. $this->$key = $factory->cache[$this->code][$key];
  71. }
  72. $this->_loaded = true;
  73. }
  74. /**
  75. * Retrieves a localised message.
  76. * @param string $key string identifier of message
  77. * @return string localised message
  78. */
  79. public function getMessage($key)
  80. {
  81. if (!$this->_loaded) {
  82. $this->load();
  83. }
  84. if (!isset($this->messages[$key])) {
  85. return "[$key]";
  86. }
  87. return $this->messages[$key];
  88. }
  89. /**
  90. * Retrieves a localised error name.
  91. * @param int $int error number, corresponding to PHP's error reporting
  92. * @return string localised message
  93. */
  94. public function getErrorName($int)
  95. {
  96. if (!$this->_loaded) {
  97. $this->load();
  98. }
  99. if (!isset($this->errorNames[$int])) {
  100. return "[Error: $int]";
  101. }
  102. return $this->errorNames[$int];
  103. }
  104. /**
  105. * Converts an array list into a string readable representation
  106. * @param array $array
  107. * @return string
  108. */
  109. public function listify($array)
  110. {
  111. $sep = $this->getMessage('Item separator');
  112. $sep_last = $this->getMessage('Item separator last');
  113. $ret = '';
  114. for ($i = 0, $c = count($array); $i < $c; $i++) {
  115. if ($i == 0) {
  116. } elseif ($i + 1 < $c) {
  117. $ret .= $sep;
  118. } else {
  119. $ret .= $sep_last;
  120. }
  121. $ret .= $array[$i];
  122. }
  123. return $ret;
  124. }
  125. /**
  126. * Formats a localised message with passed parameters
  127. * @param string $key string identifier of message
  128. * @param array $args Parameters to substitute in
  129. * @return string localised message
  130. * @todo Implement conditionals? Right now, some messages make
  131. * reference to line numbers, but those aren't always available
  132. */
  133. public function formatMessage($key, $args = array())
  134. {
  135. if (!$this->_loaded) {
  136. $this->load();
  137. }
  138. if (!isset($this->messages[$key])) {
  139. return "[$key]";
  140. }
  141. $raw = $this->messages[$key];
  142. $subst = array();
  143. $generator = false;
  144. foreach ($args as $i => $value) {
  145. if (is_object($value)) {
  146. if ($value instanceof HTMLPurifier_Token) {
  147. // factor this out some time
  148. if (!$generator) {
  149. $generator = $this->context->get('Generator');
  150. }
  151. if (isset($value->name)) {
  152. $subst['$'.$i.'.Name'] = $value->name;
  153. }
  154. if (isset($value->data)) {
  155. $subst['$'.$i.'.Data'] = $value->data;
  156. }
  157. $subst['$'.$i.'.Compact'] =
  158. $subst['$'.$i.'.Serialized'] = $generator->generateFromToken($value);
  159. // a more complex algorithm for compact representation
  160. // could be introduced for all types of tokens. This
  161. // may need to be factored out into a dedicated class
  162. if (!empty($value->attr)) {
  163. $stripped_token = clone $value;
  164. $stripped_token->attr = array();
  165. $subst['$'.$i.'.Compact'] = $generator->generateFromToken($stripped_token);
  166. }
  167. $subst['$'.$i.'.Line'] = $value->line ? $value->line : 'unknown';
  168. }
  169. continue;
  170. } elseif (is_array($value)) {
  171. $keys = array_keys($value);
  172. if (array_keys($keys) === $keys) {
  173. // list
  174. $subst['$'.$i] = $this->listify($value);
  175. } else {
  176. // associative array
  177. // no $i implementation yet, sorry
  178. $subst['$'.$i.'.Keys'] = $this->listify($keys);
  179. $subst['$'.$i.'.Values'] = $this->listify(array_values($value));
  180. }
  181. continue;
  182. }
  183. $subst['$' . $i] = $value;
  184. }
  185. return strtr($raw, $subst);
  186. }
  187. }
  188. // vim: et sw=4 sts=4