mirror of
https://github.com/atlanticbiomedical/portal-legacy.git
synced 2025-07-02 01:47:28 -04:00
initial commit
This commit is contained in:
354
lib/symfony/i18n/Gettext/MO.php
Executable file
354
lib/symfony/i18n/Gettext/MO.php
Executable file
@ -0,0 +1,354 @@
|
||||
<?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: 1415 $ $Date: 2006-06-11 10:33:51 +0200 (Sun, 11 Jun 2006) $
|
||||
* @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 1415 2006-06-11 08:33:51Z fabien $
|
||||
|
||||
/**
|
||||
* File::Gettext::MO
|
||||
*
|
||||
* @author Michael Wallner <mike@php.net>
|
||||
* @license PHP License
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__).'/TGettext.class.php';
|
||||
|
||||
/**
|
||||
* File_Gettext_MO
|
||||
*
|
||||
* GNU MO file reader and writer.
|
||||
*
|
||||
* @author Michael Wallner <mike@php.net>
|
||||
* @version $Revision: 1415 $
|
||||
* @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 ($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;
|
||||
}
|
||||
}
|
159
lib/symfony/i18n/Gettext/PO.php
Executable file
159
lib/symfony/i18n/Gettext/PO.php
Executable file
@ -0,0 +1,159 @@
|
||||
<?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: 1415 $ $Date: 2006-06-11 10:33:51 +0200 (Sun, 11 Jun 2006) $
|
||||
* @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 1415 2006-06-11 08:33:51Z fabien $
|
||||
|
||||
/**
|
||||
* File::Gettext::PO
|
||||
*
|
||||
* @author Michael Wallner <mike@php.net>
|
||||
* @license PHP License
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__).'/TGettext.class.php';
|
||||
|
||||
/**
|
||||
* File_Gettext_PO
|
||||
*
|
||||
* GNU PO file reader and writer.
|
||||
*
|
||||
* @author Michael Wallner <mike@php.net>
|
||||
* @version $Revision: 1415 $
|
||||
* @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;
|
||||
}
|
||||
}
|
286
lib/symfony/i18n/Gettext/TGettext.class.php
Executable file
286
lib/symfony/i18n/Gettext/TGettext.class.php
Executable file
@ -0,0 +1,286 @@
|
||||
<?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: 3152 $ $Date: 2007-01-05 07:16:57 +0100 (Fri, 05 Jan 2007) $
|
||||
* @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.class.php 3152 2007-01-05 06:16:57Z fabien $
|
||||
|
||||
/**
|
||||
* 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: 3152 $
|
||||
* @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
|
||||
*/
|
||||
static 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;
|
||||
}
|
||||
}
|
211
lib/symfony/i18n/sfChoiceFormat.class.php
Executable file
211
lib/symfony/i18n/sfChoiceFormat.class.php
Executable file
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfChoiceFormat 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 $Id: sfChoiceFormat.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* sfChoiceFormat class.
|
||||
*
|
||||
* sfChoiceFormat converts between ranges of numeric values and string
|
||||
* names for those ranges.
|
||||
*
|
||||
* A sfChoiceFormat splits the real number line -Inf to +Inf into two or
|
||||
* more contiguous ranges. Each range is mapped to a string.
|
||||
* sfChoiceFormat is generally used in a MessageFormat for displaying
|
||||
* grammatically correct plurals such as "There are 2 files."
|
||||
*
|
||||
* <code>
|
||||
* $string = '[0] are no files |[1] is one file |(1,Inf] are {number} files';
|
||||
*
|
||||
* $formatter = new sfMessageFormat(...); //init for a source
|
||||
* $translated = $formatter->format($string);
|
||||
*
|
||||
* $choice = new sfChoiceFormat();
|
||||
* echo $choice->format($translated, 0); //shows "are no files"
|
||||
* </code>
|
||||
*
|
||||
* The message/string choices are separated by the pipe "|" followed
|
||||
* by a set notation of the form
|
||||
* # <t>[1,2]</t> -- accepts values between 1 and 2, inclusive.
|
||||
* # <t>(1,2)</t> -- accepts values between 1 and 2, excluding 1 and 2.
|
||||
* # <t>{1,2,3,4}</t> -- only values defined in the set are accepted.
|
||||
* # <t>[-Inf,0)</t> -- accepts value greater or equal to negative infinity
|
||||
* and strictly less than 0
|
||||
* Any non-empty combinations of the delimiters of square and round brackets
|
||||
* are acceptable.
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 20:46:16 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfChoiceFormat
|
||||
{
|
||||
/**
|
||||
* The pattern to validate a set notation
|
||||
*/
|
||||
protected $validate = '/[\(\[\{]|[-Inf\d]+|,|[\+Inf\d]+|[\)\]\}]/ms';
|
||||
|
||||
/**
|
||||
* The pattern to parse the formatting string.
|
||||
*/
|
||||
protected $parse = '/\s?\|?([\(\[\{]([-Inf\d]+,?[\+Inf\d]*)+[\)\]\}])\s?/';
|
||||
|
||||
/**
|
||||
* The value for positive infinity.
|
||||
*/
|
||||
protected $inf;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->inf = -log(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given number belongs to a given set
|
||||
*
|
||||
* @param float the number to test.
|
||||
* @param string the set, in set notation.
|
||||
* @return boolean true if number is in the set, false otherwise.
|
||||
*/
|
||||
public function isValid($number, $set)
|
||||
{
|
||||
$n = preg_match_all($this->validate, $set, $matches, PREG_SET_ORDER);
|
||||
|
||||
if ($n < 3)
|
||||
{
|
||||
$error = 'Invalid set "%s"';
|
||||
$error = sprintf($error, $set);
|
||||
throw new sfException($error);
|
||||
}
|
||||
|
||||
$leftBracket = $matches[0][0];
|
||||
$rightBracket = $matches[$n - 1][0];
|
||||
|
||||
$i = 0;
|
||||
$elements = array();
|
||||
|
||||
foreach ($matches as $match)
|
||||
{
|
||||
$string = $match[0];
|
||||
if ($i != 0 && $i != $n - 1 && $string !== ',')
|
||||
{
|
||||
if ($string == '-Inf')
|
||||
{
|
||||
$elements[] = -1 * $this->inf;
|
||||
}
|
||||
else if ($string == '+Inf' || $string == 'Inf')
|
||||
{
|
||||
$elements[] = $this->inf;
|
||||
}
|
||||
else
|
||||
{
|
||||
$elements[] = floatval($string);
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$total = count($elements);
|
||||
$number = floatval($number);
|
||||
|
||||
if ($leftBracket == '{' && $rightBracket == '}')
|
||||
{
|
||||
return in_array($number, $elements);
|
||||
}
|
||||
|
||||
$left = false;
|
||||
if ($leftBracket == '[')
|
||||
{
|
||||
$left = $number >= $elements[0];
|
||||
}
|
||||
else if ($leftBracket == '(')
|
||||
{
|
||||
$left = $number > $elements[0];
|
||||
}
|
||||
|
||||
$right = false;
|
||||
if ($rightBracket==']')
|
||||
{
|
||||
$right = $number <= $elements[$total - 1];
|
||||
}
|
||||
else if ($rightBracket == ')')
|
||||
{
|
||||
$right = $number < $elements[$total - 1];
|
||||
}
|
||||
|
||||
if ($left && $right)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a choice string and get a list of sets and a list of strings corresponding to the sets.
|
||||
*
|
||||
* @param string the string containing the choices
|
||||
* @return array array($sets, $strings)
|
||||
*/
|
||||
public function parse($string)
|
||||
{
|
||||
$n = preg_match_all($this->parse, $string, $matches, PREG_OFFSET_CAPTURE);
|
||||
$sets = array();
|
||||
foreach ($matches[1] as $match)
|
||||
{
|
||||
$sets[] = $match[0];
|
||||
}
|
||||
|
||||
$offset = $matches[0];
|
||||
$strings = array();
|
||||
for ($i = 0; $i < $n; $i++)
|
||||
{
|
||||
$len = strlen($offset[$i][0]);
|
||||
$begin = $i == 0 ? $len : $offset[$i][1] + $len;
|
||||
$end = $i == $n - 1 ? strlen($string) : $offset[$i + 1][1];
|
||||
$strings[] = substr($string, $begin, $end - $begin);
|
||||
}
|
||||
|
||||
return array($sets, $strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the choice string, and a number, find and return the string that satisfied the set within the choices.
|
||||
*
|
||||
* @param string the choices string.
|
||||
* @param float the number to test.
|
||||
* @return string the choosen string.
|
||||
*/
|
||||
public function format($string, $number)
|
||||
{
|
||||
list($sets, $strings) = $this->parse($string);
|
||||
$total = count($sets);
|
||||
for ($i = 0; $i < $total; $i++)
|
||||
{
|
||||
if ($this->isValid($number, $sets[$i]))
|
||||
{
|
||||
return $strings[$i];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
682
lib/symfony/i18n/sfCultureInfo.class.php
Executable file
682
lib/symfony/i18n/sfCultureInfo.class.php
Executable file
@ -0,0 +1,682 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfCultureInfo 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 $Id: sfCultureInfo.class.php 4439 2007-06-27 14:24:44Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* sfCultureInfo class.
|
||||
*
|
||||
* Represents information about a specific culture including the
|
||||
* names of the culture, the calendar used, as well as access to
|
||||
* culture-specific objects that provide methods for common operations,
|
||||
* such as formatting dates, numbers, and currency.
|
||||
*
|
||||
* The sfCultureInfo class holds culture-specific information, such as the
|
||||
* associated language, sublanguage, country/region, calendar, and cultural
|
||||
* conventions. This class also provides access to culture-specific
|
||||
* instances of sfDateTimeFormatInfo and sfNumberFormatInfo. These objects
|
||||
* contain the information required for culture-specific operations,
|
||||
* such as formatting dates, numbers and currency.
|
||||
*
|
||||
* The culture names follow the format "<languagecode>_<country/regioncode>",
|
||||
* where <languagecode> is a lowercase two-letter code derived from ISO 639
|
||||
* codes. You can find a full list of the ISO-639 codes at
|
||||
* http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
|
||||
*
|
||||
* The <country/regioncode2> is an uppercase two-letter code derived from
|
||||
* ISO 3166. A copy of ISO-3166 can be found at
|
||||
* http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
|
||||
*
|
||||
* For example, Australian English is "en_AU".
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Sat Dec 04 13:41:46 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfCultureInfo
|
||||
{
|
||||
/**
|
||||
* ICU data filename extension.
|
||||
* @var string
|
||||
*/
|
||||
protected $dataFileExt = '.dat';
|
||||
|
||||
/**
|
||||
* The ICU data array.
|
||||
* @var array
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* The current culture.
|
||||
* @var string
|
||||
*/
|
||||
protected $culture;
|
||||
|
||||
/**
|
||||
* Directory where the ICU data is stored.
|
||||
* @var string
|
||||
*/
|
||||
protected $dataDir;
|
||||
|
||||
/**
|
||||
* A list of ICU date files loaded.
|
||||
* @var array
|
||||
*/
|
||||
protected $dataFiles = array();
|
||||
|
||||
/**
|
||||
* The current date time format info.
|
||||
* @var sfDateTimeFormatInfo
|
||||
*/
|
||||
protected $dateTimeFormat;
|
||||
|
||||
/**
|
||||
* The current number format info.
|
||||
* @var sfNumberFormatInfo
|
||||
*/
|
||||
protected $numberFormat;
|
||||
|
||||
/**
|
||||
* A list of properties that are accessable/writable.
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = array();
|
||||
|
||||
/**
|
||||
* Culture type, all.
|
||||
* @see getCultures()
|
||||
* @var int
|
||||
*/
|
||||
const ALL = 0;
|
||||
|
||||
/**
|
||||
* Culture type, neutral.
|
||||
* @see getCultures()
|
||||
* @var int
|
||||
*/
|
||||
const NEUTRAL = 1;
|
||||
|
||||
/**
|
||||
* Culture type, specific.
|
||||
*
|
||||
* @see getCultures()
|
||||
* @var int
|
||||
*/
|
||||
const SPECIFIC = 2;
|
||||
|
||||
/**
|
||||
* Displays the culture name.
|
||||
*
|
||||
* @return string the culture name.
|
||||
* @see getName()
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows functions that begins with 'set' to be called directly
|
||||
* as an attribute/property to retrieve the value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$getProperty = 'get'.$name;
|
||||
if (in_array($getProperty, $this->properties))
|
||||
{
|
||||
return $this->$getProperty();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Property %s does not exists.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows functions that begins with 'set' to be called directly
|
||||
* as an attribute/property to set the value.
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$setProperty = 'set'.$name;
|
||||
if (in_array($setProperty, $this->properties))
|
||||
{
|
||||
$this->$setProperty($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Property %s can not be set.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the sfCultureInfo class based on the
|
||||
* culture specified by name. E.g. <code>new sfCultureInfo('en_AU');</code>
|
||||
* The culture indentifier must be of the form
|
||||
* "<language>_(country/region/variant)".
|
||||
*
|
||||
* @param string a culture name, e.g. "en_AU".
|
||||
* @return return new sfCultureInfo.
|
||||
*/
|
||||
public function __construct($culture = 'en')
|
||||
{
|
||||
$this->properties = get_class_methods($this);
|
||||
|
||||
if (empty($culture))
|
||||
{
|
||||
$culture = 'en';
|
||||
}
|
||||
|
||||
$this->dataDir = $this->dataDir();
|
||||
$this->dataFileExt = $this->fileExt();
|
||||
|
||||
$this->setCulture($culture);
|
||||
|
||||
$this->loadCultureData('root');
|
||||
$this->loadCultureData($culture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default directory for the ICU data.
|
||||
* The default is the "data" directory for this class.
|
||||
*
|
||||
* @return string directory containing the ICU data.
|
||||
*/
|
||||
protected static function dataDir()
|
||||
{
|
||||
return sfConfig::get('sf_symfony_data_dir').'/i18n/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename extension for ICU data. Default is ".dat".
|
||||
*
|
||||
* @return string filename extension for ICU data.
|
||||
*/
|
||||
protected static function fileExt()
|
||||
{
|
||||
return '.dat';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given culture is valid. Simply checks that the
|
||||
* culture data exists.
|
||||
*
|
||||
* @param string a culture
|
||||
* @return boolean true if valid, false otherwise.
|
||||
*/
|
||||
static public function validCulture($culture)
|
||||
{
|
||||
if (preg_match('/^[a-z]{2}(_[A-Z]{2,5}){0,2}$/', $culture))
|
||||
{
|
||||
return is_file(self::dataDir().$culture.self::fileExt());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the culture for the current instance. The culture indentifier
|
||||
* must be of the form "<language>_(country/region)".
|
||||
*
|
||||
* @param string culture identifier, e.g. "fr_FR_EURO".
|
||||
*/
|
||||
protected function setCulture($culture)
|
||||
{
|
||||
if (!empty($culture))
|
||||
{
|
||||
if (!preg_match('/^[a-z]{2}(_[A-Z]{2,5}){0,2}$/', $culture))
|
||||
{
|
||||
throw new sfException(sprintf('Invalid culture supplied: %s', $culture));
|
||||
}
|
||||
}
|
||||
|
||||
$this->culture = $culture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the ICU culture data for the specific culture identifier.
|
||||
*
|
||||
* @param string the culture identifier.
|
||||
*/
|
||||
protected function loadCultureData($culture)
|
||||
{
|
||||
$file_parts = explode('_', $culture);
|
||||
$current_part = $file_parts[0];
|
||||
|
||||
$files = array($current_part);
|
||||
|
||||
for ($i = 1, $max = count($file_parts); $i < $max; $i++)
|
||||
{
|
||||
$current_part .= '_'.$file_parts[$i];
|
||||
$files[] = $current_part;
|
||||
}
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$filename = $this->dataDir.$file.$this->dataFileExt;
|
||||
|
||||
if (is_file($filename) == false)
|
||||
{
|
||||
throw new sfException(sprintf('Data file for "%s" was not found.', $file));
|
||||
}
|
||||
|
||||
if (in_array($filename, $this->dataFiles) == false)
|
||||
{
|
||||
array_unshift($this->dataFiles, $file);
|
||||
|
||||
$data = &$this->getData($filename);
|
||||
$this->data[$file] = &$data;
|
||||
|
||||
if (isset($data['__ALIAS']))
|
||||
{
|
||||
$this->loadCultureData($data['__ALIAS'][0]);
|
||||
}
|
||||
unset($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data by unserializing the ICU data from disk.
|
||||
* The data files are cached in a static variable inside
|
||||
* this function.
|
||||
*
|
||||
* @param string the ICU data filename
|
||||
* @return array ICU data
|
||||
*/
|
||||
protected function &getData($filename)
|
||||
{
|
||||
static $data = array();
|
||||
static $files = array();
|
||||
|
||||
if (!isset($files[$filename]))
|
||||
{
|
||||
$data[$filename] = unserialize(file_get_contents($filename));
|
||||
$files[$filename] = true;
|
||||
}
|
||||
|
||||
return $data[$filename];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the specific ICU data information from the data.
|
||||
* The path to the specific ICU data is separated with a slash "/".
|
||||
* E.g. To find the default calendar used by the culture, the path
|
||||
* "calendar/default" will return the corresponding default calendar.
|
||||
* Use merge=true to return the ICU including the parent culture.
|
||||
* E.g. The currency data for a variant, say "en_AU" contains one
|
||||
* entry, the currency for AUD, the other currency data are stored
|
||||
* in the "en" data file. Thus to retrieve all the data regarding
|
||||
* currency for "en_AU", you need to use findInfo("Currencies,true);.
|
||||
*
|
||||
* @param string the data you want to find.
|
||||
* @param boolean merge the data from its parents.
|
||||
* @return mixed the specific ICU data.
|
||||
*/
|
||||
protected function findInfo($path = '/', $merge = false)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($this->dataFiles as $section)
|
||||
{
|
||||
$info = $this->searchArray($this->data[$section], $path);
|
||||
|
||||
if ($info)
|
||||
{
|
||||
if ($merge)
|
||||
{
|
||||
$result = array_merge($info, $result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the array for a specific value using a path separated using
|
||||
* slash "/" separated path. e.g to find $info['hello']['world'],
|
||||
* the path "hello/world" will return the corresponding value.
|
||||
*
|
||||
* @param array the array for search
|
||||
* @param string slash "/" separated array path.
|
||||
* @return mixed the value array using the path
|
||||
*/
|
||||
protected function searchArray($info, $path = '/')
|
||||
{
|
||||
$index = explode('/', $path);
|
||||
|
||||
$array = $info;
|
||||
|
||||
for ($i = 0, $max = count($index); $i < $max; $i++)
|
||||
{
|
||||
$k = $index[$i];
|
||||
if ($i < $max - 1 && isset($array[$k]))
|
||||
{
|
||||
$array = $array[$k];
|
||||
}
|
||||
else if ($i == $max - 1 && isset($array[$k]))
|
||||
{
|
||||
return $array[$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the culture name in the format
|
||||
* "<languagecode2>_(country/regioncode2)".
|
||||
*
|
||||
* @return string culture name.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->culture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sfDateTimeFormatInfo that defines the culturally appropriate
|
||||
* format of displaying dates and times.
|
||||
*
|
||||
* @return sfDateTimeFormatInfo date time format information for the culture.
|
||||
*/
|
||||
public function getDateTimeFormat()
|
||||
{
|
||||
if (is_null($this->dateTimeFormat))
|
||||
{
|
||||
$calendar = $this->getCalendar();
|
||||
$info = $this->findInfo("calendar/{$calendar}", true);
|
||||
$this->setDateTimeFormat(new sfDateTimeFormatInfo($info));
|
||||
}
|
||||
|
||||
return $this->dateTimeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date time format information.
|
||||
*
|
||||
* @param sfDateTimeFormatInfo the new date time format info.
|
||||
*/
|
||||
public function setDateTimeFormat($dateTimeFormat)
|
||||
{
|
||||
$this->dateTimeFormat = $dateTimeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default calendar used by the culture, e.g. "gregorian".
|
||||
*
|
||||
* @return string the default calendar.
|
||||
*/
|
||||
public function getCalendar()
|
||||
{
|
||||
$info = $this->findInfo('calendar/default');
|
||||
|
||||
return $info[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the culture name in the language that the culture is set
|
||||
* to display. Returns <code>array('Language','Country');</code>
|
||||
* 'Country' is omitted if the culture is neutral.
|
||||
*
|
||||
* @return array array with language and country as elements, localized.
|
||||
*/
|
||||
public function getNativeName()
|
||||
{
|
||||
$lang = substr($this->culture, 0, 2);
|
||||
$reg = substr($this->culture, 3, 2);
|
||||
$language = $this->findInfo("Languages/{$lang}");
|
||||
$region = $this->findInfo("Countries/{$reg}");
|
||||
if ($region)
|
||||
{
|
||||
return $language[0].' ('.$region[0].')';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $language[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the culture name in English.
|
||||
* Returns <code>array('Language','Country');</code>
|
||||
* 'Country' is omitted if the culture is neutral.
|
||||
*
|
||||
* @return array array with language and country as elements.
|
||||
*/
|
||||
public function getEnglishName()
|
||||
{
|
||||
$lang = substr($this->culture, 0, 2);
|
||||
$reg = substr($this->culture, 3, 2);
|
||||
$culture = $this->getInvariantCulture();
|
||||
|
||||
$language = $culture->findInfo("Languages/{$lang}");
|
||||
$region = $culture->findInfo("Countries/{$reg}");
|
||||
|
||||
return $region ? $language[0].' ('.$region[0].')' : $language[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sfCultureInfo that is culture-independent (invariant).
|
||||
* Any changes to the invariant culture affects all other
|
||||
* instances of the invariant culture.
|
||||
* The invariant culture is assumed to be "en";
|
||||
*
|
||||
* @return sfCultureInfo invariant culture info is "en".
|
||||
*/
|
||||
static function getInvariantCulture()
|
||||
{
|
||||
static $invariant;
|
||||
|
||||
if (is_null($invariant))
|
||||
{
|
||||
$invariant = new sfCultureInfo();
|
||||
}
|
||||
|
||||
return $invariant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the current sfCultureInfo
|
||||
* represents a neutral culture. Returns true if the culture
|
||||
* only contains two characters.
|
||||
*
|
||||
* @return boolean true if culture is neutral, false otherwise.
|
||||
*/
|
||||
public function getIsNeutralCulture()
|
||||
{
|
||||
return strlen($this->culture) == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sfNumberFormatInfo that defines the culturally appropriate
|
||||
* format of displaying numbers, currency, and percentage.
|
||||
*
|
||||
* @return sfNumberFormatInfo the number format info for current culture.
|
||||
*/
|
||||
public function getNumberFormat()
|
||||
{
|
||||
if (is_null($this->numberFormat))
|
||||
{
|
||||
$elements = $this->findInfo('NumberElements');
|
||||
$patterns = $this->findInfo('NumberPatterns');
|
||||
$currencies = $this->getCurrencies();
|
||||
$data = array('NumberElements' => $elements, 'NumberPatterns' => $patterns, 'Currencies' => $currencies);
|
||||
|
||||
$this->setNumberFormat(new sfNumberFormatInfo($data));
|
||||
}
|
||||
|
||||
return $this->numberFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number format information.
|
||||
*
|
||||
* @param sfNumberFormatInfo the new number format info.
|
||||
*/
|
||||
public function setNumberFormat($numberFormat)
|
||||
{
|
||||
$this->numberFormat = $numberFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sfCultureInfo that represents the parent culture of the
|
||||
* current sfCultureInfo
|
||||
*
|
||||
* @return sfCultureInfo parent culture information.
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
if (strlen($this->culture) == 2)
|
||||
{
|
||||
return $this->getInvariantCulture();
|
||||
}
|
||||
|
||||
return new sfCultureInfo(substr($this->culture, 0, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of supported cultures filtered by the specified
|
||||
* culture type. This is an EXPENSIVE function, it needs to traverse
|
||||
* a list of ICU files in the data directory.
|
||||
* This function can be called statically.
|
||||
*
|
||||
* @param int culture type, sfCultureInfo::ALL, sfCultureInfo::NEUTRAL
|
||||
* or sfCultureInfo::SPECIFIC.
|
||||
* @return array list of culture information available.
|
||||
*/
|
||||
static function getCultures($type = sfCultureInfo::ALL)
|
||||
{
|
||||
$dataDir = sfCultureInfo::dataDir();
|
||||
$dataExt = sfCultureInfo::fileExt();
|
||||
$dir = dir($dataDir);
|
||||
|
||||
$neutral = array();
|
||||
$specific = array();
|
||||
|
||||
while (false !== ($entry = $dir->read()))
|
||||
{
|
||||
if (is_file($dataDir.$entry) && substr($entry, -4) == $dataExt && $entry != 'root'.$dataExt)
|
||||
{
|
||||
$culture = substr($entry, 0, -4);
|
||||
if (strlen($culture) == 2)
|
||||
{
|
||||
$neutral[] = $culture;
|
||||
}
|
||||
else
|
||||
{
|
||||
$specific[] = $culture;
|
||||
}
|
||||
}
|
||||
}
|
||||
$dir->close();
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case sfCultureInfo::ALL:
|
||||
$all = array_merge($neutral, $specific);
|
||||
sort($all);
|
||||
return $all;
|
||||
break;
|
||||
case sfCultureInfo::NEUTRAL:
|
||||
return $neutral;
|
||||
break;
|
||||
case sfCultureInfo::SPECIFIC:
|
||||
return $specific;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies a single element array into its own value.
|
||||
* E.g. <code>array(0 => array('hello'), 1 => 'world');</code>
|
||||
* becomes <code>array(0 => 'hello', 1 => 'world');</code>
|
||||
*
|
||||
* @param array with single elements arrays
|
||||
* @return array simplified array.
|
||||
*/
|
||||
protected function simplify($array)
|
||||
{
|
||||
for ($i = 0, $max = count($array); $i < $max; $i++)
|
||||
{
|
||||
$key = key($array);
|
||||
if (is_array($array[$key]) && count($array[$key]) == 1)
|
||||
{
|
||||
$array[$key] = $array[$key][0];
|
||||
}
|
||||
next($array);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of countries in the language of the localized version.
|
||||
*
|
||||
* @return array a list of localized country names.
|
||||
*/
|
||||
public function getCountries()
|
||||
{
|
||||
return $this->simplify($this->findInfo('Countries', true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of currencies in the language of the localized version.
|
||||
*
|
||||
* @return array a list of localized currencies.
|
||||
*/
|
||||
public function getCurrencies()
|
||||
{
|
||||
return $this->findInfo('Currencies', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of languages in the language of the localized version.
|
||||
*
|
||||
* @return array list of localized language names.
|
||||
*/
|
||||
public function getLanguages()
|
||||
{
|
||||
return $this->simplify($this->findInfo('Languages', true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of scripts in the language of the localized version.
|
||||
*
|
||||
* @return array list of localized script names.
|
||||
*/
|
||||
public function getScripts()
|
||||
{
|
||||
return $this->simplify($this->findInfo('Scripts', true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of timezones in the language of the localized version.
|
||||
*
|
||||
* @return array list of localized timezones.
|
||||
*/
|
||||
public function getTimeZones()
|
||||
{
|
||||
return $this->simplify($this->findInfo('zoneStrings', true));
|
||||
}
|
||||
}
|
798
lib/symfony/i18n/sfDateFormat.class.php
Executable file
798
lib/symfony/i18n/sfDateFormat.class.php
Executable file
@ -0,0 +1,798 @@
|
||||
<?php
|
||||
/**
|
||||
* sfDateFormat 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 $Id: sfDateFormat.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the encoding utilities
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/util.php');
|
||||
|
||||
/**
|
||||
* sfDateFormat class.
|
||||
*
|
||||
* The sfDateFormat class allows you to format dates and times with
|
||||
* predefined styles in a locale-sensitive manner. Formatting times
|
||||
* with the sfDateFormat class is similar to formatting dates.
|
||||
*
|
||||
* Formatting dates with the sfDateFormat class is a two-step process.
|
||||
* First, you create a formatter with the getDateInstance method.
|
||||
* Second, you invoke the format method, which returns a string containing
|
||||
* the formatted date.
|
||||
*
|
||||
* DateTime values are formatted using standard or custom patterns stored
|
||||
* in the properties of a DateTimeFormatInfo.
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Sat Dec 04 14:10:49 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfDateFormat
|
||||
{
|
||||
/**
|
||||
* A list of tokens and their function call.
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = array(
|
||||
'G'=>'Era',
|
||||
'y'=>'year',
|
||||
'M'=>'mon',
|
||||
'd'=>'mday',
|
||||
'h'=>'Hour12',
|
||||
'H'=>'hours',
|
||||
'm'=>'minutes',
|
||||
's'=>'seconds',
|
||||
'E'=>'wday',
|
||||
'D'=>'yday',
|
||||
'F'=>'DayInMonth',
|
||||
'w'=>'WeekInYear',
|
||||
'W'=>'WeekInMonth',
|
||||
'a'=>'AMPM',
|
||||
'k'=>'HourInDay',
|
||||
'K'=>'HourInAMPM',
|
||||
'z'=>'TimeZone'
|
||||
);
|
||||
|
||||
/**
|
||||
* A list of methods, to be used by the token function calls.
|
||||
* @var array
|
||||
*/
|
||||
protected $methods = array();
|
||||
|
||||
/**
|
||||
* The sfDateTimeFormatInfo, containing culture specific patterns and names.
|
||||
* @var sfDateTimeFormatInfo
|
||||
*/
|
||||
protected $formatInfo;
|
||||
|
||||
/**
|
||||
* Initializes a new sfDateFormat.
|
||||
*
|
||||
* @param mixed either, null, a sfCultureInfo instance, a DateTimeFormatInfo instance, or a locale.
|
||||
* @return sfDateFormat instance
|
||||
*/
|
||||
function __construct($formatInfo = null)
|
||||
{
|
||||
if (is_null($formatInfo))
|
||||
{
|
||||
$this->formatInfo = sfDateTimeFormatInfo::getInvariantInfo();
|
||||
}
|
||||
else if ($formatInfo instanceof sfCultureInfo)
|
||||
{
|
||||
$this->formatInfo = $formatInfo->DateTimeFormat;
|
||||
}
|
||||
else if ($formatInfo instanceof sfDateTimeFormatInfo)
|
||||
{
|
||||
$this->formatInfo = $formatInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->formatInfo = sfDateTimeFormatInfo::getInstance($formatInfo);
|
||||
}
|
||||
|
||||
$this->methods = get_class_methods($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses a date without calling strtotime.
|
||||
*
|
||||
* @author Olivier Verdier <Olivier.Verdier@gmail.com>
|
||||
* @param mixed the time as integer or string in strtotime format.
|
||||
* @param string the input pattern; default is sql date or timestamp
|
||||
* @return array same array as the getdate function
|
||||
*/
|
||||
public function getDate($time, $pattern = null)
|
||||
{
|
||||
if (is_null($time))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the type is not a php timestamp
|
||||
$isString = (string) $time !== (string) (int) $time;
|
||||
|
||||
if ($isString)
|
||||
{
|
||||
if (!$pattern)
|
||||
{
|
||||
if (strlen($time) == 10)
|
||||
{
|
||||
$pattern = 'i';
|
||||
}
|
||||
else // otherwise, default:
|
||||
{
|
||||
$pattern = 'I';
|
||||
}
|
||||
}
|
||||
|
||||
$pattern = $this->getPattern($pattern);
|
||||
$tokens = $this->getTokens($pattern);
|
||||
$pregPattern = '';
|
||||
$matchNames = array();
|
||||
foreach ($tokens as $token)
|
||||
{
|
||||
if ($matchName = $this->getFunctionName($token))
|
||||
{
|
||||
$pregPattern .= '(\d+)';
|
||||
$matchNames[] = $matchName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pregPattern .= '[^\d]+';
|
||||
}
|
||||
}
|
||||
preg_match('@'.$pregPattern.'@', $time, $matches);
|
||||
|
||||
array_shift($matches);
|
||||
|
||||
if (count($matchNames) == count($matches))
|
||||
{
|
||||
$date = array_combine($matchNames, $matches);
|
||||
// guess the date if input with two digits
|
||||
if (strlen($date['year']) == 2)
|
||||
{
|
||||
$date['year'] = date('Y', mktime(0, 0, 0, 1, 1, $date['year']));
|
||||
}
|
||||
$date = array_map('intval', $date);
|
||||
}
|
||||
}
|
||||
|
||||
// the last attempt has failed we fall back on the default method
|
||||
if (!isset($date))
|
||||
{
|
||||
if ($isString)
|
||||
{
|
||||
$numericalTime = @strtotime($time);
|
||||
if ($numericalTime === false)
|
||||
{
|
||||
throw new sfException(sprintf('Impossible to parse date "%s" with format "%s".', $time, $pattern));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$numericalTime = $time;
|
||||
}
|
||||
$date = @getdate($numericalTime);
|
||||
}
|
||||
|
||||
// we set default values for the time
|
||||
foreach (array('hours', 'minutes', 'seconds') as $timeDiv)
|
||||
{
|
||||
if (!isset($date[$timeDiv]))
|
||||
{
|
||||
$date[$timeDiv] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date according to the pattern.
|
||||
*
|
||||
* @param mixed the time as integer or string in strtotime format.
|
||||
* @return string formatted date time.
|
||||
*/
|
||||
public function format($time, $pattern = 'F', $inputPattern = null, $charset = 'UTF-8')
|
||||
{
|
||||
$date = $this->getDate($time, $inputPattern);
|
||||
|
||||
if (is_null($pattern))
|
||||
{
|
||||
$pattern = 'F';
|
||||
}
|
||||
|
||||
$pattern = $this->getPattern($pattern);
|
||||
$tokens = $this->getTokens($pattern);
|
||||
|
||||
for ($i = 0, $max = count($tokens); $i < $max; $i++)
|
||||
{
|
||||
$pattern = $tokens[$i];
|
||||
if ($pattern{0} == "'" && $pattern{strlen($pattern) - 1} == "'")
|
||||
{
|
||||
$tokens[$i] = str_replace('``````', '\'', preg_replace('/(^\')|(\'$)/', '', $pattern));
|
||||
}
|
||||
else if ($pattern == '``````')
|
||||
{
|
||||
$tokens[$i] = '\'';
|
||||
}
|
||||
else
|
||||
{
|
||||
$function = ucfirst($this->getFunctionName($pattern));
|
||||
if ($function != null)
|
||||
{
|
||||
$fName = 'get'.$function;
|
||||
if (in_array($fName, $this->methods))
|
||||
{
|
||||
$tokens[$i] = $this->$fName($date, $pattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Function %s not found.', $function));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return I18N_toEncoding(implode('', $tokens), $charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a particular token, get the corresponding function to call.
|
||||
*
|
||||
* @param string token
|
||||
* @return mixed the function if good token, null otherwise.
|
||||
*/
|
||||
protected function getFunctionName($token)
|
||||
{
|
||||
if (isset($this->tokens[$token{0}]))
|
||||
{
|
||||
return $this->tokens[$token{0}];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pattern from DateTimeFormatInfo or some predefined patterns.
|
||||
* If the $pattern parameter is an array of 2 element, it will assume
|
||||
* that the first element is the date, and second the time
|
||||
* and try to find an appropriate pattern and apply
|
||||
* DateTimeFormatInfo::formatDateTime
|
||||
* See the tutorial documentation for futher details on the patterns.
|
||||
*
|
||||
* @param mixed a pattern.
|
||||
* @return string a pattern.
|
||||
* @see DateTimeFormatInfo::formatDateTime()
|
||||
*/
|
||||
public function getPattern($pattern)
|
||||
{
|
||||
if (is_array($pattern) && count($pattern) == 2)
|
||||
{
|
||||
return $this->formatInfo->formatDateTime($this->getPattern($pattern[0]), $this->getPattern($pattern[1]));
|
||||
}
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'd':
|
||||
return $this->formatInfo->ShortDatePattern;
|
||||
break;
|
||||
case 'D':
|
||||
return $this->formatInfo->LongDatePattern;
|
||||
break;
|
||||
case 'p':
|
||||
return $this->formatInfo->MediumDatePattern;
|
||||
break;
|
||||
case 'P':
|
||||
return $this->formatInfo->FullDatePattern;
|
||||
break;
|
||||
case 't':
|
||||
return $this->formatInfo->ShortTimePattern;
|
||||
break;
|
||||
case 'T':
|
||||
return $this->formatInfo->LongTimePattern;
|
||||
break;
|
||||
case 'q':
|
||||
return $this->formatInfo->MediumTimePattern;
|
||||
break;
|
||||
case 'Q':
|
||||
return $this->formatInfo->FullTimePattern;
|
||||
break;
|
||||
case 'f':
|
||||
return $this->formatInfo->formatDateTime($this->formatInfo->LongDatePattern, $this->formatInfo->ShortTimePattern);
|
||||
break;
|
||||
case 'F':
|
||||
return $this->formatInfo->formatDateTime($this->formatInfo->LongDatePattern, $this->formatInfo->LongTimePattern);
|
||||
break;
|
||||
case 'g':
|
||||
return $this->formatInfo->formatDateTime($this->formatInfo->ShortDatePattern, $this->formatInfo->ShortTimePattern);
|
||||
break;
|
||||
case 'G':
|
||||
return $this->formatInfo->formatDateTime($this->formatInfo->ShortDatePattern, $this->formatInfo->LongTimePattern);
|
||||
break;
|
||||
case 'i':
|
||||
return 'yyyy-MM-dd';
|
||||
break;
|
||||
case 'I':
|
||||
return 'yyyy-MM-dd HH:mm:ss';
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
return 'MMMM dd';
|
||||
break;
|
||||
case 'R':
|
||||
case 'r':
|
||||
return 'EEE, dd MMM yyyy HH:mm:ss';
|
||||
break;
|
||||
case 's':
|
||||
return 'yyyy-MM-ddTHH:mm:ss';
|
||||
break;
|
||||
case 'u':
|
||||
return 'yyyy-MM-dd HH:mm:ss z';
|
||||
break;
|
||||
case 'U':
|
||||
return 'EEEE dd MMMM yyyy HH:mm:ss';
|
||||
break;
|
||||
case 'Y':
|
||||
case 'y':
|
||||
return 'yyyy MMMM';
|
||||
break;
|
||||
default :
|
||||
return $pattern;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an easy to parse input pattern
|
||||
* yy is replaced by yyyy and h by H
|
||||
*
|
||||
* @param string pattern.
|
||||
* @return string input pattern
|
||||
*/
|
||||
public function getInputPattern($pattern)
|
||||
{
|
||||
$pattern = $this->getPattern($pattern);
|
||||
|
||||
$pattern = strtr($pattern, array('yyyy' => 'Y', 'h'=>'H', 'z'=>'', 'a'=>''));
|
||||
$pattern = strtr($pattern, array('yy'=>'yyyy', 'Y'=>'yyyy'));
|
||||
|
||||
return trim($pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes the pattern. The tokens are delimited by group of
|
||||
* similar characters, e.g. 'aabb' will form 2 tokens of 'aa' and 'bb'.
|
||||
* Any substrings, starting and ending with a single quote (')
|
||||
* will be treated as a single token.
|
||||
*
|
||||
* @param string pattern.
|
||||
* @return array string tokens in an array.
|
||||
*/
|
||||
protected function getTokens($pattern)
|
||||
{
|
||||
$char = null;
|
||||
$tokens = array();
|
||||
$token = null;
|
||||
|
||||
$text = false;
|
||||
|
||||
for ($i = 0, $max = strlen($pattern); $i < $max; $i++)
|
||||
{
|
||||
if ($char == null || $pattern{$i} == $char || $text)
|
||||
{
|
||||
$token .= $pattern{$i};
|
||||
}
|
||||
else
|
||||
{
|
||||
$tokens[] = str_replace("''", "'", $token);
|
||||
$token = $pattern{$i};
|
||||
}
|
||||
|
||||
if ($pattern{$i} == "'" && $text == false)
|
||||
{
|
||||
$text = true;
|
||||
}
|
||||
else if ($text && $pattern{$i} == "'" && $char == "'")
|
||||
{
|
||||
$text = true;
|
||||
}
|
||||
else if ($text && $char != "'" && $pattern{$i} == "'")
|
||||
{
|
||||
$text = false;
|
||||
}
|
||||
|
||||
$char = $pattern{$i};
|
||||
|
||||
}
|
||||
$tokens[] = $token;
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
// makes a unix date from our incomplete $date array
|
||||
protected function getUnixDate($date)
|
||||
{
|
||||
return getdate(mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the year.
|
||||
* "yy" will return the last two digits of year.
|
||||
* "yyyy" will return the full integer year.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string year
|
||||
*/
|
||||
protected function getYear($date, $pattern = 'yyyy')
|
||||
{
|
||||
$year = $date['year'];
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'yy':
|
||||
return substr($year, 2);
|
||||
case 'yyyy':
|
||||
return $year;
|
||||
default:
|
||||
throw new sfException('The pattern for year is either "yy" or "yyyy".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the month.
|
||||
* "M" will return integer 1 through 12
|
||||
* "MM" will return the narrow month name, e.g. "J"
|
||||
* "MMM" will return the abrreviated month name, e.g. "Jan"
|
||||
* "MMMM" will return the month name, e.g. "January"
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string month name
|
||||
*/
|
||||
protected function getMon($date, $pattern = 'M')
|
||||
{
|
||||
$month = $date['mon'];
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'M':
|
||||
return $month;
|
||||
case 'MM':
|
||||
return str_pad($month, 2, '0', STR_PAD_LEFT);
|
||||
case 'MMM':
|
||||
return $this->formatInfo->AbbreviatedMonthNames[$month - 1];
|
||||
break;
|
||||
case 'MMMM':
|
||||
return $this->formatInfo->MonthNames[$month - 1];
|
||||
default:
|
||||
throw new sfException('The pattern for month is "M", "MM", "MMM", or "MMMM".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day of the week.
|
||||
* "E" will return integer 0 (for Sunday) through 6 (for Saturday).
|
||||
* "EE" will return the narrow day of the week, e.g. "M"
|
||||
* "EEE" will return the abrreviated day of the week, e.g. "Mon"
|
||||
* "EEEE" will return the day of the week, e.g. "Monday"
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string day of the week.
|
||||
*/
|
||||
protected function getWday($date, $pattern = 'EEEE')
|
||||
{
|
||||
// if the $date comes from our home-made get date
|
||||
if (!isset($date['wday']))
|
||||
{
|
||||
$date = $this->getUnixDate($date);
|
||||
}
|
||||
$day = $date['wday'];
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'E':
|
||||
return $day;
|
||||
break;
|
||||
case 'EE':
|
||||
return $this->formatInfo->NarrowDayNames[$day];
|
||||
case 'EEE':
|
||||
return $this->formatInfo->AbbreviatedDayNames[$day];
|
||||
break;
|
||||
case 'EEEE':
|
||||
return $this->formatInfo->DayNames[$day];
|
||||
break;
|
||||
default:
|
||||
throw new sfException('The pattern for day of the week is "E", "EE", "EEE", or "EEEE".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day of the month.
|
||||
* "d" for non-padding, "dd" will always return 2 characters.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string day of the month
|
||||
*/
|
||||
protected function getMday($date, $pattern = 'd')
|
||||
{
|
||||
$day = $date['mday'];
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'd':
|
||||
return $day;
|
||||
case 'dd':
|
||||
return str_pad($day, 2, '0', STR_PAD_LEFT);
|
||||
case 'dddd':
|
||||
return $this->getWday($date);
|
||||
default:
|
||||
throw new sfException('The pattern for day of the month is "d", "dd" or "dddd".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the era. i.e. in gregorian, year > 0 is AD, else BC.
|
||||
*
|
||||
* @todo How to support multiple Eras?, e.g. Japanese.
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string era
|
||||
*/
|
||||
protected function getEra($date, $pattern = 'G')
|
||||
{
|
||||
if ($pattern != 'G')
|
||||
{
|
||||
throw new sfException('The pattern for era is "G".');
|
||||
}
|
||||
|
||||
return $this->formatInfo->getEra($date['year'] > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hours in 24 hour format, i.e. [0-23].
|
||||
* "H" for non-padding, "HH" will always return 2 characters.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string hours in 24 hour format.
|
||||
*/
|
||||
protected function getHours($date, $pattern = 'H')
|
||||
{
|
||||
$hour = $date['hours'];
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'H':
|
||||
return $hour;
|
||||
case 'HH':
|
||||
return str_pad($hour, 2, '0', STR_PAD_LEFT);
|
||||
default:
|
||||
throw new sfException('The pattern for 24 hour format is "H" or "HH".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the AM/PM designator, 12 noon is PM, 12 midnight is AM.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string AM or PM designator
|
||||
*/
|
||||
protected function getAMPM($date, $pattern = 'a')
|
||||
{
|
||||
if ($pattern != 'a')
|
||||
{
|
||||
throw new sfException('The pattern for AM/PM marker is "a".');
|
||||
}
|
||||
|
||||
return $this->formatInfo->AMPMMarkers[intval($date['hours'] / 12)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hours in 12 hour format.
|
||||
* "h" for non-padding, "hh" will always return 2 characters.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string hours in 12 hour format.
|
||||
*/
|
||||
protected function getHour12($date, $pattern = 'h')
|
||||
{
|
||||
$hour = $date['hours'];
|
||||
$hour = ($hour == 12 | $hour == 0) ? 12 : $hour % 12;
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'h':
|
||||
return $hour;
|
||||
case 'hh':
|
||||
return str_pad($hour, 2, '0', STR_PAD_LEFT);
|
||||
default:
|
||||
throw new sfException('The pattern for 24 hour format is "H" or "HH".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minutes.
|
||||
* "m" for non-padding, "mm" will always return 2 characters.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string minutes.
|
||||
*/
|
||||
protected function getMinutes($date, $pattern = 'm')
|
||||
{
|
||||
$minutes = $date['minutes'];
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'm':
|
||||
return $minutes;
|
||||
case 'mm':
|
||||
return str_pad($minutes, 2, '0', STR_PAD_LEFT);
|
||||
default:
|
||||
throw new sfException('The pattern for minutes is "m" or "mm".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the seconds.
|
||||
* "s" for non-padding, "ss" will always return 2 characters.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string seconds
|
||||
*/
|
||||
protected function getSeconds($date, $pattern = 's')
|
||||
{
|
||||
$seconds = $date['seconds'];
|
||||
|
||||
switch ($pattern)
|
||||
{
|
||||
case 's':
|
||||
return $seconds;
|
||||
case 'ss':
|
||||
return str_pad($seconds, 2, '0', STR_PAD_LEFT);
|
||||
default:
|
||||
throw new sfException('The pattern for seconds is "s" or "ss".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timezone from the server machine.
|
||||
*
|
||||
* @todo How to get the timezone for a different region?
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return string time zone
|
||||
*/
|
||||
protected function getTimeZone($date, $pattern = 'z')
|
||||
{
|
||||
if ($pattern != 'z')
|
||||
{
|
||||
throw new sfException('The pattern for time zone is "z".');
|
||||
}
|
||||
|
||||
return @date('T', @mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day in the year, e.g. [1-366]
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return int hours in AM/PM format.
|
||||
*/
|
||||
protected function getYday($date, $pattern = 'D')
|
||||
{
|
||||
if ($pattern != 'D')
|
||||
{
|
||||
throw new sfException('The pattern for day in year is "D".');
|
||||
}
|
||||
|
||||
return $date['yday'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets day in the month.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return int day in month
|
||||
*/
|
||||
protected function getDayInMonth($date, $pattern = 'FF')
|
||||
{
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'F':
|
||||
return @date('j', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']));
|
||||
break;
|
||||
case 'FF':
|
||||
return @date('d', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']));
|
||||
break;
|
||||
default:
|
||||
throw new sfException('The pattern for day in month is "F" or "FF".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the week in the year.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return int week in year
|
||||
*/
|
||||
protected function getWeekInYear($date, $pattern = 'w')
|
||||
{
|
||||
if ($pattern != 'w')
|
||||
{
|
||||
throw new sfException('The pattern for week in year is "w".');
|
||||
}
|
||||
|
||||
return @date('W', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets week in the month.
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @return int week in month
|
||||
*/
|
||||
protected function getWeekInMonth($date, $pattern = 'W')
|
||||
{
|
||||
if ($pattern != 'W')
|
||||
{
|
||||
throw new sfException('The pattern for week in month is "W".');
|
||||
}
|
||||
|
||||
return @date('W', @mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year'])) - date('W', mktime(0, 0, 0, $date['mon'], 1, $date['year']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hours [1-24].
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return int hours [1-24]
|
||||
*/
|
||||
protected function getHourInDay($date, $pattern = 'k')
|
||||
{
|
||||
if ($pattern != 'k')
|
||||
{
|
||||
throw new sfException('The pattern for hour in day is "k".');
|
||||
}
|
||||
|
||||
return $date['hours'] + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hours in AM/PM format, e.g [1-12]
|
||||
*
|
||||
* @param array getdate format.
|
||||
* @param string a pattern.
|
||||
* @return int hours in AM/PM format.
|
||||
*/
|
||||
protected function getHourInAMPM($date, $pattern = 'K')
|
||||
{
|
||||
if ($pattern != 'K')
|
||||
{
|
||||
throw new sfException('The pattern for hour in AM/PM is "K".');
|
||||
}
|
||||
|
||||
return ($date['hours'] + 1) % 12;
|
||||
}
|
||||
}
|
546
lib/symfony/i18n/sfDateTimeFormatInfo.class.php
Executable file
546
lib/symfony/i18n/sfDateTimeFormatInfo.class.php
Executable file
@ -0,0 +1,546 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfDateTimeFormatInfo 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 $Id: sfDateTimeFormatInfo.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines how DateTime values are formatted and displayed, depending
|
||||
* on the culture.
|
||||
*
|
||||
* This class contains information, such as date patterns, time patterns,
|
||||
* and AM/PM designators.
|
||||
*
|
||||
* To create a sfDateTimeFormatInfo for a specific culture, create a
|
||||
* sfCultureInfo for that culture and retrieve the sfCultureInfo.sfDateTimeFormat
|
||||
* property. For example:
|
||||
* <code>
|
||||
* $culture = new sfCultureInfo('en_AU');
|
||||
* $dtfi = $culture->DateTimeFormat;
|
||||
* </code>
|
||||
*
|
||||
* To create a sfDateTimeFormatInfo for the invariant culture, use
|
||||
* <code>
|
||||
* sfDateTimeFormatInfo::getInstance($culture=null);
|
||||
* </code>
|
||||
* you may pass a sfCultureInfo parameter $culture to get the sfDateTimeFormatInfo
|
||||
* for a specific culture.
|
||||
*
|
||||
* sfDateTime values are formatted using standard or custom patterns stored in
|
||||
* the properties of a sfDateTimeFormatInfo.
|
||||
*
|
||||
* The standard patterns can be replaced with custom patterns by setting the
|
||||
* associated properties of sfDateTimeFormatInfo.
|
||||
*
|
||||
* The following table lists the standard format characters for each standard
|
||||
* pattern and the associated sfDateTimeFormatInfo property that can be set to
|
||||
* modify the standard pattern. The format characters are case-sensitive;
|
||||
* for example, 'g' and 'G' represent slightly different patterns.
|
||||
*
|
||||
* <code>
|
||||
* Format Character Associated Property Example Format Pattern (en-US)
|
||||
* --------------------------------------------------------------------------
|
||||
* d ShortDatePattern MM/dd/yyyy
|
||||
* D LongDatePattern dddd, dd MMMM yyyy
|
||||
* F FullDateTimePattern dddd, dd MMMM yyyy HH:mm:ss
|
||||
* m, M MonthDayPattern MMMM dd
|
||||
* r, R RFC1123Pattern ddd, dd MMM yyyy HH':'mm':'ss 'GMT'
|
||||
* s SortableDateTimePattern yyyy'-'MM'-'dd'T'HH':'mm':'ss
|
||||
* t ShortTimePattern HH:mm
|
||||
* T LongTimePattern HH:mm:ss
|
||||
* Y YearMonthPattern yyyy MMMM
|
||||
* --------------------------------------------------------------------------
|
||||
* </code>
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 03 22:30:31 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfDateTimeFormatInfo
|
||||
{
|
||||
/**
|
||||
* ICU date time formatting data.
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* A list of properties that are accessable/writable.
|
||||
*/
|
||||
protected $properties = array();
|
||||
|
||||
/**
|
||||
* Allows functions that begins with 'set' to be called directly
|
||||
* as an attribute/property to retrieve the value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function __get($name)
|
||||
{
|
||||
$getProperty = 'get'.$name;
|
||||
if (in_array($getProperty, $this->properties))
|
||||
{
|
||||
return $this->$getProperty();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Property %s does not exists.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows functions that begins with 'set' to be called directly
|
||||
* as an attribute/property to set the value.
|
||||
*/
|
||||
function __set($name, $value)
|
||||
{
|
||||
$setProperty = 'set'.$name;
|
||||
if (in_array($setProperty, $this->properties))
|
||||
{
|
||||
$this->$setProperty($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Property %s can not be set.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new writable instance of the sfDateTimeFormatInfo class
|
||||
* that is dependent on the ICU data for date time formatting
|
||||
* information. <b>N.B.</b>You should not initialize this class directly
|
||||
* unless you know what you are doing. Please use use
|
||||
* sfDateTimeFormatInfo::getInstance() to create an instance.
|
||||
*
|
||||
* @param array ICU data for date time formatting.
|
||||
* @see getInstance()
|
||||
*/
|
||||
function __construct($data = array())
|
||||
{
|
||||
$this->properties = get_class_methods($this);
|
||||
|
||||
if (empty($data))
|
||||
{
|
||||
throw new sfException('Please provide the ICU data to initialize.');
|
||||
}
|
||||
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal ICU data for date time formatting.
|
||||
*
|
||||
* @return array ICU date time formatting data.
|
||||
*/
|
||||
protected function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default sfDateTimeFormatInfo that is culture-independent (invariant).
|
||||
*
|
||||
* @return sfDateTimeFormatInfo default sfDateTimeFormatInfo.
|
||||
*/
|
||||
static function getInvariantInfo()
|
||||
{
|
||||
static $invariant;
|
||||
if (is_null($invariant))
|
||||
{
|
||||
$culture = sfCultureInfo::getInvariantCulture();
|
||||
$invariant = $culture->DateTimeFormat;
|
||||
}
|
||||
|
||||
return $invariant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sfDateTimeFormatInfo associated with the specified culture.
|
||||
*
|
||||
* @param sfCultureInfo the culture that gets the sfDateTimeFormat property.
|
||||
* @return sfDateTimeFormatInfo sfDateTimeFormatInfo for the specified
|
||||
* culture.
|
||||
*/
|
||||
static function getInstance($culture = null)
|
||||
{
|
||||
if ($culture instanceof sfCultureInfo)
|
||||
{
|
||||
return $culture->DateTimeFormat;
|
||||
}
|
||||
else if (is_string($culture))
|
||||
{
|
||||
$cultureInfo = new sfCultureInfo($culture);
|
||||
|
||||
return $cultureInfo->DateTimeFormat;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cultureInfo = sfCultureInfo::getInvariantCulture();
|
||||
|
||||
return $cultureInfo->DateTimeFormat;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-dimensional array of type String containing
|
||||
* the culture-specific abbreviated names of the days
|
||||
* of the week. The array for InvariantInfo contains
|
||||
* "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", and "Sat".
|
||||
*
|
||||
* @return array abbreviated day names
|
||||
*/
|
||||
function getAbbreviatedDayNames()
|
||||
{
|
||||
return $this->data['dayNames']['format']['abbreviated'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the abbreviated day names. The value should be
|
||||
* an array of string starting with Sunday and ends in Saturady.
|
||||
* For example,
|
||||
* <code>array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");</code>
|
||||
*
|
||||
* @param array abbreviated day names.
|
||||
*/
|
||||
function setAbbreviatedDayNames($value)
|
||||
{
|
||||
$this->data['dayNames']['format']['abbreviated'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-dimensional array of type String containing
|
||||
* the culture-specific narrow names of the days
|
||||
* of the week. The array for InvariantInfo contains
|
||||
* "S", "M", "T", "W", "T", "F", and "S".
|
||||
*
|
||||
* @return array narrow day names
|
||||
*/
|
||||
function getNarrowDayNames()
|
||||
{
|
||||
return $this->data['dayNames']['format']['narrow'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the narrow day names. The value should be
|
||||
* an array of string starting with Sunday and ends in Saturady.
|
||||
* For example,
|
||||
* <code>array("S", "M", "T", "W", "T", "F", "S");</code>
|
||||
*
|
||||
* @param array narrow day names.
|
||||
*/
|
||||
function setNarrowDayNames($value)
|
||||
{
|
||||
$this->data['dayNames']['format']['narrow'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-dimensional array of type String containing the
|
||||
* culture-specific full names of the days of the week.
|
||||
* The array for InvariantInfo contains "Sunday", "Monday",
|
||||
* "Tuesday", "Wednesday", "Thursday", "Friday", and "Saturday".
|
||||
*
|
||||
* @return array day names
|
||||
*/
|
||||
function getDayNames()
|
||||
{
|
||||
return $this->data['dayNames']['format']['wide'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the day names. The value should be
|
||||
* an array of string starting with Sunday and ends in Saturady.
|
||||
* For example,
|
||||
* <code>array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
|
||||
* "Friday", "Saturday".);</code>
|
||||
*
|
||||
* @param array day names.
|
||||
*/
|
||||
function setDayNames($value)
|
||||
{
|
||||
$this->data['dayNames']['format']['wide'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-dimensional array of type String containing the
|
||||
* culture-specific narrow names of the months. The array
|
||||
* for InvariantInfo contains "J", "F", "M", "A", "M", "J",
|
||||
* "J", "A", "S", "O", "N", and "D".
|
||||
*
|
||||
* @return array narrow month names.
|
||||
*/
|
||||
function getNarrowMonthNames()
|
||||
{
|
||||
return $this->data['monthNames']['format']['narrow'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the narrow month names. The value should be
|
||||
* an array of string starting with J and ends in D.
|
||||
* For example,
|
||||
* <code>array("J","F","M","A","M","J","J","A","S","O","N","D");</code>
|
||||
*
|
||||
* @param array month names.
|
||||
*/
|
||||
function setNarrowMonthNames($value)
|
||||
{
|
||||
$this->data['monthNames']['format']['narrow'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-dimensional array of type String containing the
|
||||
* culture-specific abbreviated names of the months. The array
|
||||
* for InvariantInfo contains "Jan", "Feb", "Mar", "Apr", "May",
|
||||
* "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", and "Dec".
|
||||
*
|
||||
* @return array abbreviated month names.
|
||||
*/
|
||||
function getAbbreviatedMonthNames()
|
||||
{
|
||||
return $this->data['monthNames']['format']['abbreviated'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the abbreviated month names. The value should be
|
||||
* an array of string starting with Jan and ends in Dec.
|
||||
* For example,
|
||||
* <code>array("Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
* "Jul", "Aug", "Sep","Oct","Nov","Dec");</code>
|
||||
*
|
||||
* @param array month names.
|
||||
*/
|
||||
function setAbbreviatedMonthNames($value)
|
||||
{
|
||||
$this->data['monthNames']['format']['abbreviated'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-dimensional array of type String containing the
|
||||
* culture-specific full names of the months. The array for
|
||||
* InvariantInfo contains "January", "February", "March", "April",
|
||||
* "May", "June", "July", "August", "September", "October", "November",
|
||||
* and "December"
|
||||
*
|
||||
* @return array month names.
|
||||
*/
|
||||
function getMonthNames()
|
||||
{
|
||||
return $this->data['monthNames']['format']['wide'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the month names. The value should be
|
||||
* an array of string starting with Janurary and ends in December.
|
||||
* For example,
|
||||
* <code>array("January", "February", "March", "April", "May", "June",
|
||||
* "July", "August", "September","October","November","December");</code>
|
||||
*
|
||||
* @param array month names.
|
||||
*/
|
||||
function setMonthNames($value)
|
||||
{
|
||||
$this->data['monthNames']['format']['wide'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A string containing the name of the era.
|
||||
*
|
||||
* @param int era The integer representing the era.
|
||||
* @return string the era name.
|
||||
*/
|
||||
function getEra($era)
|
||||
{
|
||||
return $this->data['eras']['abbreviated'][$era];
|
||||
}
|
||||
|
||||
/**
|
||||
* The string designator for hours that are "ante meridiem" (before noon).
|
||||
* The default for InvariantInfo is "AM".
|
||||
*
|
||||
* @return string AM designator.
|
||||
*/
|
||||
function getAMDesignator()
|
||||
{
|
||||
$result = $this->getAMPMMarkers();
|
||||
|
||||
return $result[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AM Designator. For example, 'AM'.
|
||||
*
|
||||
* @param string AM designator.
|
||||
*/
|
||||
function setAMDesignator($value)
|
||||
{
|
||||
$markers = $this->getAMPMMarkers();
|
||||
$markers[0] = $value;
|
||||
$this->setAMPMMarkers($markers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The string designator for hours that are "post meridiem" (after noon).
|
||||
* The default for InvariantInfo is "PM".
|
||||
*
|
||||
* @return string PM designator.
|
||||
*/
|
||||
function getPMDesignator()
|
||||
{
|
||||
$result = $this->getAMPMMarkers();
|
||||
|
||||
return $result[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PM Designator. For example, 'PM'.
|
||||
*
|
||||
* @param string PM designator.
|
||||
*/
|
||||
function setPMDesignator($value)
|
||||
{
|
||||
$markers = $this->getAMPMMarkers();
|
||||
$markers[1] = $value;
|
||||
$this->setAMPMMarkers($markers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AM and PM markers array.
|
||||
* Default InvariantInfo for AM and PM is <code>array('AM','PM');</code>
|
||||
*
|
||||
* @return array AM and PM markers
|
||||
*/
|
||||
function getAMPMMarkers()
|
||||
{
|
||||
return $this->data['AmPmMarkers'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AM and PM markers array.
|
||||
* For example <code>array('AM','PM');</code>
|
||||
*
|
||||
* @param array AM and PM markers
|
||||
*/
|
||||
function setAMPMMarkers($value)
|
||||
{
|
||||
$this->data['AmPmMarkers'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full time pattern "HH:mm:ss z" (default).
|
||||
* This is culture sensitive.
|
||||
*
|
||||
* @return string pattern "HH:mm:ss z".
|
||||
*/
|
||||
function getFullTimePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the long time pattern "HH:mm:ss z" (default).
|
||||
* This is culture sensitive.
|
||||
*
|
||||
* @return string pattern "HH:mm:ss z".
|
||||
*/
|
||||
function getLongTimePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the medium time pattern "HH:mm:ss" (default).
|
||||
* This is culture sensitive.
|
||||
*
|
||||
* @return string pattern "HH:mm:ss".
|
||||
*/
|
||||
function getMediumTimePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the short time pattern "HH:mm" (default).
|
||||
* This is culture sensitive.
|
||||
*
|
||||
* @return string pattern "HH:mm".
|
||||
*/
|
||||
function getShortTimePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full date pattern "EEEE, yyyy MMMM dd" (default).
|
||||
* This is culture sensitive.
|
||||
* @return string pattern "EEEE, yyyy MMMM dd".
|
||||
*/
|
||||
function getFullDatePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][4];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the long date pattern "yyyy MMMM d" (default).
|
||||
* This is culture sensitive.
|
||||
* @return string pattern "yyyy MMMM d".
|
||||
*/
|
||||
function getLongDatePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][5];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the medium date pattern "yyyy MMMM d" (default).
|
||||
* This is culture sensitive.
|
||||
* @return string pattern "yyyy MMM d".
|
||||
*/
|
||||
function getMediumDatePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][6];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the short date pattern "yy/MM/dd" (default).
|
||||
* This is culture sensitive.
|
||||
*
|
||||
* @return string pattern "yy/MM/dd".
|
||||
*/
|
||||
function getShortDatePattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][7];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date time order pattern, "{1} {0}" (default).
|
||||
* This is culture sensitive.
|
||||
*
|
||||
* @return string pattern "{1} {0}".
|
||||
*/
|
||||
function getDateTimeOrderPattern()
|
||||
{
|
||||
return $this->data['DateTimePatterns'][8];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the date and time in a culture sensitive paterrn.
|
||||
* The default is "Date Time".
|
||||
*
|
||||
* @return string date and time formated
|
||||
*/
|
||||
function formatDateTime($date, $time)
|
||||
{
|
||||
return str_replace(array('{0}','{1}'), array($time, $date), $this->getDateTimeOrderPattern());
|
||||
}
|
||||
}
|
198
lib/symfony/i18n/sfI18N.class.php
Executable file
198
lib/symfony/i18n/sfI18N.class.php
Executable file
@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the symfony package.
|
||||
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @version SVN: $Id: sfI18N.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
*/
|
||||
class sfI18N
|
||||
{
|
||||
protected
|
||||
$context = null,
|
||||
$globalMessageSource = null,
|
||||
$messageSource = null,
|
||||
$messageFormat = null;
|
||||
|
||||
static protected
|
||||
$instance = null;
|
||||
|
||||
static public function getInstance()
|
||||
{
|
||||
if (!isset(self::$instance))
|
||||
{
|
||||
$class = __CLASS__;
|
||||
self::$instance = new $class();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function initialize($context)
|
||||
{
|
||||
$this->context = $context;
|
||||
|
||||
$this->globalMessageSource = $this->createMessageSource(sfConfig::get('sf_app_i18n_dir'));
|
||||
$this->globalMessageFormat = $this->createMessageFormat($this->globalMessageSource);
|
||||
}
|
||||
|
||||
public function setMessageSourceDir($dir, $culture)
|
||||
{
|
||||
$this->messageSource = $this->createMessageSource($dir);
|
||||
$this->messageSource->setCulture($culture);
|
||||
$this->messageFormat = $this->createMessageFormat($this->messageSource);
|
||||
|
||||
$this->globalMessageSource->setCulture($culture);
|
||||
$this->globalMessageFormat = $this->createMessageFormat($this->globalMessageSource);
|
||||
}
|
||||
|
||||
public function createMessageSource($dir)
|
||||
{
|
||||
if (in_array(sfConfig::get('sf_i18n_source'), array('Creole', 'MySQL', 'SQLite')))
|
||||
{
|
||||
$messageSource = sfMessageSource::factory(sfConfig::get('sf_i18n_source'), sfConfig::get('sf_i18n_database', 'default'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$messageSource = sfMessageSource::factory(sfConfig::get('sf_i18n_source'), $dir);
|
||||
}
|
||||
|
||||
if (sfConfig::get('sf_i18n_cache'))
|
||||
{
|
||||
$subdir = str_replace(str_replace('/', DIRECTORY_SEPARATOR, sfConfig::get('sf_root_dir')), '', $dir);
|
||||
$cacheDir = str_replace('/', DIRECTORY_SEPARATOR, sfConfig::get('sf_i18n_cache_dir').$subdir);
|
||||
|
||||
$cache = new sfMessageCache();
|
||||
$cache->initialize(array(
|
||||
'cacheDir' => $cacheDir,
|
||||
'lifeTime' => 86400,
|
||||
));
|
||||
|
||||
$messageSource->setCache($cache);
|
||||
}
|
||||
|
||||
return $messageSource;
|
||||
}
|
||||
|
||||
public function createMessageFormat($source)
|
||||
{
|
||||
$messageFormat = new sfMessageFormat($source, sfConfig::get('sf_charset'));
|
||||
|
||||
if (sfConfig::get('sf_debug') && sfConfig::get('sf_i18n_debug'))
|
||||
{
|
||||
$messageFormat->setUntranslatedPS(array(sfConfig::get('sf_i18n_untranslated_prefix'), sfConfig::get('sf_i18n_untranslated_suffix')));
|
||||
}
|
||||
|
||||
return $messageFormat;
|
||||
}
|
||||
|
||||
public function setCulture($culture)
|
||||
{
|
||||
if ($this->messageSource)
|
||||
{
|
||||
$this->messageSource->setCulture($culture);
|
||||
$this->messageFormat = $this->createMessageFormat($this->messageSource);
|
||||
}
|
||||
|
||||
$this->globalMessageSource->setCulture($culture);
|
||||
$this->globalMessageFormat = $this->createMessageFormat($this->globalMessageSource);
|
||||
}
|
||||
|
||||
public function getMessageSource()
|
||||
{
|
||||
return $this->messageSource;
|
||||
}
|
||||
|
||||
public function getGlobalMessageSource()
|
||||
{
|
||||
return $this->globalMessageSource;
|
||||
}
|
||||
|
||||
public function getMessageFormat()
|
||||
{
|
||||
return $this->messageFormat;
|
||||
}
|
||||
|
||||
public function getGlobalMessageFormat()
|
||||
{
|
||||
return $this->globalMessageFormat;
|
||||
}
|
||||
|
||||
public function __($string, $args = array(), $catalogue = 'messages')
|
||||
{
|
||||
$retval = $this->messageFormat->formatExists($string, $args, $catalogue);
|
||||
|
||||
if (!$retval)
|
||||
{
|
||||
$retval = $this->globalMessageFormat->format($string, $args, $catalogue);
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
public static function getCountry($iso, $culture)
|
||||
{
|
||||
$c = new sfCultureInfo($culture);
|
||||
$countries = $c->getCountries();
|
||||
|
||||
return (array_key_exists($iso, $countries)) ? $countries[$iso] : '';
|
||||
}
|
||||
|
||||
public static function getNativeName($culture)
|
||||
{
|
||||
$cult = new sfCultureInfo($culture);
|
||||
return $cult->getNativeName();
|
||||
}
|
||||
|
||||
// Return timestamp from a date formatted with a given culture
|
||||
public static function getTimestampForCulture($date, $culture)
|
||||
{
|
||||
list($d, $m, $y) = self::getDateForCulture($date, $culture);
|
||||
return mktime(0, 0, 0, $m, $d, $y);
|
||||
}
|
||||
|
||||
// Return a d, m and y from a date formatted with a given culture
|
||||
public static function getDateForCulture($date, $culture)
|
||||
{
|
||||
if (!$date) return 0;
|
||||
|
||||
$dateFormatInfo = @sfDateTimeFormatInfo::getInstance($culture);
|
||||
$dateFormat = $dateFormatInfo->getShortDatePattern();
|
||||
|
||||
// We construct the regexp based on date format
|
||||
$dateRegexp = preg_replace('/[dmy]+/i', '(\d+)', $dateFormat);
|
||||
|
||||
// We parse date format to see where things are (m, d, y)
|
||||
$a = array(
|
||||
'd' => strpos($dateFormat, 'd'),
|
||||
'm' => strpos($dateFormat, 'M'),
|
||||
'y' => strpos($dateFormat, 'y'),
|
||||
);
|
||||
$tmp = array_flip($a);
|
||||
ksort($tmp);
|
||||
$i = 0;
|
||||
$c = array();
|
||||
foreach ($tmp as $value) $c[++$i] = $value;
|
||||
$datePositions = array_flip($c);
|
||||
|
||||
// We find all elements
|
||||
if (preg_match("~$dateRegexp~", $date, $matches))
|
||||
{
|
||||
// We get matching timestamp
|
||||
return array($matches[$datePositions['d']], $matches[$datePositions['m']], $matches[$datePositions['y']]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
126
lib/symfony/i18n/sfIMessageSource.class.php
Executable file
126
lib/symfony/i18n/sfIMessageSource.class.php
Executable file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfIMessageSource interface 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 $Id: sfIMessageSource.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* sfIMessageSource interface.
|
||||
*
|
||||
* All messages source used by MessageFormat must be of sfIMessageSource.
|
||||
* It defines a set of operations to add and retrieve messages from the
|
||||
* message source. In addition, message source can load a particular
|
||||
* catalogue.
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 17:40:19 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
interface sfIMessageSource
|
||||
{
|
||||
/**
|
||||
* Loads the translation table for this particular catalogue.
|
||||
* The translation should be loaded in the following order.
|
||||
* # [1] call getCatalogueList($catalogue) to get a list of variants for for the specified $catalogue.
|
||||
* # [2] for each of the variants, call getSource($variant) to get the resource, could be a file or catalogue ID.
|
||||
* # [3] verify that this resource is valid by calling isValidSource($source)
|
||||
* # [4] try to get the messages from the cache
|
||||
* # [5] if a cache miss, call load($source) to load the message array
|
||||
* # [6] store the messages to cache.
|
||||
* # [7] continue with the foreach loop, e.g. goto [2].
|
||||
*
|
||||
* @param string a catalogue to load
|
||||
* @return boolean true if loaded, false otherwise.
|
||||
*/
|
||||
function load($catalogue = 'messages');
|
||||
|
||||
/**
|
||||
* Gets the translation table. This includes all the loaded sections.
|
||||
* It must return a 2 level array of translation strings.
|
||||
* # "catalogue+variant" the catalogue and its variants.
|
||||
* # "source string" translation keys, and its translations.
|
||||
* <code>
|
||||
* array('catalogue+variant' =>
|
||||
* array('source string' => 'target string', ...)
|
||||
* ...),
|
||||
* ...);
|
||||
* </code>
|
||||
*
|
||||
* @return array 2 level array translation table.
|
||||
*/
|
||||
function read();
|
||||
|
||||
/**
|
||||
* Saves the list of untranslated blocks to the translation source.
|
||||
* If the translation was not found, you should add those
|
||||
* strings to the translation source via the <b>append()</b> method.
|
||||
*
|
||||
* @param string the catalogue to add to
|
||||
* @return boolean true if saved successfuly, false otherwise.
|
||||
*/
|
||||
function save($catalogue = 'messages');
|
||||
|
||||
/**
|
||||
* Adds a untranslated message to the source. Need to call save()
|
||||
* to save the messages to source.
|
||||
*
|
||||
* @param string message to add
|
||||
* @return void
|
||||
*/
|
||||
function append($message);
|
||||
|
||||
/**
|
||||
* Deletes a particular message from the specified catalogue.
|
||||
*
|
||||
* @param string the source message to delete.
|
||||
* @param string the catalogue to delete from.
|
||||
* @return boolean true if deleted, false otherwise.
|
||||
*/
|
||||
function delete($message, $catalogue = 'messages');
|
||||
|
||||
/**
|
||||
* Updates the translation.
|
||||
*
|
||||
* @param string the source string.
|
||||
* @param string the new translation string.
|
||||
* @param string comments
|
||||
* @param string the catalogue of the translation.
|
||||
* @return boolean true if translation was updated, false otherwise.
|
||||
*/
|
||||
function update($text, $target, $comments, $catalogue = 'messages');
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue as key and all it variants as value.
|
||||
*
|
||||
* @return array list of catalogues
|
||||
*/
|
||||
function catalogues();
|
||||
|
||||
/**
|
||||
* Set the culture for this particular message source.
|
||||
*
|
||||
* @param string the Culture name.
|
||||
*/
|
||||
function setCulture($culture);
|
||||
|
||||
/**
|
||||
* Get the culture identifier for the source.
|
||||
*
|
||||
* @return string culture identifier.
|
||||
*/
|
||||
function getCulture();
|
||||
}
|
139
lib/symfony/i18n/sfMessageCache.class.php
Executable file
139
lib/symfony/i18n/sfMessageCache.class.php
Executable file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* Translation table cache.
|
||||
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version $Id: sfMessageCache.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Cache the translation table into the file system.
|
||||
* It can cache each cataloug+variant or just the whole section.
|
||||
*
|
||||
* @package System.I18N.core
|
||||
* @author $Author: weizhuo $
|
||||
* @version $Id: sfMessageCache.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
*/
|
||||
class sfMessageCache
|
||||
{
|
||||
/**
|
||||
* Cache Lite instance.
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Cache life time, default is 1 year.
|
||||
*/
|
||||
protected $lifetime = 3153600;
|
||||
|
||||
/**
|
||||
* Creates a new Translation cache.
|
||||
*
|
||||
* @param string $cacheDir Directory to store the cache files.
|
||||
*/
|
||||
public function initialize($options = array())
|
||||
{
|
||||
$this->cache = new sfFileCache();
|
||||
$this->cache->initialize($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache life time.
|
||||
*
|
||||
* @return int Cache life time.
|
||||
*/
|
||||
public function getLifeTime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache life time.
|
||||
*
|
||||
* @param int $time Cache life time.
|
||||
*/
|
||||
public function setLifeTime($time)
|
||||
{
|
||||
$this->lifetime = intval($time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache file ID based section and locale.
|
||||
*
|
||||
* @param string $catalogue The translation section.
|
||||
* @param string $culture The translation locale, e.g. "en_AU".
|
||||
*/
|
||||
protected function getID($catalogue, $culture)
|
||||
{
|
||||
return $culture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache file GROUP based section and locale.
|
||||
*
|
||||
* @param string $catalogue The translation section.
|
||||
* @param string $culture The translation locale, e.g. "en_AU".
|
||||
*/
|
||||
protected function getGroup($catalogue, $culture)
|
||||
{
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data from the cache.
|
||||
*
|
||||
* @param string $catalogue The translation section.
|
||||
* @param string $culture The translation locale, e.g. "en_AU".
|
||||
* @param string $filename If the source is a file, this file's modified time is newer than the cache's modified time, no cache hit.
|
||||
* @return mixed Boolean FALSE if no cache hit. Otherwise, translation
|
||||
* table data for the specified section and locale.
|
||||
*/
|
||||
public function get($catalogue, $culture, $lastmodified = 0)
|
||||
{
|
||||
$ID = $this->getID($catalogue, $culture);
|
||||
$group = $this->getGroup($catalogue, $culture);
|
||||
|
||||
if ($lastmodified <= 0 || $lastmodified > $this->cache->lastModified($ID, $group))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return unserialize($this->cache->get($ID, $group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the data to cache for the specified section and locale.
|
||||
*
|
||||
* @param array $data The data to save.
|
||||
* @param string $catalogue The translation section.
|
||||
* @param string $culture The translation locale, e.g. "en_AU".
|
||||
*/
|
||||
public function save($data, $catalogue, $culture)
|
||||
{
|
||||
$ID = $this->getID($catalogue, $culture);
|
||||
$group = $this->getGroup($catalogue, $culture);
|
||||
|
||||
return $this->cache->set($ID, $group, serialize($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the cache for the specified section and locale.
|
||||
*
|
||||
* @param string $catalogue The translation section.
|
||||
* @param string $culture The translation locale, e.g. "en_AU".
|
||||
*/
|
||||
public function clean($catalogue, $culture)
|
||||
{
|
||||
$group = $this->getGroup($catalogue, $culture);
|
||||
$this->cache->clean($group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the cache. Deletes all the cache files.
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->cache->clean();
|
||||
}
|
||||
}
|
301
lib/symfony/i18n/sfMessageFormat.class.php
Executable file
301
lib/symfony/i18n/sfMessageFormat.class.php
Executable file
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfMessageFormat 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 $Id: sfMessageFormat.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the encoding utilities
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/util.php');
|
||||
|
||||
/**
|
||||
* sfMessageFormat class.
|
||||
*
|
||||
* Format a message, that is, for a particular message find the
|
||||
* translated message. The following is an example using
|
||||
* a SQLite database to store the translation message.
|
||||
* Create a new message format instance and echo "Hello"
|
||||
* in simplified Chinese. This assumes that the world "Hello"
|
||||
* is translated in the database.
|
||||
*
|
||||
* <code>
|
||||
* $source = sfMessageSource::factory('SQLite', 'sqlite://messages.db');
|
||||
* $source->setCulture('zh_CN');
|
||||
* $source->setCache(new sfMessageCache('./tmp'));
|
||||
*
|
||||
* $formatter = new sfMessageFormat($source);
|
||||
*
|
||||
* echo $formatter->format('Hello');
|
||||
* </code>
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 20:46:16 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfMessageFormat
|
||||
{
|
||||
/**
|
||||
* The message source.
|
||||
* @var sfMessageSource
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* A list of loaded message catalogues.
|
||||
* @var array
|
||||
*/
|
||||
protected $catalogues = array();
|
||||
|
||||
/**
|
||||
* The translation messages.
|
||||
* @var array
|
||||
*/
|
||||
protected $messages = array();
|
||||
|
||||
/**
|
||||
* A list of untranslated messages.
|
||||
* @var array
|
||||
*/
|
||||
protected $untranslated = array();
|
||||
|
||||
/**
|
||||
* The prefix and suffix to append to untranslated messages.
|
||||
* @var array
|
||||
*/
|
||||
protected $postscript = array('', '');
|
||||
|
||||
/**
|
||||
* Set the default catalogue.
|
||||
* @var string
|
||||
*/
|
||||
public $Catalogue;
|
||||
|
||||
/**
|
||||
* Output encoding charset
|
||||
* @var string
|
||||
*/
|
||||
protected $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a new instance of sfMessageFormat using the messages
|
||||
* from the supplied message source.
|
||||
*
|
||||
* @param MessageSource the source of translation messages.
|
||||
* @param string charset for the message output.
|
||||
*/
|
||||
function __construct(sfIMessageSource $source, $charset = 'UTF-8')
|
||||
{
|
||||
$this->source = $source;
|
||||
$this->setCharset($charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the charset for message output.
|
||||
*
|
||||
* @param string charset, default is UTF-8
|
||||
*/
|
||||
public function setCharset($charset)
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the charset for message output. Default is UTF-8.
|
||||
*
|
||||
* @return string charset, default UTF-8
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the message from a particular catalogue. A listed
|
||||
* loaded catalogues is kept to prevent reload of the same
|
||||
* catalogue. The load catalogue messages are stored
|
||||
* in the $this->message array.
|
||||
*
|
||||
* @param string message catalogue to load.
|
||||
*/
|
||||
protected function loadCatalogue($catalogue)
|
||||
{
|
||||
if (in_array($catalogue, $this->catalogues))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->source->load($catalogue))
|
||||
{
|
||||
$this->messages[$catalogue] = $this->source->read();
|
||||
$this->catalogues[] = $catalogue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the string. That is, for a particular string find
|
||||
* the corresponding translation. Variable subsitution is performed
|
||||
* for the $args parameter. A different catalogue can be specified
|
||||
* using the $catalogue parameter.
|
||||
* The output charset is determined by $this->getCharset();
|
||||
*
|
||||
* @param string the string to translate.
|
||||
* @param array a list of string to substitute.
|
||||
* @param string get the translation from a particular message
|
||||
* @param string charset, the input AND output charset catalogue.
|
||||
* @return string translated string.
|
||||
*/
|
||||
public function format($string, $args = array(), $catalogue = null, $charset = null)
|
||||
{
|
||||
if (empty($charset))
|
||||
{
|
||||
$charset = $this->getCharset();
|
||||
}
|
||||
|
||||
$s = $this->formatString(I18N_toUTF8($string, $charset), $args, $catalogue);
|
||||
|
||||
return I18N_toEncoding($s, $charset);
|
||||
}
|
||||
|
||||
public function formatExists($string, $args = array(), $catalogue = null, $charset = null)
|
||||
{
|
||||
if (empty($charset))
|
||||
{
|
||||
$charset = $this->getCharset();
|
||||
}
|
||||
|
||||
$s = $this->getFormattedString(I18N_toUTF8($string, $charset), $args, $catalogue);
|
||||
|
||||
return I18N_toEncoding($s, $charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do string translation.
|
||||
*
|
||||
* @param string the string to translate.
|
||||
* @param array a list of string to substitute.
|
||||
* @param string get the translation from a particular message catalogue.
|
||||
* @return string translated string.
|
||||
*/
|
||||
protected function formatString($string, $args = array(), $catalogue = null)
|
||||
{
|
||||
if (empty($args))
|
||||
{
|
||||
$args = array();
|
||||
}
|
||||
|
||||
$target = $this->getFormattedString($string, $args, $catalogue);
|
||||
|
||||
// well we did not find the translation string.
|
||||
if (!$target)
|
||||
{
|
||||
$this->source->append($string);
|
||||
$target = $this->postscript[0].$this->replaceArgs($string, $args).$this->postscript[1];
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
protected function getFormattedString($string, $args = array(), $catalogue = null)
|
||||
{
|
||||
if (empty($catalogue))
|
||||
{
|
||||
$catalogue = empty($this->catalogue) ? 'messages' : $this->catalogue;
|
||||
}
|
||||
|
||||
if (empty($args))
|
||||
{
|
||||
$args = array();
|
||||
}
|
||||
|
||||
$this->loadCatalogue($catalogue);
|
||||
|
||||
foreach ($this->messages[$catalogue] as $variant)
|
||||
{
|
||||
// foreach of the translation units
|
||||
foreach ($variant as $source => $result)
|
||||
{
|
||||
// we found it, so return the target translation
|
||||
if ($source == $string)
|
||||
{
|
||||
// check if it contains only strings.
|
||||
if (is_string($result))
|
||||
{
|
||||
$target = $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$target = $result[0];
|
||||
}
|
||||
|
||||
// found, but untranslated
|
||||
if (empty($target))
|
||||
{
|
||||
return $this->postscript[0].$this->replaceArgs($string, $args).$this->postscript[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->replaceArgs($target, $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function replaceArgs($string, $args)
|
||||
{
|
||||
// replace object with strings
|
||||
foreach ($args as $key => $value)
|
||||
{
|
||||
if (is_object($value) && method_exists($value, '__toString'))
|
||||
{
|
||||
$args[$key] = $value->__toString();
|
||||
}
|
||||
}
|
||||
|
||||
return strtr($string, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message source.
|
||||
*
|
||||
* @return MessageSource
|
||||
*/
|
||||
function getSource()
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix and suffix to append to untranslated messages.
|
||||
* e.g. $postscript=array('[T]','[/T]'); will output
|
||||
* "[T]Hello[/T]" if the translation for "Hello" can not be determined.
|
||||
*
|
||||
* @param array first element is the prefix, second element the suffix.
|
||||
*/
|
||||
function setUntranslatedPS($postscript)
|
||||
{
|
||||
if (is_array($postscript) && count($postscript) >= 2)
|
||||
{
|
||||
$this->postscript[0] = $postscript[0];
|
||||
$this->postscript[1] = $postscript[1];
|
||||
}
|
||||
}
|
||||
}
|
325
lib/symfony/i18n/sfMessageSource.class.php
Executable file
325
lib/symfony/i18n/sfMessageSource.class.php
Executable file
@ -0,0 +1,325 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfMessageSource 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 $Id: sfMessageSource.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract sfMessageSource class.
|
||||
*
|
||||
* The base class for all sfMessageSources. Message sources must be instantiated
|
||||
* using the factory method. The default valid sources are
|
||||
*
|
||||
* # XLIFF -- using XML XLIFF format to store the translation messages.
|
||||
* # SQLite -- Store the translation messages in a SQLite database.
|
||||
* # MySQL -- Using a MySQL database to store the messages.
|
||||
* # gettext -- Translated messages are stored in the gettext format.
|
||||
*
|
||||
* A custom message source can be instantiated by specifying the filename
|
||||
* parameter to point to the custom class file. E.g.
|
||||
* <code>
|
||||
* $resource = '...'; //custom message source resource
|
||||
* $classfile = '../sfMessageSource_MySource.php'; //custom message source
|
||||
* $source = sfMessageSource::factory('MySource', $resource, $classfile);
|
||||
* </code>
|
||||
*
|
||||
* If you are writting your own message sources, pay attention to the
|
||||
* loadCatalogue method. It details how the resources are loaded and cached.
|
||||
* See also the existing message source types as examples.
|
||||
*
|
||||
* The following example instantiates a MySQL message source, set the culture,
|
||||
* set the cache handler, and use the source in a message formatter.
|
||||
* The messages are store in a database named "messages". The source parameter
|
||||
* for the actory method is a PEAR DB style DSN.
|
||||
* <code>
|
||||
* $dsn = 'mysql://username:password@localhost/messages';
|
||||
* $source = sfMessageSource::factory('MySQL', $dsn);
|
||||
*
|
||||
* //set the culture and cache, store the cache in the /tmp directory.
|
||||
* $source->setCulture('en_AU')l
|
||||
* $source->setCache(new sfMessageCache('/tmp'));
|
||||
*
|
||||
* $formatter = new sfMessageFormat($source);
|
||||
* </code>
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 19:55:49 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
abstract class sfMessageSource implements sfIMessageSource
|
||||
{
|
||||
/**
|
||||
* The culture name for this message source.
|
||||
* @var string
|
||||
*/
|
||||
protected $culture;
|
||||
|
||||
/**
|
||||
* Array of translation messages.
|
||||
* @var array
|
||||
*/
|
||||
protected $messages = array();
|
||||
|
||||
/**
|
||||
* The source of message translations.
|
||||
* @var string
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* The translation cache.
|
||||
* @var sfMessageCache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
protected $untranslated = array();
|
||||
|
||||
/**
|
||||
* Private constructor. sfMessageSource must be initialized using
|
||||
* the factory method.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
//throw new sfException('Please use the factory method to instantiate.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to instantiate a new sfMessageSource depending on the
|
||||
* source type. The built-in source types are 'XLIFF', 'SQLite',
|
||||
* 'MySQL', 'gettext' and Creole. The source parameter is dependent on the
|
||||
* source type. For 'gettext' and 'XLIFF', it should point to the directory
|
||||
* where the messages are stored. For database types, e.g. 'SQLite' and
|
||||
* 'MySQL', it should be a PEAR DB style DSN string.
|
||||
*
|
||||
* Custom message source are possible by supplying the a filename parameter
|
||||
* in the factory method.
|
||||
*
|
||||
* @param string the message source type.
|
||||
* @param string the location of the resource.
|
||||
* @param string the filename of the custom message source.
|
||||
* @return sfMessageSource a new message source of the specified type.
|
||||
* @throws sfException
|
||||
*/
|
||||
static function factory($type, $source = '.', $filename = '')
|
||||
{
|
||||
if ($filename)
|
||||
{
|
||||
if (!is_file($filename))
|
||||
{
|
||||
throw new sfException(sprintf("File %s not found.", $filename));
|
||||
}
|
||||
|
||||
include_once($filename);
|
||||
}
|
||||
|
||||
$class = 'sfMessageSource_'.$type;
|
||||
if (!class_exists($class))
|
||||
{
|
||||
throw new sfException(sprintf('Unable to find type "%s".', $type));
|
||||
}
|
||||
|
||||
return new $class($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a particular message catalogue. Use read() to
|
||||
* to get the array of messages. The catalogue loading sequence
|
||||
* is as follows:
|
||||
*
|
||||
* # [1] Call getCatalogueList($catalogue) to get a list of variants for for the specified $catalogue.
|
||||
* # [2] For each of the variants, call getSource($variant) to get the resource, could be a file or catalogue ID.
|
||||
* # [3] Verify that this resource is valid by calling isValidSource($source)
|
||||
* # [4] Try to get the messages from the cache
|
||||
* # [5] If a cache miss, call load($source) to load the message array
|
||||
* # [6] Store the messages to cache.
|
||||
* # [7] Continue with the foreach loop, e.g. goto [2].
|
||||
*
|
||||
* @param string a catalogue to load
|
||||
* @return boolean true if loaded, false otherwise.
|
||||
* @see read()
|
||||
*/
|
||||
function load($catalogue = 'messages')
|
||||
{
|
||||
$variants = $this->getCatalogueList($catalogue);
|
||||
|
||||
$this->messages = array();
|
||||
|
||||
foreach ($variants as $variant)
|
||||
{
|
||||
$source = $this->getSource($variant);
|
||||
|
||||
if ($this->isValidSource($source) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$loadData = true;
|
||||
|
||||
if ($this->cache)
|
||||
{
|
||||
$data = $this->cache->get($variant, $this->culture, $this->getLastModified($source));
|
||||
|
||||
if (is_array($data))
|
||||
{
|
||||
$this->messages[$variant] = $data;
|
||||
$loadData = false;
|
||||
}
|
||||
|
||||
unset($data);
|
||||
}
|
||||
|
||||
if ($loadData)
|
||||
{
|
||||
$data = &$this->loadData($source);
|
||||
if (is_array($data))
|
||||
{
|
||||
$this->messages[$variant] = $data;
|
||||
if ($this->cache)
|
||||
{
|
||||
$this->cache->save($data, $variant, $this->culture);
|
||||
}
|
||||
}
|
||||
|
||||
unset($data);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of messages.
|
||||
*
|
||||
* @param parameter
|
||||
* @return array translation messages.
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache handler for this source.
|
||||
*
|
||||
* @return sfMessageCache cache handler
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache handler for caching the messages.
|
||||
*
|
||||
* @param sfMessageCache the cache handler.
|
||||
*/
|
||||
public function setCache(sfMessageCache $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a untranslated message to the source. Need to call save()
|
||||
* to save the messages to source.
|
||||
*
|
||||
* @param string message to add
|
||||
*/
|
||||
public function append($message)
|
||||
{
|
||||
if (!in_array($message, $this->untranslated))
|
||||
{
|
||||
$this->untranslated[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the culture for this message source.
|
||||
*
|
||||
* @param string culture name
|
||||
*/
|
||||
public function setCulture($culture)
|
||||
{
|
||||
$this->culture = $culture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the culture identifier for the source.
|
||||
*
|
||||
* @return string culture identifier.
|
||||
*/
|
||||
public function getCulture()
|
||||
{
|
||||
return $this->culture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified unix-time for this particular catalogue+variant.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return int last modified in unix-time format.
|
||||
*/
|
||||
protected function getLastModified($source)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the message for a particular catalogue+variant.
|
||||
* This methods needs to implemented by subclasses.
|
||||
*
|
||||
* @param string catalogue+variant.
|
||||
* @return array of translation messages.
|
||||
*/
|
||||
protected function &loadData($variant)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source, this could be a filename or database ID.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return string the resource key
|
||||
*/
|
||||
protected function getSource($variant)
|
||||
{
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the source is valid.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return boolean true if valid, false otherwise.
|
||||
*/
|
||||
protected function isValidSource($source)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the variants of a particular catalogue.
|
||||
* This method must be implemented by subclasses.
|
||||
*
|
||||
* @param string catalogue name
|
||||
* @return array list of all variants for this catalogue.
|
||||
*/
|
||||
protected function getCatalogueList($catalogue)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
511
lib/symfony/i18n/sfMessageSource_MySQL.class.php
Executable file
511
lib/symfony/i18n/sfMessageSource_MySQL.class.php
Executable file
@ -0,0 +1,511 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfMessageSource_MySQL 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 $Id: sfMessageSource_MySQL.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the I18N utility file, contains the DSN parser.
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/util.php');
|
||||
|
||||
/**
|
||||
* sfMessageSource_MySQL class.
|
||||
*
|
||||
* Retrieve the message translation from a MySQL database.
|
||||
*
|
||||
* See the MessageSource::factory() method to instantiate this class.
|
||||
*
|
||||
* MySQL schema:
|
||||
*
|
||||
* CREATE TABLE `catalogue` (
|
||||
* `cat_id` int(11) NOT NULL auto_increment,
|
||||
* `name` varchar(100) NOT NULL default '',
|
||||
* `source_lang` varchar(100) NOT NULL default '',
|
||||
* `target_lang` varchar(100) NOT NULL default '',
|
||||
* `date_created` int(11) NOT NULL default '0',
|
||||
* `date_modified` int(11) NOT NULL default '0',
|
||||
* `author` varchar(255) NOT NULL default '',
|
||||
* PRIMARY KEY (`cat_id`)
|
||||
* ) TYPE=InnoDB;
|
||||
*
|
||||
* CREATE TABLE `trans_unit` (
|
||||
* `msg_id` int(11) NOT NULL auto_increment,
|
||||
* `cat_id` int(11) NOT NULL default '1',
|
||||
* `id` varchar(255) NOT NULL default '',
|
||||
* `source` text NOT NULL,
|
||||
* `target` text NOT NULL,
|
||||
* `comments` text NOT NULL,
|
||||
* `date_added` int(11) NOT NULL default '0',
|
||||
* `date_modified` int(11) NOT NULL default '0',
|
||||
* `author` varchar(255) NOT NULL default '',
|
||||
* `translated` tinyint(1) NOT NULL default '0',
|
||||
* PRIMARY KEY (`msg_id`)
|
||||
* ) TYPE=InnoDB;
|
||||
*
|
||||
* Propel schema (in .xml format):
|
||||
*
|
||||
* <database ...>
|
||||
* ...
|
||||
* <table name="catalogue">
|
||||
* <column name="cat_id" type="integer" required="true" primaryKey="true" autoincrement="true" />
|
||||
* <column name="name" type="varchar" size="100" />
|
||||
* <column name="source_lang" type="varchar" size="100" />
|
||||
* <column name="target_lang" type="varchar" size="100" />
|
||||
* <column name="date_created" type="timestamp" />
|
||||
* <column name="date_modified" type="timestamp" />
|
||||
* <column name="author" type="varchar" size="255" />
|
||||
* </table>
|
||||
*
|
||||
* <table name="trans_unit">
|
||||
* <column name="msg_id" type="integer" required="true" primaryKey="true" autoincrement="true" />
|
||||
* <column name="cat_id" type="integer" />
|
||||
* <foreign-key foreignTable="catalogue" onDelete="cascade">
|
||||
* <reference local="cat_id" foreign="cat_id"/>
|
||||
* </foreign-key>
|
||||
* <column name="id" type="varchar" size="255" />
|
||||
* <column name="source" type="longvarchar" />
|
||||
* <column name="target" type="longvarchar" />
|
||||
* <column name="comments" type="longvarchar" />
|
||||
* <column name="date_created" type="timestamp" />
|
||||
* <column name="date_modified" type="timestamp" />
|
||||
* <column name="author" type="varchar" size="255" />
|
||||
* <column name="translated" type="integer" />
|
||||
* </table>
|
||||
* ...
|
||||
* </database>
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 16:58:58 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfMessageSource_MySQL extends sfMessageSource
|
||||
{
|
||||
/**
|
||||
* The datasource string, full DSN to the database.
|
||||
* @var string
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* The DSN array property, parsed by PEAR's DB DSN parser.
|
||||
* @var array
|
||||
*/
|
||||
protected $dsn;
|
||||
|
||||
/**
|
||||
* A resource link to the database
|
||||
* @var db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a new message source using MySQL.
|
||||
*
|
||||
* @param string MySQL datasource, in PEAR's DB DSN format.
|
||||
* @see MessageSource::factory();
|
||||
*/
|
||||
function __construct($source)
|
||||
{
|
||||
$this->source = (string) $source;
|
||||
$this->dsn = parseDSN($this->source);
|
||||
$this->db = $this->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor, closes the database connection.
|
||||
*/
|
||||
function __destruct()
|
||||
{
|
||||
@mysql_close($this->db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the MySQL datasource
|
||||
*
|
||||
* @return resource MySQL connection.
|
||||
* @throws sfException, connection and database errors.
|
||||
*/
|
||||
protected function connect()
|
||||
{
|
||||
$dsninfo = $this->dsn;
|
||||
|
||||
if (isset($dsninfo['protocol']) && $dsninfo['protocol'] == 'unix')
|
||||
{
|
||||
$dbhost = ':'.$dsninfo['socket'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
|
||||
if (!empty($dsninfo['port']))
|
||||
{
|
||||
$dbhost = ':' . $dsninfo['socket'];
|
||||
}
|
||||
}
|
||||
$user = $dsninfo['username'];
|
||||
$pw = $dsninfo['password'];
|
||||
|
||||
$connect_function = 'mysql_connect';
|
||||
|
||||
if ($dbhost && $user && $pw)
|
||||
{
|
||||
$conn = @$connect_function($dbhost, $user, $pw);
|
||||
}
|
||||
elseif ($dbhost && $user)
|
||||
{
|
||||
$conn = @$connect_function($dbhost, $user);
|
||||
}
|
||||
elseif ($dbhost)
|
||||
{
|
||||
$conn = @$connect_function($dbhost);
|
||||
}
|
||||
else
|
||||
{
|
||||
$conn = false;
|
||||
}
|
||||
|
||||
if (empty($conn))
|
||||
{
|
||||
throw new sfException(sprintf('Error in connecting to %s.', $dsninfo));
|
||||
}
|
||||
|
||||
if ($dsninfo['database'])
|
||||
{
|
||||
if (!@mysql_select_db($dsninfo['database'], $conn))
|
||||
{
|
||||
throw new sfException(sprintf('Error in connecting database, dsn: %s.', $dsninfo));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException('Please provide a database for message translation.');
|
||||
}
|
||||
|
||||
return $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database connection.
|
||||
*
|
||||
* @return db database connection.
|
||||
*/
|
||||
public function connection()
|
||||
{
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of messages for a particular catalogue and cultural variant.
|
||||
*
|
||||
* @param string the catalogue name + variant
|
||||
* @return array translation messages.
|
||||
*/
|
||||
protected function &loadData($variant)
|
||||
{
|
||||
$variant = mysql_real_escape_string($variant, $this->db);
|
||||
|
||||
$statement =
|
||||
"SELECT t.id, t.source, t.target, t.comments
|
||||
FROM trans_unit t, catalogue c
|
||||
WHERE c.cat_id = t.cat_id
|
||||
AND c.name = '{$variant}'
|
||||
ORDER BY id ASC";
|
||||
|
||||
$rs = mysql_query($statement, $this->db);
|
||||
|
||||
$result = array();
|
||||
|
||||
while ($row = mysql_fetch_array($rs, MYSQL_NUM))
|
||||
{
|
||||
$source = $row[1];
|
||||
$result[$source][] = $row[2]; //target
|
||||
$result[$source][] = $row[0]; //id
|
||||
$result[$source][] = $row[3]; //comments
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified unix-time for this particular catalogue+variant.
|
||||
* We need to query the database to get the date_modified.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return int last modified in unix-time format.
|
||||
*/
|
||||
protected function getLastModified($source)
|
||||
{
|
||||
$source = mysql_real_escape_string($source, $this->db);
|
||||
|
||||
$rs = mysql_query("SELECT date_modified FROM catalogue WHERE name = '{$source}'", $this->db);
|
||||
|
||||
$result = $rs ? intval(mysql_result($rs, 0)) : 0;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a particular catalogue+variant exists in the database.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return boolean true if the catalogue+variant is in the database, false otherwise.
|
||||
*/
|
||||
protected function isValidSource($variant)
|
||||
{
|
||||
$variant = mysql_real_escape_string ($variant, $this->db);
|
||||
|
||||
$rs = mysql_query("SELECT COUNT(*) FROM catalogue WHERE name = '{$variant}'", $this->db);
|
||||
|
||||
$row = mysql_fetch_array($rs, MYSQL_NUM);
|
||||
|
||||
$result = $row && $row[0] == '1';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the variants of a particular catalogue.
|
||||
*
|
||||
* @param string catalogue name
|
||||
* @return array list of all variants for this catalogue.
|
||||
*/
|
||||
protected function getCatalogueList($catalogue)
|
||||
{
|
||||
$variants = explode('_', $this->culture);
|
||||
|
||||
$catalogues = array($catalogue);
|
||||
|
||||
$variant = null;
|
||||
|
||||
for ($i = 0, $max = count($variants); $i < $max; $i++)
|
||||
{
|
||||
if (strlen($variants[$i]) > 0)
|
||||
{
|
||||
$variant .= $variant ? '_'.$variants[$i] : $variants[$i];
|
||||
$catalogues[] = $catalogue.'.'.$variant;
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($catalogues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves catalogue details, array($cat_id, $variant, $count).
|
||||
*
|
||||
* @param string catalogue
|
||||
* @return array catalogue details, array($cat_id, $variant, $count).
|
||||
*/
|
||||
protected function getCatalogueDetails($catalogue = 'messages')
|
||||
{
|
||||
if (empty($catalogue))
|
||||
{
|
||||
$catalogue = 'messages';
|
||||
}
|
||||
|
||||
$variant = $catalogue.'.'.$this->culture;
|
||||
|
||||
$name = mysql_real_escape_string($this->getSource($variant), $this->db);
|
||||
|
||||
$rs = mysql_query("SELECT cat_id FROM catalogue WHERE name = '{$name}'", $this->db);
|
||||
|
||||
if (mysql_num_rows($rs) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$cat_id = intval(mysql_result($rs, 0));
|
||||
|
||||
// first get the catalogue ID
|
||||
$rs = mysql_query("SELECT COUNT(*) FROM trans_unit WHERE cat_id = {$cat_id}", $this->db);
|
||||
|
||||
$count = intval(mysql_result($rs, 0));
|
||||
|
||||
return array($cat_id, $variant, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the catalogue last modified time.
|
||||
*
|
||||
* @return boolean true if updated, false otherwise.
|
||||
*/
|
||||
protected function updateCatalogueTime($cat_id, $variant)
|
||||
{
|
||||
$time = time();
|
||||
|
||||
$result = mysql_query("UPDATE catalogue SET date_modified = {$time} WHERE cat_id = {$cat_id}", $this->db);
|
||||
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the list of untranslated blocks to the translation source.
|
||||
* If the translation was not found, you should add those
|
||||
* strings to the translation source via the <b>append()</b> method.
|
||||
*
|
||||
* @param string the catalogue to add to
|
||||
* @return boolean true if saved successfuly, false otherwise.
|
||||
*/
|
||||
function save($catalogue = 'messages')
|
||||
{
|
||||
$messages = $this->untranslated;
|
||||
|
||||
if (count($messages) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$details = $this->getCatalogueDetails($catalogue);
|
||||
|
||||
if ($details)
|
||||
{
|
||||
list($cat_id, $variant, $count) = $details;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cat_id <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$inserted = 0;
|
||||
|
||||
$time = time();
|
||||
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
$count++;
|
||||
$inserted++;
|
||||
$message = mysql_real_escape_string($message, $this->db);
|
||||
$statement = "INSERT INTO trans_unit
|
||||
(cat_id,id,source,date_added) VALUES
|
||||
({$cat_id}, {$count},'{$message}',$time)";
|
||||
mysql_query($statement, $this->db);
|
||||
}
|
||||
if ($inserted > 0)
|
||||
{
|
||||
$this->updateCatalogueTime($cat_id, $variant);
|
||||
}
|
||||
|
||||
return $inserted > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a particular message from the specified catalogue.
|
||||
*
|
||||
* @param string the source message to delete.
|
||||
* @param string the catalogue to delete from.
|
||||
* @return boolean true if deleted, false otherwise.
|
||||
*/
|
||||
function delete($message, $catalogue = 'messages')
|
||||
{
|
||||
$details = $this->getCatalogueDetails($catalogue);
|
||||
if ($details)
|
||||
{
|
||||
list($cat_id, $variant, $count) = $details;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$text = mysql_real_escape_string($message, $this->db);
|
||||
|
||||
$statement = "DELETE FROM trans_unit WHERE cat_id = {$cat_id} AND source = '{$message}'";
|
||||
$deleted = false;
|
||||
|
||||
mysql_query($statement, $this->db);
|
||||
|
||||
if (mysql_affected_rows($this->db) == 1)
|
||||
{
|
||||
$deleted = $this->updateCatalogueTime($cat_id, $variant);
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the translation.
|
||||
*
|
||||
* @param string the source string.
|
||||
* @param string the new translation string.
|
||||
* @param string comments
|
||||
* @param string the catalogue of the translation.
|
||||
* @return boolean true if translation was updated, false otherwise.
|
||||
*/
|
||||
function update($text, $target, $comments, $catalogue = 'messages')
|
||||
{
|
||||
$details = $this->getCatalogueDetails($catalogue);
|
||||
if ($details)
|
||||
{
|
||||
list($cat_id, $variant, $count) = $details;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$comments = mysql_real_escape_string($comments, $this->db);
|
||||
$target = mysql_real_escape_string($target, $this->db);
|
||||
$text = mysql_real_escape_string($text, $this->db);
|
||||
|
||||
$time = time();
|
||||
|
||||
$statement = "UPDATE trans_unit SET target = '{$target}', comments = '{$comments}', date_modified = '{$time}' WHERE cat_id = {$cat_id} AND source = '{$text}'";
|
||||
|
||||
$updated = false;
|
||||
|
||||
mysql_query($statement, $this->db);
|
||||
if (mysql_affected_rows($this->db) == 1)
|
||||
{
|
||||
$updated = $this->updateCatalogueTime($cat_id, $variant);
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue as key and all it variants as value.
|
||||
*
|
||||
* @return array list of catalogues
|
||||
*/
|
||||
function catalogues()
|
||||
{
|
||||
$statement = 'SELECT name FROM catalogue ORDER BY name';
|
||||
$rs = mysql_query($statement, $this->db);
|
||||
$result = array();
|
||||
while($row = mysql_fetch_array($rs, MYSQL_NUM))
|
||||
{
|
||||
$details = explode('.', $row[0]);
|
||||
if (!isset($details[1]))
|
||||
{
|
||||
$details[1] = null;
|
||||
}
|
||||
|
||||
$result[] = $details;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
429
lib/symfony/i18n/sfMessageSource_SQLite.class.php
Executable file
429
lib/symfony/i18n/sfMessageSource_SQLite.class.php
Executable file
@ -0,0 +1,429 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfMessageSource_SQLite 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 $Id: sfMessageSource_SQLite.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the I18N utility file, contains the DSN parser.
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/util.php');
|
||||
|
||||
/**
|
||||
* sfMessageSource_SQLite class.
|
||||
*
|
||||
* Retrieve the message translation from a SQLite database.
|
||||
*
|
||||
* See the MessageSource::factory() method to instantiate this class.
|
||||
*
|
||||
* SQLite schema:
|
||||
*
|
||||
* CREATE TABLE catalogue (
|
||||
* cat_id INTEGER PRIMARY KEY,
|
||||
* name VARCHAR NOT NULL,
|
||||
* source_lang VARCHAR ,
|
||||
* target_lang VARCHAR ,
|
||||
* date_created INT,
|
||||
* date_modified INT,
|
||||
* author VARCHAR);
|
||||
*
|
||||
* CREATE TABLE trans_unit (
|
||||
* msg_id INTEGER PRIMARY KEY,
|
||||
* cat_id INTEGER NOT NULL DEFAULT '1',
|
||||
* id VARCHAR,
|
||||
* source TEXT,
|
||||
* target TEXT,
|
||||
* comments TEXT,
|
||||
* date_added INT,
|
||||
* date_modified INT,
|
||||
* author VARCHAR,
|
||||
* translated INT(1) NOT NULL DEFAULT '0');
|
||||
*
|
||||
* Propel schema (in .xml format):
|
||||
*
|
||||
* <database ...>
|
||||
* ...
|
||||
* <table name="catalogue">
|
||||
* <column name="cat_id" type="integer" required="true" primaryKey="true" autoincrement="true" />
|
||||
* <column name="name" type="varchar" size="100" />
|
||||
* <column name="source_lang" type="varchar" size="100" />
|
||||
* <column name="target_lang" type="varchar" size="100" />
|
||||
* <column name="date_created" type="timestamp" />
|
||||
* <column name="date_modified" type="timestamp" />
|
||||
* <column name="author" type="varchar" size="255" />
|
||||
* </table>
|
||||
*
|
||||
* <table name="trans_unit">
|
||||
* <column name="msg_id" type="integer" required="true" primaryKey="true" autoincrement="true" />
|
||||
* <column name="cat_id" type="integer" />
|
||||
* <foreign-key foreignTable="catalogue" onDelete="cascade">
|
||||
* <reference local="cat_id" foreign="cat_id"/>
|
||||
* </foreign-key>
|
||||
* <column name="id" type="varchar" size="255" />
|
||||
* <column name="source" type="longvarchar" />
|
||||
* <column name="target" type="longvarchar" />
|
||||
* <column name="comments" type="longvarchar" />
|
||||
* <column name="date_created" type="timestamp" />
|
||||
* <column name="date_modified" type="timestamp" />
|
||||
* <column name="author" type="varchar" size="255" />
|
||||
* <column name="translated" type="integer" />
|
||||
* </table>
|
||||
* ...
|
||||
* </database>
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 16:58:58 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfMessageSource_SQLite extends sfMessageSource
|
||||
{
|
||||
/**
|
||||
* The SQLite datasource, the filename of the database.
|
||||
* @var string
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a new message source using SQLite.
|
||||
* @see MessageSource::factory();
|
||||
* @param string SQLite datasource, in PEAR's DB DSN format.
|
||||
*/
|
||||
function __construct($source)
|
||||
{
|
||||
$dsn = parseDSN((string) $source);
|
||||
$this->source = $dsn['database'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of messages for a particular catalogue and cultural variant.
|
||||
*
|
||||
* @param string the catalogue name + variant
|
||||
* @return array translation messages.
|
||||
*/
|
||||
protected function &loadData($variant)
|
||||
{
|
||||
$variant = sqlite_escape_string($variant);
|
||||
|
||||
$statement =
|
||||
"SELECT t.id, t.source, t.target, t.comments
|
||||
FROM trans_unit t, catalogue c
|
||||
WHERE c.cat_id = t.cat_id
|
||||
AND c.name = '{$variant}'
|
||||
ORDER BY id ASC";
|
||||
|
||||
$db = sqlite_open($this->source);
|
||||
$rs = sqlite_query($statement, $db);
|
||||
|
||||
$result = array();
|
||||
|
||||
while($row = sqlite_fetch_array($rs, SQLITE_NUM))
|
||||
{
|
||||
$source = $row[1];
|
||||
$result[$source][] = $row[2]; //target
|
||||
$result[$source][] = $row[0]; //id
|
||||
$result[$source][] = $row[3]; //comments
|
||||
}
|
||||
|
||||
sqlite_close($db);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified unix-time for this particular catalogue+variant.
|
||||
* We need to query the database to get the date_modified.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return int last modified in unix-time format.
|
||||
*/
|
||||
protected function getLastModified($source)
|
||||
{
|
||||
$source = sqlite_escape_string($source);
|
||||
|
||||
$db = sqlite_open($this->source);
|
||||
|
||||
$rs = sqlite_query("SELECT date_modified FROM catalogue WHERE name = '{$source}'", $db);
|
||||
|
||||
$result = $rs ? intval(sqlite_fetch_single($rs)) : 0;
|
||||
|
||||
sqlite_close($db);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a particular catalogue+variant exists in the database.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return boolean true if the catalogue+variant is in the database, false otherwise.
|
||||
*/
|
||||
protected function isValidSource($variant)
|
||||
{
|
||||
$variant = sqlite_escape_string($variant);
|
||||
$db = sqlite_open($this->source);
|
||||
$rs = sqlite_query("SELECT COUNT(*) FROM catalogue WHERE name = '{$variant}'", $db);
|
||||
$result = $rs && intval(sqlite_fetch_single($rs));
|
||||
sqlite_close($db);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the variants of a particular catalogue.
|
||||
*
|
||||
* @param string catalogue name
|
||||
* @return array list of all variants for this catalogue.
|
||||
*/
|
||||
protected function getCatalogueList($catalogue)
|
||||
{
|
||||
$variants = explode('_', $this->culture);
|
||||
|
||||
$catalogues = array($catalogue);
|
||||
|
||||
$variant = null;
|
||||
|
||||
for ($i = 0, $max = count($variants); $i < $max; $i++)
|
||||
{
|
||||
if (strlen($variants[$i]) > 0)
|
||||
{
|
||||
$variant .= ($variant) ? '_'.$variants[$i] : $variants[$i];
|
||||
$catalogues[] = $catalogue.'.'.$variant;
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($catalogues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves catalogue details, array($cat_id, $variant, $count).
|
||||
*
|
||||
* @param string catalogue
|
||||
* @return array catalogue details, array($cat_id, $variant, $count).
|
||||
*/
|
||||
protected function getCatalogueDetails($catalogue = 'messages')
|
||||
{
|
||||
if (empty($catalogue))
|
||||
{
|
||||
$catalogue = 'messages';
|
||||
}
|
||||
|
||||
$variant = $catalogue.'.'.$this->culture;
|
||||
|
||||
$name = sqlite_escape_string($this->getSource($variant));
|
||||
|
||||
$db = sqlite_open($this->source);
|
||||
|
||||
$rs = sqlite_query("SELECT cat_id FROM catalogue WHERE name = '{$name}'", $db);
|
||||
|
||||
if (sqlite_num_rows($rs) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$cat_id = intval(sqlite_fetch_single($rs));
|
||||
|
||||
//first get the catalogue ID
|
||||
$rs = sqlite_query("SELECT count(msg_id) FROM trans_unit WHERE cat_id = {$cat_id}", $db);
|
||||
|
||||
$count = intval(sqlite_fetch_single($rs));
|
||||
|
||||
sqlite_close($db);
|
||||
|
||||
return array($cat_id, $variant, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the catalogue last modified time.
|
||||
*
|
||||
* @return boolean true if updated, false otherwise.
|
||||
*/
|
||||
protected function updateCatalogueTime($cat_id, $variant, $db)
|
||||
{
|
||||
$time = time();
|
||||
|
||||
$result = sqlite_query("UPDATE catalogue SET date_modified = {$time} WHERE cat_id = {$cat_id}", $db);
|
||||
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the list of untranslated blocks to the translation source.
|
||||
* If the translation was not found, you should add those
|
||||
* strings to the translation source via the <b>append()</b> method.
|
||||
*
|
||||
* @param string the catalogue to add to
|
||||
* @return boolean true if saved successfuly, false otherwise.
|
||||
*/
|
||||
function save($catalogue='messages')
|
||||
{
|
||||
$messages = $this->untranslated;
|
||||
|
||||
if (count($messages) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$details = $this->getCatalogueDetails($catalogue);
|
||||
|
||||
if ($details)
|
||||
{
|
||||
list($cat_id, $variant, $count) = $details;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cat_id <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$inserted = 0;
|
||||
|
||||
$db = sqlite_open($this->source);
|
||||
$time = time();
|
||||
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
$message = sqlite_escape_string($message);
|
||||
$statement = "INSERT INTO trans_unit (cat_id,id,source,date_added) VALUES ({$cat_id}, {$count},'{$message}',$time)";
|
||||
if (sqlite_query($statement, $db))
|
||||
{
|
||||
$count++;
|
||||
$inserted++;
|
||||
}
|
||||
}
|
||||
if ($inserted > 0)
|
||||
{
|
||||
$this->updateCatalogueTime($cat_id, $variant, $db);
|
||||
}
|
||||
|
||||
sqlite_close($db);
|
||||
|
||||
return $inserted > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the translation.
|
||||
*
|
||||
* @param string the source string.
|
||||
* @param string the new translation string.
|
||||
* @param string comments
|
||||
* @param string the catalogue of the translation.
|
||||
* @return boolean true if translation was updated, false otherwise.
|
||||
*/
|
||||
function update($text, $target, $comments, $catalogue = 'messages')
|
||||
{
|
||||
$details = $this->getCatalogueDetails($catalogue);
|
||||
if ($details)
|
||||
{
|
||||
list($cat_id, $variant, $count) = $details;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$comments = sqlite_escape_string($comments);
|
||||
$target = sqlite_escape_string($target);
|
||||
$text = sqlite_escape_string($text);
|
||||
|
||||
$time = time();
|
||||
|
||||
$db = sqlite_open($this->source);
|
||||
|
||||
$statement = "UPDATE trans_unit SET target = '{$target}', comments = '{$comments}', date_modified = '{$time}' WHERE cat_id = {$cat_id} AND source = '{$text}'";
|
||||
|
||||
$updated = false;
|
||||
|
||||
if (sqlite_query($statement, $db))
|
||||
{
|
||||
$updated = $this->updateCatalogueTime($cat_id, $variant, $db);
|
||||
}
|
||||
|
||||
sqlite_close($db);
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a particular message from the specified catalogue.
|
||||
*
|
||||
* @param string the source message to delete.
|
||||
* @param string the catalogue to delete from.
|
||||
* @return boolean true if deleted, false otherwise.
|
||||
*/
|
||||
function delete($message, $catalogue = 'messages')
|
||||
{
|
||||
$details = $this->getCatalogueDetails($catalogue);
|
||||
if ($details)
|
||||
{
|
||||
list($cat_id, $variant, $count) = $details;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$db = sqlite_open($this->source);
|
||||
$text = sqlite_escape_string($message);
|
||||
|
||||
$statement = "DELETE FROM trans_unit WHERE cat_id = {$cat_id} AND source = '{$message}'";
|
||||
$deleted = false;
|
||||
|
||||
if (sqlite_query($statement, $db))
|
||||
{
|
||||
$deleted = $this->updateCatalogueTime($cat_id, $variant, $db);
|
||||
}
|
||||
|
||||
sqlite_close($db);
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue as key and all it variants as value.
|
||||
*
|
||||
* @return array list of catalogues
|
||||
*/
|
||||
function catalogues()
|
||||
{
|
||||
$db = sqlite_open($this->source);
|
||||
$statement = 'SELECT name FROM catalogue ORDER BY name';
|
||||
$rs = sqlite_query($statement, $db);
|
||||
$result = array();
|
||||
while ($row = sqlite_fetch_array($rs, SQLITE_NUM))
|
||||
{
|
||||
$details = explode('.',$row[0]);
|
||||
if (!isset($details[1]))
|
||||
{
|
||||
$details[1] = null;
|
||||
}
|
||||
|
||||
$result[] = $details;
|
||||
}
|
||||
sqlite_close($db);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
523
lib/symfony/i18n/sfMessageSource_XLIFF.class.php
Executable file
523
lib/symfony/i18n/sfMessageSource_XLIFF.class.php
Executable file
@ -0,0 +1,523 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfMessageSource_XLIFF 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 $Id: sfMessageSource_XLIFF.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* sfMessageSource_XLIFF class.
|
||||
*
|
||||
* Using XML XLIFF format as the message source for translation.
|
||||
* Details and example of XLIFF can be found in the following URLs.
|
||||
*
|
||||
* # http://www.opentag.com/xliff.htm
|
||||
* # http://www-106.ibm.com/developerworks/xml/library/x-localis2/
|
||||
*
|
||||
* See the MessageSource::factory() method to instantiate this class.
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 16:18:44 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfMessageSource_XLIFF extends sfMessageSource
|
||||
{
|
||||
/**
|
||||
* Message data filename extension.
|
||||
* @var string
|
||||
*/
|
||||
protected $dataExt = '.xml';
|
||||
|
||||
/**
|
||||
* Separator between culture name and source.
|
||||
* @var string
|
||||
*/
|
||||
protected $dataSeparator = '.';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string the directory where the messages are stored.
|
||||
* @see MessageSource::factory();
|
||||
*/
|
||||
function __construct($source)
|
||||
{
|
||||
$this->source = (string) $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the messages from a XLIFF file.
|
||||
*
|
||||
* @param string XLIFF file.
|
||||
* @return array of messages.
|
||||
*/
|
||||
protected function &loadData($filename)
|
||||
{
|
||||
//load it.
|
||||
|
||||
$XML = simplexml_load_file($filename);
|
||||
|
||||
if (!$XML)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$translationUnit = $XML->xpath('//trans-unit');
|
||||
|
||||
$translations = array();
|
||||
|
||||
foreach ($translationUnit as $unit)
|
||||
{
|
||||
$source = (string) $unit->source;
|
||||
$translations[$source][] = (string) $unit->target;
|
||||
$translations[$source][]= (string) $unit['id'];
|
||||
$translations[$source][]= (string) $unit->note;
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified unix-time for this particular catalogue+variant.
|
||||
* Just use the file modified time.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return int last modified in unix-time format.
|
||||
*/
|
||||
protected function getLastModified($source)
|
||||
{
|
||||
return is_file($source) ? filemtime($source) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the XLIFF file for a specific message catalogue and cultural variant.
|
||||
*
|
||||
* @param string message catalogue
|
||||
* @return string full path to the XLIFF file.
|
||||
*/
|
||||
protected function getSource($variant)
|
||||
{
|
||||
return $this->source.'/'.$variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the XLIFF file source is valid.
|
||||
*
|
||||
* @param string XLIFF file
|
||||
* @return boolean true if valid, false otherwise.
|
||||
*/
|
||||
protected function isValidSource($source)
|
||||
{
|
||||
return is_file($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the variants of a particular catalogue.
|
||||
*
|
||||
* @param string catalogue name
|
||||
* @return array list of all variants for this catalogue.
|
||||
*/
|
||||
protected function getCatalogueList($catalogue)
|
||||
{
|
||||
$variants = explode('_', $this->culture);
|
||||
$source = $catalogue.$this->dataExt;
|
||||
|
||||
$catalogues = array($source);
|
||||
|
||||
$variant = null;
|
||||
|
||||
for ($i = 0, $max = count($variants); $i < $max; $i++)
|
||||
{
|
||||
if (strlen($variants[$i]) > 0)
|
||||
{
|
||||
$variant .= $variant ? '_'.$variants[$i] : $variants[$i];
|
||||
$catalogues[] = $catalogue.$this->dataSeparator.$variant.$this->dataExt;
|
||||
}
|
||||
}
|
||||
|
||||
$byDir = $this->getCatalogueByDir($catalogue);
|
||||
$catalogues = array_merge($byDir, array_reverse($catalogues));
|
||||
|
||||
return $catalogues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses through the directory structure to find the catalogues.
|
||||
* This should only be called by getCatalogueList()
|
||||
*
|
||||
* @param string a particular catalogue.
|
||||
* @return array a list of catalogues.
|
||||
* @see getCatalogueList()
|
||||
*/
|
||||
protected function getCatalogueByDir($catalogue)
|
||||
{
|
||||
$variants = explode('_', $this->culture);
|
||||
$catalogues = array();
|
||||
|
||||
$variant = null;
|
||||
|
||||
for ($i = 0, $max = count($variants); $i < $max; $i++)
|
||||
{
|
||||
if (strlen($variants[$i]) > 0)
|
||||
{
|
||||
$variant .= $variant ? '_'.$variants[$i] : $variants[$i];
|
||||
$catalogues[] = $variant.'/'.$catalogue.$this->dataExt;
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($catalogues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue and its culture ID.
|
||||
* E.g. array('messages', 'en_AU')
|
||||
*
|
||||
* @return array list of catalogues
|
||||
* @see getCatalogues()
|
||||
*/
|
||||
public function catalogues()
|
||||
{
|
||||
return $this->getCatalogues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue and its culture ID. This takes care
|
||||
* of directory structures.
|
||||
* E.g. array('messages', 'en_AU')
|
||||
*
|
||||
* @return array list of catalogues
|
||||
*/
|
||||
protected function getCatalogues($dir = null, $variant = null)
|
||||
{
|
||||
$dir = $dir ? $dir : $this->source;
|
||||
$files = scandir($dir);
|
||||
|
||||
$catalogue = array();
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
if (is_dir($dir.'/'.$file) && preg_match('/^[a-z]{2}(_[A-Z]{2,3})?$/', $file))
|
||||
{
|
||||
$catalogue = array_merge($catalogue, $this->getCatalogues($dir.'/'.$file, $file));
|
||||
}
|
||||
|
||||
$pos = strpos($file,$this->dataExt);
|
||||
if ($pos > 0 && substr($file, -1 * strlen($this->dataExt)) == $this->dataExt)
|
||||
{
|
||||
$name = substr($file, 0, $pos);
|
||||
$dot = strrpos($name, $this->dataSeparator);
|
||||
$culture = $variant;
|
||||
$cat = $name;
|
||||
if (is_int($dot))
|
||||
{
|
||||
$culture = substr($name, $dot + 1,strlen($name));
|
||||
$cat = substr($name, 0, $dot);
|
||||
}
|
||||
$details[0] = $cat;
|
||||
$details[1] = $culture;
|
||||
|
||||
$catalogue[] = $details;
|
||||
}
|
||||
}
|
||||
sort($catalogue);
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variant for a catalogue depending on the current culture.
|
||||
*
|
||||
* @param string catalogue
|
||||
* @return string the variant.
|
||||
* @see save()
|
||||
* @see update()
|
||||
* @see delete()
|
||||
*/
|
||||
protected function getVariants($catalogue = 'messages')
|
||||
{
|
||||
if (is_null($catalogue))
|
||||
{
|
||||
$catalogue = 'messages';
|
||||
}
|
||||
|
||||
foreach ($this->getCatalogueList($catalogue) as $variant)
|
||||
{
|
||||
$file = $this->getSource($variant);
|
||||
if (is_file($file))
|
||||
{
|
||||
return array($variant, $file);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the list of untranslated blocks to the translation source.
|
||||
* If the translation was not found, you should add those
|
||||
* strings to the translation source via the <b>append()</b> method.
|
||||
*
|
||||
* @param string the catalogue to add to
|
||||
* @return boolean true if saved successfuly, false otherwise.
|
||||
*/
|
||||
public function save($catalogue = 'messages')
|
||||
{
|
||||
$messages = $this->untranslated;
|
||||
if (count($messages) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$variants = $this->getVariants($catalogue);
|
||||
if ($variants)
|
||||
{
|
||||
list($variant, $filename) = $variants;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($filename) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to save to file %s, file must be writable.", $filename));
|
||||
}
|
||||
|
||||
// create a new dom, import the existing xml
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($filename);
|
||||
|
||||
// find the body element
|
||||
$xpath = new DomXPath($dom);
|
||||
$body = $xpath->query('//body')->item(0);
|
||||
|
||||
// find the biggest "id" used
|
||||
$lastNodes = $xpath->query('//trans-unit[not(@id <= preceding-sibling::trans-unit/@id) and not(@id <= following-sibling::trans-unit/@id)]');
|
||||
if (null !== $last = $lastNodes->item(0))
|
||||
{
|
||||
$count = intval($last->getAttribute('id'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
// for each message add it to the XML file using DOM
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
$unit = $dom->createElement('trans-unit');
|
||||
$unit->setAttribute('id', ++$count);
|
||||
|
||||
$source = $dom->createElement('source', $message);
|
||||
$target = $dom->createElement('target', '');
|
||||
|
||||
$unit->appendChild($dom->createTextNode("\n"));
|
||||
$unit->appendChild($source);
|
||||
$unit->appendChild($dom->createTextNode("\n"));
|
||||
$unit->appendChild($target);
|
||||
$unit->appendChild($dom->createTextNode("\n"));
|
||||
|
||||
$body->appendChild($dom->createTextNode("\n"));
|
||||
$body->appendChild($unit);
|
||||
$body->appendChild($dom->createTextNode("\n"));
|
||||
}
|
||||
|
||||
$fileNode = $xpath->query('//file')->item(0);
|
||||
$fileNode->setAttribute('date', @date('Y-m-d\TH:i:s\Z'));
|
||||
|
||||
// save it and clear the cache for this variant
|
||||
$dom->save($filename);
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the translation.
|
||||
*
|
||||
* @param string the source string.
|
||||
* @param string the new translation string.
|
||||
* @param string comments
|
||||
* @param string the catalogue to save to.
|
||||
* @return boolean true if translation was updated, false otherwise.
|
||||
*/
|
||||
public function update($text, $target, $comments, $catalogue = 'messages')
|
||||
{
|
||||
$variants = $this->getVariants($catalogue);
|
||||
if ($variants)
|
||||
{
|
||||
list($variant, $filename) = $variants;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($filename) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to update file %s, file must be writable.", $filename));
|
||||
}
|
||||
|
||||
// create a new dom, import the existing xml
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($filename);
|
||||
|
||||
// find the body element
|
||||
$xpath = new DomXPath($dom);
|
||||
$units = $xpath->query('//trans-unit');
|
||||
|
||||
// for each of the existin units
|
||||
foreach ($units as $unit)
|
||||
{
|
||||
$found = false;
|
||||
$targetted = false;
|
||||
$commented = false;
|
||||
|
||||
//in each unit, need to find the source, target and comment nodes
|
||||
//it will assume that the source is before the target.
|
||||
foreach ($unit->childNodes as $node)
|
||||
{
|
||||
// source node
|
||||
if ($node->nodeName == 'source' && $node->firstChild->wholeText == $text)
|
||||
{
|
||||
$found = true;
|
||||
}
|
||||
|
||||
// found source, get the target and notes
|
||||
if ($found)
|
||||
{
|
||||
// set the new translated string
|
||||
if ($node->nodeName == 'target')
|
||||
{
|
||||
$node->nodeValue = $target;
|
||||
$targetted = true;
|
||||
}
|
||||
|
||||
// set the notes
|
||||
if (!empty($comments) && $node->nodeName == 'note')
|
||||
{
|
||||
$node->nodeValue = $comments;
|
||||
$commented = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// append a target
|
||||
if ($found && !$targetted)
|
||||
{
|
||||
$unit->appendChild($dom->createElement('target', $target));
|
||||
}
|
||||
|
||||
// append a note
|
||||
if ($found && !$commented && !empty($comments))
|
||||
{
|
||||
$unit->appendChild($dom->createElement('note',$comments));
|
||||
}
|
||||
|
||||
// finished searching
|
||||
if ($found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$fileNode = $xpath->query('//file')->item(0);
|
||||
$fileNode->setAttribute('date', @date('Y-m-d\TH:i:s\Z'));
|
||||
|
||||
if ($dom->save($filename) > 0)
|
||||
{
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a particular message from the specified catalogue.
|
||||
*
|
||||
* @param string the source message to delete.
|
||||
* @param string the catalogue to delete from.
|
||||
* @return boolean true if deleted, false otherwise.
|
||||
*/
|
||||
public function delete($message, $catalogue='messages')
|
||||
{
|
||||
$variants = $this->getVariants($catalogue);
|
||||
if ($variants)
|
||||
{
|
||||
list($variant, $filename) = $variants;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($filename) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to modify file %s, file must be writable.", $filename));
|
||||
}
|
||||
|
||||
// create a new dom, import the existing xml
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($filename);
|
||||
|
||||
// find the body element
|
||||
$xpath = new DomXPath($dom);
|
||||
$units = $xpath->query('//trans-unit');
|
||||
|
||||
// for each of the existin units
|
||||
foreach ($units as $unit)
|
||||
{
|
||||
//in each unit, need to find the source, target and comment nodes
|
||||
//it will assume that the source is before the target.
|
||||
foreach ($unit->childNodes as $node)
|
||||
{
|
||||
// source node
|
||||
if ($node->nodeName == 'source' && $node->firstChild->wholeText == $message)
|
||||
{
|
||||
// we found it, remove and save the xml file.
|
||||
$unit->parentNode->removeChild($unit);
|
||||
|
||||
$fileNode = $xpath->query('//file')->item(0);
|
||||
$fileNode->setAttribute('date', @date('Y-m-d\TH:i:s\Z'));
|
||||
|
||||
if ($dom->save($filename) > 0)
|
||||
{
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
466
lib/symfony/i18n/sfMessageSource_gettext.class.php
Executable file
466
lib/symfony/i18n/sfMessageSource_gettext.class.php
Executable file
@ -0,0 +1,466 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfMessageSource_gettext 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 $Id: sfMessageSource_gettext.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* sfMessageSource_gettext class.
|
||||
*
|
||||
* Using Gettext MO format as the message source for translation.
|
||||
* The gettext classes are based on PEAR's gettext MO and PO classes.
|
||||
*
|
||||
* See the MessageSource::factory() method to instantiate this class.
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 24 16:18:44 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfMessageSource_gettext extends sfMessageSource
|
||||
{
|
||||
/**
|
||||
* Message data filename extension.
|
||||
* @var string
|
||||
*/
|
||||
protected $dataExt = '.mo';
|
||||
|
||||
/**
|
||||
* PO data filename extension
|
||||
* @var string
|
||||
*/
|
||||
protected $poExt = '.po';
|
||||
|
||||
/**
|
||||
* Separator between culture name and source.
|
||||
* @var string
|
||||
*/
|
||||
protected $dataSeparator = '.';
|
||||
|
||||
function __construct($source)
|
||||
{
|
||||
$this->source = (string) $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the messages from a MO file.
|
||||
*
|
||||
* @param string MO file.
|
||||
* @return array of messages.
|
||||
*/
|
||||
protected function &loadData($filename)
|
||||
{
|
||||
$mo = TGettext::factory('MO',$filename);
|
||||
$mo->load();
|
||||
$result = $mo->toArray();
|
||||
|
||||
$results = array();
|
||||
$count = 0;
|
||||
foreach ($result['strings'] as $source => $target)
|
||||
{
|
||||
$results[$source][] = $target; //target
|
||||
$results[$source][] = $count++; //id
|
||||
$results[$source][] = ''; //comments
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the MO file source is valid.
|
||||
*
|
||||
* @param string MO file
|
||||
* @return boolean true if valid, false otherwise.
|
||||
*/
|
||||
protected function isValidSource($filename)
|
||||
{
|
||||
return is_file($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MO file for a specific message catalogue and cultural variant.
|
||||
*
|
||||
* @param string message catalogue
|
||||
* @return string full path to the MO file.
|
||||
*/
|
||||
protected function getSource($variant)
|
||||
{
|
||||
return $this->source.'/'.$variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified unix-time for this particular catalogue+variant.
|
||||
* Just use the file modified time.
|
||||
*
|
||||
* @param string catalogue+variant
|
||||
* @return int last modified in unix-time format.
|
||||
*/
|
||||
protected function getLastModified($source)
|
||||
{
|
||||
return is_file($source) ? filemtime($source) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the variants of a particular catalogue.
|
||||
*
|
||||
* @param string catalogue name
|
||||
* @return array list of all variants for this catalogue.
|
||||
*/
|
||||
protected function getCatalogueList($catalogue)
|
||||
{
|
||||
$variants = explode('_', $this->culture);
|
||||
$source = $catalogue.$this->dataExt;
|
||||
|
||||
$catalogues = array($source);
|
||||
|
||||
$variant = null;
|
||||
|
||||
for ($i = 0, $max = count($variants); $i < $max; $i++)
|
||||
{
|
||||
if (strlen($variants[$i]) > 0)
|
||||
{
|
||||
$variant .= $variant ? '_'.$variants[$i] : $variants[$i];
|
||||
$catalogues[] = $catalogue.$this->dataSeparator.$variant.$this->dataExt;
|
||||
}
|
||||
}
|
||||
$byDir = $this->getCatalogueByDir($catalogue);
|
||||
$catalogues = array_merge($byDir,array_reverse($catalogues));
|
||||
|
||||
return $catalogues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses through the directory structure to find the catalogues.
|
||||
* This should only be called by getCatalogueList()
|
||||
*
|
||||
* @param string a particular catalogue.
|
||||
* @return array a list of catalogues.
|
||||
* @see getCatalogueList()
|
||||
*/
|
||||
protected function getCatalogueByDir($catalogue)
|
||||
{
|
||||
$variants = explode('_', $this->culture);
|
||||
$catalogues = array();
|
||||
|
||||
$variant = null;
|
||||
|
||||
for($i = 0, $max = count($variants); $i < $max; $i++)
|
||||
{
|
||||
if (strlen($variants[$i]) > 0)
|
||||
{
|
||||
$variant .= $variant ? '_'.$variants[$i] : $variants[$i];
|
||||
$catalogues[] = $variant.'/'.$catalogue.$this->dataExt;
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($catalogues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variant for a catalogue depending on the current culture.
|
||||
*
|
||||
* @param string catalogue
|
||||
* @return string the variant.
|
||||
* @see save()
|
||||
* @see update()
|
||||
* @see delete()
|
||||
*/
|
||||
protected function getVariants($catalogue = 'messages')
|
||||
{
|
||||
if (empty($catalogue))
|
||||
{
|
||||
$catalogue = 'messages';
|
||||
}
|
||||
|
||||
foreach ($this->getCatalogueList($catalogue) as $variant)
|
||||
{
|
||||
$file = $this->getSource($variant);
|
||||
$po = $this->getPOFile($file);
|
||||
if (is_file($file) || is_file($po))
|
||||
{
|
||||
return array($variant, $file, $po);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getPOFile($MOFile)
|
||||
{
|
||||
return substr($MOFile, 0, strlen($MOFile) - strlen($this->dataExt)).$this->poExt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the list of untranslated blocks to the translation source.
|
||||
* If the translation was not found, you should add those
|
||||
* strings to the translation source via the <b>append()</b> method.
|
||||
*
|
||||
* @param string the catalogue to add to
|
||||
* @return boolean true if saved successfuly, false otherwise.
|
||||
*/
|
||||
function save($catalogue = 'messages')
|
||||
{
|
||||
$messages = $this->untranslated;
|
||||
|
||||
if (count($messages) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$variants = $this->getVariants($catalogue);
|
||||
|
||||
if ($variants)
|
||||
{
|
||||
list($variant, $MOFile, $POFile) = $variants;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($MOFile) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to save to file %s, file must be writable.", $MOFile));
|
||||
}
|
||||
if (is_writable($POFile) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to save to file %s, file must be writable.", $POFile));
|
||||
}
|
||||
|
||||
// set the strings as untranslated.
|
||||
$strings = array();
|
||||
foreach ($messages as $message)
|
||||
{
|
||||
$strings[$message] = '';
|
||||
}
|
||||
|
||||
// load the PO
|
||||
$po = TGettext::factory('PO',$POFile);
|
||||
$po->load();
|
||||
$result = $po->toArray();
|
||||
|
||||
$existing = count($result['strings']);
|
||||
|
||||
// add to strings to the existing message list
|
||||
$result['strings'] = array_merge($result['strings'],$strings);
|
||||
|
||||
$new = count($result['strings']);
|
||||
|
||||
if ($new > $existing)
|
||||
{
|
||||
// change the date 2004-12-25 12:26
|
||||
$result['meta']['PO-Revision-Date'] = @date('Y-m-d H:i:s');
|
||||
|
||||
$po->fromArray($result);
|
||||
$mo = $po->toMO();
|
||||
if ($po->save() && $mo->save($MOFile))
|
||||
{
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a particular message from the specified catalogue.
|
||||
*
|
||||
* @param string the source message to delete.
|
||||
* @param string the catalogue to delete from.
|
||||
* @return boolean true if deleted, false otherwise.
|
||||
*/
|
||||
function delete($message, $catalogue = 'messages')
|
||||
{
|
||||
$variants = $this->getVariants($catalogue);
|
||||
if ($variants)
|
||||
{
|
||||
list($variant, $MOFile, $POFile) = $variants;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($MOFile) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to modify file %s, file must be writable.", $MOFile));
|
||||
}
|
||||
|
||||
if (is_writable($POFile) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to modify file %s, file must be writable.", $POFile));
|
||||
}
|
||||
|
||||
$po = TGettext::factory('PO', $POFile);
|
||||
$po->load();
|
||||
$result = $po->toArray();
|
||||
|
||||
foreach ($result['strings'] as $string => $value)
|
||||
{
|
||||
if ($string == $message)
|
||||
{
|
||||
$result['meta']['PO-Revision-Date'] = @date('Y-m-d H:i:s');
|
||||
unset($result['strings'][$string]);
|
||||
|
||||
$po->fromArray($result);
|
||||
$mo = $po->toMO();
|
||||
if ($po->save() && $mo->save($MOFile))
|
||||
{
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the translation.
|
||||
*
|
||||
* @param string the source string.
|
||||
* @param string the new translation string.
|
||||
* @param string comments
|
||||
* @param string the catalogue of the translation.
|
||||
* @return boolean true if translation was updated, false otherwise.
|
||||
*/
|
||||
function update($text, $target, $comments, $catalogue = 'messages')
|
||||
{
|
||||
$variants = $this->getVariants($catalogue);
|
||||
if ($variants)
|
||||
{
|
||||
list($variant, $MOFile, $POFile) = $variants;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($MOFile) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to update file %s, file must be writable.", $MOFile));
|
||||
}
|
||||
|
||||
if (is_writable($POFile) == false)
|
||||
{
|
||||
throw new sfException(sprintf("Unable to update file %s, file must be writable.", $POFile));
|
||||
}
|
||||
|
||||
$po = TGettext::factory('PO',$POFile);
|
||||
$po->load();
|
||||
$result = $po->toArray();
|
||||
|
||||
foreach ($result['strings'] as $string => $value)
|
||||
{
|
||||
if ($string == $text)
|
||||
{
|
||||
$result['strings'][$string] = $target;
|
||||
$result['meta']['PO-Revision-Date'] = @date('Y-m-d H:i:s');
|
||||
|
||||
$po->fromArray($result);
|
||||
$mo = $po->toMO();
|
||||
|
||||
if ($po->save() && $mo->save($MOFile))
|
||||
{
|
||||
if (!empty($this->cache))
|
||||
{
|
||||
$this->cache->clean($variant, $this->culture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue as key and all it variants as value.
|
||||
*
|
||||
* @return array list of catalogues
|
||||
*/
|
||||
function catalogues()
|
||||
{
|
||||
return $this->getCatalogues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of catalogue and its culture ID. This takes care
|
||||
* of directory structures.
|
||||
* E.g. array('messages','en_AU')
|
||||
*
|
||||
* @return array list of catalogues
|
||||
*/
|
||||
protected function getCatalogues($dir = null, $variant = null)
|
||||
{
|
||||
$dir = $dir ? $dir : $this->source;
|
||||
$files = scandir($dir);
|
||||
|
||||
$catalogue = array();
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
if (is_dir($dir.'/'.$file) && preg_match('/^[a-z]{2}(_[A-Z]{2,3})?$/', $file))
|
||||
{
|
||||
$catalogue = array_merge($catalogue, $this->getCatalogues($dir.'/'.$file, $file));
|
||||
}
|
||||
|
||||
$pos = strpos($file, $this->dataExt);
|
||||
|
||||
if ($pos > 0 && substr($file, -1 * strlen($this->dataExt)) == $this->dataExt)
|
||||
{
|
||||
$name = substr($file, 0, $pos);
|
||||
$dot = strrpos($name, $this->dataSeparator);
|
||||
$culture = $variant;
|
||||
$cat = $name;
|
||||
if (is_int($dot))
|
||||
{
|
||||
$culture = substr($name, $dot + 1, strlen($name));
|
||||
$cat = substr($name, 0, $dot);
|
||||
}
|
||||
$details[0] = $cat;
|
||||
$details[1] = $culture;
|
||||
|
||||
$catalogue[] = $details;
|
||||
}
|
||||
}
|
||||
sort($catalogue);
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
}
|
316
lib/symfony/i18n/sfNumberFormat.class.php
Executable file
316
lib/symfony/i18n/sfNumberFormat.class.php
Executable file
@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfNumberFormat 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 $Id: sfNumberFormat.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the encoding utilities
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/util.php');
|
||||
|
||||
/**
|
||||
* sfNumberFormat class.
|
||||
*
|
||||
* sfNumberFormat formats decimal numbers in any locale. The decimal
|
||||
* number is formatted according to a particular pattern. These
|
||||
* patterns can arise from the sfNumberFormatInfo object which is
|
||||
* culturally sensitive. The sfNumberFormat class can be instantiated in
|
||||
* many ways. E.g.
|
||||
*
|
||||
* <code>
|
||||
* //create a invariant number formatter.
|
||||
* $formatter = new sfNumberFormat();
|
||||
*
|
||||
* //create a number format for the french language locale.
|
||||
* $fr = new sfNumberFormat('fr');
|
||||
*
|
||||
* //create a number format base on a sfNumberFormatInfo instance $numberInfo.
|
||||
* $format = new sfNumberFormat($numberInfo);
|
||||
* </code>
|
||||
*
|
||||
* A normal decimal number can also be displayed as a currency
|
||||
* or as a percentage. For example
|
||||
* <code>
|
||||
* $format->format(1234.5); //Decimal number "1234.5"
|
||||
* $format->format(1234.5,'c'); //Default currency "$1234.50"
|
||||
* $format->format(0.25, 'p') //Percent "25%"
|
||||
* </code>
|
||||
*
|
||||
* Currency is formated using the localized currency pattern. For example
|
||||
* to format the number as Japanese Yen:
|
||||
* <code>
|
||||
* $ja = new sfNumberFormat('ja_JP');
|
||||
*
|
||||
* //Japanese currency pattern, and using Japanese Yen symbol
|
||||
* $ja->format(123.14,'c','JPY'); //ï¿?123 (Yen 123)
|
||||
* </code>
|
||||
* For each culture, the symbol for each currency may be different.
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Fri Dec 10 18:10:20 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfNumberFormat
|
||||
{
|
||||
/**
|
||||
* The DateTimeFormatInfo, containing culture specific patterns and names.
|
||||
* @var DateTimeFormatInfo
|
||||
*/
|
||||
protected $formatInfo;
|
||||
|
||||
/**
|
||||
* Creates a new number format instance. The constructor can be instantiated
|
||||
* with a string that represent a culture/locale. Similarly, passing
|
||||
* a sfCultureInfo or sfNumberFormatInfo instance will instantiated a instance
|
||||
* for that particular culture.
|
||||
*
|
||||
* @param mixed either null, a sfCultureInfo, a sfNumberFormatInfo, or string
|
||||
* @return sfNumberFormat
|
||||
*/
|
||||
function __construct($formatInfo = null)
|
||||
{
|
||||
if (is_null($formatInfo))
|
||||
{
|
||||
$this->formatInfo = sfNumberFormatInfo::getInvariantInfo();
|
||||
}
|
||||
else if ($formatInfo instanceof sfCultureInfo)
|
||||
{
|
||||
$this->formatInfo = $formatInfo->sfNumberFormat;
|
||||
}
|
||||
else if ($formatInfo instanceof sfNumberFormatInfo)
|
||||
{
|
||||
$this->formatInfo = $formatInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->formatInfo = sfNumberFormatInfo::getInstance($formatInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the number for a certain pattern. The valid patterns are
|
||||
* 'c', 'd', 'e', 'p' or a custom pattern, such as "#.000" for
|
||||
* 3 decimal places.
|
||||
*
|
||||
* @param mixed the number to format.
|
||||
* @param string the format pattern, either, 'c', 'd', 'e', 'p'
|
||||
* or a custom pattern. E.g. "#.000" will format the number to
|
||||
* 3 decimal places.
|
||||
* @param string 3-letter ISO 4217 code. For example, the code
|
||||
* "USD" represents the US Dollar and "EUR" represents the Euro currency.
|
||||
* @return string formatted number string
|
||||
*/
|
||||
function format($number, $pattern = 'd', $currency = 'USD', $charset = 'UTF-8')
|
||||
{
|
||||
$this->setPattern($pattern);
|
||||
|
||||
if (strtolower($pattern) == 'p')
|
||||
{
|
||||
$number = $number * 100;
|
||||
}
|
||||
|
||||
$string = (string) $number;
|
||||
|
||||
list($number, $decimal) = $this->formatDecimal($string);
|
||||
$integer = $this->formatInteger(abs($number));
|
||||
|
||||
$result = (strlen($decimal) > 0) ? $integer.$decimal : $integer;
|
||||
|
||||
// get the suffix
|
||||
if ($number >= 0)
|
||||
{
|
||||
$suffix = $this->formatInfo->PositivePattern;
|
||||
}
|
||||
else if ($number < 0)
|
||||
{
|
||||
$suffix = $this->formatInfo->NegativePattern;
|
||||
}
|
||||
else
|
||||
{
|
||||
$suffix = array('', '');
|
||||
}
|
||||
|
||||
// append and prepend suffix
|
||||
$result = $suffix[0].$result.$suffix[1];
|
||||
|
||||
// replace currency sign
|
||||
$symbol = @$this->formatInfo->getCurrencySymbol($currency);
|
||||
if (is_null($symbol))
|
||||
{
|
||||
$symbol = $currency;
|
||||
}
|
||||
|
||||
$result = str_replace('¤', $symbol, $result);
|
||||
|
||||
return I18N_toEncoding($result, $charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the integer, perform groupings and string padding.
|
||||
*
|
||||
* @param string the decimal number in string form.
|
||||
* @return string formatted integer string with grouping
|
||||
*/
|
||||
protected function formatInteger($string)
|
||||
{
|
||||
$string = (string) $string;
|
||||
$dp = strpos($string, '.');
|
||||
|
||||
if (is_int($dp))
|
||||
{
|
||||
$string = substr($string, 0, $dp);
|
||||
}
|
||||
|
||||
$integer = '';
|
||||
|
||||
$len = strlen($string);
|
||||
|
||||
$groupSeparator = $this->formatInfo->GroupSeparator;
|
||||
$groupSize = $this->formatInfo->GroupSizes;
|
||||
|
||||
$firstGroup = true;
|
||||
$multiGroup = is_int($groupSize[1]);
|
||||
$count = 0;
|
||||
|
||||
if (is_int($groupSize[0]))
|
||||
{
|
||||
// now for the integer groupings
|
||||
for ($i = 0; $i < $len; $i++)
|
||||
{
|
||||
$char = $string{$len - $i - 1};
|
||||
|
||||
if ($multiGroup && $count == 0)
|
||||
{
|
||||
if ($i != 0 && $i % $groupSize[0] == 0)
|
||||
{
|
||||
$integer = $groupSeparator.$integer;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
else if ($multiGroup && $count >= 1)
|
||||
{
|
||||
if ($i != 0 && ($i-$groupSize[0])%$groupSize[1] == 0)
|
||||
{
|
||||
$integer = $groupSeparator.$integer;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($i != 0 && $i % $groupSize[0] == 0)
|
||||
{
|
||||
$integer = $groupSeparator.$integer;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
$integer = $char.$integer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$integer = $string;
|
||||
}
|
||||
|
||||
return $integer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the decimal places.
|
||||
*
|
||||
* @param string the decimal number in string form.
|
||||
* @return string formatted decimal places.
|
||||
*/
|
||||
protected function formatDecimal($string)
|
||||
{
|
||||
$dp = strpos($string, '.');
|
||||
$decimal = '';
|
||||
|
||||
$decimalDigits = $this->formatInfo->DecimalDigits;
|
||||
$decimalSeparator = $this->formatInfo->DecimalSeparator;
|
||||
|
||||
if (is_int($dp))
|
||||
{
|
||||
if ($decimalDigits == -1)
|
||||
{
|
||||
$decimal = substr($string, $dp + 1);
|
||||
}
|
||||
else if (is_int($decimalDigits))
|
||||
{
|
||||
$string = $float = round((float) $string, $decimalDigits);
|
||||
if (strpos((string) $float, '.') === false)
|
||||
{
|
||||
$decimal = str_pad($decimal, $decimalDigits, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
$decimal = substr($float, strpos($float,'.') + 1);
|
||||
if (strlen($decimal)<$decimalDigits)
|
||||
{
|
||||
$decimal = str_pad($decimal, $decimalDigits, '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return array($string, $decimal);
|
||||
}
|
||||
|
||||
return array($string, $decimalSeparator.$decimal);
|
||||
}
|
||||
else if ($decimalDigits > 0)
|
||||
{
|
||||
return array($string, $decimalSeparator.str_pad($decimal, $decimalDigits, '0'));
|
||||
}
|
||||
|
||||
return array($string, $decimal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pattern to format against. The default patterns
|
||||
* are retrieved from the sfNumberFormatInfo instance.
|
||||
*
|
||||
* @param string the requested patterns.
|
||||
* @return string a number format pattern.
|
||||
*/
|
||||
protected function setPattern($pattern)
|
||||
{
|
||||
switch ($pattern)
|
||||
{
|
||||
case 'c':
|
||||
case 'C':
|
||||
$this->formatInfo->setPattern(sfNumberFormatInfo::CURRENCY);
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
$this->formatInfo->setPattern(sfNumberFormatInfo::DECIMAL);
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
$this->formatInfo->setPattern(sfNumberFormatInfo::SCIENTIFIC);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
$this->formatInfo->setPattern(sfNumberFormatInfo::PERCENTAGE);
|
||||
break;
|
||||
default:
|
||||
$this->formatInfo->setPattern($pattern);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
681
lib/symfony/i18n/sfNumberFormatInfo.class.php
Executable file
681
lib/symfony/i18n/sfNumberFormatInfo.class.php
Executable file
@ -0,0 +1,681 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* sfNumberFormatInfo 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 $Id: sfNumberFormatInfo.class.php 4340 2007-06-23 06:47:05Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
/**
|
||||
* sfNumberFormatInfo class
|
||||
*
|
||||
* Defines how numeric values are formatted and displayed,
|
||||
* depending on the culture. Numeric values are formatted using
|
||||
* standard or custom patterns stored in the properties of a
|
||||
* sfNumberFormatInfo.
|
||||
*
|
||||
* This class contains information, such as currency, decimal
|
||||
* separators, and other numeric symbols.
|
||||
*
|
||||
* To create a sfNumberFormatInfo for a specific culture,
|
||||
* create a sfCultureInfo for that culture and retrieve the
|
||||
* sfCultureInfo->NumberFormat property. Or use
|
||||
* sfNumberFormatInfo::getInstance($culture).
|
||||
* To create a sfNumberFormatInfo for the invariant culture, use the
|
||||
* InvariantInfo::getInvariantInfo().
|
||||
*
|
||||
*
|
||||
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version v1.0, last update on Sun Dec 05 14:48:26 EST 2004
|
||||
* @package System.I18N.core
|
||||
*/
|
||||
class sfNumberFormatInfo
|
||||
{
|
||||
/**
|
||||
* ICU number formatting data.
|
||||
* @var array
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* A list of properties that are accessable/writable.
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = array();
|
||||
|
||||
/**
|
||||
* The number pattern.
|
||||
* @var array
|
||||
*/
|
||||
protected $pattern = array();
|
||||
|
||||
const DECIMAL = 0;
|
||||
const CURRENCY = 1;
|
||||
const PERCENTAGE = 2;
|
||||
const SCIENTIFIC = 3;
|
||||
|
||||
/**
|
||||
* Allows functions that begins with 'set' to be called directly
|
||||
* as an attribute/property to retrieve the value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function __get($name)
|
||||
{
|
||||
$getProperty = 'get'.$name;
|
||||
if (in_array($getProperty, $this->properties))
|
||||
{
|
||||
return $this->$getProperty();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Property %s does not exists.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows functions that begins with 'set' to be called directly
|
||||
* as an attribute/property to set the value.
|
||||
*/
|
||||
function __set($name, $value)
|
||||
{
|
||||
$setProperty = 'set'.$name;
|
||||
if (in_array($setProperty, $this->properties))
|
||||
{
|
||||
$this->$setProperty($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new sfException(sprintf('Property %s can not be set.', $name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new writable instance of the sfNumberFormatInfo class
|
||||
* that is dependent on the ICU data for number, decimal, and currency
|
||||
* formatting information. <b>N.B.</b>You should not initialize this
|
||||
* class directly unless you know what you are doing. Please use use
|
||||
* sfNumberFormatInfo::getInstance() to create an instance.
|
||||
*
|
||||
* @param array ICU data for date time formatting.
|
||||
* @see getInstance()
|
||||
*/
|
||||
function __construct($data = array(), $type = sfNumberFormatInfo::DECIMAL)
|
||||
{
|
||||
$this->properties = get_class_methods($this);
|
||||
|
||||
if (empty($data))
|
||||
{
|
||||
throw new sfException('Please provide the ICU data to initialize.');
|
||||
}
|
||||
|
||||
$this->data = $data;
|
||||
|
||||
$this->setPattern($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pattern for a specific number pattern. The validate patterns
|
||||
* sfNumberFormatInfo::DECIMAL, sfNumberFormatInfo::CURRENCY,
|
||||
* sfNumberFormatInfo::PERCENTAGE, or sfNumberFormatInfo::SCIENTIFIC
|
||||
*
|
||||
* @param int pattern type.
|
||||
*/
|
||||
function setPattern($type = sfNumberFormatInfo::DECIMAL)
|
||||
{
|
||||
if (is_int($type))
|
||||
{
|
||||
$this->pattern = $this->parsePattern($this->data['NumberPatterns'][$type]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->pattern = $this->parsePattern($type);
|
||||
}
|
||||
|
||||
$this->pattern['negInfty'] = $this->data['NumberElements'][6].$this->data['NumberElements'][9];
|
||||
|
||||
$this->pattern['posInfty'] = $this->data['NumberElements'][11].$this->data['NumberElements'][9];
|
||||
}
|
||||
|
||||
function getPattern()
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default sfNumberFormatInfo that is culture-independent (invariant).
|
||||
*
|
||||
* @return sfNumberFormatInfo default sfNumberFormatInfo.
|
||||
*/
|
||||
public function getInvariantInfo($type = sfNumberFormatInfo::DECIMAL)
|
||||
{
|
||||
static $invariant;
|
||||
if (is_null($invariant))
|
||||
{
|
||||
$culture = sfCultureInfo::getInvariantCulture();
|
||||
$invariant = $culture->NumberFormat;
|
||||
$invariant->setPattern($type);
|
||||
}
|
||||
|
||||
return $invariant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sfNumberFormatInfo associated with the specified culture.
|
||||
*
|
||||
* @param sfCultureInfo the culture that gets the sfNumberFormat property.
|
||||
* @param int the number formatting type, it should be
|
||||
* sfNumberFormatInfo::DECIMAL, sfNumberFormatInfo::CURRENCY,
|
||||
* sfNumberFormatInfo::PERCENTAGE, or sfNumberFormatInfo::SCIENTIFIC
|
||||
* @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
|
||||
* @see getCurrencyInstance();
|
||||
* @see getPercentageInstance();
|
||||
* @see getScientificInstance();
|
||||
*/
|
||||
public static function getInstance($culture = null, $type = sfNumberFormatInfo::DECIMAL)
|
||||
{
|
||||
if ($culture instanceof sfCultureInfo)
|
||||
{
|
||||
$formatInfo = $culture->getNumberFormat();
|
||||
$formatInfo->setPattern($type);
|
||||
|
||||
return $formatInfo;
|
||||
}
|
||||
else if (is_string($culture))
|
||||
{
|
||||
$sfCultureInfo = new sfCultureInfo($culture);
|
||||
$formatInfo = $sfCultureInfo->getNumberFormat();
|
||||
$formatInfo->setPattern($type);
|
||||
|
||||
return $formatInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sfCultureInfo = new sfCultureInfo();
|
||||
$formatInfo = $sfCultureInfo->getNumberFormat();
|
||||
$formatInfo->setPattern($type);
|
||||
|
||||
return $formatInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currency format info associated with the specified culture.
|
||||
*
|
||||
* @param sfCultureInfo the culture that gets the NumberFormat property.
|
||||
* @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
|
||||
*/
|
||||
public static function getCurrencyInstance($culture = null)
|
||||
{
|
||||
return self::getInstance($culture, self::CURRENCY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the percentage format info associated with the specified culture.
|
||||
*
|
||||
* @param sfCultureInfo the culture that gets the NumberFormat property.
|
||||
* @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
|
||||
*/
|
||||
public static function getPercentageInstance($culture = null)
|
||||
{
|
||||
return self::getInstance($culture, self::PERCENTAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scientific format info associated with the specified culture.
|
||||
*
|
||||
* @param sfCultureInfo the culture that gets the NumberFormat property.
|
||||
* @return sfNumberFormatInfo sfNumberFormatInfo for the specified culture.
|
||||
*/
|
||||
public static function getScientificInstance($culture = null)
|
||||
{
|
||||
return self::getInstance($culture, self::SCIENTIFIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given pattern and return a list of known properties.
|
||||
*
|
||||
* @param string a number pattern.
|
||||
* @return array list of pattern properties.
|
||||
*/
|
||||
protected function parsePattern($pattern)
|
||||
{
|
||||
$pattern = explode(';', $pattern);
|
||||
|
||||
$negative = null;
|
||||
if (count($pattern) > 1)
|
||||
{
|
||||
$negative = $pattern[1];
|
||||
}
|
||||
$pattern = $pattern[0];
|
||||
|
||||
$comma = ',';
|
||||
$dot = '.';
|
||||
$digit = '0';
|
||||
$hash = '#';
|
||||
|
||||
// find the first group point, and decimal point
|
||||
$groupPos1 = strrpos($pattern, $comma);
|
||||
$decimalPos = strrpos($pattern, $dot);
|
||||
|
||||
$groupPos2 = false;
|
||||
$groupSize1 = false;
|
||||
$groupSize2 = false;
|
||||
$decimalPoints = is_int($decimalPos) ? -1 : false;
|
||||
|
||||
$info['negPref'] = $this->data['NumberElements'][6];
|
||||
$info['negPost'] = '';
|
||||
|
||||
$info['negative'] = $negative;
|
||||
$info['positive'] = $pattern;
|
||||
|
||||
// find the negative prefix and postfix
|
||||
if ($negative)
|
||||
{
|
||||
$prefixPostfix = $this->getPrePostfix($negative);
|
||||
$info['negPref'] = $prefixPostfix[0];
|
||||
$info['negPost'] = $prefixPostfix[1];
|
||||
}
|
||||
|
||||
$posfix = $this->getPrePostfix($pattern);
|
||||
$info['posPref'] = $posfix[0];
|
||||
$info['posPost'] = $posfix[1];
|
||||
|
||||
if (is_int($groupPos1))
|
||||
{
|
||||
// get the second group
|
||||
$groupPos2 = strrpos(substr($pattern, 0, $groupPos1), $comma);
|
||||
|
||||
// get the number of decimal digits
|
||||
if (is_int($decimalPos))
|
||||
{
|
||||
$groupSize1 = $decimalPos - $groupPos1 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no decimal point, so traverse from the back
|
||||
// to find the groupsize 1.
|
||||
for ($i = strlen($pattern) - 1; $i >= 0; $i--)
|
||||
{
|
||||
if ($pattern{$i} == $digit || $pattern{$i} == $hash)
|
||||
{
|
||||
$groupSize1 = $i - $groupPos1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get the second group size
|
||||
if (is_int($groupPos2))
|
||||
{
|
||||
$groupSize2 = $groupPos1 - $groupPos2 - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_int($decimalPos))
|
||||
{
|
||||
for ($i = strlen($pattern) - 1; $i >= 0; $i--)
|
||||
{
|
||||
if ($pattern{$i} == $dot)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ($pattern{$i} == $digit)
|
||||
{
|
||||
$decimalPoints = $i - $decimalPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$info['groupPos1'] = $groupPos1;
|
||||
$info['groupSize1'] = $groupSize1;
|
||||
$info['groupPos2'] = $groupPos2;
|
||||
$info['groupSize2'] = $groupSize2;
|
||||
$info['decimalPos'] = $decimalPos;
|
||||
$info['decimalPoints'] = $decimalPoints;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the prefix and postfix of a pattern.
|
||||
*
|
||||
* @param string pattern
|
||||
* @return array of prefix and postfix, array(prefix,postfix).
|
||||
*/
|
||||
protected function getPrePostfix($pattern)
|
||||
{
|
||||
$regexp = '/[#,\.0]+/';
|
||||
$result = preg_split($regexp, $pattern);
|
||||
|
||||
return array($result[0], $result[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the number of decimal places.
|
||||
*
|
||||
* @return int number of decimal places.
|
||||
*/
|
||||
function getDecimalDigits()
|
||||
{
|
||||
return $this->pattern['decimalPoints'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of decimal places.
|
||||
*
|
||||
* @param int number of decimal places.
|
||||
*/
|
||||
function setDecimalDigits($value)
|
||||
{
|
||||
return $this->pattern['decimalPoints'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string to use as the decimal separator.
|
||||
*
|
||||
* @return string decimal separator.
|
||||
*/
|
||||
function getDecimalSeparator()
|
||||
{
|
||||
return $this->data['NumberElements'][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string to use as the decimal separator.
|
||||
*
|
||||
* @param string the decimal point
|
||||
*/
|
||||
function setDecimalSeparator($value)
|
||||
{
|
||||
return $this->data['NumberElements'][0] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that separates groups of digits to the left
|
||||
* of the decimal in currency values.
|
||||
*
|
||||
* @param parameter
|
||||
* @return string currency group separator.
|
||||
*/
|
||||
function getGroupSeparator()
|
||||
{
|
||||
return $this->data['NumberElements'][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string to use as the group separator.
|
||||
*
|
||||
* @param string the group separator.
|
||||
*/
|
||||
function setGroupSeparator($value)
|
||||
{
|
||||
return $this->data['NumberElements'][1] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of digits in each group to the left of the decimal
|
||||
* There can be two grouping sizes, this fucntion
|
||||
* returns <b>array(group1, group2)</b>, if there is only 1 grouping size,
|
||||
* group2 will be false.
|
||||
*
|
||||
* @return array grouping size(s).
|
||||
*/
|
||||
function getGroupSizes()
|
||||
{
|
||||
$group1 = $this->pattern['groupSize1'];
|
||||
$group2 = $this->pattern['groupSize2'];
|
||||
|
||||
return array($group1, $group2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of digits in each group to the left of the decimal.
|
||||
* There can be two grouping sizes, the value should
|
||||
* be an <b>array(group1, group2)</b>, if there is only 1 grouping size,
|
||||
* group2 should be false.
|
||||
*
|
||||
* @param array grouping size(s).
|
||||
*/
|
||||
function setGroupSizes($groupSize)
|
||||
{
|
||||
$this->pattern['groupSize1'] = $groupSize[0];
|
||||
$this->pattern['groupSize2'] = $groupSize[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the format pattern for negative values.
|
||||
* The negative pattern is composed of a prefix, and postfix.
|
||||
* This function returns <b>array(prefix, postfix)</b>.
|
||||
*
|
||||
* @return arary negative pattern.
|
||||
*/
|
||||
function getNegativePattern()
|
||||
{
|
||||
$prefix = $this->pattern['negPref'];
|
||||
$postfix = $this->pattern['negPost'];
|
||||
|
||||
return array($prefix, $postfix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the format pattern for negative values.
|
||||
* The negative pattern is composed of a prefix, and postfix in the form
|
||||
* <b>array(prefix, postfix)</b>.
|
||||
*
|
||||
* @param arary negative pattern.
|
||||
*/
|
||||
function setNegativePattern($pattern)
|
||||
{
|
||||
$this->pattern['negPref'] = $pattern[0];
|
||||
$this->pattern['negPost'] = $pattern[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the format pattern for positive values.
|
||||
* The positive pattern is composed of a prefix, and postfix.
|
||||
* This function returns <b>array(prefix, postfix)</b>.
|
||||
*
|
||||
* @return arary positive pattern.
|
||||
*/
|
||||
function getPositivePattern()
|
||||
{
|
||||
$prefix = $this->pattern['posPref'];
|
||||
$postfix = $this->pattern['posPost'];
|
||||
|
||||
return array($prefix, $postfix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the format pattern for positive values.
|
||||
* The positive pattern is composed of a prefix, and postfix in the form
|
||||
* <b>array(prefix, postfix)</b>.
|
||||
*
|
||||
* @param arary positive pattern.
|
||||
*/
|
||||
function setPositivePattern($pattern)
|
||||
{
|
||||
$this->pattern['posPref'] = $pattern[0];
|
||||
$this->pattern['posPost'] = $pattern[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string to use as the currency symbol.
|
||||
*
|
||||
* @return string currency symbol.
|
||||
*/
|
||||
function getCurrencySymbol($currency = 'USD')
|
||||
{
|
||||
if (isset($this->pattern['symbol']))
|
||||
{
|
||||
return $this->pattern['symbol'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->data['Currencies'][$currency][0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string to use as the currency symbol.
|
||||
*
|
||||
* @param string currency symbol.
|
||||
*/
|
||||
function setCurrencySymbol($symbol)
|
||||
{
|
||||
$this->pattern['symbol'] = $symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that represents negative infinity.
|
||||
*
|
||||
* @return string negative infinity.
|
||||
*/
|
||||
function getNegativeInfinitySymbol()
|
||||
{
|
||||
return $this->pattern['negInfty'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string that represents negative infinity.
|
||||
*
|
||||
* @param string negative infinity.
|
||||
*/
|
||||
function setNegativeInfinitySymbol($value)
|
||||
{
|
||||
$this->pattern['negInfty'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that represents positive infinity.
|
||||
*
|
||||
* @return string positive infinity.
|
||||
*/
|
||||
function getPositiveInfinitySymbol()
|
||||
{
|
||||
return $this->pattern['posInfty'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string that represents positive infinity.
|
||||
*
|
||||
* @param string positive infinity.
|
||||
*/
|
||||
function setPositiveInfinitySymbol($value)
|
||||
{
|
||||
$this->pattern['posInfty'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that denotes that the associated number is negative.
|
||||
*
|
||||
* @return string negative sign.
|
||||
*/
|
||||
function getNegativeSign()
|
||||
{
|
||||
return $this->data['NumberElements'][6];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string that denotes that the associated number is negative.
|
||||
*
|
||||
* @param string negative sign.
|
||||
*/
|
||||
function setNegativeSign($value)
|
||||
{
|
||||
$this->data['NumberElements'][6] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that denotes that the associated number is positive.
|
||||
*
|
||||
* @return string positive sign.
|
||||
*/
|
||||
function getPositiveSign()
|
||||
{
|
||||
return $this->data['NumberElements'][11];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string that denotes that the associated number is positive.
|
||||
*
|
||||
* @param string positive sign.
|
||||
*/
|
||||
function setPositiveSign($value)
|
||||
{
|
||||
$this->data['NumberElements'][11] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string that represents the IEEE NaN (not a number) value.
|
||||
*
|
||||
* @return string NaN symbol.
|
||||
*/
|
||||
function getNaNSymbol()
|
||||
{
|
||||
return $this->data['NumberElements'][10];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string that represents the IEEE NaN (not a number) value.
|
||||
*
|
||||
* @param string NaN symbol.
|
||||
*/
|
||||
function setNaNSymbol($value)
|
||||
{
|
||||
$this->data['NumberElements'][10] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string to use as the percent symbol.
|
||||
*
|
||||
* @return string percent symbol.
|
||||
*/
|
||||
function getPercentSymbol()
|
||||
{
|
||||
return $this->data['NumberElements'][3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string to use as the percent symbol.
|
||||
*
|
||||
* @param string percent symbol.
|
||||
*/
|
||||
function setPercentSymbol($value)
|
||||
{
|
||||
$this->data['NumberElements'][3] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string to use as the per mille symbol.
|
||||
*
|
||||
* @return string percent symbol.
|
||||
*/
|
||||
function getPerMilleSymbol()
|
||||
{
|
||||
return $this->data['NumberElements'][8];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string to use as the per mille symbol.
|
||||
*
|
||||
* @param string percent symbol.
|
||||
*/
|
||||
function setPerMilleSymbol($value)
|
||||
{
|
||||
$this->data['NumberElements'][8] = $value;
|
||||
}
|
||||
}
|
177
lib/symfony/i18n/util.php
Executable file
177
lib/symfony/i18n/util.php
Executable file
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* I18N Utility 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 Wei Zhuo. All rights reserved.
|
||||
*
|
||||
* To contact the author write to <weizhuo[at]gmail[dot]com>
|
||||
* The latest version of PRADO can be obtained from:
|
||||
* {@link http://prado.sourceforge.net/}
|
||||
*
|
||||
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
|
||||
* @version $Id: util.php 2757 2006-11-18 10:11:00Z fabien $
|
||||
* @package symfony
|
||||
* @subpackage i18n
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* For a given DSN (database connection string), return some information
|
||||
* about the DSN. This function comes from PEAR's DB package.
|
||||
* @param string DSN format, similar to PEAR's DB
|
||||
* @return array DSN information.
|
||||
*/
|
||||
function parseDSN($dsn)
|
||||
{
|
||||
if (is_array($dsn)) {
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
$parsed = array(
|
||||
'phptype' => false,
|
||||
'dbsyntax' => false,
|
||||
'username' => false,
|
||||
'password' => false,
|
||||
'protocol' => false,
|
||||
'hostspec' => false,
|
||||
'port' => false,
|
||||
'socket' => false,
|
||||
'database' => false
|
||||
);
|
||||
|
||||
// Find phptype and dbsyntax
|
||||
if (($pos = strpos($dsn, '://')) !== false) {
|
||||
$str = substr($dsn, 0, $pos);
|
||||
$dsn = substr($dsn, $pos + 3);
|
||||
} else {
|
||||
$str = $dsn;
|
||||
$dsn = NULL;
|
||||
}
|
||||
|
||||
// Get phptype and dbsyntax
|
||||
// $str => phptype(dbsyntax)
|
||||
if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
|
||||
$parsed['phptype'] = $arr[1];
|
||||
$parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
|
||||
} else {
|
||||
$parsed['phptype'] = $str;
|
||||
$parsed['dbsyntax'] = $str;
|
||||
}
|
||||
|
||||
if (empty($dsn)) {
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
// Get (if found): username and password
|
||||
// $dsn => username:password@protocol+hostspec/database
|
||||
if (($at = strrpos($dsn,'@')) !== false) {
|
||||
$str = substr($dsn, 0, $at);
|
||||
$dsn = substr($dsn, $at + 1);
|
||||
if (($pos = strpos($str, ':')) !== false) {
|
||||
$parsed['username'] = rawurldecode(substr($str, 0, $pos));
|
||||
$parsed['password'] = rawurldecode(substr($str, $pos + 1));
|
||||
} else {
|
||||
$parsed['username'] = rawurldecode($str);
|
||||
}
|
||||
}
|
||||
|
||||
// Find protocol and hostspec
|
||||
|
||||
// $dsn => proto(proto_opts)/database
|
||||
if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
|
||||
$proto = $match[1];
|
||||
$proto_opts = (!empty($match[2])) ? $match[2] : false;
|
||||
$dsn = $match[3];
|
||||
|
||||
// $dsn => protocol+hostspec/database (old format)
|
||||
} else {
|
||||
if (strpos($dsn, '+') !== false) {
|
||||
list($proto, $dsn) = explode('+', $dsn, 2);
|
||||
}
|
||||
if (strpos($dsn, '/') !== false) {
|
||||
list($proto_opts, $dsn) = explode('/', $dsn, 2);
|
||||
} else {
|
||||
$proto_opts = $dsn;
|
||||
$dsn = null;
|
||||
}
|
||||
}
|
||||
|
||||
// process the different protocol options
|
||||
$parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
|
||||
$proto_opts = rawurldecode($proto_opts);
|
||||
if ($parsed['protocol'] == 'tcp') {
|
||||
if (strpos($proto_opts, ':') !== false) {
|
||||
list($parsed['hostspec'], $parsed['port']) = explode(':', $proto_opts);
|
||||
} else {
|
||||
$parsed['hostspec'] = $proto_opts;
|
||||
}
|
||||
} elseif ($parsed['protocol'] == 'unix') {
|
||||
$parsed['socket'] = $proto_opts;
|
||||
}
|
||||
|
||||
// Get dabase if any
|
||||
// $dsn => database
|
||||
if (!empty($dsn)) {
|
||||
// /database
|
||||
if (($pos = strpos($dsn, '?')) === false) {
|
||||
$parsed['database'] = $dsn;
|
||||
// /database?param1=value1¶m2=value2
|
||||
} else {
|
||||
$parsed['database'] = substr($dsn, 0, $pos);
|
||||
$dsn = substr($dsn, $pos + 1);
|
||||
if (strpos($dsn, '&') !== false) {
|
||||
$opts = explode('&', $dsn);
|
||||
} else { // database?param1=value1
|
||||
$opts = array($dsn);
|
||||
}
|
||||
foreach ($opts as $opt) {
|
||||
list($key, $value) = explode('=', $opt);
|
||||
if (!isset($parsed[$key])) { // don't allow params overwrite
|
||||
$parsed[$key] = rawurldecode($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert strings to UTF-8 via iconv. NB, the result may not by UTF-8
|
||||
* if the conversion failed.
|
||||
* @param string string to convert to UTF-8
|
||||
* @return string UTF-8 encoded string, original string if iconv failed.
|
||||
*/
|
||||
function I18N_toUTF8($string, $from)
|
||||
{
|
||||
$from = strtoupper($from);
|
||||
if ($from != 'UTF-8')
|
||||
{
|
||||
$s = iconv($from,'UTF-8',$string); //to UTF-8
|
||||
return $s !== false ? $s : $string; //it could return false
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert UTF-8 strings to a different encoding. NB. The result
|
||||
* may not have been encoded if iconv fails.
|
||||
* @param string the UTF-8 string for conversion
|
||||
* @return string encoded string.
|
||||
*/
|
||||
function I18N_toEncoding($string, $to)
|
||||
{
|
||||
$to = strtoupper($to);
|
||||
if ($to != 'UTF-8')
|
||||
{
|
||||
$s = iconv('UTF-8', $to, $string);
|
||||
return $s !== false ? $s : $string;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
Reference in New Issue
Block a user