@@ -0,0 +1,94 @@ | |||
<?php | |||
class JSParser { | |||
protected $content; | |||
protected $keywords; | |||
protected $regs = array(); | |||
protected $regsCounter = 0; | |||
protected $strings = array(); | |||
protected $stringsCounter = 0; | |||
protected function _extractRegs($match) { | |||
$this->regs[$this->regsCounter] = $match[1]; | |||
$id = "<<reg{$this->regsCounter}>>"; | |||
$this->regsCounter++; | |||
return $id; | |||
} | |||
protected function _extractStrings($match) { | |||
$this->strings[$this->stringsCounter] = $this->importRegExps($match[0]); | |||
$id = "<<s{$this->stringsCounter}>>"; | |||
$this->stringsCounter++; | |||
return $id; | |||
} | |||
protected function importRegExps($input) { | |||
$regs = $this->regs; | |||
return preg_replace_callback("#<<reg(\d+)>>#", function ($match) use($regs) { | |||
return $regs[$match[1]]; | |||
}, $input); | |||
} | |||
protected function importStrings($input) { | |||
$strings = $this->strings; | |||
return preg_replace_callback("#<<s(\d+)>>#", function ($match) use($strings) { | |||
return $strings[$match[1]]; | |||
}, $input); | |||
} | |||
public function __construct($file, $keywords = '_') { | |||
$this->content = file_get_contents($file); | |||
$this->keywords = (array)$keywords; | |||
} | |||
public function parse() { | |||
$output = htmlspecialchars($this->content, ENT_NOQUOTES); | |||
// extract reg exps | |||
$output = preg_replace_callback( | |||
'# ( / (?: (?>[^/\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\/ )+ (?<!\\\\)/ ) [a-z]* \b #ix', | |||
array($this, '_extractRegs'), $output | |||
); | |||
// extract strings | |||
$output = preg_replace_callback( | |||
array( | |||
'# " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" #ix', | |||
"# ' ( (?: (?>[^'\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\' )* ) (?<!\\\\)' #ix" | |||
), array($this, '_extractStrings'), $output | |||
); | |||
// delete line comments | |||
$output = preg_replace("#(//.*?)$#m", '', $output); | |||
// delete multiline comments | |||
$output = preg_replace('#/\*(.*?)\*/#is', '', $output); | |||
$strings = $this->strings; | |||
$output = preg_replace_callback("#<<s(\d+)>>#", function($match) use($strings) { | |||
return $strings[$match[1]]; | |||
}, $output); | |||
$keywords = implode('|', $this->keywords); | |||
$strings = array(); | |||
// extract func calls | |||
preg_match_all( | |||
'# (?:'.$keywords.') \(\\ *" ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)"\\ *\) #ix', | |||
$output, $matches, PREG_SET_ORDER | |||
); | |||
foreach ($matches as $m) $strings[] = stripslashes($m[1]); | |||
$matches = array(); | |||
preg_match_all( | |||
"# (?:$keywords) \(\\ *' ( (?: (?>[^'\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\' )* ) (?<!\\\\)'\\ *\) #ix", | |||
$output, $matches, PREG_SET_ORDER | |||
); | |||
foreach ($matches as $m) $strings[] = stripslashes($m[1]); | |||
return $strings; | |||
} | |||
} | |||
?> |
@@ -0,0 +1,83 @@ | |||
<?php | |||
require_once 'PoeditString.php'; | |||
class PoeditParser { | |||
protected $file; | |||
protected $header = ''; | |||
protected $strings = array(); | |||
protected function _fixQuotes($str) { | |||
return stripslashes($str); | |||
} | |||
public function __construct($file) { | |||
$this->file = $file; | |||
} | |||
public function parse() { | |||
$contents = file_get_contents($this->file); | |||
$parts = preg_split('#(\r\n|\n){2}#', $contents, -1, PREG_SPLIT_NO_EMPTY); | |||
$this->header = array_shift($parts); | |||
foreach ($parts as $part) { | |||
// parse comments | |||
$comments = array(); | |||
preg_match_all('#^\\#: (.*?)$#m', $part, $matches, PREG_SET_ORDER); | |||
foreach ($matches as $m) $comments[] = $m[1]; | |||
$isFuzzy = preg_match('#^\\#, fuzzy$#im', $part) ? true : false; | |||
preg_match_all('# ^ (msgid|msgstr)\ " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" $ #ixm', $part, $matches2, PREG_SET_ORDER); | |||
$k = $this->_fixQuotes($matches2[0][2]); | |||
$v = !empty($matches2[1][2]) ? $this->_fixQuotes($matches2[1][2]) : ''; | |||
$this->strings[$k] = new PoeditString($k, $v, $isFuzzy, $comments); | |||
} | |||
} | |||
public function merge($strings) { | |||
foreach ((array)$strings as $str) { | |||
if (!in_array($str, array_keys($this->strings))) { | |||
$this->strings[$str] = new PoeditString($str); | |||
} | |||
} | |||
} | |||
public function getHeader() { | |||
return $this->header; | |||
} | |||
public function getStrings() { | |||
return $this->strings; | |||
} | |||
public function getJSON() { | |||
$str = array(); | |||
foreach ($this->strings as $s) { | |||
if ($s->value) $str[$s->key] = $s->value; | |||
} | |||
return json_encode($str); | |||
} | |||
public function toJSON($outputFilename, $varName = 'l10n') { | |||
$str = "$varName = " . $this->getJSON(); | |||
return file_put_contents($outputFilename, $str) !== false; | |||
} | |||
public function save($filename = null) { | |||
$data = $this->header . "\n\n"; | |||
foreach ($this->strings as $str) { | |||
$data .= $str; | |||
} | |||
return file_put_contents($filename ? $filename : $this->file, $data) !== false; | |||
} | |||
} | |||
?> |
@@ -0,0 +1,29 @@ | |||
<?php | |||
class PoeditString { | |||
public $key; | |||
public $value; | |||
public $fuzzy; | |||
public $comments; | |||
function __construct($key, $value = '', $fuzzy = false, $comments = array()) { | |||
$this->key = $key; | |||
$this->value = $value; | |||
$this->fuzzy = $fuzzy; | |||
$this->comments = (array)$comments; | |||
} | |||
public function __toString() { | |||
$str =''; | |||
foreach ($this->comments as $c) { | |||
$str .= "#: $c\n"; | |||
} | |||
if ($this->fuzzy) $str .= "#, fuzzy\n"; | |||
$str .= 'msgid "'.str_replace('"', '\\"', $this->key).'"' . "\n"; | |||
$str .= 'msgstr "'.str_replace('"', '\\"', $this->value).'"' . "\n"; | |||
$str .= "\n"; | |||
return $str; | |||
} | |||
} | |||
?> |
@@ -0,0 +1,59 @@ | |||
<?php | |||
require_once 'JSParser.php'; | |||
require_once 'PoeditParser.php'; | |||
function buildOptions($args) { | |||
$options = array( | |||
'files' => array(), | |||
'-o' => null, | |||
'-k' => '_' | |||
); | |||
$len = count($args); | |||
$i = 0; | |||
while ($i < $len) { | |||
if (preg_match('#^-[a-z]$#i', $args[$i])) { | |||
$options[$args[$i]] = isset($args[$i+1]) ? trim($args[$i+1]) : true; | |||
$i += 2; | |||
} | |||
else { | |||
$options['files'][] = $args[$i]; | |||
$i++; | |||
} | |||
} | |||
return $options; | |||
} | |||
$options = buildOptions($argv); | |||
if (!file_exists($options['-o']) || !is_writable($options['-o'])) { | |||
die("Invalid output file name. Make sure it exists and is writable."); | |||
} | |||
$inputFiles = $options['files']; | |||
if (empty($inputFiles)) { | |||
die("You did not provide any input file."); | |||
} | |||
$poeditParser = new PoeditParser($options['-o']); | |||
$poeditParser->parse(); | |||
$errors = array(); | |||
foreach ($inputFiles as $f) { | |||
if (!is_readable($f) || !preg_match('#\.js$#', $f)) { | |||
$errors[] = ("$f is not a valid javascript file."); | |||
continue; | |||
} | |||
$jsparser = new JSParser($f, explode(' ', $options['-k'])); | |||
$jsStrings = $jsparser->parse(); | |||
$poeditParser->merge($jsStrings); | |||
} | |||
if (!empty($errors)) { | |||
echo "\nThe following errors occured:\n" . implode("\n", $errors) . "\n"; | |||
} | |||
$poeditParser->save(); | |||
?> |
@@ -0,0 +1,42 @@ | |||
<?php | |||
require_once 'PoeditParser.php'; | |||
function buildOptions($args) { | |||
$options = array( | |||
'-o' => null, | |||
'-i' => null, | |||
'-n' => 'l10n' | |||
); | |||
$len = count($args); | |||
$i = 0; | |||
while ($i < $len) { | |||
if (preg_match('#^-[a-z]$#i', $args[$i])) { | |||
$options[$args[$i]] = isset($args[$i+1]) ? trim($args[$i+1]) : true; | |||
$i += 2; | |||
} | |||
else { | |||
$options[] = $args[$i]; | |||
$i++; | |||
} | |||
} | |||
return $options; | |||
} | |||
$options = buildOptions($argv); | |||
if (!file_exists($options['-i']) || !is_readable($options['-i'])) { | |||
die("Invalid input file. Make sure it exists and is readable."); | |||
} | |||
$poeditParser = new PoeditParser($options['-i']); | |||
$poeditParser->parse(); | |||
if ($poeditParser->toJSON($options['-o'], $options['-n'])) { | |||
$strings = count($poeditParser->getStrings()); | |||
echo "Successfully exported " . count($strings) . " strings.\n"; | |||
} | |||
else { | |||
echo "Cannor write to file '{$options['-o']}'.\n"; | |||
} | |||
?> |
@@ -0,0 +1,27 @@ | |||
function _(s) { | |||
return typeof l10n[s] != 'undefined' ? l10n[s] : s; | |||
} | |||
function test(param) { | |||
var a = _("Hello world, testing jsgettext"); | |||
func(_('Test string')); | |||
var reg1 = /"[a-z]+"/i; | |||
var reg2 = /[a-z]+\+\/"aa"/i; | |||
var s1 = _('string 1: single quotes'); | |||
var s2 = _("string 2: double quotes"); | |||
var s3 = _("/* comment in string */"); | |||
var s4 = _("regexp in string: /[a-z]+/i"); | |||
var s5 = jsgettext( "another function" ); | |||
var s6 = avoidme("should not see me!"); | |||
var s7 = _("string 2: \"escaped double quotes\""); | |||
var s8 = _('string 2: \'escaped single quotes\''); | |||
// "string in comment" | |||
//; | |||
/** | |||
* multiple | |||
* lines | |||
* comment | |||
* _("Hello world from comment") | |||
*/ | |||
} |