Changeset 36752
- Timestamp:
- 02/28/2016 10:33:15 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tools/i18n/makepot.php
r33448 r36752 8 8 } 9 9 10 /** 11 * Class to create POT files for 12 * - WordPress 3.4+ 13 * - WordPress plugins 14 * - WordPress themes 15 * - GlotPress (standalone) 16 * - WordPress.org projects (Rosetta, forums, directories) 17 * - WordCamp.org 18 * 19 * Support for older projects can be found in the legacy branch: 20 * https://i18n.trac.wordpress.org/browser/tools/branches/legacy 21 */ 10 22 class MakePOT { 11 var$max_header_lines = 30;12 13 var$projects = array(23 private $max_header_lines = 30; 24 25 public $projects = array( 14 26 'generic', 15 27 'wp-frontend', 16 28 'wp-admin', 17 29 'wp-network-admin', 18 'wp-core',19 'wp-ms',20 30 'wp-tz', 21 31 'wp-plugin', 22 32 'wp-theme', 23 'bb',24 'mu',25 'bp',26 33 'glotpress', 27 34 'rosetta', 28 35 'wporg-bb-forums', 36 'wporg-themes', 37 'wporg-plugins', 38 'wporg-forums', 39 'wordcamporg', 29 40 ); 30 41 31 var$rules = array(42 public $rules = array( 32 43 '_' => array('string'), 33 44 '__' => array('string'), … … 54 65 ); 55 66 56 var $ms_files = array( 'ms-.*', '.*/ms-.*', '.*/my-.*', 'wp-activate\.php', 'wp-signup\.php', 'wp-admin/network\.php', 'wp-admin/includes/ms\.php', 'wp-admin/network/.*\.php', 'wp-admin/includes/class-wp-ms.*' ); 57 58 var $temp_files = array(); 59 60 var $meta = array( 67 private $ms_files = array( 68 'ms-.*', '.*/ms-.*', '.*/my-.*', 'wp-activate\.php', 'wp-signup\.php', 69 'wp-admin/network\.php', 'wp-admin/network/.*\.php', 'wp-admin/includes/ms\.php', 70 'wp-admin/includes/class-wp-ms.*', 'wp-admin/includes/network\.php', 71 ); 72 73 private $temp_files = array(); 74 75 public $meta = array( 61 76 'default' => array( 62 77 'from-code' => 'utf-8', … … 85 100 'package-version' => '{version}', 86 101 ), 87 'wp- core' => array(88 'description' => 'Translation of WordPress {version}',102 'wp-tz' => array( 103 'description' => 'Translation of timezone strings in WordPress {version}', 89 104 'copyright-holder' => 'WordPress', 90 105 'package-name' => 'WordPress', 91 106 'package-version' => '{version}', 92 ),93 'wp-ms' => array(94 'description' => 'Translation of multisite strings in WordPress {version}',95 'copyright-holder' => 'WordPress',96 'package-name' => 'WordPress',97 'package-version' => '{version}',98 ),99 'wp-tz' => array(100 'description' => 'Translation of timezone strings in WordPress {version}',101 'copyright-holder' => 'WordPress',102 'package-name' => 'WordPress',103 'package-version' => '{version}',104 ),105 'bb' => array(106 'description' => 'Translation of bbPress',107 'copyright-holder' => 'bbPress',108 'package-name' => 'bbPress',109 107 ), 110 108 'wp-plugin' => array( … … 123 121 'comments' => 'Copyright (C) {year} {author}\nThis file is distributed under the same license as the {package-name} package.', 124 122 ), 125 'bp' => array(126 'description' => 'Translation of BuddyPress',127 'copyright-holder' => 'BuddyPress',128 'package-name' => 'BuddyPress',129 ),130 123 'glotpress' => array( 131 124 'description' => 'Translation of GlotPress', … … 138 131 'package-name' => 'WordPress.org International Forums', 139 132 ), 133 'wporg' => array( 134 'description' => 'WordPress.org', 135 'copyright-holder' => 'WordPress', 136 'package-name' => 'WordPress.org', 137 ), 138 'wordcamporg' => array( 139 'description' => 'WordCamp.org', 140 'copyright-holder' => 'WordPress', 141 'package-name' => 'WordCamp.org', 142 ), 140 143 'rosetta' => array( 141 144 'description' => 'Rosetta (.wordpress.org locale sites)', … … 145 148 ); 146 149 147 function __construct($deprecated = true) {150 public function __construct($deprecated = true) { 148 151 $this->extractor = new StringExtractor( $this->rules ); 149 152 } 150 153 151 function __destruct() {154 public function __destruct() { 152 155 foreach ( $this->temp_files as $temp_file ) 153 156 unlink( $temp_file ); 154 157 } 155 158 156 function tempnam( $file ) {159 private function tempnam( $file ) { 157 160 $tempnam = tempnam( sys_get_temp_dir(), $file ); 158 161 $this->temp_files[] = $tempnam; … … 160 163 } 161 164 162 function realpath_missing($path) {165 private function realpath_missing($path) { 163 166 return realpath(dirname($path)).DIRECTORY_SEPARATOR.basename($path); 164 167 } 165 168 166 function xgettext($project, $dir, $output_file, $placeholders = array(), $excludes = array(), $includes = array()) {169 private function xgettext($project, $dir, $output_file, $placeholders = array(), $excludes = array(), $includes = array()) { 167 170 $meta = array_merge( $this->meta['default'], $this->meta[$project] ); 168 171 $placeholders = array_merge( $meta, $placeholders ); … … 193 196 } 194 197 195 function wp_generic($dir, $args) {198 public function wp_generic($dir, $args) { 196 199 $defaults = array( 197 200 'project' => 'wp-core', … … 200 203 'includes' => array(), 201 204 'excludes' => array_merge( 202 array( 'wp-admin/includes/continents-cities\.php', 'wp-content/themes/twenty.*', ),205 array( 'wp-admin/includes/continents-cities\.php', 'wp-content/themes/twenty.*', ), 203 206 $this->ms_files 204 207 ), … … 233 236 } 234 237 235 function wp_core($dir, $output) { 236 if ( file_exists( "$dir/wp-admin/user/about.php" ) ) return false; 237 238 return $this->wp_generic( $dir, array( 239 'project' => 'wp-core', 'output' => $output, 240 'extract_not_gettexted' => true, 241 'not_gettexted_files_filter' => array( $this, 'is_not_ms_file' ), 242 ) ); 243 } 244 245 function wp_frontend( $dir, $output ) { 238 public function wp_frontend( $dir, $output ) { 246 239 if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) { 247 240 return false; … … 263 256 } 264 257 265 function wp_admin($dir, $output) { 266 if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) { 267 return false; 268 } 269 258 public function wp_admin($dir, $output) { 270 259 $frontend_pot = $this->tempnam( 'frontend.pot' ); 271 260 if ( false === $frontend_pot ) { … … 277 266 return false; 278 267 } 268 269 $network_admin_files = $this->get_wp_network_admin_files( $dir ); 279 270 280 271 $result = $this->wp_generic( $dir, array( 281 272 'project' => 'wp-admin', 'output' => $output, 282 273 'includes' => array( 'wp-admin/.*' ), 283 'excludes' => array ( 'wp-admin/includes/continents-cities\.php', 'wp-admin/network/.*', 'wp-admin/network.php'),274 'excludes' => array_merge( array( 'wp-admin/includes/continents-cities\.php' ), $network_admin_files ), 284 275 'default_output' => 'wordpress-admin.pot', 285 276 ) ); … … 316 307 } 317 308 318 function wp_network_admin($dir, $output) {309 public function wp_network_admin($dir, $output) { 319 310 if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false; 320 311 … … 335 326 $result = $this->wp_generic( $dir, array( 336 327 'project' => 'wp-network-admin', 'output' => $output, 337 'includes' => array( 'wp-admin/network/.*', 'wp-admin/network.php'),328 'includes' => $this->get_wp_network_admin_files( $dir ), 338 329 'excludes' => array(), 339 330 'default_output' => 'wordpress-admin-network.pot', … … 354 345 } 355 346 356 function wp_ms($dir, $output) { 357 if ( file_exists( "$dir/wp-admin/user/about.php" ) ) return false; 358 if ( !is_file("$dir/wp-admin/ms-users.php") ) return false; 359 $core_pot = $this->tempnam( 'wordpress.pot' ); 360 if ( false === $core_pot ) return false; 361 $core_result = $this->wp_core( $dir, $core_pot ); 362 if ( ! $core_result ) 363 return false; 364 $ms_result = $this->wp_generic( $dir, array( 365 'project' => 'wp-ms', 'output' => $output, 366 'includes' => $this->ms_files, 367 'excludes' => array(), 368 'default_output' => 'wordpress-ms.pot', 369 'extract_not_gettexted' => true, 370 'not_gettexted_files_filter' => array( $this, 'is_ms_file' ), 371 ) ); 372 if ( !$ms_result ) { 373 return false; 374 } 375 $common_pot = $this->tempnam( 'common.pot' ); 376 if ( ! $common_pot ) 377 return false; 378 $ms_pot = realpath( is_null( $output )? 'wordpress-ms.pot' : $output ); 379 system( "msgcat --more-than=1 --use-first $core_pot $ms_pot > $common_pot" ); 380 system( "msgcat -u --use-first $ms_pot $common_pot -o $ms_pot" ); 381 return true; 382 } 383 384 function wp_tz($dir, $output) { 385 $continents_path = 'wp-admin/includes/continents-cities.php'; 386 if ( !file_exists( "$dir/$continents_path" ) ) return false; 347 private function get_wp_network_admin_files( $dir ) { 348 $wp_version = $this->wp_version( $dir ); 349 350 // https://core.trac.wordpress.org/ticket/19852 351 $files = array( 'wp-admin/network/.*', 'wp-admin/network.php' ); 352 353 // https://core.trac.wordpress.org/ticket/34910 354 if ( version_compare( $wp_version, '4.5-beta', '>=' ) ) { 355 $files = array_merge( $files, array( 356 'wp-admin/includes/class-wp-ms.*', 357 'wp-admin/includes/network.php', 358 ) ); 359 } 360 361 return $files; 362 } 363 364 public function wp_tz( $dir, $output ) { 387 365 return $this->wp_generic( $dir, array( 388 366 'project' => 'wp-tz', 'output' => $output, 389 'includes' => array( $continents_path),367 'includes' => array( 'wp-admin/includes/continents-cities\.php' ), 390 368 'excludes' => array(), 391 369 'default_output' => 'wordpress-continents-cities.pot', … … 393 371 } 394 372 395 function wp_version($dir) {373 private function wp_version( $dir ) { 396 374 $version_php = $dir.'/wp-includes/version.php'; 397 375 if ( !is_readable( $version_php ) ) return false; … … 399 377 } 400 378 401 402 function mu($dir, $output) { 403 $placeholders = array(); 404 if (preg_match('/\$wpmu_version\s*=\s*\'(.*?)\';/', file_get_contents($dir.'/wp-includes/version.php'), $matches)) { 405 $placeholders['version'] = $matches[1]; 406 } 407 $output = is_null($output)? 'wordpress.pot' : $output; 408 return $this->xgettext('wp', $dir, $output, $placeholders); 409 } 410 411 412 function bb($dir, $output) { 413 $placeholders = array(); 414 $output = is_null($output)? 'bbpress.pot' : $output; 415 return $this->xgettext('bb', $dir, $output, $placeholders); 416 417 } 418 419 function get_first_lines($filename, $lines = 30) { 379 public function get_first_lines($filename, $lines = 30) { 420 380 $extf = fopen($filename, 'r'); 421 381 if (!$extf) return false; … … 429 389 $first_lines .= $line; 430 390 } 391 392 // PHP will close file handle, but we are good citizens. 393 fclose( $extf ); 394 395 // Make sure we catch CR-only line endings. 396 $first_lines = str_replace( "\r", "\n", $first_lines ); 397 431 398 return $first_lines; 432 399 } 433 400 434 435 function get_addon_header($header, &$source) { 436 if (preg_match('|'.$header.':(.*)$|mi', $source, $matches)) 437 return trim($matches[1]); 438 else 439 return false; 440 } 441 442 function generic($dir, $output) { 401 public function get_addon_header($header, &$source) { 402 /* 403 * A few things this needs to handle: 404 * - 'Header: Value\n' 405 * - '// Header: Value' 406 * - '/* Header: Value * /' 407 * - '<?php // Header: Value ?>' 408 * - '<?php /* Header: Value * / $foo='bar'; ?>' 409 */ 410 if ( preg_match( '/^(?:[ \t]*<\?php)?[ \t\/*#@]*' . preg_quote( $header, '/' ) . ':(.*)$/mi', $source, $matches ) ) { 411 return $this->_cleanup_header_comment( $matches[1] ); 412 } else { 413 return false; 414 } 415 } 416 417 /** 418 * Removes any trailing closing comment / PHP tags from the header value 419 */ 420 private function _cleanup_header_comment( $str ) { 421 return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) ); 422 } 423 424 public function generic($dir, $output) { 443 425 $output = is_null($output)? "generic.pot" : $output; 444 426 return $this->xgettext('generic', $dir, $output, array()); 445 427 } 446 428 447 function guess_plugin_slug($dir) {429 private function guess_plugin_slug($dir) { 448 430 if ('trunk' == basename($dir)) { 449 431 $slug = basename(dirname($dir)); … … 456 438 } 457 439 458 function wp_plugin($dir, $output, $slug = null) { 440 public function wp_plugin( $dir, $output, $slug = null, $args = array() ) { 441 $defaults = array( 442 'excludes' => array(), 443 'includes' => array(), 444 ); 445 $args = array_merge( $defaults, $args ); 459 446 $placeholders = array(); 460 447 // guess plugin slug … … 507 494 508 495 $output = is_null($output)? "$slug.pot" : $output; 509 $res = $this->xgettext( 'wp-plugin', $dir, $output, $placeholders);496 $res = $this->xgettext( 'wp-plugin', $dir, $output, $placeholders, $args['excludes'], $args['includes'] ); 510 497 if (!$res) return false; 511 498 $potextmeta = new PotExtMeta; … … 517 504 } 518 505 519 function wp_theme($dir, $output, $slug = null) {506 public function wp_theme($dir, $output, $slug = null) { 520 507 $placeholders = array(); 521 508 // guess plugin slug … … 572 559 } 573 560 574 function bp($dir, $output) { 575 $output = is_null($output)? "buddypress.pot" : $output; 576 return $this->xgettext('bp', $dir, $output, array(), array('bp-forums/bbpress/.*')); 577 } 578 579 function glotpress( $dir, $output ) { 561 public function glotpress( $dir, $output ) { 580 562 $output = is_null( $output ) ? "glotpress.pot" : $output; 581 563 return $this->xgettext( 'glotpress', $dir, $output ); 582 564 } 583 565 584 function wporg_bb_forums( $dir, $output ) {566 public function wporg_bb_forums( $dir, $output ) { 585 567 $output = is_null( $output ) ? 'wporg.pot' : $output; 586 568 return $this->xgettext( 'wporg-bb-forums', $dir, $output, array(), array( 587 569 'bb-plugins/elfakismet/.*', 588 570 'bb-plugins/support-forum/.*', 589 ) ); 590 } 591 592 function rosetta( $dir, $output ) { 571 'themes/.*', 572 ) ); 573 } 574 575 public function wporg_themes( $dir, $output ) { 576 $output = is_null( $output ) ? 'wporg-themes.pot' : $output; 577 return $this->xgettext( 'wporg', $dir, $output, array(), array(), array( 578 'plugins/theme-directory/.*', 579 'themes/pub/wporg-themes/.*' 580 ) ); 581 } 582 583 public function wporg_plugins( $dir, $output ) { 584 $output = is_null( $output ) ? 'wporg-plugins.pot' : $output; 585 return $this->xgettext( 'wporg', $dir, $output, array(), array( 586 'plugins/svn-track/i18n-tools/.*' 587 ), array( 588 '.*\.php', 589 ) ); 590 } 591 592 public function wporg_forums( $dir, $output ) { 593 $output = is_null( $output ) ? 'wporg-forums.pot' : $output; 594 return $this->xgettext( 'wporg', $dir, $output, array(), array(), array( 595 '.*\.php', 596 ) ); 597 } 598 599 public function wordcamporg( $dir, $output ) { 600 $output = is_null( $output ) ? 'wordcamporg.pot' : $output; 601 return $this->xgettext( 'wordcamporg', $dir, $output, array(), array(), array( 602 '.*\.php', 603 ) ); 604 } 605 606 public function rosetta( $dir, $output ) { 593 607 $output = is_null( $output )? 'rosetta.pot' : $output; 594 return $this->xgettext( 'rosetta', $dir, $output, array(), array(), array( 608 return $this->xgettext( 'rosetta', $dir, $output, array(), array( 609 'mu-plugins/rosetta/i18n-tools/.*', 610 'mu-plugins/rosetta/locales/.*', 611 ), array( 595 612 'mu-plugins/(roles|showcase|downloads)/.*\.php', 613 'mu-plugins/jetpack-settings.php', 596 614 'mu-plugins/rosetta.*\.php', 597 615 'mu-plugins/rosetta/[^/]+\.php', … … 599 617 'themes/rosetta/.*\.php', 600 618 ) ); 601 }602 603 function is_ms_file( $file_name ) {604 $is_ms_file = false;605 $prefix = substr( $file_name, 0, 2 ) === './'? '\./' : '';606 foreach( $this->ms_files as $ms_file )607 if ( preg_match( '|^'.$prefix.$ms_file.'$|', $file_name ) ) {608 $is_ms_file = true;609 break;610 }611 return $is_ms_file;612 }613 614 function is_not_ms_file( $file_name ) {615 return !$this->is_ms_file( $file_name );616 619 } 617 620 }
Note: See TracChangeset
for help on using the changeset viewer.