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