sfMessageSource_gettext.class.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. /**
  3. * sfMessageSource_gettext 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: sfMessageSource_gettext.class.php 9128 2008-05-21 00:58:19Z Carl.Vondrick $
  16. * @package symfony
  17. * @subpackage i18n
  18. */
  19. /**
  20. * sfMessageSource_gettext class.
  21. *
  22. * Using Gettext MO format as the message source for translation.
  23. * The gettext classes are based on PEAR's gettext MO and PO classes.
  24. *
  25. * See the MessageSource::factory() method to instantiate this class.
  26. *
  27. * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
  28. * @version v1.0, last update on Fri Dec 24 16:18:44 EST 2004
  29. * @package symfony
  30. * @subpackage i18n
  31. */
  32. class sfMessageSource_gettext extends sfMessageSource_File
  33. {
  34. /**
  35. * Message data filename extension.
  36. * @var string
  37. */
  38. protected $dataExt = '.mo';
  39. /**
  40. * PO data filename extension
  41. * @var string
  42. */
  43. protected $poExt = '.po';
  44. /**
  45. * Loads the messages from a MO file.
  46. *
  47. * @param string $filename MO file.
  48. * @return array of messages.
  49. */
  50. public function &loadData($filename)
  51. {
  52. $mo = TGettext::factory('MO',$filename);
  53. $mo->load();
  54. $result = $mo->toArray();
  55. $results = array();
  56. $count = 0;
  57. foreach ($result['strings'] as $source => $target)
  58. {
  59. $results[$source][] = $target; //target
  60. $results[$source][] = $count++; //id
  61. $results[$source][] = ''; //comments
  62. }
  63. return $results;
  64. }
  65. /**
  66. * Gets the variant for a catalogue depending on the current culture.
  67. *
  68. * @param string $catalogue catalogue
  69. * @return string the variant.
  70. * @see save()
  71. * @see update()
  72. * @see delete()
  73. */
  74. protected function getVariants($catalogue = 'messages')
  75. {
  76. if (empty($catalogue))
  77. {
  78. $catalogue = 'messages';
  79. }
  80. foreach ($this->getCatalogueList($catalogue) as $variant)
  81. {
  82. $file = $this->getSource($variant);
  83. $po = $this->getPOFile($file);
  84. if (is_file($file) || is_file($po))
  85. {
  86. return array($variant, $file, $po);
  87. }
  88. }
  89. return false;
  90. }
  91. protected function getPOFile($MOFile)
  92. {
  93. return substr($MOFile, 0, strlen($MOFile) - strlen($this->dataExt)).$this->poExt;
  94. }
  95. /**
  96. * Saves the list of untranslated blocks to the translation source.
  97. * If the translation was not found, you should add those
  98. * strings to the translation source via the <b>append()</b> method.
  99. *
  100. * @param string $catalogue the catalogue to add to
  101. * @return boolean true if saved successfuly, false otherwise.
  102. */
  103. function save($catalogue = 'messages')
  104. {
  105. $messages = $this->untranslated;
  106. if (count($messages) <= 0)
  107. {
  108. return false;
  109. }
  110. $variants = $this->getVariants($catalogue);
  111. if ($variants)
  112. {
  113. list($variant, $MOFile, $POFile) = $variants;
  114. }
  115. else
  116. {
  117. list($variant, $MOFile, $POFile) = $this->createMessageTemplate($catalogue);
  118. }
  119. if (is_writable($MOFile) == false)
  120. {
  121. throw new sfException(sprintf("Unable to save to file %s, file must be writable.", $MOFile));
  122. }
  123. if (is_writable($POFile) == false)
  124. {
  125. throw new sfException(sprintf("Unable to save to file %s, file must be writable.", $POFile));
  126. }
  127. // set the strings as untranslated.
  128. $strings = array();
  129. foreach ($messages as $message)
  130. {
  131. $strings[$message] = '';
  132. }
  133. // load the PO
  134. $po = TGettext::factory('PO',$POFile);
  135. $po->load();
  136. $result = $po->toArray();
  137. $existing = count($result['strings']);
  138. // add to strings to the existing message list
  139. $result['strings'] = array_merge($result['strings'],$strings);
  140. $new = count($result['strings']);
  141. if ($new > $existing)
  142. {
  143. // change the date 2004-12-25 12:26
  144. $result['meta']['PO-Revision-Date'] = @date('Y-m-d H:i:s');
  145. $po->fromArray($result);
  146. $mo = $po->toMO();
  147. if ($po->save() && $mo->save($MOFile))
  148. {
  149. if ($this->cache)
  150. {
  151. $this->cache->remove($variant.':'.$this->culture);
  152. }
  153. return true;
  154. }
  155. else
  156. {
  157. return false;
  158. }
  159. }
  160. return false;
  161. }
  162. /**
  163. * Deletes a particular message from the specified catalogue.
  164. *
  165. * @param string $message the source message to delete.
  166. * @param string $catalogue the catalogue to delete from.
  167. * @return boolean true if deleted, false otherwise.
  168. */
  169. function delete($message, $catalogue = 'messages')
  170. {
  171. $variants = $this->getVariants($catalogue);
  172. if ($variants)
  173. {
  174. list($variant, $MOFile, $POFile) = $variants;
  175. }
  176. else
  177. {
  178. return false;
  179. }
  180. if (is_writable($MOFile) == false)
  181. {
  182. throw new sfException(sprintf("Unable to modify file %s, file must be writable.", $MOFile));
  183. }
  184. if (is_writable($POFile) == false)
  185. {
  186. throw new sfException(sprintf("Unable to modify file %s, file must be writable.", $POFile));
  187. }
  188. $po = TGettext::factory('PO', $POFile);
  189. $po->load();
  190. $result = $po->toArray();
  191. foreach ($result['strings'] as $string => $value)
  192. {
  193. if ($string == $message)
  194. {
  195. $result['meta']['PO-Revision-Date'] = @date('Y-m-d H:i:s');
  196. unset($result['strings'][$string]);
  197. $po->fromArray($result);
  198. $mo = $po->toMO();
  199. if ($po->save() && $mo->save($MOFile))
  200. {
  201. if ($this->cache)
  202. {
  203. $this->cache->remove($variant.':'.$this->culture);
  204. }
  205. return true;
  206. }
  207. else
  208. {
  209. return false;
  210. }
  211. }
  212. }
  213. return false;
  214. }
  215. /**
  216. * Updates the translation.
  217. *
  218. * @param string $text the source string.
  219. * @param string $target the new translation string.
  220. * @param string $comments comments
  221. * @param string $catalogue the catalogue of the translation.
  222. * @return boolean true if translation was updated, false otherwise.
  223. */
  224. function update($text, $target, $comments, $catalogue = 'messages')
  225. {
  226. $variants = $this->getVariants($catalogue);
  227. if ($variants)
  228. {
  229. list($variant, $MOFile, $POFile) = $variants;
  230. }
  231. else
  232. {
  233. return false;
  234. }
  235. if (is_writable($MOFile) == false)
  236. {
  237. throw new sfException(sprintf("Unable to update file %s, file must be writable.", $MOFile));
  238. }
  239. if (is_writable($POFile) == false)
  240. {
  241. throw new sfException(sprintf("Unable to update file %s, file must be writable.", $POFile));
  242. }
  243. $po = TGettext::factory('PO',$POFile);
  244. $po->load();
  245. $result = $po->toArray();
  246. foreach ($result['strings'] as $string => $value)
  247. {
  248. if ($string == $text)
  249. {
  250. $result['strings'][$string] = $target;
  251. $result['meta']['PO-Revision-Date'] = @date('Y-m-d H:i:s');
  252. $po->fromArray($result);
  253. $mo = $po->toMO();
  254. if ($po->save() && $mo->save($MOFile))
  255. {
  256. if ($this->cache)
  257. {
  258. $this->cache->remove($variant.':'.$this->culture);
  259. }
  260. return true;
  261. }
  262. else
  263. {
  264. return false;
  265. }
  266. }
  267. }
  268. return false;
  269. }
  270. protected function createMessageTemplate($catalogue)
  271. {
  272. if (is_null($catalogue))
  273. {
  274. $catalogue = 'messages';
  275. }
  276. $variants = $this->getCatalogueList($catalogue);
  277. $variant = array_shift($variants);
  278. $mo_file = $this->getSource($variant);
  279. $po_file = $this->getPOFile($mo_file);
  280. $dir = dirname($mo_file);
  281. if (!is_dir($dir))
  282. {
  283. @mkdir($dir);
  284. @chmod($dir, 0777);
  285. }
  286. if (!is_dir($dir))
  287. {
  288. throw new sfException(sprintf("Unable to create directory %s.", $dir));
  289. }
  290. $po = TGettext::factory('PO', $po_file);
  291. $result['meta']['PO-Revision-Date'] = date('Y-m-d H:i:s');
  292. $result['strings'] = array();
  293. $po->fromArray($result);
  294. $mo = $po->toMO();
  295. if ($po->save() && $mo->save($mo_file))
  296. {
  297. return array($variant, $mo_file, $po_file);
  298. }
  299. else
  300. {
  301. throw new sfException(sprintf("Unable to create file %s and %s.", $po_file, $mo_file));
  302. }
  303. }
  304. }