/node_modules/grunt-wp-i18n/vendor/wp-i18n-tools/not-gettexted.php

https://gitlab.com/CueFox/cf-utility-pro · PHP · 243 lines · 210 code · 24 blank · 9 comment · 41 complexity · eafb1b57b59bc00ad7bf3e09e718fcdd MD5 · raw file

  1. <?php
  2. /**
  3. * Console application, which extracts or replaces strings for
  4. * translation, which cannot be gettexted
  5. *
  6. * @package wordpress-i18n
  7. * @subpackage tools
  8. */
  9. // see: http://php.net/tokenizer
  10. if ( ! defined( 'T_ML_COMMENT' ) ) {
  11. define( 'T_ML_COMMENT', T_COMMENT );
  12. } else {
  13. define( 'T_DOC_COMMENT', T_ML_COMMENT );
  14. }
  15. $pomo = dirname( __FILE__ ) . '/pomo';
  16. require_once( "$pomo/po.php" );
  17. require_once( "$pomo/mo.php" );
  18. class NotGettexted {
  19. public $enable_logging = false;
  20. public $STAGE_OUTSIDE = 0;
  21. public $STAGE_START_COMMENT = 1;
  22. public $STAGE_WHITESPACE_BEFORE = 2;
  23. public $STAGE_STRING = 3;
  24. public $STAGE_WHITESPACE_AFTER = 4;
  25. public $STAGE_END_COMMENT = 4;
  26. public $commands = array( 'extract' => 'command_extract', 'replace' => 'command_replace' );
  27. public function logmsg() {
  28. $args = func_get_args();
  29. if ( $this->enable_logging ) {
  30. error_log( implode( ' ', $args ) );
  31. }
  32. }
  33. public function stderr( $msg, $nl=true ) {
  34. fwrite( STDERR, $msg . ( $nl ? "\n" : "" ) );
  35. }
  36. public function cli_die( $msg ) {
  37. $this->stderr( $msg );
  38. exit( 1 );
  39. }
  40. public function unchanged_token( $token, $s = '' ) {
  41. return is_array( $token )? $token[1] : $token;
  42. }
  43. public function ignore_token( $token, $s = '' ) {
  44. return '';
  45. }
  46. public function list_php_files( $dir ) {
  47. $files = array();
  48. $items = scandir( $dir );
  49. foreach ( (array) $items as $item ) {
  50. $full_item = $dir . '/' . $item;
  51. if ( '.' == $item || '..' == $item ) {
  52. continue;
  53. }
  54. if ( '.php' == substr( $item, -4 ) ) {
  55. $files[] = $full_item;
  56. }
  57. if ( is_dir( $full_item ) ) {
  58. $files += array_merge( $files, NotGettexted::list_php_files( $full_item, $files ) );
  59. }
  60. }
  61. return $files;
  62. }
  63. public function make_string_aggregator( $global_array_name, $filename ) {
  64. $a = $global_array_name;
  65. return create_function( '$string, $comment_id, $line_number', 'global $' . $a . '; $' . $a . '[] = array($string, $comment_id, ' . var_export( $filename, true ) . ', $line_number);' );
  66. }
  67. public function make_mo_replacer( $global_mo_name ) {
  68. $m = $global_mo_name;
  69. return create_function( '$token, $string', 'global $' . $m . '; return var_export($' . $m . '->translate($string), true);' );
  70. }
  71. public function walk_tokens( &$tokens, $string_action, $other_action, $register_action = null ) {
  72. $current_comment_id = '';
  73. $current_string = '';
  74. $current_string_line = 0;
  75. $result = '';
  76. $line = 1;
  77. foreach( $tokens as $token ) {
  78. if ( is_array( $token ) ) {
  79. list( $id, $text ) = $token;
  80. $line += substr_count( $text, "\n" );
  81. if ( ( T_ML_COMMENT == $id || T_COMMENT == $id ) && preg_match( '|/\*\s*(/?WP_I18N_[a-z_]+)\s*\*/|i', $text, $matches ) ) {
  82. if ( $this->STAGE_OUTSIDE == $stage ) {
  83. $stage = $this->STAGE_START_COMMENT;
  84. $current_comment_id = $matches[1];
  85. $this->logmsg( 'start comment', $current_comment_id );
  86. $result .= call_user_func( $other_action, $token );
  87. continue;
  88. }
  89. if ( $this->STAGE_START_COMMENT <= $stage && $stage <= $this->STAGE_WHITESPACE_AFTER && '/' . $current_comment_id == $matches[1] ) {
  90. $stage = $this->STAGE_END_COMMENT;
  91. $this->logmsg( 'end comment', $current_comment_id );
  92. $result .= call_user_func( $other_action, $token );
  93. if ( ! is_null( $register_action ) ) {
  94. call_user_func( $register_action, $current_string, $current_comment_id, $current_string_line );
  95. }
  96. continue;
  97. }
  98. } elseif ( T_CONSTANT_ENCAPSED_STRING == $id ) {
  99. if ( $this->STAGE_START_COMMENT <= $stage && $stage < $this->STAGE_WHITESPACE_AFTER ) {
  100. eval( '$current_string=' . $text . ';' );
  101. $this->logmsg( 'string', $current_string );
  102. $current_string_line = $line;
  103. $result .= call_user_func( $string_action, $token, $current_string );
  104. continue;
  105. }
  106. } elseif ( T_WHITESPACE == $id ) {
  107. if ( $this->STAGE_START_COMMENT <= $stage && $stage < $this->STAGE_STRING ) {
  108. $stage = $this->STAGE_WHITESPACE_BEFORE;
  109. $this->logmsg( 'whitespace before' );
  110. $result .= call_user_func( $other_action, $token );
  111. continue;
  112. }
  113. if ( $this->STAGE_STRING < $stage && $stage < $this->STAGE_END_COMMENT ) {
  114. $stage = $this->STAGE_WHITESPACE_AFTER;
  115. $this->logmsg( 'whitespace after' );
  116. $result .= call_user_func( $other_action, $token );
  117. continue;
  118. }
  119. }
  120. }
  121. $result .= call_user_func( $other_action, $token );
  122. $stage = $this->STAGE_OUTSIDE;
  123. $current_comment_id = '';
  124. $current_string = '';
  125. $current_string_line = 0;
  126. }
  127. return $result;
  128. }
  129. public function command_extract() {
  130. $args = func_get_args();
  131. $pot_filename = $args[0];
  132. if ( isset( $args[1] ) && is_array( $args[1] ) ) {
  133. $filenames = $args[1];
  134. } else {
  135. $filenames = array_slice($args, 1);
  136. }
  137. $global_name = '__entries_' . mt_rand( 1, 1000 );
  138. $GLOBALS[ $global_name ] = array();
  139. foreach( $filenames as $filename ) {
  140. $tokens = token_get_all( file_get_contents( $filename ) );
  141. $aggregator = $this->make_string_aggregator( $global_name, $filename );
  142. $this->walk_tokens( $tokens, array( $this, 'ignore_token' ), array( $this, 'ignore_token' ), $aggregator );
  143. }
  144. $potf = '-' == $pot_filename ? STDOUT : @fopen( $pot_filename, 'a' );
  145. if ( false === $potf ) {
  146. $this->cli_die( "Couldn't open pot file: $pot_filename" );
  147. }
  148. foreach( $GLOBALS[ $global_name ] as $item ) {
  149. @list( $string, $comment_id, $filename, $line_number ) = $item;
  150. $filename = isset( $filename ) ? preg_replace( '|^\./|', '', $filename ) : '';
  151. $ref_line_number = isset( $line_number ) ? ":$line_number" : '';
  152. $args = array(
  153. 'singular' => $string,
  154. 'extracted_comments' => "Not gettexted string $comment_id",
  155. 'references' => array( "$filename$ref_line_number" ),
  156. );
  157. $entry = new Translation_Entry( $args );
  158. fwrite( $potf, "\n" . PO::export_entry( $entry ) . "\n");
  159. }
  160. if ( '-' != $pot_filename ) {
  161. fclose($potf);
  162. }
  163. return true;
  164. }
  165. public function command_replace() {
  166. $args = func_get_args();
  167. $mo_filename = $args[0];
  168. if ( isset( $args[1] ) && is_array( $args[1] ) ) {
  169. $filenames = $args[1];
  170. } else {
  171. $filenames = array_slice( $args, 1 );
  172. }
  173. $global_name = '__mo_' . mt_rand( 1, 1000 );
  174. $GLOBALS[ $global_name ] = new MO();
  175. $replacer = $this->make_mo_replacer( $global_name );
  176. $res = $GLOBALS[ $global_name ]->import_from_file( $mo_filename );
  177. if ( false === $res ) {
  178. $this->cli_die("Couldn't read MO file '$mo_filename'!");
  179. }
  180. foreach( $filenames as $filename ) {
  181. $source = file_get_contents( $filename );
  182. if ( strlen( $source ) > 150000 ) {
  183. continue;
  184. }
  185. $tokens = token_get_all( $source );
  186. $new_file = $this->walk_tokens( $tokens, $replacer, array( $this, 'unchanged_token' ) );
  187. $f = fopen( $filename, 'w' );
  188. fwrite( $f, $new_file );
  189. fclose( $f );
  190. }
  191. return true;
  192. }
  193. public function usage() {
  194. $this->stderr( 'php i18n-comments.php COMMAND OUTPUTFILE INPUTFILES' );
  195. $this->stderr( 'Extracts and replaces strings, which cannot be gettexted' );
  196. $this->stderr( 'Commands:' );
  197. $this->stderr( ' extract POTFILE PHPFILES appends the strings to POTFILE' );
  198. $this->stderr( ' replace MOFILE PHPFILES replaces strings in PHPFILES with translations from MOFILE' );
  199. }
  200. public function cli() {
  201. global $argv, $commands;
  202. if ( count( $argv ) < 4 || ! in_array( $argv[1], array_keys( $this->commands ) ) ) {
  203. $this->usage();
  204. exit( 1 );
  205. }
  206. call_user_func_array( array( $this, $this->commands[ $argv[1] ] ), array_slice( $argv, 2 ) );
  207. }
  208. }
  209. // Run the CLI only if the file wasn't included.
  210. $included_files = get_included_files();
  211. if ( __FILE__ == $included_files[0] ) {
  212. error_reporting( E_ALL );
  213. $not_gettexted = new NotGettexted;
  214. $not_gettexted->cli();
  215. }