00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 ob_start();
00031
00032 $singularReturn = __('Singular string return __()', true);
00033 $singularEcho = __('Singular string echo __()');
00034
00035 $pluralReturn = __n('% apple in the bowl (plural string return __n())', '% apples in the blowl (plural string 2 return __n())', 3, true);
00036 $pluralEcho = __n('% apple in the bowl (plural string 2 echo __n())', '% apples in the blowl (plural string 2 echo __n()', 3);
00037
00038 $singularDomainReturn = __d('controllers', 'Singular string domain lookup return __d()', true);
00039 $singularDomainEcho = __d('controllers', 'Singular string domain lookup echo __d()');
00040
00041 $pluralDomainReturn = __dn('controllers', '% pears in the bowl (plural string domain lookup return __dn())', '% pears in the blowl (plural string domain lookup return __dn())', 3, true);
00042 $pluralDomainEcho = __dn('controllers', '% pears in the bowl (plural string domain lookup echo __dn())', '% pears in the blowl (plural string domain lookup echo __dn())', 3);
00043
00044 $singularDomainCategoryReturn = __dc('controllers', 'Singular string domain and category lookup return __dc()', 5, true);
00045 $singularDomainCategoryEcho = __dc('controllers', 'Singular string domain and category lookup echo __dc()', 5);
00046
00047 $pluralDomainCategoryReturn = __dcn('controllers', '% apple in the bowl (plural string 1 domain and category lookup return __dcn())', '% apples in the blowl (plural string 2 domain and category lookup return __dcn())', 3, 5, true);
00048 $pluralDomainCategoryEcho = __dcn('controllers', '% apple in the bowl (plural string 1 domain and category lookup echo __dcn())', '% apples in the blowl (plural string 2 domain and category lookup echo __dcn())', 3, 5);
00049
00050 $categoryReturn = __c('Category string lookup line return __c()', 5, true);
00051 $categoryEcho = __c('Category string lookup line echo __c()', 5);
00052
00053 ob_end_clean();
00054
00055
00056
00057
00058
00059
00060 class ExtractTask extends Shell{
00061
00062
00063
00064
00065
00066
00067 var $path = null;
00068
00069
00070
00071
00072
00073
00074 var $files = array();
00075
00076
00077
00078
00079
00080
00081 var $__filename = 'default';
00082
00083
00084
00085
00086
00087
00088 var $__oneFile = true;
00089
00090
00091
00092
00093
00094
00095 var $__file = null;
00096
00097
00098
00099
00100
00101
00102 var $__tokens = array();
00103
00104
00105
00106
00107
00108
00109 var $__strings = array();
00110
00111
00112
00113
00114
00115
00116 var $__fileVersions = array();
00117
00118
00119
00120
00121
00122
00123 var $__output = null;
00124
00125
00126
00127
00128
00129 function execute() {
00130 if (isset($this->params['files']) && !is_array($this->params['files'])) {
00131 $this->files = explode(',', $this->params['files']);
00132 }
00133 if (isset($this->params['path'])) {
00134 $this->path = $this->params['path'];
00135 } else {
00136 $response = '';
00137 while ($response == '') {
00138 $response = $this->in("What is the full path you would like to extract?\nExample: " . $this->params['root'] . DS . "myapp\n[Q]uit", null, $this->params['working']);
00139 if (strtoupper($response) === 'Q') {
00140 $this->out('Extract Aborted');
00141 $this->_stop();
00142 }
00143 }
00144
00145 if (is_dir($response)) {
00146 $this->path = $response;
00147 } else {
00148 $this->err('The directory path you supplied was not found. Please try again.');
00149 $this->execute();
00150 }
00151 }
00152
00153 if (isset($this->params['debug'])) {
00154 $this->path = ROOT;
00155 $this->files = array(__FILE__);
00156 }
00157
00158 if (isset($this->params['output'])) {
00159 $this->__output = $this->params['output'];
00160 } else {
00161 $response = '';
00162 while ($response == '') {
00163 $response = $this->in("What is the full path you would like to output?\nExample: " . $this->path . DS . "locale\n[Q]uit", null, $this->path . DS . "locale");
00164 if (strtoupper($response) === 'Q') {
00165 $this->out('Extract Aborted');
00166 $this->_stop();
00167 }
00168 }
00169
00170 if (is_dir($response)) {
00171 $this->__output = $response . DS;
00172 } else {
00173 $this->err('The directory path you supplied was not found. Please try again.');
00174 $this->execute();
00175 }
00176 }
00177
00178 if (empty($this->files)) {
00179 $this->files = $this->__searchDirectory();
00180 }
00181 $this->__extract();
00182 }
00183
00184
00185
00186
00187
00188 function __extract() {
00189 $this->out('');
00190 $this->out('');
00191 $this->out(__('Extracting...', true));
00192 $this->hr();
00193 $this->out(__('Path: ', true). $this->path);
00194 $this->out(__('Output Directory: ', true). $this->__output);
00195 $this->hr();
00196
00197 $response = '';
00198 $filename = '';
00199 while ($response == '') {
00200 $response = $this->in(__('Would you like to merge all translations into one file?', true), array('y','n'), 'y');
00201 if (strtolower($response) == 'n') {
00202 $this->__oneFile = false;
00203 } else {
00204 while ($filename == '') {
00205 $filename = $this->in(__('What should we name this file?', true), null, $this->__filename);
00206 if ($filename == '') {
00207 $this->out(__('The filesname you supplied was empty. Please try again.', true));
00208 }
00209 }
00210 $this->__filename = $filename;
00211 }
00212 }
00213 $this->__extractTokens();
00214 }
00215
00216
00217
00218
00219
00220 function help() {
00221 $this->out(__('CakePHP Language String Extraction:', true));
00222 $this->hr();
00223 $this->out(__('The Extract script generates .pot file(s) with translations', true));
00224 $this->out(__('By default the .pot file(s) will be place in the locale directory of -app', true));
00225 $this->out(__('By default -app is ROOT/app', true));
00226 $this->hr();
00227 $this->out(__('usage: cake i18n extract [command] [path...]', true));
00228 $this->out('');
00229 $this->out(__('commands:', true));
00230 $this->out(__(' -app [path...]: directory where your application is located', true));
00231 $this->out(__(' -root [path...]: path to install', true));
00232 $this->out(__(' -core [path...]: path to cake directory', true));
00233 $this->out(__(' -path [path...]: Full path to directory to extract strings', true));
00234 $this->out(__(' -output [path...]: Full path to output directory', true));
00235 $this->out(__(' -files: [comma separated list of files, full path to file is needed]', true));
00236 $this->out(__(' cake i18n extract help: Shows this help message.', true));
00237 $this->out(__(' -debug: Perform self test.', true));
00238 $this->out('');
00239 }
00240
00241
00242
00243
00244
00245 function __extractTokens() {
00246 foreach ($this->files as $file) {
00247 $this->__file = $file;
00248 $this->out(sprintf(__('Processing %s...', true), $file));
00249
00250 $code = file_get_contents($file);
00251
00252 $this->__findVersion($code, $file);
00253 $allTokens = token_get_all($code);
00254 $this->__tokens = array();
00255 $lineNumber = 1;
00256
00257 foreach ($allTokens as $token) {
00258 if ((!is_array($token)) || (($token[0] != T_WHITESPACE) && ($token[0] != T_INLINE_HTML))) {
00259 if (is_array($token)) {
00260 $token[] = $lineNumber;
00261 }
00262 $this->__tokens[] = $token;
00263 }
00264
00265 if (is_array($token)) {
00266 $lineNumber += count(split("\n", $token[1])) - 1;
00267 } else {
00268 $lineNumber += count(split("\n", $token)) - 1;
00269 }
00270 }
00271 unset($allTokens);
00272 $this->basic();
00273 $this->basic('__c');
00274 $this->extended();
00275 $this->extended('__dc', 2);
00276 $this->extended('__n', 0, true);
00277 $this->extended('__dn', 2, true);
00278 $this->extended('__dcn', 4, true);
00279 }
00280 $this->__buildFiles();
00281 $this->__writeFiles();
00282 $this->out('Done.');
00283 }
00284
00285
00286
00287
00288
00289
00290 function basic($functionName = '__') {
00291 $count = 0;
00292 $tokenCount = count($this->__tokens);
00293
00294 while (($tokenCount - $count) > 3) {
00295 list($countToken, $parenthesis, $middle, $right) = array($this->__tokens[$count], $this->__tokens[$count + 1], $this->__tokens[$count + 2], $this->__tokens[$count + 3]);
00296 if (!is_array($countToken)) {
00297 $count++;
00298 continue;
00299 }
00300
00301 list($type, $string, $line) = $countToken;
00302 if (($type == T_STRING) && ($string == $functionName) && ($parenthesis == '(')) {
00303
00304 if (in_array($right, array(')', ','))
00305 && (is_array($middle) && ($middle[0] == T_CONSTANT_ENCAPSED_STRING))) {
00306
00307 if ($this->__oneFile === true) {
00308 $this->__strings[$this->__formatString($middle[1])][$this->__file][] = $line;
00309 } else {
00310 $this->__strings[$this->__file][$this->__formatString($middle[1])][] = $line;
00311 }
00312 } else {
00313 $this->__markerError($this->__file, $line, $functionName, $count);
00314 }
00315 }
00316 $count++;
00317 }
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327 function extended($functionName = '__d', $shift = 0, $plural = false) {
00328 $count = 0;
00329 $tokenCount = count($this->__tokens);
00330
00331 while (($tokenCount - $count) > 7) {
00332 list($countToken, $firstParenthesis) = array($this->__tokens[$count], $this->__tokens[$count + 1]);
00333 if (!is_array($countToken)) {
00334 $count++;
00335 continue;
00336 }
00337
00338 list($type, $string, $line) = $countToken;
00339 if (($type == T_STRING) && ($string == $functionName) && ($firstParenthesis == '(')) {
00340 $position = $count;
00341 $depth = 0;
00342
00343 while ($depth == 0) {
00344 if ($this->__tokens[$position] == '(') {
00345 $depth++;
00346 } elseif ($this->__tokens[$position] == ')') {
00347 $depth--;
00348 }
00349 $position++;
00350 }
00351
00352 if ($plural) {
00353 $end = $position + $shift + 7;
00354
00355 if ($this->__tokens[$position + $shift + 5] === ')') {
00356 $end = $position + $shift + 5;
00357 }
00358
00359 if (empty($shift)) {
00360 list($singular, $firstComma, $plural, $seoncdComma, $endParenthesis) = array($this->__tokens[$position], $this->__tokens[$position + 1], $this->__tokens[$position + 2], $this->__tokens[$position + 3], $this->__tokens[$end]);
00361 $condition = ($seoncdComma == ',');
00362 } else {
00363 list($domain, $firstComma, $singular, $seoncdComma, $plural, $comma3, $endParenthesis) = array($this->__tokens[$position], $this->__tokens[$position + 1], $this->__tokens[$position + 2], $this->__tokens[$position + 3], $this->__tokens[$position + 4], $this->__tokens[$position + 5], $this->__tokens[$end]);
00364 $condition = ($comma3 == ',');
00365 }
00366 $condition = $condition &&
00367 (is_array($singular) && ($singular[0] == T_CONSTANT_ENCAPSED_STRING)) &&
00368 (is_array($plural) && ($plural[0] == T_CONSTANT_ENCAPSED_STRING));
00369 } else {
00370 if ($this->__tokens[$position + $shift + 5] === ')') {
00371 $comma = $this->__tokens[$position + $shift + 3];
00372 $end = $position + $shift + 5;
00373 } else {
00374 $comma = null;
00375 $end = $position + $shift + 3;
00376 }
00377
00378 list($domain, $firstComma, $text, $seoncdComma, $endParenthesis) = array($this->__tokens[$position], $this->__tokens[$position + 1], $this->__tokens[$position + 2], $comma, $this->__tokens[$end]);
00379 $condition = ($seoncdComma == ',' || $seoncdComma === null) &&
00380 (is_array($domain) && ($domain[0] == T_CONSTANT_ENCAPSED_STRING)) &&
00381 (is_array($text) && ($text[0] == T_CONSTANT_ENCAPSED_STRING));
00382 }
00383
00384 if (($endParenthesis == ')') && $condition) {
00385 if ($this->__oneFile === true) {
00386 if ($plural) {
00387 $this->__strings[$this->__formatString($singular[1]) . "\0" . $this->__formatString($plural[1])][$this->__file][] = $line;
00388 } else {
00389 $this->__strings[$this->__formatString($text[1])][$this->__file][] = $line;
00390 }
00391 } else {
00392 if ($plural) {
00393 $this->__strings[$this->__file][$this->__formatString($singular[1]) . "\0" . $this->__formatString($plural[1])][] = $line;
00394 } else {
00395 $this->__strings[$this->__file][$this->__formatString($text[1])][] = $line;
00396 }
00397 }
00398 } else {
00399 $this->__markerError($this->__file, $line, $functionName, $count);
00400 }
00401 }
00402 $count++;
00403 }
00404 }
00405
00406
00407
00408
00409
00410 function __buildFiles() {
00411 foreach ($this->__strings as $str => $fileInfo) {
00412 $output = '';
00413 $occured = $fileList = array();
00414
00415 if ($this->__oneFile === true) {
00416 foreach ($fileInfo as $file => $lines) {
00417 $occured[] = "$file:" . join(';', $lines);
00418
00419 if (isset($this->__fileVersions[$file])) {
00420 $fileList[] = $this->__fileVersions[$file];
00421 }
00422 }
00423 $occurances = join("\n#: ", $occured);
00424 $occurances = str_replace($this->path, '', $occurances);
00425 $output = "#: $occurances\n";
00426 $filename = $this->__filename;
00427
00428 if (strpos($str, "\0") === false) {
00429 $output .= "msgid \"$str\"\n";
00430 $output .= "msgstr \"\"\n";
00431 } else {
00432 list($singular, $plural) = explode("\0", $str);
00433 $output .= "msgid \"$singular\"\n";
00434 $output .= "msgid_plural \"$plural\"\n";
00435 $output .= "msgstr[0] \"\"\n";
00436 $output .= "msgstr[1] \"\"\n";
00437 }
00438 $output .= "\n";
00439 } else {
00440 foreach ($fileInfo as $file => $lines) {
00441 $filename = $str;
00442 $occured = array("$str:" . join(';', $lines));
00443
00444 if (isset($this->__fileVersions[$str])) {
00445 $fileList[] = $this->__fileVersions[$str];
00446 }
00447 $occurances = join("\n#: ", $occured);
00448 $occurances = str_replace($this->path, '', $occurances);
00449 $output .= "#: $occurances\n";
00450
00451 if (strpos($file, "\0") === false) {
00452 $output .= "msgid \"$file\"\n";
00453 $output .= "msgstr \"\"\n";
00454 } else {
00455 list($singular, $plural) = explode("\0", $file);
00456 $output .= "msgid \"$singular\"\n";
00457 $output .= "msgid_plural \"$plural\"\n";
00458 $output .= "msgstr[0] \"\"\n";
00459 $output .= "msgstr[1] \"\"\n";
00460 }
00461 $output .= "\n";
00462 }
00463 }
00464 $this->__store($filename, $output, $fileList);
00465 }
00466 }
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 function __store($file = 0, $input = 0, $fileList = array(), $get = 0) {
00478 static $storage = array();
00479
00480 if (!$get) {
00481 if (isset($storage[$file])) {
00482 $storage[$file][1] = array_unique(array_merge($storage[$file][1], $fileList));
00483 $storage[$file][] = $input;
00484 } else {
00485 $storage[$file] = array();
00486 $storage[$file][0] = $this->__writeHeader();
00487 $storage[$file][1] = $fileList;
00488 $storage[$file][2] = $input;
00489 }
00490 } else {
00491 return $storage;
00492 }
00493 }
00494
00495
00496
00497
00498
00499 function __writeFiles() {
00500 $output = $this->__store(0, 0, array(), 1);
00501 $output = $this->__mergeFiles($output);
00502
00503 foreach ($output as $file => $content) {
00504 $tmp = str_replace(array($this->path, '.php','.ctp','.thtml', '.inc','.tpl' ), '', $file);
00505 $tmp = str_replace(DS, '.', $tmp);
00506 $file = str_replace('.', '-', $tmp) .'.pot';
00507 $fileList = $content[1];
00508
00509 unset($content[1]);
00510
00511 $fileList = str_replace(array($this->path), '', $fileList);
00512
00513 if (count($fileList) > 1) {
00514 $fileList = "Generated from files:\n# " . join("\n# ", $fileList);
00515 } elseif (count($fileList) == 1) {
00516 $fileList = 'Generated from file: ' . join('', $fileList);
00517 } else {
00518 $fileList = 'No version information was available in the source files.';
00519 }
00520
00521 if (is_file($this->__output . $file)) {
00522 $response = '';
00523 while ($response == '') {
00524 $response = $this->in("\n\nError: ".$file . ' already exists in this location. Overwrite?', array('y','n', 'q'), 'n');
00525 if (strtoupper($response) === 'Q') {
00526 $this->out('Extract Aborted');
00527 $this->_stop();
00528 } elseif (strtoupper($response) === 'N') {
00529 $response = '';
00530 while ($response == '') {
00531 $response = $this->in("What would you like to name this file?\nExample: new_" . $file, null, "new_" . $file);
00532 $file = $response;
00533 }
00534 }
00535 }
00536 }
00537 $fp = fopen($this->__output . $file, 'w');
00538 fwrite($fp, str_replace('--VERSIONS--', $fileList, join('', $content)));
00539 fclose($fp);
00540 }
00541 }
00542
00543
00544
00545
00546
00547
00548
00549 function __mergeFiles($output) {
00550 foreach ($output as $file => $content) {
00551 if (count($content) <= 1 && $file != $this->__filename) {
00552 @$output[$this->__filename][1] = array_unique(array_merge($output[$this->__filename][1], $content[1]));
00553
00554 if (!isset($output[$this->__filename][0])) {
00555 $output[$this->__filename][0] = $content[0];
00556 }
00557 unset($content[0]);
00558 unset($content[1]);
00559
00560 foreach ($content as $msgid) {
00561 $output[$this->__filename][] = $msgid;
00562 }
00563 unset($output[$file]);
00564 }
00565 }
00566 return $output;
00567 }
00568
00569
00570
00571
00572
00573
00574 function __writeHeader() {
00575 $output = "# LANGUAGE translation of CakePHP Application\n";
00576 $output .= "# Copyright YEAR NAME <EMAIL@ADDRESS>\n";
00577 $output .= "# --VERSIONS--\n";
00578 $output .= "#\n";
00579 $output .= "#, fuzzy\n";
00580 $output .= "msgid \"\"\n";
00581 $output .= "msgstr \"\"\n";
00582 $output .= "\"Project-Id-Version: PROJECT VERSION\\n\"\n";
00583 $output .= "\"POT-Creation-Date: " . date("Y-m-d H:iO") . "\\n\"\n";
00584 $output .= "\"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\\n\"\n";
00585 $output .= "\"Last-Translator: NAME <EMAIL@ADDRESS>\\n\"\n";
00586 $output .= "\"Language-Team: LANGUAGE <EMAIL@ADDRESS>\\n\"\n";
00587 $output .= "\"MIME-Version: 1.0\\n\"\n";
00588 $output .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
00589 $output .= "\"Content-Transfer-Encoding: 8bit\\n\"\n";
00590 $output .= "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n";
00591 return $output;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600 function __findVersion($code, $file) {
00601 $header = '$Id' . ':';
00602 if (preg_match('/\\' . $header . ' [\\w.]* ([\\d]*)/', $code, $versionInfo)) {
00603 $version = str_replace(ROOT, '', 'Revision: ' . $versionInfo[1] . ' ' .$file);
00604 $this->__fileVersions[$file] = $version;
00605 }
00606 }
00607
00608
00609
00610
00611
00612
00613
00614 function __formatString($string) {
00615 $quote = substr($string, 0, 1);
00616 $string = substr($string, 1, -1);
00617 if ($quote == '"') {
00618 $string = stripcslashes($string);
00619 } else {
00620 $string = strtr($string, array("\\'" => "'", "\\\\" => "\\"));
00621 }
00622 $string = str_replace("\r\n", "\n", $string);
00623 return addcslashes($string, "\0..\37\\\"");
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 function __markerError($file, $line, $marker, $count) {
00635 $this->out("Invalid marker content in $file:$line\n* $marker(", true);
00636 $count += 2;
00637 $tokenCount = count($this->__tokens);
00638 $parenthesis = 1;
00639
00640 while ((($tokenCount - $count) > 0) && $parenthesis) {
00641 if (is_array($this->__tokens[$count])) {
00642 $this->out($this->__tokens[$count][1], false);
00643 } else {
00644 $this->out($this->__tokens[$count], false);
00645 if ($this->__tokens[$count] == '(') {
00646 $parenthesis++;
00647 }
00648
00649 if ($this->__tokens[$count] == ')') {
00650 $parenthesis--;
00651 }
00652 }
00653 $count++;
00654 }
00655 $this->out("\n", true);
00656 }
00657
00658
00659
00660
00661
00662
00663
00664 function __searchDirectory($path = null) {
00665 if ($path === null) {
00666 $path = $this->path .DS;
00667 }
00668 $files = glob("$path*.{php,ctp,thtml,inc,tpl}", GLOB_BRACE);
00669 $dirs = glob("$path*", GLOB_ONLYDIR);
00670
00671 $files = $files ? $files : array();
00672 $dirs = $dirs ? $dirs : array();
00673
00674 foreach ($dirs as $dir) {
00675 if (!preg_match("!(^|.+/)(CVS|.svn)$!", $dir)) {
00676 $files = array_merge($files, $this->__searchDirectory("$dir" . DS));
00677 if (($id = array_search($dir . DS . 'extract.php', $files)) !== FALSE) {
00678 unset($files[$id]);
00679 }
00680 }
00681 }
00682 return $files;
00683 }
00684 }
00685 ?>