CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 1.3 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 1.3
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Classes

  • AclBase
  • AclBehavior
  • AclComponent
  • AclNode
  • AclShell
  • Aco
  • AcoAction
  • AjaxHelper
  • ApcEngine
  • ApiShell
  • App
  • AppController
  • AppHelper
  • AppModel
  • Aro
  • AuthComponent
  • BakeShell
  • BakeTask
  • BehaviorCollection
  • Cache
  • CacheEngine
  • CacheHelper
  • CakeErrorController
  • CakeLog
  • CakeRoute
  • CakeSchema
  • CakeSession
  • CakeSocket
  • ClassRegistry
  • Component
  • Configure
  • ConnectionManager
  • ConsoleShell
  • ContainableBehavior
  • Controller
  • ControllerTask
  • CookieComponent
  • DataSource
  • DbAcl
  • DbConfigTask
  • DboMssql
  • DboMysql
  • DboMysqlBase
  • DboMysqli
  • DboOracle
  • DboPostgres
  • DboSource
  • DboSqlite
  • Debugger
  • EmailComponent
  • ErrorHandler
  • ExtractTask
  • File
  • FileEngine
  • FileLog
  • FixtureTask
  • Folder
  • FormHelper
  • Helper
  • HtmlHelper
  • HttpSocket
  • I18n
  • I18nModel
  • I18nShell
  • Inflector
  • IniAcl
  • JavascriptHelper
  • JqueryEngineHelper
  • JsBaseEngineHelper
  • JsHelper
  • L10n
  • MagicDb
  • MagicFileResource
  • MediaView
  • MemcacheEngine
  • Model
  • ModelBehavior
  • ModelTask
  • MootoolsEngineHelper
  • Multibyte
  • NumberHelper
  • Object
  • Overloadable
  • Overloadable2
  • PagesController
  • PaginatorHelper
  • Permission
  • PluginShortRoute
  • PluginTask
  • ProjectTask
  • PrototypeEngineHelper
  • RequestHandlerComponent
  • Router
  • RssHelper
  • Sanitize
  • Scaffold
  • ScaffoldView
  • SchemaShell
  • Security
  • SecurityComponent
  • SessionComponent
  • SessionHelper
  • Set
  • Shell
  • String
  • TemplateTask
  • TestSuiteShell
  • TestTask
  • TextHelper
  • ThemeView
  • TimeHelper
  • TranslateBehavior
  • TreeBehavior
  • Validation
  • View
  • ViewTask
  • XcacheEngine
  • Xml
  • XmlElement
  • XmlHelper
  • XmlManager
  • XmlNode
  • XmlTextNode

Functions

  • mb_encode_mimeheader
  • mb_stripos
  • mb_stristr
  • mb_strlen
  • mb_strpos
  • mb_strrchr
  • mb_strrichr
  • mb_strripos
  • mb_strrpos
  • mb_strstr
  • mb_strtolower
  • mb_strtoupper
  • mb_substr
  • mb_substr_count
  1: <?php
  2: /**
  3:  * Language string extractor
  4:  *
  5:  * PHP versions 4 and 5
  6:  *
  7:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8:  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9:  *
 10:  * Licensed under The MIT License
 11:  * Redistributions of files must retain the above copyright notice.
 12:  *
 13:  * @copyright     Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
 14:  * @link          http://cakephp.org CakePHP(tm) Project
 15:  * @package       cake
 16:  * @subpackage    cake.cake.console.libs
 17:  * @since         CakePHP(tm) v 1.2.0.5012
 18:  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 19:  */
 20: 
 21: /**
 22:  * Language string extractor
 23:  *
 24:  * @package       cake
 25:  * @subpackage    cake.cake.console.libs.tasks
 26:  */
 27: class ExtractTask extends Shell {
 28: 
 29: /**
 30:  * Paths to use when looking for strings
 31:  *
 32:  * @var string
 33:  * @access private
 34:  */
 35:     var $__paths = array();
 36: 
 37: /**
 38:  * Files from where to extract
 39:  *
 40:  * @var array
 41:  * @access private
 42:  */
 43:     var $__files = array();
 44: 
 45: /**
 46:  * Merge all domains string into the default.pot file
 47:  *
 48:  * @var boolean
 49:  * @access private
 50:  */
 51:     var $__merge = false;
 52: 
 53: /**
 54:  * Current file being processed
 55:  *
 56:  * @var string
 57:  * @access private
 58:  */
 59:     var $__file = null;
 60: 
 61: /**
 62:  * Contains all content waiting to be write
 63:  *
 64:  * @var string
 65:  * @access private
 66:  */
 67:     var $__storage = array();
 68: 
 69: /**
 70:  * Extracted tokens
 71:  *
 72:  * @var array
 73:  * @access private
 74:  */
 75:     var $__tokens = array();
 76: 
 77: /**
 78:  * Extracted strings
 79:  *
 80:  * @var array
 81:  * @access private
 82:  */
 83:     var $__strings = array();
 84: 
 85: /**
 86:  * Destination path
 87:  *
 88:  * @var string
 89:  * @access private
 90:  */
 91:     var $__output = null;
 92: 
 93: /**
 94:  * Execution method always used for tasks
 95:  *
 96:  * @return void
 97:  * @access private
 98:  */
 99:     function execute() {
100:         if (isset($this->params['files']) && !is_array($this->params['files'])) {
101:             $this->__files = explode(',', $this->params['files']);
102:         }
103:         if (isset($this->params['paths'])) {
104:             $this->__paths = explode(',', $this->params['paths']);
105:         } else {
106:             $defaultPath = $this->params['working'];
107:             $message = sprintf(__("What is the full path you would like to extract?\nExample: %s\n[Q]uit [D]one", true), $this->params['root'] . DS . 'myapp');
108:             while (true) {
109:                 $response = $this->in($message, null, $defaultPath);
110:                 if (strtoupper($response) === 'Q') {
111:                     $this->out(__('Extract Aborted', true));
112:                     $this->_stop();
113:                 } elseif (strtoupper($response) === 'D') {
114:                     $this->out();
115:                     break;
116:                 } elseif (is_dir($response)) {
117:                     $this->__paths[] = $response;
118:                     $defaultPath = 'D';
119:                 } else {
120:                     $this->err(__('The directory path you supplied was not found. Please try again.', true));
121:                 }
122:                 $this->out();
123:             }
124:         }
125: 
126:         if (isset($this->params['output'])) {
127:             $this->__output = $this->params['output'];
128:         } else {
129:             $message = sprintf(__("What is the full path you would like to output?\nExample: %s\n[Q]uit", true), $this->__paths[0] . DS . 'locale');
130:             while (true) {
131:                 $response = $this->in($message, null, $this->__paths[0] . DS . 'locale');
132:                 if (strtoupper($response) === 'Q') {
133:                     $this->out(__('Extract Aborted', true));
134:                     $this->_stop();
135:                 } elseif (is_dir($response)) {
136:                     $this->__output = $response . DS;
137:                     break;
138:                 } else {
139:                     $this->err(__('The directory path you supplied was not found. Please try again.', true));
140:                 }
141:                 $this->out();
142:             }
143:         }
144: 
145:         if (isset($this->params['merge'])) {
146:             $this->__merge = !(strtolower($this->params['merge']) === 'no');
147:         } else {
148:             $this->out();
149:             $response = $this->in(sprintf(__('Would you like to merge all domains strings into the default.pot file?', true)), array('y', 'n'), 'n');
150:             $this->__merge = strtolower($response) === 'y';
151:         }
152: 
153:         if (empty($this->__files)) {
154:             $this->__searchFiles();
155:         }
156:         $this->__extract();
157:     }
158: 
159: /**
160:  * Extract text
161:  *
162:  * @return void
163:  * @access private
164:  */
165:     function __extract() {
166:         $this->out();
167:         $this->out();
168:         $this->out(__('Extracting...', true));
169:         $this->hr();
170:         $this->out(__('Paths:', true));
171:         foreach ($this->__paths as $path) {
172:             $this->out('   ' . $path);
173:         }
174:         $this->out(__('Output Directory: ', true) . $this->__output);
175:         $this->hr();
176:         $this->__extractTokens();
177:         $this->__buildFiles();
178:         $this->__writeFiles();
179:         $this->__paths = $this->__files = $this->__storage = array();
180:         $this->__strings = $this->__tokens = array();
181:         $this->out();
182:         $this->out(__('Done.', true));
183:     }
184: 
185: /**
186:  * Show help options
187:  *
188:  * @return void
189:  * @access public
190:  */
191:     function help() {
192:         $this->out(__('CakePHP Language String Extraction:', true));
193:         $this->hr();
194:         $this->out(__('The Extract script generates .pot file(s) with translations', true));
195:         $this->out(__('By default the .pot file(s) will be place in the locale directory of -app', true));
196:         $this->out(__('By default -app is ROOT/app', true));
197:         $this->hr();
198:         $this->out(__('Usage: cake i18n extract <command> <param1> <param2>...', true));
199:         $this->out();
200:         $this->out(__('Params:', true));
201:         $this->out(__('   -app [path...]: directory where your application is located', true));
202:         $this->out(__('   -root [path...]: path to install', true));
203:         $this->out(__('   -core [path...]: path to cake directory', true));
204:         $this->out(__('   -paths [comma separated list of paths, full path is needed]', true));
205:         $this->out(__('   -merge [yes|no]: Merge all domains strings into the default.pot file', true));
206:         $this->out(__('   -output [path...]: Full path to output directory', true));
207:         $this->out(__('   -files: [comma separated list of files, full path to file is needed]', true));
208:         $this->out();
209:         $this->out(__('Commands:', true));
210:         $this->out(__('   cake i18n extract help: Shows this help message.', true));
211:         $this->out();
212:     }
213: 
214: /**
215:  * Extract tokens out of all files to be processed
216:  *
217:  * @return void
218:  * @access private
219:  */
220:     function __extractTokens() {
221:         foreach ($this->__files as $file) {
222:             $this->__file = $file;
223:             $this->out(sprintf(__('Processing %s...', true), $file));
224: 
225:             $code = file_get_contents($file);
226:             $allTokens = token_get_all($code);
227:             $this->__tokens = array();
228:             $lineNumber = 1;
229: 
230:             foreach ($allTokens as $token) {
231:                 if ((!is_array($token)) || (($token[0] != T_WHITESPACE) && ($token[0] != T_INLINE_HTML))) {
232:                     if (is_array($token)) {
233:                         $token[] = $lineNumber;
234:                     }
235:                     $this->__tokens[] = $token;
236:                 }
237: 
238:                 if (is_array($token)) {
239:                     $lineNumber += count(explode("\n", $token[1])) - 1;
240:                 } else {
241:                     $lineNumber += count(explode("\n", $token)) - 1;
242:                 }
243:             }
244:             unset($allTokens);
245:             $this->__parse('__', array('singular'));
246:             $this->__parse('__n', array('singular', 'plural'));
247:             $this->__parse('__d', array('domain', 'singular'));
248:             $this->__parse('__c', array('singular'));
249:             $this->__parse('__dc', array('domain', 'singular'));
250:             $this->__parse('__dn', array('domain', 'singular', 'plural'));
251:             $this->__parse('__dcn', array('domain', 'singular', 'plural'));
252:         }
253:     }
254: 
255: /**
256:  * Parse tokens
257:  *
258:  * @param string $functionName Function name that indicates translatable string (e.g: '__')
259:  * @param array $map Array containing what variables it will find (e.g: domain, singular, plural)
260:  * @return void
261:  * @access private
262:  */
263:     function __parse($functionName, $map) {
264:         $count = 0;
265:         $tokenCount = count($this->__tokens);
266: 
267:         while (($tokenCount - $count) > 1) {
268:             list($countToken, $firstParenthesis) = array($this->__tokens[$count], $this->__tokens[$count + 1]);
269:             if (!is_array($countToken)) {
270:                 $count++;
271:                 continue;
272:             }
273: 
274:             list($type, $string, $line) = $countToken;
275:             if (($type == T_STRING) && ($string == $functionName) && ($firstParenthesis == '(')) {
276:                 $position = $count;
277:                 $depth = 0;
278: 
279:                 while ($depth == 0) {
280:                     if ($this->__tokens[$position] == '(') {
281:                         $depth++;
282:                     } elseif ($this->__tokens[$position] == ')') {
283:                         $depth--;
284:                     }
285:                     $position++;
286:                 }
287: 
288:                 $mapCount = count($map);
289:                 $strings = $this->__getStrings($position, $mapCount);
290: 
291:                 if ($mapCount == count($strings)) {
292:                     extract(array_combine($map, $strings));
293:                     $domain = isset($domain) ? $domain : 'default';
294:                     $string = isset($plural) ? $singular . "\0" . $plural : $singular;
295:                     $this->__strings[$domain][$string][$this->__file][] = $line;
296:                 } else {
297:                     $this->__markerError($this->__file, $line, $functionName, $count);
298:                 }
299:             }
300:             $count++;
301:         }
302:     }
303: 
304: /**
305: * Get the strings from the position forward
306: *
307: * @param integer $position Actual position on tokens array
308: * @param integer $target Number of strings to extract
309: * @return array Strings extracted
310: */
311:     function __getStrings($position, $target) {
312:         $strings = array();
313:         while (count($strings) < $target && ($this->__tokens[$position] == ',' || $this->__tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING)) {
314:             $condition1 = ($this->__tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING && $this->__tokens[$position+1] == '.');
315:             $condition2 = ($this->__tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING && $this->__tokens[$position+1][0] == T_COMMENT);
316:             if ($condition1 || $condition2) {
317:                 $string = '';
318:                 while ($this->__tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING || $this->__tokens[$position][0] == T_COMMENT || $this->__tokens[$position] == '.') {
319:                     if ($this->__tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING) {
320:                         $string .= $this->__formatString($this->__tokens[$position][1]);
321:                     }
322:                     $position++;
323:                 }
324:                 if ($this->__tokens[$position][0] == T_COMMENT || $this->__tokens[$position] == ',' || $this->__tokens[$position] == ')') {
325:                     $strings[] = $string;
326:                 }
327:             } else if ($this->__tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING) {
328:                 $strings[] = $this->__formatString($this->__tokens[$position][1]);
329:             }
330:             $position++;
331:         }
332:         return $strings;
333:     }
334:     
335: /**
336:  * Build the translate template file contents out of obtained strings
337:  *
338:  * @return void
339:  * @access private
340:  */
341:     function __buildFiles() {
342:         foreach ($this->__strings as $domain => $strings) {
343:             foreach ($strings as $string => $files) {
344:                 $occurrences = array();
345:                 foreach ($files as $file => $lines) {
346:                     $occurrences[] = $file . ':' . implode(';', $lines);
347:                 }
348:                 $occurrences = implode("\n#: ", $occurrences);
349:                 $header = '#: ' . str_replace($this->__paths, '', $occurrences) . "\n";
350: 
351:                 if (strpos($string, "\0") === false) {
352:                     $sentence = "msgid \"{$string}\"\n";
353:                     $sentence .= "msgstr \"\"\n\n";
354:                 } else {
355:                     list($singular, $plural) = explode("\0", $string);
356:                     $sentence = "msgid \"{$singular}\"\n";
357:                     $sentence .= "msgid_plural \"{$plural}\"\n";
358:                     $sentence .= "msgstr[0] \"\"\n";
359:                     $sentence .= "msgstr[1] \"\"\n\n";
360:                 }
361: 
362:                 $this->__store($domain, $header, $sentence);
363:                 if ($domain != 'default' && $this->__merge) {
364:                     $this->__store('default', $header, $sentence);
365:                 }
366:             }
367:         }
368:     }
369: 
370: /**
371:  * Prepare a file to be stored
372:  *
373:  * @return void
374:  * @access private
375:  */
376:     function __store($domain, $header, $sentence) {
377:         if (!isset($this->__storage[$domain])) {
378:             $this->__storage[$domain] = array();
379:         }
380:         if (!isset($this->__storage[$domain][$sentence])) {
381:             $this->__storage[$domain][$sentence] = $header;
382:         } else {
383:             $this->__storage[$domain][$sentence] .= $header;
384:         }
385:     }
386: 
387: /**
388:  * Write the files that need to be stored
389:  *
390:  * @return void
391:  * @access private
392:  */
393:     function __writeFiles() {
394:         $overwriteAll = false;
395:         foreach ($this->__storage as $domain => $sentences) {
396:             $output = $this->__writeHeader();
397:             foreach ($sentences as $sentence => $header) {
398:                 $output .= $header . $sentence;
399:             }
400: 
401:             $filename = $domain . '.pot';
402:             $File = new File($this->__output . $filename);
403:             $response = '';
404:             while ($overwriteAll === false && $File->exists() && strtoupper($response) !== 'Y') {
405:                 $this->out();
406:                 $response = $this->in(sprintf(__('Error: %s already exists in this location. Overwrite? [Y]es, [N]o, [A]ll', true), $filename), array('y', 'n', 'a'), 'y');
407:                 if (strtoupper($response) === 'N') {
408:                     $response = '';
409:                     while ($response == '') {
410:                         $response = $this->in(sprintf(__("What would you like to name this file?\nExample: %s", true), 'new_' . $filename), null, 'new_' . $filename);
411:                         $File = new File($this->__output . $response);
412:                         $filename = $response;
413:                     }
414:                 } elseif (strtoupper($response) === 'A') {
415:                     $overwriteAll = true;
416:                 }
417:             }
418:             $File->write($output);
419:             $File->close();
420:         }
421:     }
422: 
423: /**
424:  * Build the translation template header
425:  *
426:  * @return string Translation template header
427:  * @access private
428:  */
429:     function __writeHeader() {
430:         $output  = "# LANGUAGE translation of CakePHP Application\n";
431:         $output .= "# Copyright YEAR NAME <EMAIL@ADDRESS>\n";
432:         $output .= "#\n";
433:         $output .= "#, fuzzy\n";
434:         $output .= "msgid \"\"\n";
435:         $output .= "msgstr \"\"\n";
436:         $output .= "\"Project-Id-Version: PROJECT VERSION\\n\"\n";
437:         $output .= "\"POT-Creation-Date: " . date("Y-m-d H:iO") . "\\n\"\n";
438:         $output .= "\"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\\n\"\n";
439:         $output .= "\"Last-Translator: NAME <EMAIL@ADDRESS>\\n\"\n";
440:         $output .= "\"Language-Team: LANGUAGE <EMAIL@ADDRESS>\\n\"\n";
441:         $output .= "\"MIME-Version: 1.0\\n\"\n";
442:         $output .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
443:         $output .= "\"Content-Transfer-Encoding: 8bit\\n\"\n";
444:         $output .= "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n";
445:         return $output;
446:     }
447: 
448: /**
449:  * Format a string to be added as a translateable string
450:  *
451:  * @param string $string String to format
452:  * @return string Formatted string
453:  * @access private
454:  */
455:     function __formatString($string) {
456:         $quote = substr($string, 0, 1);
457:         $string = substr($string, 1, -1);
458:         if ($quote == '"') {
459:             $string = stripcslashes($string);
460:         } else {
461:             $string = strtr($string, array("\\'" => "'", "\\\\" => "\\"));
462:         }
463:         $string = str_replace("\r\n", "\n", $string);
464:         return addcslashes($string, "\0..\37\\\"");
465:     }
466: 
467: /**
468:  * Indicate an invalid marker on a processed file
469:  *
470:  * @param string $file File where invalid marker resides
471:  * @param integer $line Line number
472:  * @param string $marker Marker found
473:  * @param integer $count Count
474:  * @return void
475:  * @access private
476:  */
477:     function __markerError($file, $line, $marker, $count) {
478:         $this->out(sprintf(__("Invalid marker content in %s:%s\n* %s(", true), $file, $line, $marker), true);
479:         $count += 2;
480:         $tokenCount = count($this->__tokens);
481:         $parenthesis = 1;
482: 
483:         while ((($tokenCount - $count) > 0) && $parenthesis) {
484:             if (is_array($this->__tokens[$count])) {
485:                 $this->out($this->__tokens[$count][1], false);
486:             } else {
487:                 $this->out($this->__tokens[$count], false);
488:                 if ($this->__tokens[$count] == '(') {
489:                     $parenthesis++;
490:                 }
491: 
492:                 if ($this->__tokens[$count] == ')') {
493:                     $parenthesis--;
494:                 }
495:             }
496:             $count++;
497:         }
498:         $this->out("\n", true);
499:     }
500: 
501: /**
502:  * Search files that may contain translateable strings
503:  *
504:  * @return void
505:  * @access private
506:  */
507:     function __searchFiles() {
508:         foreach ($this->__paths as $path) {
509:             $Folder = new Folder($path);
510:             $files = $Folder->findRecursive('.*\.(php|ctp|thtml|inc|tpl)', true);
511:             $this->__files = array_merge($this->__files, $files);
512:         }
513:     }
514: }
515: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs