sfI18nFindTask.class.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * Finds non "i18n ready" strings in an application.
  11. *
  12. * @package symfony
  13. * @subpackage task
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id: sfI18nFindTask.class.php 8453 2008-04-14 16:39:14Z fabien $
  16. */
  17. class sfI18nFindTask extends sfBaseTask
  18. {
  19. /**
  20. * @see sfTask
  21. */
  22. protected function configure()
  23. {
  24. $this->addArguments(array(
  25. new sfCommandArgument('application', sfCommandArgument::REQUIRED, 'The application name'),
  26. ));
  27. $this->addOptions(array(
  28. new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'dev'),
  29. ));
  30. $this->namespace = 'i18n';
  31. $this->name = 'find';
  32. $this->briefDescription = 'Finds non "i18n ready" strings in an application';
  33. $this->detailedDescription = <<<EOF
  34. The [i18n:find|INFO] task finds non internationalized strings embedded in templates:
  35. [./symfony i18n:find frontend|INFO]
  36. This task is able to find non internationalized strings in pure HTML and in PHP code:
  37. <p>Non i18n text</p>
  38. <p><?php echo 'Test' ?></p>
  39. As the task returns all strings embedded in PHP, you can have some false positive (especially
  40. if you use the string syntax for helper arguments).
  41. EOF;
  42. }
  43. /**
  44. * @see sfTask
  45. */
  46. public function execute($arguments = array(), $options = array())
  47. {
  48. $this->logSection('i18n', sprintf('find non "i18n ready" strings in the "%s" application', $arguments['application']));
  49. // Look in templates
  50. $dirs = array();
  51. $moduleNames = sfFinder::type('dir')->maxdepth(0)->relative()->in(sfConfig::get('sf_app_module_dir'));
  52. foreach ($moduleNames as $moduleName)
  53. {
  54. $dirs[] = sfConfig::get('sf_app_module_dir').'/'.$moduleName.'/templates';
  55. }
  56. $dirs[] = sfConfig::get('sf_app_dir').'/templates';
  57. $strings = array();
  58. foreach ($dirs as $dir)
  59. {
  60. $templates = sfFinder::type('file')->name('*.php')->in($dir);
  61. foreach ($templates as $template)
  62. {
  63. if (!isset($strings[$template]))
  64. {
  65. $strings[$template] = array();
  66. }
  67. $dom = new DomDocument('1.0', sfConfig::get('sf_charset', 'UTF-8'));
  68. $content = file_get_contents($template);
  69. // remove doctype
  70. $content = preg_replace('/<!DOCTYPE.*?>/', '', $content);
  71. @$dom->loadXML('<doc>'.$content.'</doc>');
  72. $nodes = array($dom);
  73. while ($nodes)
  74. {
  75. $node = array_shift($nodes);
  76. if (XML_TEXT_NODE === $node->nodeType)
  77. {
  78. if (!$node->isWhitespaceInElementContent())
  79. {
  80. $strings[$template][] = $node->nodeValue;
  81. }
  82. }
  83. else if ($node->childNodes)
  84. {
  85. for ($i = 0, $max = $node->childNodes->length; $i < $max; $i++)
  86. {
  87. $nodes[] = $node->childNodes->item($i);
  88. }
  89. }
  90. else if ('DOMProcessingInstruction' == get_class($node) && 'php' == $node->target)
  91. {
  92. // processing instruction node
  93. $tokens = token_get_all('<?php '.$node->nodeValue);
  94. foreach ($tokens as $token)
  95. {
  96. if (is_array($token))
  97. {
  98. list($id, $text) = $token;
  99. if (T_CONSTANT_ENCAPSED_STRING === $id)
  100. {
  101. $strings[$template][] = substr($text, 1, -1);
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108. }
  109. foreach ($strings as $template => $messages)
  110. {
  111. if (!$messages)
  112. {
  113. continue;
  114. }
  115. $this->logSection('i18n', sprintf('strings in "%s"', str_replace(sfConfig::get('sf_root_dir'), '', $template)), 1000);
  116. foreach ($messages as $message)
  117. {
  118. $this->log(" $message\n");
  119. }
  120. }
  121. }
  122. }