* @license PHP License
* @package WB
* @subpackage MailMime
*/
WBClass::load('WBCli'
, 'WBObserver');
/**
* Command Line Interface class: NLS Knife
*
* Pocket knife for NLS stuff
*
* @version 1.1.0
* @package WB
*/
class WBCli_NLSKnife extends WBCli implements WBObserver
{
/**
* Select text domain
* @var string
*/
private $domain = null;
/**
* Select language
* @var string
*/
private $lang = null;
/**
* @var WBDatasource_Table
*/
private $table;
/**
* markup scanner
* @var WBMarkup_Scanner
*/
private $scanner;
/**
* markup scanner handler
* @var WBMarkup_Handler_Xml2Xml
*/
private $handler;
/**
* XML parser resource
* @var resource
*/
private $parser;
/**
* Use strict mode
* @var bool
*/
private $strict = false;
/**
* List of open file handlers
* @var array
*/
private $fh = array();
/**
* XML stack
* @var array
*/
private $xmlStack = array();
/**
* Method to call for each XML element
* @var string
*/
private $xmlHandler = '';
/**
* Message timestamp
* @var string
*/
private $xmlTimestamp = '';
/**
* Command line arguments
* @var array
*/
protected $arguments = array(
'in' => array(
'short' => 'i',
'max' => 1,
'min' => 0,
'default' => '',
'desc' => 'in file',
),
'out' => array(
'short' => 'o',
'max' => 1,
'min' => 0,
'default' => '',
'desc' => 'out file',
),
'domain' => array(
'short' => 'd',
'max' => 1,
'min' => 0,
'default' => '',
'desc' => 'text domain',
),
'lang' => array(
'short' => 'l',
'max' => 1,
'min' => 0,
'default' => '',
'desc' => 'language code, like "de_DE"',
),
'strict' => array(
'short' => 's',
'max' => 0,
'desc' => 'Validate strict use of tags"',
),
CONSOLE_GETARGS_PARAMS => array(
'min' => 1,
'max' => -1,
'default' => 'export',
'desc' => 'Command',
)
);
/**
* 2nd constructor
*
* load config and setup importer
*/
protected function init()
{
$this->table = WBClass::create('WBDatasource_Table');
$this->table->switchTranslation(false);
$this->scanner = WBClass::create('WBMarkup_Scanner');
$this->handler = WBClass::create('WBMarkup_Handler_Xml2Xml');
$this->scanner->setHandler($this->handler);
}
/**
* execute programme
*
*
*/
protected function execute()
{
if (empty($this->commands)) {
$this->commands = array('export');
}
$optFmt = ' %10s: %s';
if ($this->args->isDefined('strict')) {
$this->strict = true;
}
$this->domain = $this->args->getValue('domain');
if (empty($this->domain)) {
$this->domain = null;
$this->pvl(sprintf($optFmt, 'Domain', 'ANY'));
}
else {
$this->domain = strtolower($this->domain);
$this->pvl(sprintf($optFmt, 'Domain', $this->domain));
}
$this->lang = $this->args->getValue('lang');
$this->pvl(sprintf($optFmt, 'Language', $this->lang));
$this->pvl(sprintf($optFmt, 'Strict', intval($this->strict)));
$cmd = strtolower(array_shift($this->commands));
switch ($cmd) {
case 'import':
$ret = $this->import();
break;
case 'export':
$ret = $this->export();
break;
case 'validate':
$ret = $this->validate();
break;
default:
$this->pl('Command "' . $cmd . '" not supported!', STDERR);
$ret = 127;
break;
}
// close all open files
foreach ($this->fh as $fh) {
fclose($fh);
}
return $ret;
}
/**
* Import XML messages to DB
*
*
*/
public function import()
{
if (empty($this->lang)) {
$this->pl('Paramerter lang is required, but empty');
return 3;
}
$in = $this->openFile($this->args->getValue('in'), 'r');
if (!$in) {
return 2;
}
$this->pvl('Import XML file ' . $this->args->getValue('in'));
$this->xmlHandler = 'Import';
$length = $this->parseXml($in);
if (0 > $length) {
$this->pl('Import failed!');
return;
}
$this->pvl('OK, imported '. $length.' bytes.');
}
/**
* Export NLS messages to XML
*
*
*/
public function export()
{
if (empty($this->lang)) {
$this->pl('Paramerter lang is required, but empty');
return 3;
}
$out = $this->openFile($this->args->getValue('out'), 'w');
if (!$out) {
return 2;
}
fputs($out, '' . "\n");
fputs($out, '
'); break; } if ('em' == $parent['element']) { $error = sprintf('Em-tag must not be parent of
'); break; } return; break; default: return; break; } $this->pl($error . sprintf(' @ %d:%d.', $me['line'], $me['column']), STDERR); } /** * Handle XML End Element: Validate * * @param string $element * @param array $attributes * @param string $cData * @param bool build parent */ private function handleXmlEndElementValidate($element, $attributes, $cData) { return false; $cData = implode('', $cData); $this->pvl(' ' . str_repeat(' ', count($this->xmlStack) * 2) . '' . $element . ' cData="' . strlen($cData) . '">'); return false; } /** * Handle XML Start Element: Validate * * @param string $element * @param array $attributes */ private function handleXmlStartElementImport($element, $attributes) { if (!strstr($element, ':')) { return; } list($ns, $element) = explode(':', $element); if ('wbnls' != $ns) { return; } if ('messages' != $element) { return; } $this->xmlTimestamp = $attributes['timestamp']; } /** * Handle XML Element: Import * * @param string $element * @param array $attributes * @param string $cData * @param bool build parent */ private function handleXmlEndElementImport($element, $attributes, $cData) { if (!strstr($element, ':')) { return true; } list($ns, $element) = explode(':', $element); if ('wbnls' != $ns) { return true; } if ('msg' != $element) { return true; } $old = $this->table->get('nlsmsg', $attributes['msgid']); if (1 != count($old)) { $this->pl('Error: msgid ' . $attributes['msgid'] . ' not found!'. STDERR); } $old = $old[0]; $cData = implode('', $cData); if ($old['trans_' . $this->lang] == $cData) { $this->pvl($attributes['msgid'] . ' skiped'); return false; } $this->pl($attributes['msgid']); $save = array( 'changed_' . $this->lang => $this->xmlTimestamp, 'trans_' . $this->lang => $cData ); $this->table->save('nlsmsg', $attributes['msgid'], $save); return false; } /** * Parse XML file * * @param resouce $handle * @return int $size of file */ private function parseXml($handle) { $this->parser = xml_parser_create(); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); xml_set_element_handler($this->parser, array($this, 'onXMLStartElement'), array($this, 'onXMLEndElement')); xml_set_character_data_handler($this->parser, array($this, 'onXMLCharacterData')); $length = 0; $error = false; while (!feof($handle)) { $line = fgets($handle, 4096); $length += strlen($line); if (0 != xml_parse($this->parser, $line, false)) { continue; } $error = true; break; } if ($error) { $code = xml_get_error_code($this->parser); $string = xml_error_string($code); $this->pl('XML-Error! ' . $string . ' in line ' . $line, STDERR); xml_parser_free($this->parser); return -1; } xml_parse($this->parser, '', true); xml_parser_free($this->parser); $this->parser = null; return $length; } /** * XML parser callback onStartElement * * @param resource $parser * @param string $element * @param array attributes */ public function onXMLStartElement($parser, $element, $attributes) { if (!$attributes) { $attributes = array(); } $this->xmlStack[] = array( 'element' => $element, 'attributes' => $attributes, 'cData' => array(), 'line' => xml_get_current_line_number($this->parser), 'column' => xml_get_current_column_number($this->parser) ); call_user_func(array($this, 'handleXmlStartElement'. ucfirst($this->xmlHandler)), $element, $attributes); } /** * XML parser callback onEndElement * * @param resource $parser * @param string $element */ public function onXMLEndElement($parser, $element) { $data = array_pop($this->xmlStack); if (!call_user_func(array($this, 'handleXmlEndElement'. ucfirst($this->xmlHandler)), $element, $data['attributes'], $data['cData'])) { return; } $attributes = ''; foreach ($data['attributes'] as $k => $v) { $attributes .= sprintf(' %s="%s"', $k, $v); } if (empty($data['cData'])) { $cData = '<' . $element . $attributes . ' />'; } else { $cData = '<' . $element . $attributes . '>' . implode('', $data['cData']) . '' . $element . '>'; } $pos = count($this->xmlStack) - 1; $this->xmlStack[$pos]['cData'][] = $cData; } /** * XML parser callback onCharacterData * * @param resource $parser * @param string $cData */ public function onXMLCharacterData($parser, $cData) { $pos = count($this->xmlStack) - 1; $this->xmlStack[$pos]['cData'][] = $cData; } /** * Prepare file handle * * @see fopen() * @param string $file * @param strong $mode */ private function openFile($file, $mode) { if (empty($file)) { $this->pl('File not set!', STDERR); return false; } // stdout and stdin if ('--' == $file) { switch ($mode) { case 'r': return STDIN; break; case 'w': return STDOUT; break; } return false; } $fh = fopen($file, $mode); if (!$fh) { $this->pl('Could not open file "'. $file .'" in mode "'. $mode .'"', STDERR); return false; } $this->fh[] = $fh; return $fh; } /** * get help text - head * * Override this method to set suitable help text * * @return string */ protected function getHelpHead() { $head = array(); $head[] = 'Wombat NLS - Pocket Knife'; $head[] = ''; $head[] = 'Multi purpose tool to handle NLS translations.'; $head[] = ''; $head[] = 'Usage: ' . basename($_SERVER['_']) . ' [OPTION]... COMMAND [PARAMETER]... '; $head[] = ''; $head[] = 'Commands are:'; $head[] = ' - export: Export messages to XML file'; $head[] = ' - validate: Validate format of XML file'; $head[] = ' - import: Import translations from XML file'; $head[] = ''; $head[] = 'Options:'; $head[] = ''; return implode("\n", $head); } /** * Get informed * * @param WBMail_Mime_Processor_Observerable_Cli $subject */ public function update($subject) { $this->pl($subject->getMsg()); } }