summaryrefslogtreecommitdiff
path: root/framework/I18N/core/Gettext
diff options
context:
space:
mode:
Diffstat (limited to 'framework/I18N/core/Gettext')
-rw-r--r--framework/I18N/core/Gettext/MO.php355
-rw-r--r--framework/I18N/core/Gettext/PO.php160
-rw-r--r--framework/I18N/core/Gettext/TGettext.php287
3 files changed, 802 insertions, 0 deletions
diff --git a/framework/I18N/core/Gettext/MO.php b/framework/I18N/core/Gettext/MO.php
new file mode 100644
index 00000000..f3be1a30
--- /dev/null
+++ b/framework/I18N/core/Gettext/MO.php
@@ -0,0 +1,355 @@
+<?php
+/**
+ * TGettext_MO class file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD License.
+ *
+ * Copyright(c) 2004 by Qiang Xue. All rights reserved.
+ *
+ * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
+ * The latest version of PRADO can be obtained from:
+ * {@link http://prado.sourceforge.net/}
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: 1.3 $ $Date: 2005/08/27 03:21:12 $
+ * @package System.I18N.core
+ */
+
+
+// +----------------------------------------------------------------------+
+// | PEAR :: File :: Gettext :: MO |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license, |
+// | that is available at http://www.php.net/license/3_0.txt |
+// | If you did not receive a copy of the PHP license and are unable |
+// | to obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 2004 Michael Wallner <mike@iworks.at> |
+// +----------------------------------------------------------------------+
+//
+// $Id: MO.php,v 1.3 2005/08/27 03:21:12 weizhuo Exp $
+
+/**
+ * File::Gettext::MO
+ *
+ * @author Michael Wallner <mike@php.net>
+ * @license PHP License
+ */
+
+require_once dirname(__FILE__).'/TGettext.php';
+
+/**
+ * File_Gettext_MO
+ *
+ * GNU MO file reader and writer.
+ *
+ * @author Michael Wallner <mike@php.net>
+ * @version $Revision: 1.3 $
+ * @access public
+ * @package System.I18N.core
+ */
+class TGettext_MO extends TGettext
+{
+ /**
+ * file handle
+ *
+ * @access private
+ * @var resource
+ */
+ protected $_handle = null;
+
+ /**
+ * big endianess
+ *
+ * Whether to write with big endian byte order.
+ *
+ * @access public
+ * @var bool
+ */
+ protected $writeBigEndian = false;
+
+ /**
+ * Constructor
+ *
+ * @access public
+ * @return object File_Gettext_MO
+ * @param string $file path to GNU MO file
+ */
+ function TGettext_MO($file = '')
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * _read
+ *
+ * @access private
+ * @return mixed
+ * @param int $bytes
+ */
+ function _read($bytes = 1)
+ {
+ if (0 < $bytes = abs($bytes)) {
+ return fread($this->_handle, $bytes);
+ }
+ return null;
+ }
+
+ /**
+ * _readInt
+ *
+ * @access private
+ * @return int
+ * @param bool $bigendian
+ */
+ function _readInt($bigendian = false)
+ {
+ //unpack returns a reference????
+ $unpacked = unpack($bigendian ? 'N' : 'V', $this->_read(4));
+ return array_shift($unpacked);
+ }
+
+ /**
+ * _writeInt
+ *
+ * @access private
+ * @return int
+ * @param int $int
+ */
+ function _writeInt($int)
+ {
+ return $this->_write(pack($this->writeBigEndian ? 'N' : 'V', (int) $int));
+ }
+
+ /**
+ * _write
+ *
+ * @access private
+ * @return int
+ * @param string $data
+ */
+ function _write($data)
+ {
+ return fwrite($this->_handle, $data);
+ }
+
+ /**
+ * _writeStr
+ *
+ * @access private
+ * @return int
+ * @param string $string
+ */
+ function _writeStr($string)
+ {
+ return $this->_write($string . "\0");
+ }
+
+ /**
+ * _readStr
+ *
+ * @access private
+ * @return string
+ * @param array $params associative array with offset and length
+ * of the string
+ */
+ function _readStr($params)
+ {
+ fseek($this->_handle, $params['offset']);
+ return $this->_read($params['length']);
+ }
+
+ /**
+ * Load MO file
+ *
+ * @access public
+ * @return mixed Returns true on success or PEAR_Error on failure.
+ * @param string $file
+ */
+ function load($file = null)
+ {
+ if (!isset($file)) {
+ $file = $this->file;
+ }
+
+ // open MO file
+ if (!is_resource($this->_handle = @fopen($file, 'rb'))) {
+ return false;
+ }
+ // lock MO file shared
+ if (!@flock($this->_handle, LOCK_SH)) {
+ @fclose($this->_handle);
+ return false;
+ }
+
+ // read (part of) magic number from MO file header and define endianess
+
+ //unpack returns a reference????
+ $unpacked = unpack('c', $this->_read(4));
+ switch ($magic = array_shift($unpacked))
+ {
+ case -34:
+ $be = false;
+ break;
+
+ case -107:
+ $be = true;
+ break;
+
+ default:
+ return false;
+ }
+
+ // check file format revision - we currently only support 0
+ if (0 !== ($_rev = $this->_readInt($be))) {
+ return false;
+ }
+
+ // count of strings in this file
+ $count = $this->_readInt($be);
+
+ // offset of hashing table of the msgids
+ $offset_original = $this->_readInt($be);
+ // offset of hashing table of the msgstrs
+ $offset_translat = $this->_readInt($be);
+
+ // move to msgid hash table
+ fseek($this->_handle, $offset_original);
+ // read lengths and offsets of msgids
+ $original = array();
+ for ($i = 0; $i < $count; $i++) {
+ $original[$i] = array(
+ 'length' => $this->_readInt($be),
+ 'offset' => $this->_readInt($be)
+ );
+ }
+
+ // move to msgstr hash table
+ fseek($this->_handle, $offset_translat);
+ // read lengths and offsets of msgstrs
+ $translat = array();
+ for ($i = 0; $i < $count; $i++) {
+ $translat[$i] = array(
+ 'length' => $this->_readInt($be),
+ 'offset' => $this->_readInt($be)
+ );
+ }
+
+ // read all
+ for ($i = 0; $i < $count; $i++) {
+ $this->strings[$this->_readStr($original[$i])] =
+ $this->_readStr($translat[$i]);
+ }
+
+ // done
+ @flock($this->_handle, LOCK_UN);
+ @fclose($this->_handle);
+ $this->_handle = null;
+
+ // check for meta info
+ if (isset($this->strings[''])) {
+ $this->meta = parent::meta2array($this->strings['']);
+ unset($this->strings['']);
+ }
+
+ return true;
+ }
+
+ /**
+ * Save MO file
+ *
+ * @access public
+ * @return mixed Returns true on success or PEAR_Error on failure.
+ * @param string $file
+ */
+ function save($file = null)
+ {
+ if (!isset($file)) {
+ $file = $this->file;
+ }
+
+ // open MO file
+ if (!is_resource($this->_handle = @fopen($file, 'wb'))) {
+ return false;
+ }
+ // lock MO file exclusively
+ if (!@flock($this->_handle, LOCK_EX)) {
+ @fclose($this->_handle);
+ return false;
+ }
+
+ // write magic number
+ if ($this->writeBigEndian) {
+ $this->_write(pack('c*', 0x95, 0x04, 0x12, 0xde));
+ } else {
+ $this->_write(pack('c*', 0xde, 0x12, 0x04, 0x95));
+ }
+
+ // write file format revision
+ $this->_writeInt(0);
+
+ $count = count($this->strings) + ($meta = (count($this->meta) ? 1 : 0));
+ // write count of strings
+ $this->_writeInt($count);
+
+ $offset = 28;
+ // write offset of orig. strings hash table
+ $this->_writeInt($offset);
+
+ $offset += ($count * 8);
+ // write offset transl. strings hash table
+ $this->_writeInt($offset);
+
+ // write size of hash table (we currently ommit the hash table)
+ $this->_writeInt(0);
+
+ $offset += ($count * 8);
+ // write offset of hash table
+ $this->_writeInt($offset);
+
+ // unshift meta info
+ if ($this->meta) {
+ $meta = '';
+ foreach ($this->meta as $key => $val) {
+ $meta .= $key . ': ' . $val . "\n";
+ }
+ $strings = array('' => $meta) + $this->strings;
+ } else {
+ $strings = $this->strings;
+ }
+
+ // write offsets for original strings
+ foreach (array_keys($strings) as $o) {
+ $len = strlen($o);
+ $this->_writeInt($len);
+ $this->_writeInt($offset);
+ $offset += $len + 1;
+ }
+
+ // write offsets for translated strings
+ foreach ($strings as $t) {
+ $len = strlen($t);
+ $this->_writeInt($len);
+ $this->_writeInt($offset);
+ $offset += $len + 1;
+ }
+
+ // write original strings
+ foreach (array_keys($strings) as $o) {
+ $this->_writeStr($o);
+ }
+
+ // write translated strings
+ foreach ($strings as $t) {
+ $this->_writeStr($t);
+ }
+
+ // done
+ @flock($this->_handle, LOCK_UN);
+ @fclose($this->_handle);
+ return true;
+ }
+}
+?>
diff --git a/framework/I18N/core/Gettext/PO.php b/framework/I18N/core/Gettext/PO.php
new file mode 100644
index 00000000..3c69c091
--- /dev/null
+++ b/framework/I18N/core/Gettext/PO.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * TGettext_PO class file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD License.
+ *
+ * Copyright(c) 2004 by Qiang Xue. All rights reserved.
+ *
+ * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
+ * The latest version of PRADO can be obtained from:
+ * {@link http://prado.sourceforge.net/}
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: 1.2 $ $Date: 2005/01/05 03:15:14 $
+ * @package System.I18N.core
+ */
+
+// +----------------------------------------------------------------------+
+// | PEAR :: File :: Gettext :: PO |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license, |
+// | that is available at http://www.php.net/license/3_0.txt |
+// | If you did not receive a copy of the PHP license and are unable |
+// | to obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 2004 Michael Wallner <mike@iworks.at> |
+// +----------------------------------------------------------------------+
+//
+// $Id: PO.php,v 1.2 2005/01/05 03:15:14 weizhuo Exp $
+
+/**
+ * File::Gettext::PO
+ *
+ * @author Michael Wallner <mike@php.net>
+ * @license PHP License
+ */
+
+require_once dirname(__FILE__).'/TGettext.php';
+
+/**
+ * File_Gettext_PO
+ *
+ * GNU PO file reader and writer.
+ *
+ * @author Michael Wallner <mike@php.net>
+ * @version $Revision: 1.2 $
+ * @access public
+ * @package System.I18N.core
+ */
+class TGettext_PO extends TGettext
+{
+ /**
+ * Constructor
+ *
+ * @access public
+ * @return object File_Gettext_PO
+ * @param string path to GNU PO file
+ */
+ function TGettext_PO($file = '')
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Load PO file
+ *
+ * @access public
+ * @return mixed Returns true on success or PEAR_Error on failure.
+ * @param string $file
+ */
+ function load($file = null)
+ {
+ if (!isset($file)) {
+ $file = $this->file;
+ }
+
+ // load file
+ if (!$contents = @file($file)) {
+ return false;
+ }
+ $contents = implode('', $contents);
+
+ // match all msgid/msgstr entries
+ $matched = preg_match_all(
+ '/(msgid\s+("([^"]|\\\\")*?"\s*)+)\s+' .
+ '(msgstr\s+("([^"]|\\\\")*?"\s*)+)/',
+ $contents, $matches
+ );
+ unset($contents);
+
+ if (!$matched) {
+ return false;
+ }
+
+ // get all msgids and msgtrs
+ for ($i = 0; $i < $matched; $i++) {
+ $msgid = preg_replace(
+ '/\s*msgid\s*"(.*)"\s*/s', '\\1', $matches[1][$i]);
+ $msgstr= preg_replace(
+ '/\s*msgstr\s*"(.*)"\s*/s', '\\1', $matches[4][$i]);
+ $this->strings[parent::prepare($msgid)] = parent::prepare($msgstr);
+ }
+
+ // check for meta info
+ if (isset($this->strings[''])) {
+ $this->meta = parent::meta2array($this->strings['']);
+ unset($this->strings['']);
+ }
+
+ return true;
+ }
+
+ /**
+ * Save PO file
+ *
+ * @access public
+ * @return mixed Returns true on success or PEAR_Error on failure.
+ * @param string $file
+ */
+ function save($file = null)
+ {
+ if (!isset($file)) {
+ $file = $this->file;
+ }
+
+ // open PO file
+ if (!is_resource($fh = @fopen($file, 'w'))) {
+ return false;
+ }
+
+ // lock PO file exclusively
+ if (!flock($fh, LOCK_EX)) {
+ fclose($fh);
+ return false;
+ }
+ // write meta info
+ if (count($this->meta)) {
+ $meta = 'msgid ""' . "\nmsgstr " . '""' . "\n";
+ foreach ($this->meta as $k => $v) {
+ $meta .= '"' . $k . ': ' . $v . '\n"' . "\n";
+ }
+ fwrite($fh, $meta . "\n");
+ }
+ // write strings
+ foreach ($this->strings as $o => $t) {
+ fwrite($fh,
+ 'msgid "' . parent::prepare($o, true) . '"' . "\n" .
+ 'msgstr "' . parent::prepare($t, true) . '"' . "\n\n"
+ );
+ }
+
+ //done
+ @flock($fh, LOCK_UN);
+ @fclose($fh);
+ return true;
+ }
+}
+?>
diff --git a/framework/I18N/core/Gettext/TGettext.php b/framework/I18N/core/Gettext/TGettext.php
new file mode 100644
index 00000000..8e87bee5
--- /dev/null
+++ b/framework/I18N/core/Gettext/TGettext.php
@@ -0,0 +1,287 @@
+<?php
+/**
+ * TGettext class file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD License.
+ *
+ * Copyright(c) 2004 by Qiang Xue. All rights reserved.
+ *
+ * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
+ * The latest version of PRADO can be obtained from:
+ * {@link http://prado.sourceforge.net/}
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: 1.4 $ $Date: 2005/01/09 23:36:23 $
+ * @package System.I18N.core
+ */
+
+// +----------------------------------------------------------------------+
+// | PEAR :: File :: Gettext |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license, |
+// | that is available at http://www.php.net/license/3_0.txt |
+// | If you did not receive a copy of the PHP license and are unable |
+// | to obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 2004 Michael Wallner <mike@iworks.at> |
+// +----------------------------------------------------------------------+
+//
+// $Id: TGettext.php,v 1.4 2005/01/09 23:36:23 qiangxue Exp $
+
+/**
+ * File::Gettext
+ *
+ * @author Michael Wallner <mike@php.net>
+ * @license PHP License
+ */
+
+/**
+ * Use PHPs builtin error messages
+ */
+//ini_set('track_errors', true);
+
+/**
+ * File_Gettext
+ *
+ * GNU gettext file reader and writer.
+ *
+ * #################################################################
+ * # All protected members of this class are public in its childs. #
+ * #################################################################
+ *
+ * @author Michael Wallner <mike@php.net>
+ * @version $Revision: 1.4 $
+ * @access public
+ * @package System.I18N.core
+ */
+class TGettext
+{
+ /**
+ * strings
+ *
+ * associative array with all [msgid => msgstr] entries
+ *
+ * @access protected
+ * @var array
+ */
+ protected $strings = array();
+
+ /**
+ * meta
+ *
+ * associative array containing meta
+ * information like project name or content type
+ *
+ * @access protected
+ * @var array
+ */
+ protected $meta = array();
+
+ /**
+ * file path
+ *
+ * @access protected
+ * @var string
+ */
+ protected $file = '';
+
+ /**
+ * Factory
+ *
+ * @static
+ * @access public
+ * @return object Returns File_Gettext_PO or File_Gettext_MO on success
+ * or PEAR_Error on failure.
+ * @param string $format MO or PO
+ * @param string $file path to GNU gettext file
+ */
+ function factory($format, $file = '')
+ {
+ $format = strToUpper($format);
+ $filename = dirname(__FILE__).'/'.$format.'.php';
+ if(is_file($filename) == false)
+ throw new Exception ("Class file $file not found");
+
+ include_once $filename;
+ $class = 'TGettext_' . $format;
+
+ return new $class($file);
+ }
+
+ /**
+ * poFile2moFile
+ *
+ * That's a simple fake of the 'msgfmt' console command. It reads the
+ * contents of a GNU PO file and saves them to a GNU MO file.
+ *
+ * @static
+ * @access public
+ * @return mixed Returns true on success or PEAR_Error on failure.
+ * @param string $pofile path to GNU PO file
+ * @param string $mofile path to GNU MO file
+ */
+ function poFile2moFile($pofile, $mofile)
+ {
+ if (!is_file($pofile)) {
+ throw new Exception("File $pofile doesn't exist.");
+ }
+
+ include_once dirname(__FILE__).'/PO.php';
+
+ $PO = new TGettext_PO($pofile);
+ if (true !== ($e = $PO->load())) {
+ return $e;
+ }
+
+ $MO = $PO->toMO();
+ if (true !== ($e = $MO->save($mofile))) {
+ return $e;
+ }
+ unset($PO, $MO);
+
+ return true;
+ }
+
+ /**
+ * prepare
+ *
+ * @static
+ * @access protected
+ * @return string
+ * @param string $string
+ * @param bool $reverse
+ */
+ function prepare($string, $reverse = false)
+ {
+ if ($reverse) {
+ $smap = array('"', "\n", "\t", "\r");
+ $rmap = array('\"', '\\n"' . "\n" . '"', '\\t', '\\r');
+ return (string) str_replace($smap, $rmap, $string);
+ } else {
+ $string = preg_replace('/"\s+"/', '', $string);
+ $smap = array('\\n', '\\r', '\\t', '\"');
+ $rmap = array("\n", "\r", "\t", '"');
+ return (string) str_replace($smap, $rmap, $string);
+ }
+ }
+
+ /**
+ * meta2array
+ *
+ * @static
+ * @access public
+ * @return array
+ * @param string $meta
+ */
+ function meta2array($meta)
+ {
+ $array = array();
+ foreach (explode("\n", $meta) as $info) {
+ if ($info = trim($info)) {
+ list($key, $value) = explode(':', $info, 2);
+ $array[trim($key)] = trim($value);
+ }
+ }
+ return $array;
+ }
+
+ /**
+ * toArray
+ *
+ * Returns meta info and strings as an array of a structure like that:
+ * <code>
+ * array(
+ * 'meta' => array(
+ * 'Content-Type' => 'text/plain; charset=iso-8859-1',
+ * 'Last-Translator' => 'Michael Wallner <mike@iworks.at>',
+ * 'PO-Revision-Date' => '2004-07-21 17:03+0200',
+ * 'Language-Team' => 'German <mail@example.com>',
+ * ),
+ * 'strings' => array(
+ * 'All rights reserved' => 'Alle Rechte vorbehalten',
+ * 'Welcome' => 'Willkommen',
+ * // ...
+ * )
+ * )
+ * </code>
+ *
+ * @see fromArray()
+ * @access protected
+ * @return array
+ */
+ function toArray()
+ {
+ return array('meta' => $this->meta, 'strings' => $this->strings);
+ }
+
+ /**
+ * fromArray
+ *
+ * Assigns meta info and strings from an array of a structure like that:
+ * <code>
+ * array(
+ * 'meta' => array(
+ * 'Content-Type' => 'text/plain; charset=iso-8859-1',
+ * 'Last-Translator' => 'Michael Wallner <mike@iworks.at>',
+ * 'PO-Revision-Date' => date('Y-m-d H:iO'),
+ * 'Language-Team' => 'German <mail@example.com>',
+ * ),
+ * 'strings' => array(
+ * 'All rights reserved' => 'Alle Rechte vorbehalten',
+ * 'Welcome' => 'Willkommen',
+ * // ...
+ * )
+ * )
+ * </code>
+ *
+ * @see toArray()
+ * @access protected
+ * @return bool
+ * @param array $array
+ */
+ function fromArray($array)
+ {
+ if (!array_key_exists('strings', $array)) {
+ if (count($array) != 2) {
+ return false;
+ } else {
+ list($this->meta, $this->strings) = $array;
+ }
+ } else {
+ $this->meta = @$array['meta'];
+ $this->strings = @$array['strings'];
+ }
+ return true;
+ }
+
+ /**
+ * toMO
+ *
+ * @access protected
+ * @return object File_Gettext_MO
+ */
+ function toMO()
+ {
+ include_once dirname(__FILE__).'/MO.php';
+ $MO = new TGettext_MO;
+ $MO->fromArray($this->toArray());
+ return $MO;
+ }
+
+ /**
+ * toPO
+ *
+ * @access protected
+ * @return object File_Gettext_PO
+ */
+ function toPO()
+ {
+ include_once dirname(__FILE__).'/PO.php';
+ $PO = new TGettext_PO;
+ $PO->fromArray($this->toArray());
+ return $PO;
+ }
+}
+?>