PageRenderTime 26ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/4.6/includes/phpgettext/phpgettext.catalog.php

http://miacms.googlecode.com/
PHP | 454 lines | 380 code | 38 blank | 36 comment | 58 complexity | 53605b5c3dd26e50d14753532afa4909 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, LGPL-2.0
  1. <?php
  2. /**
  3. * @version 0.9
  4. * @author Carlos Souza
  5. * @copyright Copyright (c) 2005 Carlos Souza <csouza@web-sense.net>
  6. * @package PHPGettext
  7. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  8. * @link http://phpgettext.web-sense.net
  9. */
  10. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  11. define('_MODE_MO_', 'mo');
  12. define('_MODE_PO_', 'po');
  13. define('_MODE_POT_','pot');
  14. define('_MODE_GLO_','go');
  15. require_once(dirname(__FILE__).'/phpgettext.message.php');
  16. class PHPGettext_Catalog
  17. {
  18. var $mode = _MODE_MO_;
  19. var $name = '';
  20. var $path = '';
  21. var $lang = 'en';
  22. var $charset = 'utf-8';
  23. var $category = 'LC_MESSAGES';
  24. var $comments = array();
  25. var $headers = array();
  26. var $strings = array();
  27. function PHPGettext_Catalog($name, $path)
  28. {
  29. $this->name = trim($name);
  30. $this->path = trim($path);
  31. }
  32. function load()
  33. {
  34. switch ($this->mode)
  35. {
  36. case _MODE_MO_:
  37. return $this->_readMO();
  38. break;
  39. case _MODE_PO_:
  40. return $this->_readPO();
  41. break;
  42. case _MODE_POT_:
  43. return $this->_readPO();
  44. break;
  45. case _MODE_GLO_:
  46. $this->mode = _MODE_PO_;
  47. $this->lang = 'glossary';
  48. return $this->_readPO();
  49. break;
  50. default:
  51. trigger_error('Unrecognized mode in '.__CLASS__.'->'.__FUNCTION__, E_USER_ERROR);
  52. return false;
  53. break;
  54. }
  55. }
  56. function save()
  57. {
  58. $langdir = $this->path.DIRECTORY_SEPARATOR.$this->lang;
  59. if (!is_dir($langdir)) {
  60. $this->createdir($langdir.DIRECTORY_SEPARATOR.$this->category);
  61. }
  62. switch ($this->mode)
  63. {
  64. case _MODE_MO_:
  65. return $this->_writeMO();
  66. break;
  67. case _MODE_PO_:
  68. $this->setRevisionDate();
  69. return $this->_writePO();
  70. case _MODE_POT_:
  71. return $this->_writePO();
  72. break;
  73. case _MODE_GLO_:
  74. $this->mode = _MODE_PO_;
  75. $this->lang = 'glossary';
  76. return $this->_writePO();
  77. break;
  78. default:
  79. trigger_error('Unrecognized mode in '.__CLASS__.'->'.__FUNCTION__, E_USER_ERROR);
  80. return false;
  81. break;
  82. }
  83. }
  84. function filename()
  85. {
  86. $return = $this->path.DIRECTORY_SEPARATOR;
  87. $return .= !empty($this->lang) ? $this->lang.DIRECTORY_SEPARATOR : '';
  88. $return .= (!empty($this->category) && $this->mode == _MODE_MO_) ? $this->category.DIRECTORY_SEPARATOR : '';
  89. $return .= $this->name.'.'.$this->mode;
  90. return $return;
  91. }
  92. function createdir($path)
  93. {
  94. if (!file_exists($path))
  95. {
  96. // The directory doesn't exist. Recurse, passing in the parent
  97. // directory so that it gets created.
  98. $this->createdir(dirname($path));
  99. mkdir($path, 0777);
  100. }
  101. }
  102. function setRevisionDate()
  103. {
  104. $this->headers['PO-Revision-Date'] = date('Y-m-d G:iO');
  105. }
  106. function setComments($comments)
  107. {
  108. $comments = trim($comments);
  109. if (is_string($comments)) {
  110. $comments = explode("\n", $comments);
  111. if (is_array($comments)) {
  112. foreach ($comments as $comment) {
  113. if (strpos($comment, '#') == 1) {
  114. $this->comments .= $comment."\n";
  115. }
  116. }
  117. }
  118. }
  119. }
  120. function setHeaders($headers)
  121. {
  122. if (!is_array($headers)) {
  123. return false;
  124. }
  125. foreach ($headers as $key => $value) {
  126. $this->headers[$key] = $value;
  127. }
  128. }
  129. function setproperty($property, $value = null) {
  130. $return = $this->$property;
  131. $this->$property = $value;
  132. return $return;
  133. }
  134. function getproperty($property) {
  135. return $this->$property;
  136. }
  137. function addentry($msgid, $msgid_plural=null, $msgstr=null, $comments=array())
  138. {
  139. $entry = new PHPGettext_Message($msgid, $msgid_plural);
  140. if (!is_null($msgstr)) $entry->setmsgstr($msgstr);
  141. if (!empty($comments)) $entry->setcomments($comments);
  142. $this->strings[$msgid] = $entry;
  143. }
  144. function translate(&$translations)
  145. {
  146. $n = count($this->strings);
  147. for ($i=0;$i<$n;$i++){
  148. if (!empty($translations[$this->strings[$i]->msgid])){
  149. $this->strings[$i]->setmsgstr ($translations[$this->strings[$i]->msgid]);
  150. }
  151. }
  152. }
  153. function merge(&$glossary)
  154. {
  155. foreach ($this->strings as $msgid => $string){
  156. if (!$glossary[$string->msgid]){
  157. $glossary[$string->msgid] = $string;
  158. }else{
  159. $glossary[$string->msgid]->comments = array_merge($glossary[$string->msgid]->comments,$string->comments);
  160. $glossary[$string->msgid]->comments = array_unique($glossary[$string->msgid]->comments);
  161. }
  162. }
  163. $n = count($glossary);
  164. unset($this->strings);
  165. foreach ($glossary as $msgid => $string){
  166. $this->addentry($msgid, $string->msgid_plural, $string->msgstr, $string->comments);
  167. }
  168. }
  169. function _writePO()
  170. {
  171. $file = $this->filename();
  172. // open PO file
  173. if (!is_resource($res = @fopen($file, 'a'))) {
  174. trigger_error("Cannot create '$file'. ", E_USER_WARNING);
  175. return false;
  176. }
  177. // lock PO file exclusively
  178. if (!@flock($res, LOCK_EX)) {
  179. @fclose($res);
  180. trigger_error("Cannot lock '$file'. ", E_USER_WARNING);
  181. return false;
  182. }
  183. @ftruncate($res,0);
  184. // write comments
  185. if (count($this->comments > 0)) {
  186. foreach ($this->comments as $line) {
  187. fwrite($res, trim($line)."\n");
  188. }
  189. }
  190. // write meta info
  191. if (count($this->headers > 0)) {
  192. $header = 'msgid ""' . "\nmsgstr " . '""' . "\n";
  193. foreach ($this->headers as $k => $v) {
  194. $header .= '"' . $k . ': ' . $v . '\n"' . "\n";
  195. }
  196. fwrite($res, $header . "\n");
  197. }
  198. // write strings
  199. if (count($this->strings > 0)) {
  200. foreach ($this->strings as $string) {
  201. fwrite($res, $string->toString());
  202. }
  203. }
  204. //done
  205. @flock($res, LOCK_UN);
  206. @fclose($res);
  207. return true;
  208. }
  209. function _readPO()
  210. {
  211. $file = $this->filename();
  212. if (!is_readable($file)) {
  213. trigger_error('Gettext Catalog '.$this->filename().' not found', E_USER_WARNING);
  214. return false;
  215. }
  216. // load file
  217. if (!$data = @file($file)) {
  218. trigger_error('Gettext Catalog '.$this->filename().' not found', E_USER_WARNING);
  219. return false;
  220. }
  221. $count = 0;
  222. $comments = '';
  223. $is_fuzzy = false;
  224. $nplural = false;
  225. // get all strings
  226. foreach ($data as $line) {
  227. // comments
  228. if (strncmp($line, "#", 1) == 0) {
  229. if ($count < 1) {
  230. $this->comments[] = $line;
  231. } else {
  232. if (strncmp($line, "#,", 2) == 0 && preg_match('/fuzzy/', $line)) {
  233. unset($line);
  234. $is_fuzzy = true;
  235. }
  236. if (isset($line)) {
  237. $comments[] = $line;
  238. }
  239. }
  240. }// msgid
  241. elseif (preg_match('/^msgid\s*"(.*)"\s*|^msgid_plural\s*"(.*)"\s*/s', $line, $matches)) {
  242. if (preg_match('/^msgid_plural\s*/s', $line, $arr)) {
  243. $nplural = true;
  244. $strings[$count]['msgid_plural'] = $matches[2];
  245. } else {
  246. $count++;
  247. $strings[$count]['comments'] = isset($comments) ? $comments : '';
  248. $strings[$count]['msgid'] = '';
  249. $strings[$count]['msgid_plural'] = '';
  250. $strings[$count]['msgstr'] = '';
  251. $strings[$count]['is_fuzzy'] = $is_fuzzy;
  252. if (!empty($matches[1])) {
  253. $strings[$count]['msgid'] = $matches[1];
  254. }
  255. unset($msgstr);
  256. unset($comments);
  257. $nplural = false;
  258. $is_fuzzy = false;
  259. }
  260. } // msgstr
  261. elseif (preg_match('/^msgstr\s*"(.*)"\s*|^msgstr\[[0-9]\]\s*"(.*)"\s*/s', $line, $matches)) {
  262. $msgstr = true;
  263. if ($nplural) {
  264. $strings[$count]['msgstr'][] = isset($matches[2]) ? $matches[2] : '';
  265. } else {
  266. $strings[$count]['msgstr'] = $matches[1];
  267. }
  268. } // multiline msgid or msgstr
  269. elseif (preg_match('/^"(.*)"\s*$/s', $line, $matches)) {
  270. // headers
  271. if (isset($msgstr) && $count == 1) {
  272. list($key, $value) = explode(':', $matches[1], 2);
  273. $this->headers[$key] = $value;
  274. }
  275. elseif (isset($msgstr) && $count > 1) {
  276. $strings[$count]['msgstr'] .= $matches[1];
  277. }
  278. else { // msgid
  279. $strings[$count]['msgid'] .= $matches[1];
  280. }
  281. }
  282. }
  283. // load the strings
  284. array_shift($strings);
  285. for ($a=0; $a < count($strings); $a++) {
  286. $this->strings[$a] = new PHPGettext_Message($strings[$a]['msgid'], $strings[$a]['msgid_plural']);
  287. $this->strings[$a]->setmsgstr($strings[$a]['msgstr']);
  288. $this->strings[$a]->setfuzzy($strings[$a]['is_fuzzy']);
  289. $this->strings[$a]->setcomments($strings[$a]['comments']);
  290. }
  291. return true;
  292. }
  293. function _writeMO()
  294. {
  295. $file = $this->filename();
  296. // open MO file
  297. if (!is_resource($res = @fopen($file, 'w'))) {
  298. trigger_error("Cannot create '$file'. ", E_USER_WARNING);
  299. }
  300. // lock MO file exclusively
  301. if (!@flock($res, LOCK_EX)) {
  302. @fclose($res);
  303. trigger_error("Cannot lock '$file'. ", E_USER_WARNING);
  304. }
  305. // get the headers
  306. $headers = "";
  307. foreach ($this->headers as $key => $val) {
  308. $headers .= $key . ': ' . $val . "\n";
  309. }
  310. $strings[] = array('msgid' => "", 'msgstr' => $headers);
  311. // don't write fuzzy entries
  312. foreach ($this->strings as $message) {
  313. if (!$message->is_fuzzy) {
  314. $strings[] = array('msgid' => $message->msgid,'msgid_plural' => $message->msgid_plural, 'msgstr' => $message->msgstr);
  315. }
  316. }
  317. $count = count($strings);
  318. fwrite($res, pack('L', (int) 0x950412de)); // magic number
  319. fwrite($res, pack('L', 0)); // revision 0
  320. fwrite($res, pack('L', $count)); // N - number of strings
  321. $offset = 28;
  322. fwrite($res, pack('L', $offset)); // O - offset of table with original strings
  323. $offset += ($count * 8);
  324. fwrite($res, pack('L', $offset)); // T - offset of table with translation strings
  325. fwrite($res, pack('L', 0)); // S - size of hashing table (set to 0 to omit the table)
  326. $offset += ($count * 8);
  327. fwrite($res, pack('L', $offset)); // H - offset of hashing table
  328. // offsets for original strings
  329. for ($a=0; $a<$count; $a++) {
  330. if (isset($strings[$a]['msgid_plural'])) { // plurals
  331. $strings[$a]['msgid'] = $strings[$a]['msgid'] ."\0".$strings[$a]['msgid_plural'];
  332. }
  333. $len = strlen($strings[$a]['msgid']);
  334. fwrite($res, pack('L', $len));
  335. fwrite($res, pack('L', $offset));
  336. $offset += $len + 1;
  337. }
  338. // offsets for translated strings
  339. for ($a=0; $a<$count; $a++) {
  340. if (is_array($strings[$a]['msgstr'])) { // plurals
  341. $strings[$a]['msgstr'] = implode("\0", $strings[$a]['msgstr']);
  342. }
  343. $len = strlen($strings[$a]['msgstr']);
  344. fwrite($res, pack('L', $len));
  345. fwrite($res, pack('L', $offset));
  346. $offset += $len + 1;
  347. }
  348. // write original strings
  349. foreach ($strings as $str) {
  350. fwrite($res, $str['msgid'] . "\0");
  351. }
  352. // write translated strings
  353. foreach ($strings as $str) {
  354. fwrite($res, $str['msgstr'] . "\0");
  355. }
  356. // done
  357. @flock($res, LOCK_UN);
  358. @fclose($res);
  359. return true;
  360. }
  361. function _readMO()
  362. {
  363. $file = $this->filename();
  364. if (!file_exists($file)) return false;
  365. // read in data file completely
  366. $f = fopen($file, "rb");
  367. $data = fread($f, 1<<20);
  368. fclose($f);
  369. // extract header fields and check file magic
  370. if ($data) {
  371. $header = substr($data, 0, 20);
  372. $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
  373. extract($header);
  374. $magicNumber = substr(dechex($magic),-8);
  375. if (($magicNumber == "950412de") && ($version == 0)) {
  376. // fetch all strings
  377. for ($a=0; $a<$count; $a++) {
  378. // msgid
  379. $r = unpack("L1len/L1offs", substr($data, $o_msg + $a * 8, 8));
  380. $msgid = substr($data, $r["offs"], $r["len"]);
  381. unset($msgid_plural);
  382. if (strpos($msgid, "\0")) { // plurals
  383. list($msgid, $msgid_plural) = explode("\0", $msgid);
  384. }
  385. // msgstr
  386. $r = unpack("L1len/L1offs", substr($data, $o_trn + $a * 8, 8));
  387. $msgstr = substr($data, $r["offs"], $r["len"]);
  388. if (isset($msgid_plural)) { // plurals
  389. $msgstr = explode("\0", $msgstr);
  390. }
  391. $strings[$a]['msgid'] = $msgid;
  392. $strings[$a]['msgstr'] = $msgstr;
  393. $strings[$a]['msgid_plural'] = isset($msgid_plural) ? $msgid_plural : '';
  394. }
  395. if (!empty($strings[0]['msgstr'])){ // header
  396. $str = explode("\n", $strings[0]['msgstr']);
  397. foreach ($str as $s){
  398. if (!empty($s)) {
  399. @list($key, $value) = explode(':', $s, 2);
  400. $this->headers[$key] = $value;
  401. }
  402. }
  403. }
  404. // load the strings
  405. array_shift($strings);
  406. for ($a=0; $a < count($strings); $a++) {
  407. $this->strings[$a] = new PHPGettext_Message($strings[$a]['msgid'], $strings[$a]['msgid_plural']);
  408. $this->strings[$a]->setmsgstr($strings[$a]['msgstr']);
  409. }
  410. return true;
  411. }
  412. }
  413. return false;
  414. }
  415. }
  416. ?>