sfMessageFormat.class.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. /**
  3. * sfMessageFormat class file.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the BSD License.
  7. *
  8. * Copyright(c) 2004 by Qiang Xue. All rights reserved.
  9. *
  10. * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
  11. * The latest version of PRADO can be obtained from:
  12. * {@link http://prado.sourceforge.net/}
  13. *
  14. * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
  15. * @version $Id: sfMessageFormat.class.php 9675 2008-06-19 13:50:40Z fabien $
  16. * @package symfony
  17. * @subpackage i18n
  18. */
  19. /**
  20. * sfMessageFormat class.
  21. *
  22. * Format a message, that is, for a particular message find the
  23. * translated message. The following is an example using
  24. * a SQLite database to store the translation message.
  25. * Create a new message format instance and echo "Hello"
  26. * in simplified Chinese. This assumes that the world "Hello"
  27. * is translated in the database.
  28. *
  29. * <code>
  30. * $source = sfMessageSource::factory('SQLite', 'sqlite://messages.db');
  31. * $source->setCulture('zh_CN');
  32. * $source->setCache(new sfMessageCache('./tmp'));
  33. *
  34. * $formatter = new sfMessageFormat($source);
  35. *
  36. * echo $formatter->format('Hello');
  37. * </code>
  38. *
  39. * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
  40. * @version v1.0, last update on Fri Dec 24 20:46:16 EST 2004
  41. * @package symfony
  42. * @subpackage i18n
  43. */
  44. class sfMessageFormat
  45. {
  46. /**
  47. * The message source.
  48. * @var sfMessageSource
  49. */
  50. protected $source;
  51. /**
  52. * A list of loaded message catalogues.
  53. * @var array
  54. */
  55. protected $catalogues = array();
  56. /**
  57. * The translation messages.
  58. * @var array
  59. */
  60. protected $messages = array();
  61. /**
  62. * A list of untranslated messages.
  63. * @var array
  64. */
  65. protected $untranslated = array();
  66. /**
  67. * The prefix and suffix to append to untranslated messages.
  68. * @var array
  69. */
  70. protected $postscript = array('', '');
  71. /**
  72. * Set the default catalogue.
  73. * @var string
  74. */
  75. public $catalogue;
  76. /**
  77. * Output encoding charset
  78. * @var string
  79. */
  80. protected $charset = 'UTF-8';
  81. /**
  82. * Constructor.
  83. * Create a new instance of sfMessageFormat using the messages
  84. * from the supplied message source.
  85. *
  86. * @param sfMessageSource $source the source of translation messages.
  87. * @param string charset $charset for the message output.
  88. */
  89. function __construct(sfIMessageSource $source, $charset = 'UTF-8')
  90. {
  91. $this->source = $source;
  92. $this->setCharset($charset);
  93. }
  94. /**
  95. * Sets the charset for message output.
  96. *
  97. * @param string $charset charset, default is UTF-8
  98. */
  99. public function setCharset($charset)
  100. {
  101. $this->charset = $charset;
  102. }
  103. /**
  104. * Gets the charset for message output. Default is UTF-8.
  105. *
  106. * @return string charset, default UTF-8
  107. */
  108. public function getCharset()
  109. {
  110. return $this->charset;
  111. }
  112. /**
  113. * Loads the message from a particular catalogue. A listed
  114. * loaded catalogues is kept to prevent reload of the same
  115. * catalogue. The load catalogue messages are stored
  116. * in the $this->message array.
  117. *
  118. * @param string $catalogue message catalogue to load.
  119. */
  120. protected function loadCatalogue($catalogue)
  121. {
  122. if (in_array($catalogue, $this->catalogues))
  123. {
  124. return;
  125. }
  126. if ($this->source->load($catalogue))
  127. {
  128. $this->messages[$catalogue] = $this->source->read();
  129. $this->catalogues[] = $catalogue;
  130. }
  131. }
  132. /**
  133. * Formats the string. That is, for a particular string find
  134. * the corresponding translation. Variable subsitution is performed
  135. * for the $args parameter. A different catalogue can be specified
  136. * using the $catalogue parameter.
  137. * The output charset is determined by $this->getCharset();
  138. *
  139. * @param string $string the string to translate.
  140. * @param array $args a list of string to substitute.
  141. * @param string $catalogue get the translation from a particular message
  142. * @param string $charset charset, the input AND output charset catalogue.
  143. * @return string translated string.
  144. */
  145. public function format($string, $args = array(), $catalogue = null, $charset = null)
  146. {
  147. if (empty($charset))
  148. {
  149. $charset = $this->getCharset();
  150. }
  151. $s = $this->formatString(sfToolkit::I18N_toUTF8($string, $charset), $args, $catalogue);
  152. return sfToolkit::I18N_toEncoding($s, $charset);
  153. }
  154. /**
  155. * Do string translation.
  156. *
  157. * @param string $string the string to translate.
  158. * @param array $args a list of string to substitute.
  159. * @param string $catalogue get the translation from a particular message catalogue.
  160. * @return string translated string.
  161. */
  162. protected function formatString($string, $args = array(), $catalogue = null)
  163. {
  164. if (empty($args))
  165. {
  166. $args = array();
  167. }
  168. if (empty($catalogue))
  169. {
  170. $catalogue = empty($this->catalogue) ? 'messages' : $this->catalogue;
  171. }
  172. $this->loadCatalogue($catalogue);
  173. foreach ($this->messages[$catalogue] as $variant)
  174. {
  175. // we found it, so return the target translation
  176. if (isset($variant[$string]))
  177. {
  178. $target = $variant[$string];
  179. // check if it contains only strings.
  180. if (is_array($target))
  181. {
  182. $target = array_shift($target);
  183. }
  184. // found, but untranslated
  185. if (empty($target))
  186. {
  187. return $this->postscript[0].$this->replaceArgs($string, $args).$this->postscript[1];
  188. }
  189. return $this->replaceArgs($target, $args);
  190. }
  191. }
  192. // well we did not find the translation string.
  193. $this->source->append($string);
  194. return $this->postscript[0].$this->replaceArgs($string, $args).$this->postscript[1];
  195. }
  196. protected function replaceArgs($string, $args)
  197. {
  198. // replace object with strings
  199. foreach ($args as $key => $value)
  200. {
  201. if (is_object($value) && method_exists($value, '__toString'))
  202. {
  203. $args[$key] = $value->__toString();
  204. }
  205. }
  206. return strtr($string, $args);
  207. }
  208. /**
  209. * Gets the message source.
  210. *
  211. * @return MessageSource
  212. */
  213. function getSource()
  214. {
  215. return $this->source;
  216. }
  217. /**
  218. * Sets the prefix and suffix to append to untranslated messages.
  219. * e.g. $postscript=array('[T]','[/T]'); will output
  220. * "[T]Hello[/T]" if the translation for "Hello" can not be determined.
  221. *
  222. * @param array $postscript first element is the prefix, second element the suffix.
  223. */
  224. function setUntranslatedPS($postscript)
  225. {
  226. if (is_array($postscript) && count($postscript) >= 2)
  227. {
  228. $this->postscript[0] = $postscript[0];
  229. $this->postscript[1] = $postscript[1];
  230. }
  231. }
  232. }