Comet Cache - Version 160417

Version Description

= v160416 =

Requires WordPress v4.2+.

Download this release

Release Info

Developer raamdev
Plugin Icon 128x128 Comet Cache
Version 160417
Comparing to
See all releases

Code changes from version 160416 to 160417

comet-cache.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Version: 160416
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
1
  <?php
2
  /*
3
+ Version: 160417
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
readme.txt CHANGED
@@ -1,6 +1,6 @@
1
  === Comet Cache ===
2
 
3
- Stable tag: 160416
4
  Requires at least: 4.2
5
  Tested up to: 4.6-alpha
6
  Text Domain: comet-cache
@@ -336,6 +336,10 @@ Requires WordPress v4.2+.
336
 
337
  == Changelog ==
338
 
 
 
 
 
339
  = v160416 =
340
 
341
  - **Enhancement**: Several PHP 5.4+ enhancements, most notably a conversion from PHP Closures to PHP Traits. See [Issue #635](https://github.com/websharks/comet-cache/issues/635).
1
  === Comet Cache ===
2
 
3
+ Stable tag: 160417
4
  Requires at least: 4.2
5
  Tested up to: 4.6-alpha
6
  Text Domain: comet-cache
336
 
337
  == Changelog ==
338
 
339
+ = v160417 =
340
+
341
+ - **Bug Fix**: Fixed a "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_SCHEME'" with introduced by the previous release (v160416). This issue only affected sites where Feed Caching was enabled (_Comet Cache → Plugin Options → RSS, RDF, and Atom Feeds_). Props to MassimoD and @emanwebdev for reporting. See [Issue #739](https://github.com/websharks/comet-cache/issues/739).
342
+
343
  = v160416 =
344
 
345
  - **Enhancement**: Several PHP 5.4+ enhancements, most notably a conversion from PHP Closures to PHP Traits. See [Issue #635](https://github.com/websharks/comet-cache/issues/635).
src/includes/classes/FeedUtils.php CHANGED
@@ -1,12 +1,14 @@
1
  <?php
2
  namespace WebSharks\CometCache\Classes;
3
 
 
 
4
  /**
5
  * Feed Utils.
6
  *
7
  * @since 150422 Rewrite.
8
  */
9
- class FeedUtils extends AbsBase
10
  {
11
  /**
12
  * @type string WordPress `home_url()`.
1
  <?php
2
  namespace WebSharks\CometCache\Classes;
3
 
4
+ use WebSharks\CometCache\Interfaces;
5
+
6
  /**
7
  * Feed Utils.
8
  *
9
  * @since 150422 Rewrite.
10
  */
11
+ class FeedUtils extends AbsBase implements Interfaces\Shared\CachePathConsts
12
  {
13
  /**
14
  * @type string WordPress `home_url()`.
src/includes/stub.php CHANGED
@@ -13,7 +13,7 @@ if (!defined('WPINC')) {
13
  require_once dirname(__DIR__).'/vendor/autoload.php';
14
  require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
- ${__FILE__}['version'] = '160416'; //version//
17
  ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
13
  require_once dirname(__DIR__).'/vendor/autoload.php';
14
  require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
+ ${__FILE__}['version'] = '160417'; //version//
17
  ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
src/vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit1282194a29af7710e5b95305c89863ea::getLoader();
src/vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitc1a53f596a710aab47629b58885a6ec2', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit1282194a29af7710e5b95305c89863ea
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit1282194a29af7710e5b95305c89863ea', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit1282194a29af7710e5b95305c89863ea', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
src/vendor/websharks/wp-i18n-tools/CHANGELOG.md DELETED
@@ -1,3 +0,0 @@
1
- ## v15xxxx
2
-
3
- - Initial release.
 
 
 
src/vendor/websharks/wp-i18n-tools/README.md DELETED
@@ -1,14 +0,0 @@
1
- ## WP i18n Tools
2
-
3
- Modified slightly by WebSharks, Inc.
4
-
5
- #### Differences from original:
6
-
7
- - Adding shebang line to the top of `makepot.php`.
8
- - Now distributing a packaged PHAR binary w/ each release.
9
- - Setting executable bit on `makepot.php` and preserving that with Git.
10
- - Updated to support PHP/translations embedded into `.js` files too.
11
- - Disabling line wrapping from final output to ensure better consistency.
12
- - Adding support for plugin directories that use a `plugin.php` file instead of `[slug].php`.
13
- - Adding `composer.json` and package on Packagist.org.
14
- - Auto-exclude `(?:.+?/)?vendor/.*` in themes/plugins.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/add-textdomain.php DELETED
@@ -1,110 +0,0 @@
1
- <?php
2
- /**
3
- * Console application, which adds textdomain argument
4
- * to all i18n function calls
5
- *
6
- * @author
7
- * @version $Id$
8
- * @package wordpress-i18n
9
- */
10
- error_reporting(E_ALL);
11
-
12
- require_once dirname( __FILE__ ) . '/makepot.php';
13
-
14
- class AddTextdomain {
15
-
16
- var $modified_contents = '';
17
- var $funcs;
18
-
19
- function AddTextdomain() {
20
- $makepot = new MakePOT;
21
- $this->funcs = array_keys( $makepot->rules );
22
- }
23
-
24
- function usage() {
25
- $usage = "Usage: php add-textdomain.php [-i] <domain> <file>\n\nAdds the string <domain> as a last argument to all i18n function calls in <file>\nand prints the modified php file on standard output.\n\nOptions:\n -i Modifies the PHP file in place, instead of printing it to standard output.\n";
26
- fwrite(STDERR, $usage);
27
- exit(1);
28
- }
29
-
30
- function process_token($token_text, $inplace) {
31
- if ($inplace)
32
- $this->modified_contents .= $token_text;
33
- else
34
- echo $token_text;
35
- }
36
-
37
-
38
- function process_file($domain, $source_filename, $inplace) {
39
-
40
- $this->modified_contents = '';
41
- $domain = addslashes($domain);
42
-
43
- $source = file_get_contents($source_filename);
44
- $tokens = token_get_all($source);
45
-
46
- $in_func = false;
47
- $args_started = false;
48
- $parens_balance = 0;
49
- $found_domain = false;
50
-
51
- foreach($tokens as $token) {
52
- $string_success = false;
53
- if (is_array($token)) {
54
- list($id, $text) = $token;
55
- if (T_STRING == $id && in_array($text, $this->funcs)) {
56
- $in_func = true;
57
- $parens_balance = 0;
58
- $args_started = false;
59
- $found_domain = false;
60
- } elseif (T_CONSTANT_ENCAPSED_STRING == $id && ("'$domain'" == $text || "\"$domain\"" == $text)) {
61
- if ($in_func && $args_started) {
62
- $found_domain = true;
63
- }
64
- }
65
- $token = $text;
66
- } elseif ('(' == $token){
67
- $args_started = true;
68
- ++$parens_balance;
69
- } elseif (')' == $token) {
70
- --$parens_balance;
71
- if ($in_func && 0 == $parens_balance) {
72
- $token = $found_domain? ')' : ", '$domain')";
73
- $in_func = false;
74
- $args_started = false;
75
- $found_domain = false;
76
- }
77
- }
78
- $this->process_token($token, $inplace);
79
- }
80
-
81
- if ($inplace) {
82
- $f = fopen($source_filename, 'w');
83
- fwrite($f, $this->modified_contents);
84
- fclose($f);
85
- }
86
- }
87
- }
88
-
89
-
90
- // run the CLI only if the file
91
- // wasn't included
92
- $included_files = get_included_files();
93
- if ($included_files[0] == __FILE__) {
94
- $adddomain = new AddTextdomain;
95
-
96
- if (!isset($argv[1]) || !isset($argv[2])) {
97
- $adddomain->usage();
98
- }
99
-
100
- $inplace = false;
101
- if ('-i' == $argv[1]) {
102
- $inplace = true;
103
- if (!isset($argv[3])) $adddomain->usage();
104
- array_shift($argv);
105
- }
106
-
107
- $adddomain->process_file($argv[1], $argv[2], $inplace);
108
- }
109
-
110
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/cron-svn-pots.php DELETED
@@ -1,117 +0,0 @@
1
- <?php
2
- require_once dirname( __FILE__ ) . '/makepot.php';
3
-
4
- function silent_system( $command ) {
5
- global $at_least_one_error;
6
- ob_start();
7
- system( "$command 2>&1", $exit_code );
8
- $output = ob_get_contents();
9
- ob_end_clean();
10
- if ( $exit_code != 0 ) {
11
- echo "ERROR:\t$command\nCODE:\t$exit_code\nOUTPUT:\n";
12
- echo $output."\n";
13
- } else {
14
- echo "OK:\t$command\n";
15
- }
16
- return $exit_code;
17
- }
18
-
19
-
20
- $options = getopt( 'c:p:m:n:sa:b:u:w:df' );
21
- if ( empty( $options ) ) {
22
- ?>
23
- -s No branch/version directories, it's all flat
24
- -c Application svn checkout
25
- -p POT svn checkout
26
- -m MakePOT project
27
- -n POT filename
28
- -a Relative path of application inside version dir in -c
29
- -b Relative patch of POT dir inside version dir in -p
30
- -u SVN username (optional)
31
- -w SVN password (optional)
32
- -d Dry-run
33
- -f Fast - do not update checkouts
34
- <?php
35
- die;
36
- }
37
-
38
- $application_svn_checkout = realpath( $options['c'] );
39
- $pot_svn_checkout = realpath( $options['p'] );
40
- $makepot_project = str_replace( '-', '_', $options['m'] );
41
- $pot_name = $options['n'];
42
- $no_branch_dirs = isset( $options['s'] );
43
- $relative_application_path = isset( $options['a'] )? '/'.$options['a'] : '';
44
- $relative_pot_path = isset( $options['b'] )? '/'.$options['b'] : '';
45
- $dry_run = isset( $options['d'] );
46
-
47
- $makepot = new MakePOT;
48
- $svn_args = array('--non-interactive');
49
- if ( isset( $options['u'] ) && isset( $options['w'] ) ) {
50
- $svn_args[] = '--username='.$options['u'];
51
- $svn_args[] = '--password='.$options['w'];
52
- $svn_args[] = '--no-auth-cache';
53
- }
54
- $svn_args_str = implode( ' ', array_map( 'escapeshellarg', $svn_args ) );
55
- $svn = 'svn '.$svn_args_str;
56
-
57
-
58
- $versions = array();
59
-
60
- chdir( $application_svn_checkout );
61
- if ( ! isset( $options['f'] ) ) {
62
- $exit = silent_system( "$svn cleanup" );
63
- if ( 0 != $exit ) die();
64
- $exit = silent_system( "$svn up" );
65
- if ( 0 != $exit ) die();
66
- }
67
- if ( is_dir( 'trunk' ) ) $versions[] = 'trunk';
68
- $branches = glob( 'branches/*' );
69
- if ( false !== $branches ) $versions = array_merge( $versions, $branches );
70
- $tags = glob( 'tags/*' );
71
- if ( false !== $tags ) $versions = array_merge( $versions, $tags );
72
-
73
- if ( $no_branch_dirs ) {
74
- $versions = array( '.' );
75
- }
76
-
77
- chdir( $pot_svn_checkout );
78
- if ( $application_svn_checkout != $pot_svn_checkout && ! isset( $options['f'] ) ) {
79
- $exit = silent_system( "$svn cleanup" );
80
- if ( 0 != $exit ) die();
81
- $exit = silent_system( "$svn up" );
82
- if ( 0 != $exit ) die();
83
- }
84
- $real_application_svn_checkout = realpath( $application_svn_checkout );
85
- foreach( $versions as $version ) {
86
- $application_path = "$real_application_svn_checkout/$version{$relative_application_path}";
87
- if ( !is_dir( $application_path ) ) continue;
88
- $pot = "$version{$relative_pot_path}/$pot_name";
89
- $exists = is_file( $pot );
90
- // do not update old tag pots
91
- if ( 'tags/' == substr( $version, 0, 5 ) && $exists ) continue;
92
- if ( !is_dir( $version ) ) {
93
- $exit = silent_system( "$svn mkdir $version" );
94
- if ( 0 != $exit ) continue;
95
- }
96
- if ( !is_dir(dirname("$pot_svn_checkout/$pot")) ) continue;
97
- if ( !call_user_func( array( &$makepot, $makepot_project ), $application_path, "$pot_svn_checkout/$pot" ) ) continue;
98
- if ( !file_exists( "$pot_svn_checkout/$pot" ) ) continue;
99
- if ( !$exists ) {
100
- $exit = silent_system( "$svn add $pot" );
101
- if ( 0 != $exit ) continue;
102
- }
103
- // do not commit if the difference is only in the header, but always commit a new file
104
- $real_differences = `svn diff $pot | wc -l` > 16;
105
- $target = $exists ? $pot : $version;
106
- if ( !$exists || $real_differences ) {
107
- preg_match( '/Revision:\s+(\d+)/', `svn info $application_path`, $matches );
108
- $logmsg = isset( $matches[1] ) && intval( $matches[1] )? "POT, generated from r".intval( $matches[1] ) : 'Automatic POT update';
109
- $command = "$svn ci $target --non-interactive --message='$logmsg'";
110
- if ( !$dry_run )
111
- silent_system( $command );
112
- else
113
- echo "CMD:\t$command\n";
114
- } else {
115
- silent_system( "$svn revert $target" );
116
- }
117
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/extract/ExtractTest.php DELETED
@@ -1,160 +0,0 @@
1
- <?php
2
-
3
- require_once dirname( __FILE__ ) . '/extract.php';
4
-
5
- class ExtractTest extends PHPUnit_Framework_TestCase {
6
-
7
- function setUp() {
8
- $this->extractor = new StringExtractor;
9
- $this->extractor->rules = array(
10
- '__' => array('string'),
11
- );
12
- }
13
-
14
- function test_with_just_a_string() {
15
- $expected = new Translation_Entry( array( 'singular' => 'baba', 'references' => array('baba.php:1') ) );
16
- $result = $this->extractor->extract_entries('<?php __("baba"); ?>', 'baba.php' );
17
- $this->assertEquals( $expected, $result->entries['baba'] );
18
- }
19
-
20
- function test_entry_from_call_simple() {
21
- $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba') ), 'baba.php' );
22
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba' ) ) );
23
- }
24
-
25
- function test_entry_from_call_nonexisting_function() {
26
- $entry = $this->extractor->entry_from_call( array( 'name' => 'f', 'args' => array('baba') ), 'baba.php' );
27
- $this->assertEquals( $entry, null );
28
- }
29
-
30
- function test_entry_from_call_too_few_args() {
31
- $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array() ), 'baba.php' );
32
- $this->assertEquals( $entry, null );
33
- }
34
-
35
- function test_entry_from_call_non_expected_null_arg() {
36
- $this->extractor->rules = array( '_nx' => array( 'singular', 'plural', 'context' ) );
37
- $entry = $this->extractor->entry_from_call( array( 'name' => '_nx', 'args' => array('%s baba', null, 'noun') ), 'baba.php' );
38
- $this->assertEquals( $entry, null );
39
- }
40
-
41
- function test_entry_from_call_more_args_should_be_ok() {
42
- $this->extractor->rules = array( '__' => array('string') );
43
- $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba', 5, 'pijo', null) ), 'baba.php' );
44
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba' ) ) );
45
- }
46
-
47
-
48
- function test_entry_from_call_context() {
49
- $this->extractor->rules = array( '_x' => array( 'string', 'context' ) );
50
- $entry = $this->extractor->entry_from_call( array( 'name' => '_x', 'args' => array('baba', 'noun') ), 'baba.php' );
51
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba', 'context' => 'noun' ) ) );
52
- }
53
-
54
- function test_entry_from_call_plural() {
55
- $this->extractor->rules = array( '_n' => array( 'singular', 'plural' ) );
56
- $entry = $this->extractor->entry_from_call( array( 'name' => '_n', 'args' => array('%s baba', '%s babas') ), 'baba.php' );
57
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => '%s baba', 'plural' => '%s babas' ) ) );
58
- }
59
-
60
- function test_entry_from_call_plural_and_context() {
61
- $this->extractor->rules = array( '_nx' => array( 'singular', 'plural', 'context' ) );
62
- $entry = $this->extractor->entry_from_call( array( 'name' => '_nx', 'args' => array('%s baba', '%s babas', 'noun') ), 'baba.php' );
63
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => '%s baba', 'plural' => '%s babas', 'context' => 'noun' ) ) );
64
- }
65
-
66
- function test_entry_from_call_extracted_comment() {
67
- $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba'), 'comment' => 'translators: give me back my pants!' ), 'baba.php' );
68
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba', 'extracted_comments' => "translators: give me back my pants!\n" ) ) );
69
- }
70
-
71
- function test_entry_from_call_line_number() {
72
- $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('baba'), 'line' => 10 ), 'baba.php' );
73
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => 'baba', 'references' => array('baba.php:10') ) ) );
74
- }
75
-
76
- function test_entry_from_call_zero() {
77
- $entry = $this->extractor->entry_from_call( array( 'name' => '__', 'args' => array('0') ), 'baba.php' );
78
- $this->assertEquals( $entry, new Translation_Entry( array( 'singular' => '0' ) ) );
79
- }
80
-
81
- function test_entry_from_call_multiple() {
82
- $this->extractor->rules = array( 'c' => array( 'string', 'singular', 'plural' ) );
83
- $entries = $this->extractor->entry_from_call( array( 'name' => 'c', 'args' => array('baba', 'dyado', 'dyados') ), 'baba.php' );
84
- $this->assertEquals( array(
85
- new Translation_Entry( array( 'singular' => 'baba' ) ), new Translation_Entry( array( 'singular' => 'dyado', 'plural' => 'dyados' ) ) ), $entries );
86
- }
87
-
88
- function test_entry_from_call_multiple_first_plural_then_two_strings() {
89
- $this->extractor->rules = array( 'c' => array( 'singular', 'plural', null, 'string', 'string' ) );
90
- $entries = $this->extractor->entry_from_call( array( 'name' => 'c', 'args' => array('dyado', 'dyados', 'baba', 'foo', 'bar') ), 'baba.php' );
91
- $this->assertEquals( array(
92
- new Translation_Entry( array( 'singular' => 'dyado', 'plural' => 'dyados' ) ),
93
- new Translation_Entry( array( 'singular' => 'foo' ) ),
94
- new Translation_Entry( array( 'singular' => 'bar' ) ) ), $entries );
95
- }
96
-
97
- function test_find_function_calls_one_arg_literal() {
98
- $this->assertEquals( array( array( 'name' => '__', 'args' => array( 'baba' ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('__'), '<?php __("baba"); ?>' ) );
99
- }
100
-
101
- function test_find_function_calls_one_arg_zero() {
102
- $this->assertEquals( array( array( 'name' => '__', 'args' => array( '0' ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('__'), '<?php __("0"); ?>' ) );
103
- }
104
-
105
- function test_find_function_calls_one_arg_non_literal() {
106
- $this->assertEquals( array( array( 'name' => '__', 'args' => array( null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('__'), '<?php __("baba" . "dudu"); ?>' ) );
107
- }
108
-
109
- function test_find_function_calls_shouldnt_be_mistaken_by_a_class() {
110
- $this->assertEquals( array(), $this->extractor->find_function_calls( array('__'), '<?php class __ { }; ("dyado");' ) );
111
- }
112
-
113
- function test_find_function_calls_2_args_bad_literal() {
114
- $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null, "baba" ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f(5, "baba" ); ' ) );
115
- }
116
-
117
- function test_find_function_calls_2_args_bad_literal_bad() {
118
- $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null, "baba", null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f(5, "baba", 5 ); ' ) );
119
- }
120
-
121
- function test_find_function_calls_1_arg_bad_concat() {
122
- $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( "baba" . "baba" ); ' ) );
123
- }
124
-
125
- function test_find_function_calls_1_arg_bad_function_call() {
126
- $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( g( "baba" ) ); ' ) );
127
- }
128
-
129
- function test_find_function_calls_2_arg_literal_bad() {
130
- $this->assertEquals( array( array( 'name' => 'f', 'args' => array( "baba", null ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( "baba", null ); ' ) );
131
- }
132
-
133
- function test_find_function_calls_2_arg_bad_with_parens_literal() {
134
- $this->assertEquals( array( array( 'name' => 'f', 'args' => array( null, "baba" ), 'line' => 1 ) ), $this->extractor->find_function_calls( array('f'), '<?php f( g( "dyado", "chicho", "lelya "), "baba" ); ' ) );
135
- }
136
-
137
- function test_find_function_calls_with_comment() {
138
- $this->assertEquals(
139
- array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'translators: let your ears fly!' ) ),
140
- $this->extractor->find_function_calls( array('f'), '<?php /* translators: let your ears fly! */ f( "baba" ); ' ) );
141
- }
142
-
143
- function test_find_function_calls_with_not_immediate_comment() {
144
- $this->assertEquals(
145
- array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'translators: let your ears fly!' ) ),
146
- $this->extractor->find_function_calls( array('f'), '<?php /* translators: let your ears fly! */ $foo = g ( f( "baba" ) ); ' ) );
147
- }
148
-
149
- function test_find_function_calls_with_not_immediate_comment_include_only_latest() {
150
- $this->assertEquals(
151
- array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'translators: let your ears fly!' ) ),
152
- $this->extractor->find_function_calls( array('f'), '<?php /* translators: boo */ /* translators: let your ears fly! */ /* baba */ $foo = g ( f( "baba" ) ); ' ) );
153
- }
154
-
155
- function test_comment_prefix_should_be_case_insensitive() {
156
- $this->assertEquals(
157
- array( array( 'name' => 'f', 'args' => array( 'baba' ), 'line' => 1, 'comment' => 'Translators: let your ears fly!' ) ),
158
- $this->extractor->find_function_calls( array('f'), '<?php /* Translators: let your ears fly! */ f( "baba" ); ' ) );
159
- }
160
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/extract/TODO DELETED
@@ -1 +0,0 @@
1
- * php-format
 
src/vendor/websharks/wp-i18n-tools/extract/extract.php DELETED
@@ -1,209 +0,0 @@
1
- <?php
2
- require_once dirname( __FILE__ ) . '/../pomo/entry.php';
3
- require_once dirname( __FILE__ ) . '/../pomo/translations.php';
4
-
5
- class StringExtractor {
6
-
7
- var $rules = array();
8
- var $comment_prefix = 'translators:';
9
-
10
- function __construct( $rules = array() ) {
11
- $this->rules = $rules;
12
- }
13
-
14
- function extract_from_directory( $dir, $excludes = array(), $includes = array(), $prefix = '' ) {
15
- $old_cwd = getcwd();
16
- chdir( $dir );
17
- $translations = new Translations;
18
- $file_names = (array) scandir( '.' );
19
- foreach ( $file_names as $file_name ) {
20
- if ( '.' == $file_name || '..' == $file_name ) continue;
21
- if ( preg_match( '/\.(?:php|js)$/', $file_name ) && $this->does_file_name_match( $prefix . $file_name, $excludes, $includes ) ) {
22
- $translations->merge_originals_with( $this->extract_from_file( $file_name, $prefix ) );
23
- }
24
- if ( is_dir( $file_name ) ) {
25
- $translations->merge_originals_with( $this->extract_from_directory( $file_name, $excludes, $includes, $prefix . $file_name . '/' ) );
26
- }
27
- }
28
- chdir( $old_cwd );
29
- return $translations;
30
- }
31
-
32
- function extract_from_file( $file_name, $prefix ) {
33
- $code = file_get_contents( $file_name );
34
- return $this->extract_entries( $code, $prefix . $file_name );
35
- }
36
-
37
- function does_file_name_match( $path, $excludes, $includes ) {
38
- if ( $includes ) {
39
- $matched_any_include = false;
40
- foreach( $includes as $include ) {
41
- if ( preg_match( '|^'.$include.'$|', $path ) ) {
42
- $matched_any_include = true;
43
- break;
44
- }
45
- }
46
- if ( !$matched_any_include ) return false;
47
- }
48
- if ( $excludes ) {
49
- foreach( $excludes as $exclude ) {
50
- if ( preg_match( '|^'.$exclude.'$|', $path ) ) {
51
- return false;
52
- }
53
- }
54
- }
55
- return true;
56
- }
57
-
58
- function entry_from_call( $call, $file_name ) {
59
- $rule = isset( $this->rules[$call['name']] )? $this->rules[$call['name']] : null;
60
- if ( !$rule ) return null;
61
- $entry = new Translation_Entry;
62
- $multiple = array();
63
- $complete = false;
64
- for( $i = 0; $i < count( $rule ); ++$i ) {
65
- if ( $rule[$i] && ( !isset( $call['args'][$i] ) || !is_string( $call['args'][$i] ) || '' == $call['args'][$i] ) ) return false;
66
- switch( $rule[$i] ) {
67
- case 'string':
68
- if ( $complete ) {
69
- $multiple[] = $entry;
70
- $entry = new Translation_Entry;
71
- $complete = false;
72
- }
73
- $entry->singular = $call['args'][$i];
74
- $complete = true;
75
- break;
76
- case 'singular':
77
- if ( $complete ) {
78
- $multiple[] = $entry;
79
- $entry = new Translation_Entry;
80
- $complete = false;
81
- }
82
- $entry->singular = $call['args'][$i];
83
- $entry->is_plural = true;
84
- break;
85
- case 'plural':
86
- $entry->plural = $call['args'][$i];
87
- $entry->is_plural = true;
88
- $complete = true;
89
- break;
90
- case 'context':
91
- $entry->context = $call['args'][$i];
92
- foreach( $multiple as &$single_entry ) {
93
- $single_entry->context = $entry->context;
94
- }
95
- break;
96
- }
97
- }
98
- if ( isset( $call['line'] ) && $call['line'] ) {
99
- $references = array( $file_name . ':' . $call['line'] );
100
- $entry->references = $references;
101
- foreach( $multiple as &$single_entry ) {
102
- $single_entry->references = $references;
103
- }
104
- }
105
- if ( isset( $call['comment'] ) && $call['comment'] ) {
106
- $comments = rtrim( $call['comment'] ) . "\n";
107
- $entry->extracted_comments = $comments;
108
- foreach( $multiple as &$single_entry ) {
109
- $single_entry->extracted_comments = $comments;
110
- }
111
- }
112
- if ( $multiple && $entry ) {
113
- $multiple[] = $entry;
114
- return $multiple;
115
- }
116
-
117
- return $entry;
118
- }
119
-
120
- function extract_entries( $code, $file_name ) {
121
- $translations = new Translations;
122
- $function_calls = $this->find_function_calls( array_keys( $this->rules ), $code );
123
- foreach( $function_calls as $call ) {
124
- $entry = $this->entry_from_call( $call, $file_name );
125
- if ( is_array( $entry ) )
126
- foreach( $entry as $single_entry )
127
- $translations->add_entry_or_merge( $single_entry );
128
- elseif ( $entry)
129
- $translations->add_entry_or_merge( $entry );
130
- }
131
- return $translations;
132
- }
133
-
134
- /**
135
- * Finds all function calls in $code and returns an array with an associative array for each function:
136
- * - name - name of the function
137
- * - args - array for the function arguments. Each string literal is represented by itself, other arguments are represented by null.
138
- * - line - line number
139
- */
140
- function find_function_calls( $function_names, $code ) {
141
- $tokens = token_get_all( $code );
142
- $function_calls = array();
143
- $latest_comment = false;
144
- $in_func = false;
145
- foreach( $tokens as $token ) {
146
- $id = $text = null;
147
- if ( is_array( $token ) ) list( $id, $text, $line ) = $token;
148
- if ( T_WHITESPACE == $id ) continue;
149
- if ( T_STRING == $id && in_array( $text, $function_names ) && !$in_func ) {
150
- $in_func = true;
151
- $paren_level = -1;
152
- $args = array();
153
- $func_name = $text;
154
- $func_line = $line;
155
- $func_comment = $latest_comment? $latest_comment : '';
156
-
157
- $just_got_into_func = true;
158
- $latest_comment = false;
159
- continue;
160
- }
161
- if ( T_COMMENT == $id ) {
162
- $text = trim( preg_replace( '%^/\*|//%', '', preg_replace( '%\*/$%', '', $text ) ) );
163
- if ( 0 === stripos( $text, $this->comment_prefix ) ) {
164
- $latest_comment = $text;
165
- }
166
- }
167
- if ( !$in_func ) continue;
168
- if ( '(' == $token ) {
169
- $paren_level++;
170
- if ( 0 == $paren_level ) { // start of first argument
171
- $just_got_into_func = false;
172
- $current_argument = null;
173
- $current_argument_is_just_literal = true;
174
- }
175
- continue;
176
- }
177
- if ( $just_got_into_func ) {
178
- // there wasn't a opening paren just after the function name -- this means it is not a function
179
- $in_func = false;
180
- $just_got_into_func = false;
181
- }
182
- if ( ')' == $token ) {
183
- if ( 0 == $paren_level ) {
184
- $in_func = false;
185
- $args[] = $current_argument;
186
- $call = array( 'name' => $func_name, 'args' => $args, 'line' => $func_line );
187
- if ( $func_comment ) $call['comment'] = $func_comment;
188
- $function_calls[] = $call;
189
- }
190
- $paren_level--;
191
- continue;
192
- }
193
- if ( ',' == $token && 0 == $paren_level ) {
194
- $args[] = $current_argument;
195
- $current_argument = null;
196
- $current_argument_is_just_literal = true;
197
- continue;
198
- }
199
- if ( T_CONSTANT_ENCAPSED_STRING == $id && $current_argument_is_just_literal ) {
200
- // we can use eval safely, because we are sure $text is just a string literal
201
- eval('$current_argument = '.$text.';' );
202
- continue;
203
- }
204
- $current_argument_is_just_literal = false;
205
- $current_argument = null;
206
- }
207
- return $function_calls;
208
- }
209
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/importers-i18n.php DELETED
@@ -1,195 +0,0 @@
1
- <?php
2
- ini_set( 'display_errors', 1 );
3
- class ImportersI18n {
4
- var $importers_slugs = array('wpcat2tag', 'wordpress', 'utw', 'textpattern', 'stp', 'rss', 'opml', 'movabletype', 'livejournal', 'greymatter', 'dotclear', 'blogware', 'blogger');
5
- var $username = 'nbachiyski';
6
- var $plugins_dir = '/www/wp-content-trunk/plugins';
7
- var $glotpress_source_dir = '/Users/nb/glotpress';
8
- var $glotpress_api_url = 'http://x/gp/api/projects/importers/%importer%/dev';
9
- var $glotpress_url = 'http://x/gp/projects/importers/%importer%/dev';
10
- var $minimum_percentage = 80;
11
-
12
- function __construct() {
13
- $this->importers = array_map( create_function( '$x', 'return $x."-importer";' ), $this->importers_slugs);
14
- }
15
-
16
- function s( $importer, $text ) {
17
- return str_replace( array( '%importer%', '%trunk%' ), array( $importer, "$importer/trunk" ), $text );
18
- }
19
-
20
- function call_on_all( $command ) {
21
- foreach( $this->importers as $importer ) {
22
- system( $this->s( $importer, $command ) );
23
- }
24
- }
25
-
26
- function ls() {
27
- $this->call_on_all( "ls %trunk%" );
28
- }
29
-
30
- function command( $command ) {
31
- $this->call_on_all( $command );
32
- }
33
-
34
-
35
- function checkout() {
36
- $this->call_on_all( "svn checkout --username=$this->username http://plugins.svn.wordpress.org/%importer%" );
37
- }
38
-
39
- function update() {
40
- $this->call_on_all( "svn up %importer%" );
41
- }
42
-
43
- function rename_main_file() {
44
- $this->call_on_all( "svn mv %importer%/trunk/*.php %importer%/trunk/%importer%.php" );
45
- }
46
-
47
- function link( $target ) {
48
- $this->call_on_all( "ln -s `pwd`/%importer%/trunk $target/%importer%" );
49
- }
50
-
51
- function add_load_plugin_textdomain_call() {
52
- foreach( $this->importers as $importer ) {
53
- $importer_underscore = str_replace( '-', '_', $importer );
54
- $main_file_name = "$importer/trunk/$importer.php";
55
- $main_file = file_get_contents( $main_file_name );
56
- $main_file .= "
57
- function {$importer_underscore}_init() {
58
- load_plugin_textdomain( '$importer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
59
- }
60
- add_action( 'init', '{$importer_underscore}_init' );
61
- ";
62
- file_put_contents( $main_file_name, $main_file );
63
- }
64
- }
65
-
66
- function make_languages_dir() {
67
- $this->call_on_all( "svn mkdir %importer%/trunk/languages" );
68
- }
69
-
70
- function generate_pot() {
71
- foreach( $this->importers as $importer ) {
72
- $old_cwd = getcwd();
73
- chdir( "$importer/trunk/languages" );
74
- system( "php ".dirname(__FILE__)."/makepot.php wp-plugin .." );
75
- chdir( $old_cwd );
76
- }
77
- }
78
-
79
-
80
- function diff() {
81
- $this->call_on_all( "svn diff %trunk%" );
82
- }
83
-
84
- function st() {
85
- $this->call_on_all( "svn st %trunk%" );
86
- }
87
-
88
- function svn_add_missing() {
89
- $this->call_on_all( "svn add %trunk%/*" );
90
- $this->call_on_all( "svn add %trunk%/languages/*" );
91
- }
92
-
93
- function lint() {
94
- $this->call_on_all( "php -l %importer% %trunk%/%importer%.php" );
95
- }
96
-
97
-
98
- function add_textdomain() {
99
- $this->call_on_all( "php ".dirname(__FILE__)."/add-textdomain.php -i %importer% %trunk%/%importer%.php" );
100
- }
101
-
102
- function sync() {
103
- $this->call_on_all( "cp -R %trunk% $this->plugins_dir/%importer%" );
104
- }
105
-
106
- function commit($message) {
107
- $this->call_on_all( "svn ci %trunk% -m ".escapeshellarg($message) );
108
- }
109
-
110
- function update_translations() {
111
- require_once $this->glotpress_source_dir . '/locales/locales.php';
112
- foreach( $this->importers as $importer ) {
113
- $project_details_json = file_get_contents( $this->s( $importer, $this->glotpress_api_url ) );
114
- $project_details = json_decode( $project_details_json );
115
- if ( !is_object( $project_details ) ) {
116
- echo "Couldn't get project JSON from GlotPress for $importer.\n";
117
- continue;
118
- }
119
- foreach( $project_details->translation_sets as $set ) {
120
- $locale = GP_Locales::by_slug( $set->locale );
121
- if ( !$locale->wp_locale ) {
122
- echo "Locale '$set->locale' doesn't have WordPress equivalent.\n";
123
- continue;
124
- }
125
- $po_file = file_get_contents( $this->s( $importer, $this->glotpress_url ) . "/$locale->slug/$set->slug/export-translations" );
126
- if ( !$po_file ) {
127
- echo "Couldn't download translation for '$importer' in '$set->locale'.\n";
128
- continue;
129
- }
130
- $po_path = $this->s( $importer, "%trunk%/languages/$locale->wp_locale.po" );
131
- $mo_path = str_replace( '.po', '.mo', $po_path );
132
- file_put_contents( $po_path, $po_file );
133
- $msgfmt_output = `msgfmt --statistics $po_path -o $mo_path 2>&1`;
134
- preg_match( '/(\d+) translated messages(?:\.|, (\d+) untranslated messages)/', $msgfmt_output, $matches );
135
- if ( isset( $matches[2] ) ) {
136
- $translated_percentage = $matches[1] / ( $matches[1] + $matches[2] ) * 100;
137
- if ( $translated_percentage < $this->minimum_percentage ) {
138
- unlink( $po_path );
139
- unlink( $mo_path );
140
- echo "Translation of '$importer' in '$locale->slug' has only $translated_percentage% translated, $this->minimum_percentage% are required.\n";
141
- }
142
- }
143
- }
144
- }
145
- }
146
-
147
- function create_glotpress_projects( $parent_project_path ) {
148
- require_once $this->glotpress_source_dir . '/gp-load.php';
149
- require_once dirname(__FILE__) . '/makepot.php';
150
- $makepot = new MakePOT;
151
- $parent_project = GP::$project->by_path( $parent_project_path );
152
- if ( !$parent_project ) {
153
- echo "Couldn't find project with path $parent_project_path.\n";
154
- return;
155
- }
156
- foreach( $this->importers as $importer ) {
157
- $source = $makepot->get_first_lines( $this->s( $importer, '%trunk%/%importer%.php' ), $makepot->max_header_lines);
158
- if ( !GP::$project->by_path( "$parent_project_path/$importer") ) {
159
- $importer_project = GP::$project->create_and_select(array(
160
- 'name' => $makepot->get_addon_header('Plugin Name', $source),
161
- 'slug' => $importer,
162
- 'description' => $makepot->get_addon_header('Description', $source),
163
- 'parent_project_id' => $parent_project->id,
164
- ));
165
- } else {
166
- echo "Project $parent_project_path/$importer already exists.\n";
167
- }
168
- if ( !GP::$project->by_path( "$parent_project_path/$importer/dev") ) {
169
- $trunk_project = GP::$project->create_and_select(array(
170
- 'name' => 'Development (trunk)',
171
- 'slug' => 'dev',
172
- 'description' => 'Development version of ' . $makepot->get_addon_header('Plugin Name', $source),
173
- 'parent_project_id' => $importer_project->id,
174
- 'source_url_template' => $this->s($importer, "http://plugins.trac.wordpress.org/browser/%importer%/trunk/%file%#L%line%"),
175
- ));
176
- } else {
177
- echo "Project $parent_project_path/$importer/dev already exists.\n";
178
- }
179
- }
180
- }
181
-
182
- function import_glotpress_originals( $parent_project_path ) {
183
- foreach( $this->importers as $importer ) {
184
- system( $this->s( $importer, "php $this->glotpress_source_dir/scripts/import-originals.php -p $parent_project_path/%importer%/dev -f %trunk%/languages/%importer%.pot" ) );
185
- }
186
- }
187
-
188
- function line_of_text( $line ) {
189
- foreach( $this->importers as $importer ) {
190
- echo $this->s( $importer, $line ) . "\n";
191
- }
192
- }
193
- }
194
- $importers_i18n = new ImportersI18n;
195
- call_user_func_array( array( &$importers_i18n, $argv[1] ), array_slice( $argv, 2 ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/makepot.php DELETED
@@ -1,570 +0,0 @@
1
- #!/usr/bin/env php
2
- <?php
3
- require_once dirname( __FILE__ ) . '/not-gettexted.php';
4
- require_once dirname( __FILE__ ) . '/pot-ext-meta.php';
5
- require_once dirname( __FILE__ ) . '/extract/extract.php';
6
-
7
- if ( !defined( 'STDERR' ) ) {
8
- define( 'STDERR', fopen( 'php://stderr', 'w' ) );
9
- }
10
-
11
- class MakePOT {
12
- var $max_header_lines = 30;
13
-
14
- var $projects = array(
15
- 'generic',
16
- 'wp-frontend',
17
- 'wp-admin',
18
- 'wp-network-admin',
19
- 'wp-core',
20
- 'wp-ms',
21
- 'wp-tz',
22
- 'wp-plugin',
23
- 'wp-theme',
24
- 'bb',
25
- 'mu',
26
- 'bp',
27
- 'rosetta',
28
- 'wporg-bb-forums',
29
- );
30
-
31
- var $rules = array(
32
- '_' => array('string'),
33
- '__' => array('string'),
34
- '_e' => array('string'),
35
- '_c' => array('string'),
36
- '_n' => array('singular', 'plural'),
37
- '_n_noop' => array('singular', 'plural'),
38
- '_nc' => array('singular', 'plural'),
39
- '__ngettext' => array('singular', 'plural'),
40
- '__ngettext_noop' => array('singular', 'plural'),
41
- '_x' => array('string', 'context'),
42
- '_ex' => array('string', 'context'),
43
- '_nx' => array('singular', 'plural', null, 'context'),
44
- '_nx_noop' => array('singular', 'plural', 'context'),
45
- '_n_js' => array('singular', 'plural'),
46
- '_nx_js' => array('singular', 'plural', 'context'),
47
- 'esc_attr__' => array('string'),
48
- 'esc_html__' => array('string'),
49
- 'esc_attr_e' => array('string'),
50
- 'esc_html_e' => array('string'),
51
- 'esc_attr_x' => array('string', 'context'),
52
- 'esc_html_x' => array('string', 'context'),
53
- 'comments_number_link' => array('string', 'singular', 'plural'),
54
- );
55
-
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(
61
- 'default' => array(
62
- 'from-code' => 'utf-8',
63
- 'msgid-bugs-address' => 'http://wppolyglots.wordpress.com',
64
- 'language' => 'php',
65
- 'add-comments' => 'translators',
66
- 'comments' => "Copyright (C) {year} {package-name}\nThis file is distributed under the same license as the {package-name} package.",
67
- ),
68
- 'generic' => array(),
69
- 'wp-frontend' => array(
70
- 'description' => 'Translation of frontend strings in WordPress {version}',
71
- 'copyright-holder' => 'WordPress',
72
- 'package-name' => 'WordPress',
73
- 'package-version' => '{version}',
74
- ),
75
- 'wp-admin' => array(
76
- 'description' => 'Translation of site admin strings in WordPress {version}',
77
- 'copyright-holder' => 'WordPress',
78
- 'package-name' => 'WordPress',
79
- 'package-version' => '{version}',
80
- ),
81
- 'wp-network-admin' => array(
82
- 'description' => 'Translation of network admin strings in WordPress {version}',
83
- 'copyright-holder' => 'WordPress',
84
- 'package-name' => 'WordPress',
85
- 'package-version' => '{version}',
86
- ),
87
- 'wp-core' => array(
88
- 'description' => 'Translation of WordPress {version}',
89
- 'copyright-holder' => 'WordPress',
90
- 'package-name' => 'WordPress',
91
- '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
- ),
110
- 'wp-plugin' => array(
111
- 'description' => 'Translation of the WordPress plugin {name} {version} by {author}',
112
- 'msgid-bugs-address' => 'http://wordpress.org/tag/{slug}',
113
- 'copyright-holder' => '{author}',
114
- 'package-name' => '{name}',
115
- 'package-version' => '{version}',
116
- ),
117
- 'wp-theme' => array(
118
- 'description' => 'Translation of the WordPress theme {name} {version} by {author}',
119
- 'msgid-bugs-address' => 'http://wordpress.org/tags/{slug}',
120
- 'copyright-holder' => '{author}',
121
- 'package-name' => '{name}',
122
- 'package-version' => '{version}',
123
- 'comments' => 'Copyright (C) {year} {author}\nThis file is distributed under the same license as the {package-name} package.',
124
- ),
125
- 'bp' => array(
126
- 'description' => 'Translation of BuddyPress',
127
- 'copyright-holder' => 'BuddyPress',
128
- 'package-name' => 'BuddyPress',
129
- ),
130
- 'glotpress' => array(
131
- 'description' => 'Translation of GlotPress',
132
- 'copyright-holder' => 'GlotPress',
133
- 'package-name' => 'GlotPress',
134
- ),
135
- 'wporg-bb-forums' => array(
136
- 'description' => 'WordPress.org International Forums',
137
- 'copyright-holder' => 'WordPress',
138
- 'package-name' => 'WordPress.org International Forums',
139
- ),
140
- 'rosetta' => array(
141
- 'description' => 'Rosetta (.wordpress.org locale sites)',
142
- 'copyright-holder' => 'WordPress',
143
- 'package-name' => 'Rosetta',
144
- ),
145
- );
146
-
147
- function __construct($deprecated = true) {
148
- $this->extractor = new StringExtractor( $this->rules );
149
- }
150
-
151
- function __destruct() {
152
- foreach ( $this->temp_files as $temp_file )
153
- unlink( $temp_file );
154
- }
155
-
156
- function tempnam( $file ) {
157
- $tempnam = tempnam( sys_get_temp_dir(), $file );
158
- $this->temp_files[] = $tempnam;
159
- return $tempnam;
160
- }
161
-
162
- function realpath_missing($path) {
163
- return realpath(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
164
- }
165
-
166
- function xgettext($project, $dir, $output_file, $placeholders = array(), $excludes = array(), $includes = array()) {
167
- $meta = array_merge( $this->meta['default'], $this->meta[$project] );
168
- $placeholders = array_merge( $meta, $placeholders );
169
- $meta['output'] = $this->realpath_missing( $output_file );
170
- $placeholders['year'] = date( 'Y' );
171
- $placeholder_keys = array_map( create_function( '$x', 'return "{".$x."}";' ), array_keys( $placeholders ) );
172
- $placeholder_values = array_values( $placeholders );
173
- foreach($meta as $key => $value) {
174
- $meta[$key] = str_replace($placeholder_keys, $placeholder_values, $value);
175
- }
176
-
177
- $originals = $this->extractor->extract_from_directory( $dir, $excludes, $includes );
178
- $pot = new PO;
179
- $pot->entries = $originals->entries;
180
-
181
- $pot->set_header( 'Project-Id-Version', $meta['package-name'].' '.$meta['package-version'] );
182
- $pot->set_header( 'Report-Msgid-Bugs-To', $meta['msgid-bugs-address'] );
183
- $pot->set_header( 'POT-Creation-Date', gmdate( 'Y-m-d H:i:s+00:00' ) );
184
- $pot->set_header( 'MIME-Version', '1.0' );
185
- $pot->set_header( 'Content-Type', 'text/plain; charset=UTF-8' );
186
- $pot->set_header( 'Content-Transfer-Encoding', '8bit' );
187
- $pot->set_header( 'PO-Revision-Date', date( 'Y') . '-MO-DA HO:MI+ZONE' );
188
- $pot->set_header( 'Last-Translator', 'FULL NAME <EMAIL@ADDRESS>' );
189
- $pot->set_header( 'Language-Team', 'LANGUAGE <LL@li.org>' );
190
- $pot->set_comment_before_headers( $meta['comments'] );
191
- $pot->export_to_file( $output_file );
192
- return true;
193
- }
194
-
195
- function wp_generic($dir, $args) {
196
- $defaults = array(
197
- 'project' => 'wp-core',
198
- 'output' => null,
199
- 'default_output' => 'wordpress.pot',
200
- 'includes' => array(),
201
- 'excludes' => array_merge(
202
- array('wp-admin/includes/continents-cities\.php', 'wp-content/themes/twenty.*', ),
203
- $this->ms_files
204
- ),
205
- 'extract_not_gettexted' => false,
206
- 'not_gettexted_files_filter' => false,
207
- );
208
- $args = array_merge( $defaults, $args );
209
- extract( $args );
210
- $placeholders = array();
211
- if ( $wp_version = $this->wp_version( $dir ) )
212
- $placeholders['version'] = $wp_version;
213
- else
214
- return false;
215
- $output = is_null( $output )? $default_output : $output;
216
- $res = $this->xgettext( $project, $dir, $output, $placeholders, $excludes, $includes );
217
- if ( !$res ) return false;
218
-
219
- if ( $extract_not_gettexted ) {
220
- $old_dir = getcwd();
221
- $output = realpath( $output );
222
- chdir( $dir );
223
- $php_files = NotGettexted::list_php_files('.');
224
- $php_files = array_filter( $php_files, $not_gettexted_files_filter );
225
- $not_gettexted = new NotGettexted;
226
- $res = $not_gettexted->command_extract( $output, $php_files );
227
- chdir( $old_dir );
228
- /* Adding non-gettexted strings can repeat some phrases */
229
- $output_shell = escapeshellarg( $output );
230
- system( "msguniq --use-first $output_shell -o $output_shell" );
231
- }
232
- return $res;
233
- }
234
-
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) {
246
- if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
247
-
248
- return $this->wp_generic( $dir, array(
249
- 'project' => 'wp-frontend', 'output' => $output,
250
- 'includes' => array(), 'excludes' => array( 'wp-admin/.*', 'wp-content/themes/.*' ),
251
- 'default_output' => 'wordpress.pot',
252
- ) );
253
- }
254
-
255
- function wp_admin($dir, $output) {
256
- if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
257
-
258
- $frontend_pot = $this->tempnam( 'frontend.pot' );
259
- if ( false === $frontend_pot ) return false;
260
-
261
- $frontend_result = $this->wp_frontend( $dir, $frontend_pot );
262
- if ( ! $frontend_result )
263
- return false;
264
-
265
- $result = $this->wp_generic( $dir, array(
266
- 'project' => 'wp-admin', 'output' => $output,
267
- 'includes' => array( 'wp-admin/.*' ), 'excludes' => array( 'wp-admin/includes/continents-cities\.php', 'wp-admin/network/.*', 'wp-admin/network.php' ),
268
- 'default_output' => 'wordpress-admin.pot',
269
- ) );
270
-
271
- if ( ! $result )
272
- return false;
273
-
274
- $potextmeta = new PotExtMeta;
275
- $result = $potextmeta->append( "$dir/wp-content/plugins/akismet/akismet.php", $output );
276
- if ( ! $result )
277
- return false;
278
- $result = $potextmeta->append( "$dir/wp-content/plugins/hello.php", $output );
279
- if ( ! $result )
280
- return false;
281
- /* Adding non-gettexted strings can repeat some phrases */
282
- $output_shell = escapeshellarg($output);
283
- system("msguniq $output_shell -o $output_shell");
284
-
285
- $common_pot = $this->tempnam( 'common.pot' );
286
- if ( ! $common_pot )
287
- return false;
288
- $admin_pot = realpath( is_null( $output ) ? 'wordpress-admin.pot' : $output );
289
- system( "msgcat --more-than=1 --use-first $frontend_pot $admin_pot > $common_pot" );
290
- system( "msgcat -u --use-first $admin_pot $common_pot -o $admin_pot" );
291
- return true;
292
- }
293
-
294
- function wp_network_admin($dir, $output) {
295
- if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
296
-
297
- $frontend_pot = $this->tempnam( 'frontend.pot' );
298
- if ( false === $frontend_pot ) return false;
299
-
300
- $frontend_result = $this->wp_frontend( $dir, $frontend_pot );
301
- if ( ! $frontend_result )
302
- return false;
303
-
304
- $admin_pot = $this->tempnam( 'admin.pot' );
305
- if ( false === $admin_pot ) return false;
306
-
307
- $admin_result = $this->wp_admin( $dir, $admin_pot );
308
- if ( ! $admin_result )
309
- return false;
310
-
311
- $result = $this->wp_generic( $dir, array(
312
- 'project' => 'wp-network-admin', 'output' => $output,
313
- 'includes' => array( 'wp-admin/network/.*', 'wp-admin/network.php' ), 'excludes' => array(),
314
- 'default_output' => 'wordpress-admin-network.pot',
315
- ) );
316
-
317
- if ( ! $result ) {
318
- return false;
319
- }
320
-
321
- $common_pot = $this->tempnam( 'common.pot' );
322
- if ( ! $common_pot )
323
- return false;
324
-
325
- $net_admin_pot = realpath( is_null( $output ) ? 'wordpress-network-admin.pot' : $output );
326
- system( "msgcat --more-than=1 --use-first $frontend_pot $admin_pot $net_admin_pot > $common_pot" );
327
- system( "msgcat -u --use-first $net_admin_pot $common_pot -o $net_admin_pot" );
328
- return true;
329
- }
330
-
331
- function wp_ms($dir, $output) {
332
- if ( file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
333
- if ( !is_file("$dir/wp-admin/ms-users.php") ) return false;
334
- $core_pot = $this->tempnam( 'wordpress.pot' );
335
- if ( false === $core_pot ) return false;
336
- $core_result = $this->wp_core( $dir, $core_pot );
337
- if ( ! $core_result )
338
- return false;
339
- $ms_result = $this->wp_generic( $dir, array(
340
- 'project' => 'wp-ms', 'output' => $output,
341
- 'includes' => $this->ms_files, 'excludes' => array(),
342
- 'default_output' => 'wordpress-ms.pot',
343
- 'extract_not_gettexted' => true,
344
- 'not_gettexted_files_filter' => array( &$this, 'is_ms_file' ),
345
- ) );
346
- if ( !$ms_result ) {
347
- return false;
348
- }
349
- $common_pot = $this->tempnam( 'common.pot' );
350
- if ( ! $common_pot )
351
- return false;
352
- $ms_pot = realpath( is_null( $output )? 'wordpress-ms.pot' : $output );
353
- system( "msgcat --more-than=1 --use-first $core_pot $ms_pot > $common_pot" );
354
- system( "msgcat -u --use-first $ms_pot $common_pot -o $ms_pot" );
355
- return true;
356
- }
357
-
358
- function wp_tz($dir, $output) {
359
- $continents_path = 'wp-admin/includes/continents-cities.php';
360
- if ( !file_exists( "$dir/$continents_path" ) ) return false;
361
- return $this->wp_generic( $dir, array(
362
- 'project' => 'wp-tz', 'output' => $output,
363
- 'includes' => array($continents_path), 'excludes' => array(),
364
- 'default_output' => 'wordpress-continents-cities.pot',
365
- ) );
366
- }
367
-
368
- function wp_version($dir) {
369
- $version_php = $dir.'/wp-includes/version.php';
370
- if ( !is_readable( $version_php ) ) return false;
371
- return preg_match( '/\$wp_version\s*=\s*\'(.*?)\';/', file_get_contents( $version_php ), $matches )? $matches[1] : false;
372
- }
373
-
374
-
375
- function mu($dir, $output) {
376
- $placeholders = array();
377
- if (preg_match('/\$wpmu_version\s*=\s*\'(.*?)\';/', file_get_contents($dir.'/wp-includes/version.php'), $matches)) {
378
- $placeholders['version'] = $matches[1];
379
- }
380
- $output = is_null($output)? 'wordpress.pot' : $output;
381
- return $this->xgettext('wp', $dir, $output, $placeholders);
382
- }
383
-
384
-
385
- function bb($dir, $output) {
386
- $placeholders = array();
387
- $output = is_null($output)? 'bbpress.pot' : $output;
388
- return $this->xgettext('bb', $dir, $output, $placeholders);
389
-
390
- }
391
-
392
- function get_first_lines($filename, $lines = 30) {
393
- $extf = fopen($filename, 'r');
394
- if (!$extf) return false;
395
- $first_lines = '';
396
- foreach(range(1, $lines) as $x) {
397
- $line = fgets($extf);
398
- if (feof($extf)) break;
399
- if (false === $line) {
400
- return false;
401
- }
402
- $first_lines .= $line;
403
- }
404
- return $first_lines;
405
- }
406
-
407
-
408
- function get_addon_header($header, &$source) {
409
- if (preg_match('|'.$header.':(.*)$|mi', $source, $matches))
410
- return trim($matches[1]);
411
- else
412
- return false;
413
- }
414
-
415
- function generic($dir, $output) {
416
- $output = is_null($output)? "generic.pot" : $output;
417
- return $this->xgettext('generic', $dir, $output, array());
418
- }
419
-
420
- function guess_plugin_slug($dir) {
421
- if ('trunk' == basename($dir)) {
422
- $slug = basename(dirname($dir));
423
- } elseif (in_array(basename(dirname($dir)), array('branches', 'tags'))) {
424
- $slug = basename(dirname(dirname($dir)));
425
- } else {
426
- $slug = basename($dir);
427
- }
428
- return $slug;
429
- }
430
-
431
- function wp_plugin($dir, $output, $slug = null) {
432
- $placeholders = array();
433
- // guess plugin slug
434
- if (is_null($slug)) {
435
- $slug = $this->guess_plugin_slug($dir);
436
- }
437
- $main_file = $dir.'/'.$slug.'.php';
438
- if(!is_file($main_file)) $main_file = $dir.'/plugin.php';
439
- $source = $this->get_first_lines($main_file, $this->max_header_lines);
440
-
441
- $placeholders['version'] = $this->get_addon_header('Version', $source);
442
- $placeholders['author'] = $this->get_addon_header('Author', $source);
443
- $placeholders['name'] = $this->get_addon_header('Plugin Name', $source);
444
- $placeholders['slug'] = $slug;
445
-
446
- $output = is_null($output)? "$slug.pot" : $output;
447
- $res = $this->xgettext('wp-plugin', $dir, $output, $placeholders, array('(?:.+?/)?vendor/.*'));
448
- if (!$res) return false;
449
- $potextmeta = new PotExtMeta;
450
- $res = $potextmeta->append($main_file, $output);
451
- /* Adding non-gettexted strings can repeat some phrases */
452
- $output_shell = escapeshellarg($output);
453
- system("msguniq $output_shell -o $output_shell --no-wrap");
454
- return $res;
455
- }
456
-
457
- function wp_theme($dir, $output, $slug = null) {
458
- $placeholders = array();
459
- // guess plugin slug
460
- if (is_null($slug)) {
461
- $slug = $this->guess_plugin_slug($dir);
462
- }
463
- $main_file = $dir.'/style.css';
464
- $source = $this->get_first_lines($main_file, $this->max_header_lines);
465
-
466
- $placeholders['version'] = $this->get_addon_header('Version', $source);
467
- $placeholders['author'] = $this->get_addon_header('Author', $source);
468
- $placeholders['name'] = $this->get_addon_header('Theme Name', $source);
469
- $placeholders['slug'] = $slug;
470
-
471
- $license = $this->get_addon_header( 'License', $source );
472
- if ( $license )
473
- $this->meta['wp-theme']['comments'] = "Copyright (C) {year} {author}\nThis file is distributed under the {$license}.";
474
- else
475
- $this->meta['wp-theme']['comments'] = "Copyright (C) {year} {author}\nThis file is distributed under the same license as the {package-name} package.";
476
-
477
- $output = is_null($output)? "$slug.pot" : $output;
478
- $res = $this->xgettext('wp-theme', $dir, $output, $placeholders, array('(?:.+?/)?vendor/.*'));
479
- if (! $res )
480
- return false;
481
- $potextmeta = new PotExtMeta;
482
- $res = $potextmeta->append( $main_file, $output, array( 'Theme Name', 'Theme URI', 'Description', 'Author', 'Author URI' ) );
483
- if ( ! $res )
484
- return false;
485
- // If we're dealing with a pre-3.4 default theme, don't extract page templates before 3.4.
486
- $extract_templates = ! in_array( $slug, array( 'twentyten', 'twentyeleven', 'default', 'classic' ) );
487
- if ( ! $extract_templates ) {
488
- $wp_dir = dirname( dirname( dirname( $dir ) ) );
489
- $extract_templates = file_exists( "$wp_dir/wp-admin/user/about.php" ) || ! file_exists( "$wp_dir/wp-load.php" );
490
- }
491
- if ( $extract_templates ) {
492
- $res = $potextmeta->append( $dir, $output, array( 'Template Name' ) );
493
- if ( ! $res )
494
- return false;
495
- $files = scandir( $dir );
496
- foreach ( $files as $file ) {
497
- if ( '.' == $file[0] || 'CVS' == $file )
498
- continue;
499
- if ( is_dir( $dir . '/' . $file ) ) {
500
- $res = $potextmeta->append( $dir . '/' . $file, $output, array( 'Template Name' ) );
501
- if ( ! $res )
502
- return false;
503
- }
504
- }
505
- }
506
- /* Adding non-gettexted strings can repeat some phrases */
507
- $output_shell = escapeshellarg($output);
508
- system("msguniq $output_shell -o $output_shell --no-wrap");
509
- return $res;
510
- }
511
-
512
- function bp($dir, $output) {
513
- $output = is_null($output)? "buddypress.pot" : $output;
514
- return $this->xgettext('bp', $dir, $output, array(), array('bp-forums/bbpress/.*'));
515
- }
516
-
517
- function glotpress( $dir, $output ) {
518
- $output = is_null( $output ) ? "glotpress.pot" : $output;
519
- return $this->xgettext( 'glotpress', $dir, $output );
520
- }
521
-
522
- function wporg_bb_forums( $dir, $output ) {
523
- $output = is_null( $output ) ? 'wporg.pot' : $output;
524
- return $this->xgettext( 'wporg-bb-forums', $dir, $output, array(), array(
525
- 'bb-plugins/elfakismet/.*',
526
- 'bb-plugins/support-forum/.*',
527
- ) );
528
- }
529
-
530
- function rosetta( $dir, $output ) {
531
- $output = is_null( $output )? 'rosetta.pot' : $output;
532
- return $this->xgettext( 'rosetta', $dir, $output, array(), array(), array(
533
- 'mu-plugins/rosetta.*\.php',
534
- 'mu-plugins/rosetta/[^/]+\.php',
535
- 'mu-plugins/rosetta/tmpl/.*\.php',
536
- 'themes/rosetta/.*\.php',
537
- ) );
538
- }
539
-
540
- function is_ms_file( $file_name ) {
541
- $is_ms_file = false;
542
- $prefix = substr( $file_name, 0, 2 ) === './'? '\./' : '';
543
- foreach( $this->ms_files as $ms_file )
544
- if ( preg_match( '|^'.$prefix.$ms_file.'$|', $file_name ) ) {
545
- $is_ms_file = true;
546
- break;
547
- }
548
- return $is_ms_file;
549
- }
550
-
551
- function is_not_ms_file( $file_name ) {
552
- return !$this->is_ms_file( $file_name );
553
- }
554
- }
555
-
556
- if ((defined('IS_PHAR_MAKEPOT') && IS_PHAR_MAKEPOT) || (($included_files = get_included_files()) && $included_files[0] == __FILE__)) {
557
- $makepot = new MakePOT;
558
- if ((3 == count($argv) || 4 == count($argv)) && in_array($method = str_replace('-', '_', $argv[1]), get_class_methods($makepot))) {
559
- $res = call_user_func(array(&$makepot, $method), realpath($argv[2]), isset($argv[3])? $argv[3] : null);
560
- if (false === $res) {
561
- fwrite(STDERR, "Couldn't generate POT file!\n");
562
- }
563
- } else {
564
- $usage = "Usage: php makepot.php PROJECT DIRECTORY [OUTPUT]\n\n";
565
- $usage .= "Generate POT file from the files in DIRECTORY [OUTPUT]\n";
566
- $usage .= "Available projects: ".implode(', ', $makepot->projects)."\n";
567
- fwrite(STDERR, $usage);
568
- exit(1);
569
- }
570
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/not-gettexted.php DELETED
@@ -1,234 +0,0 @@
1
- <?php
2
- /**
3
- * Console application, which extracts or replaces strings for
4
- * translation, which cannot be gettexted
5
- *
6
- * @version $Id$
7
- * @package wordpress-i18n
8
- * @subpackage tools
9
- */
10
- // see: http://php.net/tokenizer
11
- if ( ! defined( 'T_ML_COMMENT' ) )
12
- define( 'T_ML_COMMENT', T_COMMENT );
13
- else
14
- define( 'T_DOC_COMMENT', T_ML_COMMENT );
15
-
16
- require_once dirname( __FILE__ ) . '/pomo/po.php';
17
- require_once dirname( __FILE__ ) . '/pomo/mo.php';
18
-
19
- class NotGettexted {
20
- var $enable_logging = false;
21
-
22
- var $STAGE_OUTSIDE = 0;
23
- var $STAGE_START_COMMENT = 1;
24
- var $STAGE_WHITESPACE_BEFORE = 2;
25
- var $STAGE_STRING = 3;
26
- var $STAGE_WHITESPACE_AFTER = 4;
27
- var $STAGE_END_COMMENT = 4;
28
-
29
- var $commands = array('extract' => 'command_extract', 'replace' => 'command_replace' );
30
-
31
-
32
- function logmsg() {
33
- $args = func_get_args();
34
- if ($this->enable_logging) error_log(implode(' ', $args));
35
- }
36
-
37
- function stderr($msg, $nl=true) {
38
- fwrite(STDERR, $msg.($nl? "\n" : ""));
39
- }
40
-
41
- function cli_die($msg) {
42
- $this->stderr($msg);
43
- exit(1);
44
- }
45
-
46
- function unchanged_token($token, $s='') {
47
- return is_array($token)? $token[1] : $token;
48
- }
49
-
50
- function ignore_token($token, $s='') {
51
- return '';
52
- }
53
-
54
- function list_php_files($dir) {
55
- $files = array();
56
- $items = scandir( $dir );
57
- foreach ( (array) $items as $item ) {
58
- $full_item = $dir . '/' . $item;
59
- if ('.' == $item || '..' == $item)
60
- continue;
61
- if ('.php' == substr($item, -4))
62
- $files[] = $full_item;
63
- if (is_dir($full_item))
64
- $files += array_merge($files, NotGettexted::list_php_files($full_item, $files));
65
- }
66
- return $files;
67
- }
68
-
69
-
70
- function make_string_aggregator($global_array_name, $filename) {
71
- $a = $global_array_name;
72
- return create_function('$string, $comment_id, $line_number', 'global $'.$a.'; $'.$a.'[] = array($string, $comment_id, '.var_export($filename, true).', $line_number);');
73
- }
74
-
75
- function make_mo_replacer($global_mo_name) {
76
- $m = $global_mo_name;
77
- return create_function('$token, $string', 'global $'.$m.'; return var_export($'.$m.'->translate($string), true);');
78
- }
79
-
80
- function walk_tokens(&$tokens, $string_action, $other_action, $register_action=null) {
81
-
82
- $current_comment_id = '';
83
- $current_string = '';
84
- $current_string_line = 0;
85
-
86
- $result = '';
87
- $line = 1;
88
-
89
- foreach($tokens as $token) {
90
- if (is_array($token)) {
91
- list($id, $text) = $token;
92
- $line += substr_count($text, "\n");
93
- if ((T_ML_COMMENT == $id || T_COMMENT == $id) && preg_match('|/\*\s*(/?WP_I18N_[a-z_]+)\s*\*/|i', $text, $matches)) {
94
- if ($this->STAGE_OUTSIDE == $stage) {
95
- $stage = $this->STAGE_START_COMMENT;
96
- $current_comment_id = $matches[1];
97
- $this->logmsg('start comment', $current_comment_id);
98
- $result .= call_user_func($other_action, $token);
99
- continue;
100
- }
101
- if ($this->STAGE_START_COMMENT <= $stage && $stage <= $this->STAGE_WHITESPACE_AFTER && '/'.$current_comment_id == $matches[1]) {
102
- $stage = $this->STAGE_END_COMMENT;
103
- $this->logmsg('end comment', $current_comment_id);
104
- $result .= call_user_func($other_action, $token);
105
- if (!is_null($register_action)) call_user_func($register_action, $current_string, $current_comment_id, $current_string_line);
106
- continue;
107
- }
108
- } else if (T_CONSTANT_ENCAPSED_STRING == $id) {
109
- if ($this->STAGE_START_COMMENT <= $stage && $stage < $this->STAGE_WHITESPACE_AFTER) {
110
- eval('$current_string='.$text.';');
111
- $this->logmsg('string', $current_string);
112
- $current_string_line = $line;
113
- $result .= call_user_func($string_action, $token, $current_string);
114
- continue;
115
- }
116
- } else if (T_WHITESPACE == $id) {
117
- if ($this->STAGE_START_COMMENT <= $stage && $stage < $this->STAGE_STRING) {
118
- $stage = $this->STAGE_WHITESPACE_BEFORE;
119
- $this->logmsg('whitespace before');
120
- $result .= call_user_func($other_action, $token);
121
- continue;
122
- }
123
- if ($this->STAGE_STRING < $stage && $stage < $this->STAGE_END_COMMENT) {
124
- $stage = $this->STAGE_WHITESPACE_AFTER;
125
- $this->logmsg('whitespace after');
126
- $result .= call_user_func($other_action, $token);
127
- continue;
128
- }
129
- }
130
- }
131
- $result .= call_user_func($other_action, $token);
132
- $stage = $this->STAGE_OUTSIDE;
133
- $current_comment_id = '';
134
- $current_string = '';
135
- $current_string_line = 0;
136
- }
137
- return $result;
138
- }
139
-
140
-
141
- function command_extract() {
142
- $args = func_get_args();
143
- $pot_filename = $args[0];
144
- if (isset($args[1]) && is_array($args[1]))
145
- $filenames = $args[1];
146
- else
147
- $filenames = array_slice($args, 1);
148
-
149
- $global_name = '__entries_'.mt_rand(1, 1000);
150
- $GLOBALS[$global_name] = array();
151
-
152
- foreach($filenames as $filename) {
153
- $tokens = token_get_all(file_get_contents($filename));
154
- $aggregator = $this->make_string_aggregator($global_name, $filename);
155
- $this->walk_tokens($tokens, array(&$this, 'ignore_token'), array(&$this, 'ignore_token'), $aggregator);
156
- }
157
-
158
- $potf = '-' == $pot_filename? STDOUT : @fopen($pot_filename, 'a');
159
- if (false === $potf) {
160
- $this->cli_die("Couldn't open pot file: $pot_filename");
161
- }
162
-
163
- foreach($GLOBALS[$global_name] as $item) {
164
- @list($string, $comment_id, $filename, $line_number) = $item;
165
- $filename = isset($filename)? preg_replace('|^\./|', '', $filename) : '';
166
- $ref_line_number = isset($line_number)? ":$line_number" : '';
167
- $args = array(
168
- 'singular' => $string,
169
- 'extracted_comments' => "Not gettexted string $comment_id",
170
- 'references' => array("$filename$ref_line_number"),
171
- );
172
- $entry = new Translation_Entry($args);
173
- fwrite($potf, "\n".PO::export_entry($entry)."\n");
174
- }
175
- if ('-' != $pot_filename) fclose($potf);
176
- return true;
177
- }
178
-
179
- function command_replace() {
180
- $args = func_get_args();
181
- $mo_filename = $args[0];
182
- if (isset($args[1]) && is_array($args[1]))
183
- $filenames = $args[1];
184
- else
185
- $filenames = array_slice($args, 1);
186
-
187
- $global_name = '__mo_'.mt_rand(1, 1000);
188
- $GLOBALS[$global_name] = new MO();
189
- $replacer = $this->make_mo_replacer($global_name);
190
-
191
- $res = $GLOBALS[$global_name]->import_from_file($mo_filename);
192
- if (false === $res) {
193
- $this->cli_die("Couldn't read MO file '$mo_filename'!");
194
- }
195
- foreach($filenames as $filename) {
196
- $source = file_get_contents($filename);
197
- if ( strlen($source) > 150000 ) continue;
198
- $tokens = token_get_all($source);
199
- $new_file = $this->walk_tokens($tokens, $replacer, array(&$this, 'unchanged_token'));
200
- $f = fopen($filename, 'w');
201
- fwrite($f, $new_file);
202
- fclose($f);
203
- }
204
- return true;
205
- }
206
-
207
- function usage() {
208
- $this->stderr('php i18n-comments.php COMMAND OUTPUTFILE INPUTFILES');
209
- $this->stderr('Extracts and replaces strings, which cannot be gettexted');
210
- $this->stderr('Commands:');
211
- $this->stderr(' extract POTFILE PHPFILES appends the strings to POTFILE');
212
- $this->stderr(' replace MOFILE PHPFILES replaces strings in PHPFILES with translations from MOFILE');
213
- }
214
-
215
- function cli() {
216
- global $argv, $commands;
217
- if (count($argv) < 4 || !in_array($argv[1], array_keys($this->commands))) {
218
- $this->usage();
219
- exit(1);
220
- }
221
- call_user_func_array(array(&$this, $this->commands[$argv[1]]), array_slice($argv, 2));
222
- }
223
- }
224
-
225
- // run the CLI only if the file
226
- // wasn't included
227
- $included_files = get_included_files();
228
- if ($included_files[0] == __FILE__) {
229
- error_reporting(E_ALL);
230
- $not_gettexted = new NotGettexted;
231
- $not_gettexted->cli();
232
- }
233
-
234
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/pomo/entry.php DELETED
@@ -1,78 +0,0 @@
1
- <?php
2
- /**
3
- * Contains Translation_Entry class
4
- *
5
- * @version $Id: entry.php 718 2012-10-31 00:32:02Z nbachiyski $
6
- * @package pomo
7
- * @subpackage entry
8
- */
9
-
10
- if ( !class_exists( 'Translation_Entry' ) ):
11
- /**
12
- * Translation_Entry class encapsulates a translatable string
13
- */
14
- class Translation_Entry {
15
-
16
- /**
17
- * Whether the entry contains a string and its plural form, default is false
18
- *
19
- * @var boolean
20
- */
21
- var $is_plural = false;
22
-
23
- var $context = null;
24
- var $singular = null;
25
- var $plural = null;
26
- var $translations = array();
27
- var $translator_comments = '';
28
- var $extracted_comments = '';
29
- var $references = array();
30
- var $flags = array();
31
-
32
- /**
33
- * @param array $args associative array, support following keys:
34
- * - singular (string) -- the string to translate, if omitted and empty entry will be created
35
- * - plural (string) -- the plural form of the string, setting this will set {@link $is_plural} to true
36
- * - translations (array) -- translations of the string and possibly -- its plural forms
37
- * - context (string) -- a string differentiating two equal strings used in different contexts
38
- * - translator_comments (string) -- comments left by translators
39
- * - extracted_comments (string) -- comments left by developers
40
- * - references (array) -- places in the code this strings is used, in relative_to_root_path/file.php:linenum form
41
- * - flags (array) -- flags like php-format
42
- */
43
- function Translation_Entry($args=array()) {
44
- // if no singular -- empty object
45
- if (!isset($args['singular'])) {
46
- return;
47
- }
48
- // get member variable values from args hash
49
- foreach ($args as $varname => $value) {
50
- $this->$varname = $value;
51
- }
52
- if (isset($args['plural'])) $this->is_plural = true;
53
- if (!is_array($this->translations)) $this->translations = array();
54
- if (!is_array($this->references)) $this->references = array();
55
- if (!is_array($this->flags)) $this->flags = array();
56
- }
57
-
58
- /**
59
- * Generates a unique key for this entry
60
- *
61
- * @return string|bool the key or false if the entry is empty
62
- */
63
- function key() {
64
- if (is_null($this->singular)) return false;
65
- // prepend context and EOT, like in MO files
66
- return is_null($this->context)? $this->singular : $this->context.chr(4).$this->singular;
67
- }
68
-
69
- function merge_with(&$other) {
70
- $this->flags = array_unique( array_merge( $this->flags, $other->flags ) );
71
- $this->references = array_unique( array_merge( $this->references, $other->references ) );
72
- if ( $this->extracted_comments != $other->extracted_comments ) {
73
- $this->extracted_comments .= $other->extracted_comments;
74
- }
75
-
76
- }
77
- }
78
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/pomo/mo.php DELETED
@@ -1,258 +0,0 @@
1
- <?php
2
- /**
3
- * Class for working with MO files
4
- *
5
- * @version $Id: mo.php 780 2013-06-19 12:12:28Z markoheijnen $
6
- * @package pomo
7
- * @subpackage mo
8
- */
9
-
10
- require_once dirname(__FILE__) . '/translations.php';
11
- require_once dirname(__FILE__) . '/streams.php';
12
-
13
- if ( !class_exists( 'MO' ) ):
14
- class MO extends Gettext_Translations {
15
-
16
- var $_nplurals = 2;
17
-
18
- /**
19
- * Fills up with the entries from MO file $filename
20
- *
21
- * @param string $filename MO file to load
22
- */
23
- function import_from_file($filename) {
24
- $reader = new POMO_FileReader($filename);
25
- if (!$reader->is_resource())
26
- return false;
27
- return $this->import_from_reader($reader);
28
- }
29
-
30
- function export_to_file($filename) {
31
- $fh = fopen($filename, 'wb');
32
- if ( !$fh ) return false;
33
- $res = $this->export_to_file_handle( $fh );
34
- fclose($fh);
35
- return $res;
36
- }
37
-
38
- function export() {
39
- $tmp_fh = fopen("php://temp", 'r+');
40
- if ( !$tmp_fh ) return false;
41
- $this->export_to_file_handle( $tmp_fh );
42
- rewind( $tmp_fh );
43
- return stream_get_contents( $tmp_fh );
44
- }
45
-
46
- function is_entry_good_for_export( $entry ) {
47
- if ( empty( $entry->translations ) ) {
48
- return false;
49
- }
50
-
51
- if ( !array_filter( $entry->translations ) ) {
52
- return false;
53
- }
54
-
55
- return true;
56
- }
57
-
58
- function export_to_file_handle($fh) {
59
- $entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
60
- ksort($entries);
61
- $magic = 0x950412de;
62
- $revision = 0;
63
- $total = count($entries) + 1; // all the headers are one entry
64
- $originals_lenghts_addr = 28;
65
- $translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
66
- $size_of_hash = 0;
67
- $hash_addr = $translations_lenghts_addr + 8 * $total;
68
- $current_addr = $hash_addr;
69
- fwrite($fh, pack('V*', $magic, $revision, $total, $originals_lenghts_addr,
70
- $translations_lenghts_addr, $size_of_hash, $hash_addr));
71
- fseek($fh, $originals_lenghts_addr);
72
-
73
- // headers' msgid is an empty string
74
- fwrite($fh, pack('VV', 0, $current_addr));
75
- $current_addr++;
76
- $originals_table = chr(0);
77
-
78
- foreach($entries as $entry) {
79
- $originals_table .= $this->export_original($entry) . chr(0);
80
- $length = strlen($this->export_original($entry));
81
- fwrite($fh, pack('VV', $length, $current_addr));
82
- $current_addr += $length + 1; // account for the NULL byte after
83
- }
84
-
85
- $exported_headers = $this->export_headers();
86
- fwrite($fh, pack('VV', strlen($exported_headers), $current_addr));
87
- $current_addr += strlen($exported_headers) + 1;
88
- $translations_table = $exported_headers . chr(0);
89
-
90
- foreach($entries as $entry) {
91
- $translations_table .= $this->export_translations($entry) . chr(0);
92
- $length = strlen($this->export_translations($entry));
93
- fwrite($fh, pack('VV', $length, $current_addr));
94
- $current_addr += $length + 1;
95
- }
96
-
97
- fwrite($fh, $originals_table);
98
- fwrite($fh, $translations_table);
99
- return true;
100
- }
101
-
102
- function export_original($entry) {
103
- //TODO: warnings for control characters
104
- $exported = $entry->singular;
105
- if ($entry->is_plural) $exported .= chr(0).$entry->plural;
106
- if (!is_null($entry->context)) $exported = $entry->context . chr(4) . $exported;
107
- return $exported;
108
- }
109
-
110
- function export_translations($entry) {
111
- //TODO: warnings for control characters
112
- return implode(chr(0), $entry->translations);
113
- }
114
-
115
- function export_headers() {
116
- $exported = '';
117
- foreach($this->headers as $header => $value) {
118
- $exported.= "$header: $value\n";
119
- }
120
- return $exported;
121
- }
122
-
123
- function get_byteorder($magic) {
124
- // The magic is 0x950412de
125
-
126
- // bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
127
- $magic_little = (int) - 1794895138;
128
- $magic_little_64 = (int) 2500072158;
129
- // 0xde120495
130
- $magic_big = ((int) - 569244523) & 0xFFFFFFFF;
131
- if ($magic_little == $magic || $magic_little_64 == $magic) {
132
- return 'little';
133
- } else if ($magic_big == $magic) {
134
- return 'big';
135
- } else {
136
- return false;
137
- }
138
- }
139
-
140
- function import_from_reader($reader) {
141
- $endian_string = MO::get_byteorder($reader->readint32());
142
- if (false === $endian_string) {
143
- return false;
144
- }
145
- $reader->setEndian($endian_string);
146
-
147
- $endian = ('big' == $endian_string)? 'N' : 'V';
148
-
149
- $header = $reader->read(24);
150
- if ($reader->strlen($header) != 24)
151
- return false;
152
-
153
- // parse header
154
- $header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header);
155
- if (!is_array($header))
156
- return false;
157
-
158
- extract( $header );
159
-
160
- // support revision 0 of MO format specs, only
161
- if ($revision != 0)
162
- return false;
163
-
164
- // seek to data blocks
165
- $reader->seekto($originals_lenghts_addr);
166
-
167
- // read originals' indices
168
- $originals_lengths_length = $translations_lenghts_addr - $originals_lenghts_addr;
169
- if ( $originals_lengths_length != $total * 8 )
170
- return false;
171
-
172
- $originals = $reader->read($originals_lengths_length);
173
- if ( $reader->strlen( $originals ) != $originals_lengths_length )
174
- return false;
175
-
176
- // read translations' indices
177
- $translations_lenghts_length = $hash_addr - $translations_lenghts_addr;
178
- if ( $translations_lenghts_length != $total * 8 )
179
- return false;
180
-
181
- $translations = $reader->read($translations_lenghts_length);
182
- if ( $reader->strlen( $translations ) != $translations_lenghts_length )
183
- return false;
184
-
185
- // transform raw data into set of indices
186
- $originals = $reader->str_split( $originals, 8 );
187
- $translations = $reader->str_split( $translations, 8 );
188
-
189
- // skip hash table
190
- $strings_addr = $hash_addr + $hash_length * 4;
191
-
192
- $reader->seekto($strings_addr);
193
-
194
- $strings = $reader->read_all();
195
- $reader->close();
196
-
197
- for ( $i = 0; $i < $total; $i++ ) {
198
- $o = unpack( "{$endian}length/{$endian}pos", $originals[$i] );
199
- $t = unpack( "{$endian}length/{$endian}pos", $translations[$i] );
200
- if ( !$o || !$t ) return false;
201
-
202
- // adjust offset due to reading strings to separate space before
203
- $o['pos'] -= $strings_addr;
204
- $t['pos'] -= $strings_addr;
205
-
206
- $original = $reader->substr( $strings, $o['pos'], $o['length'] );
207
- $translation = $reader->substr( $strings, $t['pos'], $t['length'] );
208
-
209
- if ('' === $original) {
210
- $headers = $this->make_headers($translation);
211
- $this->set_headers($headers);
212
- } else {
213
- $entry = &$this->make_entry($original, $translation);
214
- $this->entries[$entry->key()] = &$entry;
215
- }
216
- }
217
- return true;
218
- }
219
-
220
- /**
221
- * Build a Translation_Entry from original string and translation strings,
222
- * found in a MO file
223
- *
224
- * @static
225
- * @param string $original original string to translate from MO file. Might contain
226
- * 0x04 as context separator or 0x00 as singular/plural separator
227
- * @param string $translation translation string from MO file. Might contain
228
- * 0x00 as a plural translations separator
229
- */
230
- function &make_entry($original, $translation) {
231
- $entry = new Translation_Entry();
232
- // look for context
233
- $parts = explode(chr(4), $original);
234
- if (isset($parts[1])) {
235
- $original = $parts[1];
236
- $entry->context = $parts[0];
237
- }
238
- // look for plural original
239
- $parts = explode(chr(0), $original);
240
- $entry->singular = $parts[0];
241
- if (isset($parts[1])) {
242
- $entry->is_plural = true;
243
- $entry->plural = $parts[1];
244
- }
245
- // plural translations are also separated by \0
246
- $entry->translations = explode(chr(0), $translation);
247
- return $entry;
248
- }
249
-
250
- function select_plural_form($count) {
251
- return $this->gettext_select_plural_form($count);
252
- }
253
-
254
- function get_plural_forms_count() {
255
- return $this->_nplurals;
256
- }
257
- }
258
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/pomo/po.php DELETED
@@ -1,385 +0,0 @@
1
- <?php
2
- /**
3
- * Class for working with PO files
4
- *
5
- * @version $Id: po.php 812 2013-10-18 17:34:16Z markoheijnen $
6
- * @package pomo
7
- * @subpackage po
8
- */
9
-
10
- require_once dirname(__FILE__) . '/translations.php';
11
-
12
- define('PO_MAX_LINE_LEN', 79);
13
-
14
- ini_set('auto_detect_line_endings', 1);
15
-
16
- /**
17
- * Routines for working with PO files
18
- */
19
- if ( !class_exists( 'PO' ) ):
20
- class PO extends Gettext_Translations {
21
-
22
- var $comments_before_headers = '';
23
-
24
- /**
25
- * Exports headers to a PO entry
26
- *
27
- * @return string msgid/msgstr PO entry for this PO file headers, doesn't contain newline at the end
28
- */
29
- function export_headers() {
30
- $header_string = '';
31
- foreach($this->headers as $header => $value) {
32
- $header_string.= "$header: $value\n";
33
- }
34
- $poified = PO::poify($header_string);
35
- if ($this->comments_before_headers)
36
- $before_headers = $this->prepend_each_line(rtrim($this->comments_before_headers)."\n", '# ');
37
- else
38
- $before_headers = '';
39
- return rtrim("{$before_headers}msgid \"\"\nmsgstr $poified");
40
- }
41
-
42
- /**
43
- * Exports all entries to PO format
44
- *
45
- * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end
46
- */
47
- function export_entries() {
48
- //TODO sorting
49
- return implode("\n\n", array_map(array('PO', 'export_entry'), $this->entries));
50
- }
51
-
52
- /**
53
- * Exports the whole PO file as a string
54
- *
55
- * @param bool $include_headers whether to include the headers in the export
56
- * @return string ready for inclusion in PO file string for headers and all the enrtries
57
- */
58
- function export($include_headers = true) {
59
- $res = '';
60
- if ($include_headers) {
61
- $res .= $this->export_headers();
62
- $res .= "\n\n";
63
- }
64
- $res .= $this->export_entries();
65
- return $res;
66
- }
67
-
68
- /**
69
- * Same as {@link export}, but writes the result to a file
70
- *
71
- * @param string $filename where to write the PO string
72
- * @param bool $include_headers whether to include tje headers in the export
73
- * @return bool true on success, false on error
74
- */
75
- function export_to_file($filename, $include_headers = true) {
76
- $fh = fopen($filename, 'w');
77
- if (false === $fh) return false;
78
- $export = $this->export($include_headers);
79
- $res = fwrite($fh, $export);
80
- if (false === $res) return false;
81
- return fclose($fh);
82
- }
83
-
84
- /**
85
- * Text to include as a comment before the start of the PO contents
86
- *
87
- * Doesn't need to include # in the beginning of lines, these are added automatically
88
- */
89
- function set_comment_before_headers( $text ) {
90
- $this->comments_before_headers = $text;
91
- }
92
-
93
- /**
94
- * Formats a string in PO-style
95
- *
96
- * @static
97
- * @param string $string the string to format
98
- * @return string the poified string
99
- */
100
- public static function poify($string) {
101
- $quote = '"';
102
- $slash = '\\';
103
- $newline = "\n";
104
-
105
- $replaces = array(
106
- "$slash" => "$slash$slash",
107
- "$quote" => "$slash$quote",
108
- "\t" => '\t',
109
- );
110
-
111
- $string = str_replace(array_keys($replaces), array_values($replaces), $string);
112
-
113
- $po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
114
- // add empty string on first line for readbility
115
- if (false !== strpos($string, $newline) &&
116
- (substr_count($string, $newline) > 1 || !($newline === substr($string, -strlen($newline))))) {
117
- $po = "$quote$quote$newline$po";
118
- }
119
- // remove empty strings
120
- $po = str_replace("$newline$quote$quote", '', $po);
121
- return $po;
122
- }
123
-
124
- /**
125
- * Gives back the original string from a PO-formatted string
126
- *
127
- * @static
128
- * @param string $string PO-formatted string
129
- * @return string enascaped string
130
- */
131
- public static function unpoify($string) {
132
- $escapes = array('t' => "\t", 'n' => "\n", '\\' => '\\');
133
- $lines = array_map('trim', explode("\n", $string));
134
- $lines = array_map(array('PO', 'trim_quotes'), $lines);
135
- $unpoified = '';
136
- $previous_is_backslash = false;
137
- foreach($lines as $line) {
138
- preg_match_all('/./u', $line, $chars);
139
- $chars = $chars[0];
140
- foreach($chars as $char) {
141
- if (!$previous_is_backslash) {
142
- if ('\\' == $char)
143
- $previous_is_backslash = true;
144
- else
145
- $unpoified .= $char;
146
- } else {
147
- $previous_is_backslash = false;
148
- $unpoified .= isset($escapes[$char])? $escapes[$char] : $char;
149
- }
150
- }
151
- }
152
- return $unpoified;
153
- }
154
-
155
- /**
156
- * Inserts $with in the beginning of every new line of $string and
157
- * returns the modified string
158
- *
159
- * @static
160
- * @param string $string prepend lines in this string
161
- * @param string $with prepend lines with this string
162
- */
163
- public static function prepend_each_line($string, $with) {
164
- $php_with = var_export($with, true);
165
- $lines = explode("\n", $string);
166
- // do not prepend the string on the last empty line, artefact by explode
167
- if ("\n" == substr($string, -1)) unset($lines[count($lines) - 1]);
168
- $res = implode("\n", array_map(create_function('$x', "return $php_with.\$x;"), $lines));
169
- // give back the empty line, we ignored above
170
- if ("\n" == substr($string, -1)) $res .= "\n";
171
- return $res;
172
- }
173
-
174
- /**
175
- * Prepare a text as a comment -- wraps the lines and prepends #
176
- * and a special character to each line
177
- *
178
- * @access private
179
- * @param string $text the comment text
180
- * @param string $char character to denote a special PO comment,
181
- * like :, default is a space
182
- */
183
- public static function comment_block($text, $char=' ') {
184
- $text = wordwrap($text, PO_MAX_LINE_LEN - 3);
185
- return PO::prepend_each_line($text, "#$char ");
186
- }
187
-
188
- /**
189
- * Builds a string from the entry for inclusion in PO file
190
- *
191
- * @static
192
- * @param object &$entry the entry to convert to po string
193
- * @return string|bool PO-style formatted string for the entry or
194
- * false if the entry is empty
195
- */
196
- public static function export_entry(&$entry) {
197
- if (is_null($entry->singular)) return false;
198
- $po = array();
199
- if (!empty($entry->translator_comments)) $po[] = PO::comment_block($entry->translator_comments);
200
- if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.');
201
- if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':');
202
- if (!empty($entry->flags)) $po[] = PO::comment_block(implode(", ", $entry->flags), ',');
203
- if (!is_null($entry->context)) $po[] = 'msgctxt '.PO::poify($entry->context);
204
- $po[] = 'msgid '.PO::poify($entry->singular);
205
- if (!$entry->is_plural) {
206
- $translation = empty($entry->translations)? '' : $entry->translations[0];
207
- $po[] = 'msgstr '.PO::poify($translation);
208
- } else {
209
- $po[] = 'msgid_plural '.PO::poify($entry->plural);
210
- $translations = empty($entry->translations)? array('', '') : $entry->translations;
211
- foreach($translations as $i => $translation) {
212
- $po[] = "msgstr[$i] ".PO::poify($translation);
213
- }
214
- }
215
- return implode("\n", $po);
216
- }
217
-
218
- function import_from_file($filename) {
219
- $f = fopen($filename, 'r');
220
- if (!$f) return false;
221
- $lineno = 0;
222
- while (true) {
223
- $res = $this->read_entry($f, $lineno);
224
- if (!$res) break;
225
- if ($res['entry']->singular == '') {
226
- $headers = $this->make_headers($res['entry']->translations[0]);
227
- $this->set_headers($headers);
228
- } else {
229
- $this->add_entry($res['entry']);
230
- }
231
- }
232
- PO::read_line($f, 'clear');
233
- if ( false === $res ) {
234
- return false;
235
- }
236
- if ( ! $this->headers && ! $this->entries ) {
237
- return false;
238
- }
239
- return true;
240
- }
241
-
242
- function read_entry($f, $lineno = 0) {
243
- $entry = new Translation_Entry();
244
- // where were we in the last step
245
- // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
246
- $context = '';
247
- $msgstr_index = 0;
248
- $is_final = create_function('$context', 'return $context == "msgstr" || $context == "msgstr_plural";');
249
- while (true) {
250
- $lineno++;
251
- $line = PO::read_line($f);
252
- if (!$line) {
253
- if (feof($f)) {
254
- if ($is_final($context))
255
- break;
256
- elseif (!$context) // we haven't read a line and eof came
257
- return null;
258
- else
259
- return false;
260
- } else {
261
- return false;
262
- }
263
- }
264
- if ($line == "\n") continue;
265
- $line = trim($line);
266
- if (preg_match('/^#/', $line, $m)) {
267
- // the comment is the start of a new entry
268
- if ($is_final($context)) {
269
- PO::read_line($f, 'put-back');
270
- $lineno--;
271
- break;
272
- }
273
- // comments have to be at the beginning
274
- if ($context && $context != 'comment') {
275
- return false;
276
- }
277
- // add comment
278
- $this->add_comment_to_entry($entry, $line);
279
- } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
280
- if ($is_final($context)) {
281
- PO::read_line($f, 'put-back');
282
- $lineno--;
283
- break;
284
- }
285
- if ($context && $context != 'comment') {
286
- return false;
287
- }
288
- $context = 'msgctxt';
289
- $entry->context .= PO::unpoify($m[1]);
290
- } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
291
- if ($is_final($context)) {
292
- PO::read_line($f, 'put-back');
293
- $lineno--;
294
- break;
295
- }
296
- if ($context && $context != 'msgctxt' && $context != 'comment') {
297
- return false;
298
- }
299
- $context = 'msgid';
300
- $entry->singular .= PO::unpoify($m[1]);
301
- } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
302
- if ($context != 'msgid') {
303
- return false;
304
- }
305
- $context = 'msgid_plural';
306
- $entry->is_plural = true;
307
- $entry->plural .= PO::unpoify($m[1]);
308
- } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
309
- if ($context != 'msgid') {
310
- return false;
311
- }
312
- $context = 'msgstr';
313
- $entry->translations = array(PO::unpoify($m[1]));
314
- } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
315
- if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
316
- return false;
317
- }
318
- $context = 'msgstr_plural';
319
- $msgstr_index = $m[1];
320
- $entry->translations[$m[1]] = PO::unpoify($m[2]);
321
- } elseif (preg_match('/^".*"$/', $line)) {
322
- $unpoified = PO::unpoify($line);
323
- switch ($context) {
324
- case 'msgid':
325
- $entry->singular .= $unpoified; break;
326
- case 'msgctxt':
327
- $entry->context .= $unpoified; break;
328
- case 'msgid_plural':
329
- $entry->plural .= $unpoified; break;
330
- case 'msgstr':
331
- $entry->translations[0] .= $unpoified; break;
332
- case 'msgstr_plural':
333
- $entry->translations[$msgstr_index] .= $unpoified; break;
334
- default:
335
- return false;
336
- }
337
- } else {
338
- return false;
339
- }
340
- }
341
- if (array() == array_filter($entry->translations, create_function('$t', 'return $t || "0" === $t;'))) {
342
- $entry->translations = array();
343
- }
344
- return array('entry' => $entry, 'lineno' => $lineno);
345
- }
346
-
347
- function read_line($f, $action = 'read') {
348
- static $last_line = '';
349
- static $use_last_line = false;
350
- if ('clear' == $action) {
351
- $last_line = '';
352
- return true;
353
- }
354
- if ('put-back' == $action) {
355
- $use_last_line = true;
356
- return true;
357
- }
358
- $line = $use_last_line? $last_line : fgets($f);
359
- $line = ( "\r\n" == substr( $line, -2 ) ) ? rtrim( $line, "\r\n" ) . "\n" : $line;
360
- $last_line = $line;
361
- $use_last_line = false;
362
- return $line;
363
- }
364
-
365
- function add_comment_to_entry(&$entry, $po_comment_line) {
366
- $first_two = substr($po_comment_line, 0, 2);
367
- $comment = trim(substr($po_comment_line, 2));
368
- if ('#:' == $first_two) {
369
- $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
370
- } elseif ('#.' == $first_two) {
371
- $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
372
- } elseif ('#,' == $first_two) {
373
- $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
374
- } else {
375
- $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
376
- }
377
- }
378
-
379
- public static function trim_quotes($s) {
380
- if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
381
- if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
382
- return $s;
383
- }
384
- }
385
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/pomo/streams.php DELETED
@@ -1,209 +0,0 @@
1
- <?php
2
- /**
3
- * Classes, which help reading streams of data from files.
4
- * Based on the classes from Danilo Segan <danilo@kvota.net>
5
- *
6
- * @version $Id: streams.php 718 2012-10-31 00:32:02Z nbachiyski $
7
- * @package pomo
8
- * @subpackage streams
9
- */
10
-
11
- if ( !class_exists( 'POMO_Reader' ) ):
12
- class POMO_Reader {
13
-
14
- var $endian = 'little';
15
- var $_post = '';
16
-
17
- function POMO_Reader() {
18
- $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
19
- $this->_pos = 0;
20
- }
21
-
22
- /**
23
- * Sets the endianness of the file.
24
- *
25
- * @param $endian string 'big' or 'little'
26
- */
27
- function setEndian($endian) {
28
- $this->endian = $endian;
29
- }
30
-
31
- /**
32
- * Reads a 32bit Integer from the Stream
33
- *
34
- * @return mixed The integer, corresponding to the next 32 bits from
35
- * the stream of false if there are not enough bytes or on error
36
- */
37
- function readint32() {
38
- $bytes = $this->read(4);
39
- if (4 != $this->strlen($bytes))
40
- return false;
41
- $endian_letter = ('big' == $this->endian)? 'N' : 'V';
42
- $int = unpack($endian_letter, $bytes);
43
- return array_shift($int);
44
- }
45
-
46
- /**
47
- * Reads an array of 32-bit Integers from the Stream
48
- *
49
- * @param integer count How many elements should be read
50
- * @return mixed Array of integers or false if there isn't
51
- * enough data or on error
52
- */
53
- function readint32array($count) {
54
- $bytes = $this->read(4 * $count);
55
- if (4*$count != $this->strlen($bytes))
56
- return false;
57
- $endian_letter = ('big' == $this->endian)? 'N' : 'V';
58
- return unpack($endian_letter.$count, $bytes);
59
- }
60
-
61
-
62
- function substr($string, $start, $length) {
63
- if ($this->is_overloaded) {
64
- return mb_substr($string, $start, $length, 'ascii');
65
- } else {
66
- return substr($string, $start, $length);
67
- }
68
- }
69
-
70
- function strlen($string) {
71
- if ($this->is_overloaded) {
72
- return mb_strlen($string, 'ascii');
73
- } else {
74
- return strlen($string);
75
- }
76
- }
77
-
78
- function str_split($string, $chunk_size) {
79
- if (!function_exists('str_split')) {
80
- $length = $this->strlen($string);
81
- $out = array();
82
- for ($i = 0; $i < $length; $i += $chunk_size)
83
- $out[] = $this->substr($string, $i, $chunk_size);
84
- return $out;
85
- } else {
86
- return str_split( $string, $chunk_size );
87
- }
88
- }
89
-
90
-
91
- function pos() {
92
- return $this->_pos;
93
- }
94
-
95
- function is_resource() {
96
- return true;
97
- }
98
-
99
- function close() {
100
- return true;
101
- }
102
- }
103
- endif;
104
-
105
- if ( !class_exists( 'POMO_FileReader' ) ):
106
- class POMO_FileReader extends POMO_Reader {
107
- function POMO_FileReader($filename) {
108
- parent::POMO_Reader();
109
- $this->_f = fopen($filename, 'rb');
110
- }
111
-
112
- function read($bytes) {
113
- return fread($this->_f, $bytes);
114
- }
115
-
116
- function seekto($pos) {
117
- if ( -1 == fseek($this->_f, $pos, SEEK_SET)) {
118
- return false;
119
- }
120
- $this->_pos = $pos;
121
- return true;
122
- }
123
-
124
- function is_resource() {
125
- return is_resource($this->_f);
126
- }
127
-
128
- function feof() {
129
- return feof($this->_f);
130
- }
131
-
132
- function close() {
133
- return fclose($this->_f);
134
- }
135
-
136
- function read_all() {
137
- $all = '';
138
- while ( !$this->feof() )
139
- $all .= $this->read(4096);
140
- return $all;
141
- }
142
- }
143
- endif;
144
-
145
- if ( !class_exists( 'POMO_StringReader' ) ):
146
- /**
147
- * Provides file-like methods for manipulating a string instead
148
- * of a physical file.
149
- */
150
- class POMO_StringReader extends POMO_Reader {
151
-
152
- var $_str = '';
153
-
154
- function POMO_StringReader($str = '') {
155
- parent::POMO_Reader();
156
- $this->_str = $str;
157
- $this->_pos = 0;
158
- }
159
-
160
-
161
- function read($bytes) {
162
- $data = $this->substr($this->_str, $this->_pos, $bytes);
163
- $this->_pos += $bytes;
164
- if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
165
- return $data;
166
- }
167
-
168
- function seekto($pos) {
169
- $this->_pos = $pos;
170
- if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
171
- return $this->_pos;
172
- }
173
-
174
- function length() {
175
- return $this->strlen($this->_str);
176
- }
177
-
178
- function read_all() {
179
- return $this->substr($this->_str, $this->_pos, $this->strlen($this->_str));
180
- }
181
-
182
- }
183
- endif;
184
-
185
- if ( !class_exists( 'POMO_CachedFileReader' ) ):
186
- /**
187
- * Reads the contents of the file in the beginning.
188
- */
189
- class POMO_CachedFileReader extends POMO_StringReader {
190
- function POMO_CachedFileReader($filename) {
191
- parent::POMO_StringReader();
192
- $this->_str = file_get_contents($filename);
193
- if (false === $this->_str)
194
- return false;
195
- $this->_pos = 0;
196
- }
197
- }
198
- endif;
199
-
200
- if ( !class_exists( 'POMO_CachedIntFileReader' ) ):
201
- /**
202
- * Reads the contents of the file in the beginning.
203
- */
204
- class POMO_CachedIntFileReader extends POMO_CachedFileReader {
205
- function POMO_CachedIntFileReader($filename) {
206
- parent::POMO_CachedFileReader($filename);
207
- }
208
- }
209
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/pomo/translations.php DELETED
@@ -1,275 +0,0 @@
1
- <?php
2
- /**
3
- * Class for a set of entries for translation and their associated headers
4
- *
5
- * @version $Id: translations.php 811 2013-10-18 17:26:21Z markoheijnen $
6
- * @package pomo
7
- * @subpackage translations
8
- */
9
-
10
- require_once dirname(__FILE__) . '/entry.php';
11
-
12
- if ( !class_exists( 'Translations' ) ):
13
- class Translations {
14
- var $entries = array();
15
- var $headers = array();
16
-
17
- /**
18
- * Add entry to the PO structure
19
- *
20
- * @param object &$entry
21
- * @return bool true on success, false if the entry doesn't have a key
22
- */
23
- function add_entry($entry) {
24
- if (is_array($entry)) {
25
- $entry = new Translation_Entry($entry);
26
- }
27
- $key = $entry->key();
28
- if (false === $key) return false;
29
- $this->entries[$key] = &$entry;
30
- return true;
31
- }
32
-
33
- function add_entry_or_merge($entry) {
34
- if (is_array($entry)) {
35
- $entry = new Translation_Entry($entry);
36
- }
37
- $key = $entry->key();
38
- if (false === $key) return false;
39
- if (isset($this->entries[$key]))
40
- $this->entries[$key]->merge_with($entry);
41
- else
42
- $this->entries[$key] = &$entry;
43
- return true;
44
- }
45
-
46
- /**
47
- * Sets $header PO header to $value
48
- *
49
- * If the header already exists, it will be overwritten
50
- *
51
- * TODO: this should be out of this class, it is gettext specific
52
- *
53
- * @param string $header header name, without trailing :
54
- * @param string $value header value, without trailing \n
55
- */
56
- function set_header($header, $value) {
57
- $this->headers[$header] = $value;
58
- }
59
-
60
- function set_headers($headers) {
61
- foreach($headers as $header => $value) {
62
- $this->set_header($header, $value);
63
- }
64
- }
65
-
66
- function get_header($header) {
67
- return isset($this->headers[$header])? $this->headers[$header] : false;
68
- }
69
-
70
- function translate_entry(&$entry) {
71
- $key = $entry->key();
72
- return isset($this->entries[$key])? $this->entries[$key] : false;
73
- }
74
-
75
- function translate($singular, $context=null) {
76
- $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context));
77
- $translated = $this->translate_entry($entry);
78
- return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular;
79
- }
80
-
81
- /**
82
- * Given the number of items, returns the 0-based index of the plural form to use
83
- *
84
- * Here, in the base Translations class, the common logic for English is implemented:
85
- * 0 if there is one element, 1 otherwise
86
- *
87
- * This function should be overrided by the sub-classes. For example MO/PO can derive the logic
88
- * from their headers.
89
- *
90
- * @param integer $count number of items
91
- */
92
- function select_plural_form($count) {
93
- return 1 == $count? 0 : 1;
94
- }
95
-
96
- function get_plural_forms_count() {
97
- return 2;
98
- }
99
-
100
- function translate_plural($singular, $plural, $count, $context = null) {
101
- $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context));
102
- $translated = $this->translate_entry($entry);
103
- $index = $this->select_plural_form($count);
104
- $total_plural_forms = $this->get_plural_forms_count();
105
- if ($translated && 0 <= $index && $index < $total_plural_forms &&
106
- is_array($translated->translations) &&
107
- isset($translated->translations[$index]))
108
- return $translated->translations[$index];
109
- else
110
- return 1 == $count? $singular : $plural;
111
- }
112
-
113
- /**
114
- * Merge $other in the current object.
115
- *
116
- * @param Object &$other Another Translation object, whose translations will be merged in this one
117
- * @return void
118
- **/
119
- function merge_with(&$other) {
120
- foreach( $other->entries as $entry ) {
121
- $this->entries[$entry->key()] = $entry;
122
- }
123
- }
124
-
125
- function merge_originals_with(&$other) {
126
- foreach( $other->entries as $entry ) {
127
- if ( !isset( $this->entries[$entry->key()] ) )
128
- $this->entries[$entry->key()] = $entry;
129
- else
130
- $this->entries[$entry->key()]->merge_with($entry);
131
- }
132
- }
133
- }
134
-
135
- class Gettext_Translations extends Translations {
136
- /**
137
- * The gettext implementation of select_plural_form.
138
- *
139
- * It lives in this class, because there are more than one descendand, which will use it and
140
- * they can't share it effectively.
141
- *
142
- */
143
- function gettext_select_plural_form($count) {
144
- if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) {
145
- list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
146
- $this->_nplurals = $nplurals;
147
- $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
148
- }
149
- return call_user_func($this->_gettext_select_plural_form, $count);
150
- }
151
-
152
- function nplurals_and_expression_from_header($header) {
153
- if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) {
154
- $nplurals = (int)$matches[1];
155
- $expression = trim($this->parenthesize_plural_exression($matches[2]));
156
- return array($nplurals, $expression);
157
- } else {
158
- return array(2, 'n != 1');
159
- }
160
- }
161
-
162
- /**
163
- * Makes a function, which will return the right translation index, according to the
164
- * plural forms header
165
- */
166
- function make_plural_form_function($nplurals, $expression) {
167
- $expression = str_replace('n', '$n', $expression);
168
- $func_body = "
169
- \$index = (int)($expression);
170
- return (\$index < $nplurals)? \$index : $nplurals - 1;";
171
- return create_function('$n', $func_body);
172
- }
173
-
174
- /**
175
- * Adds parantheses to the inner parts of ternary operators in
176
- * plural expressions, because PHP evaluates ternary oerators from left to right
177
- *
178
- * @param string $expression the expression without parentheses
179
- * @return string the expression with parentheses added
180
- */
181
- function parenthesize_plural_exression($expression) {
182
- $expression .= ';';
183
- $res = '';
184
- $depth = 0;
185
- for ($i = 0; $i < strlen($expression); ++$i) {
186
- $char = $expression[$i];
187
- switch ($char) {
188
- case '?':
189
- $res .= ' ? (';
190
- $depth++;
191
- break;
192
- case ':':
193
- $res .= ') : (';
194
- break;
195
- case ';':
196
- $res .= str_repeat(')', $depth) . ';';
197
- $depth= 0;
198
- break;
199
- default:
200
- $res .= $char;
201
- }
202
- }
203
- return rtrim($res, ';');
204
- }
205
-
206
- function make_headers($translation) {
207
- $headers = array();
208
- // sometimes \ns are used instead of real new lines
209
- $translation = str_replace('\n', "\n", $translation);
210
- $lines = explode("\n", $translation);
211
- foreach($lines as $line) {
212
- $parts = explode(':', $line, 2);
213
- if (!isset($parts[1])) continue;
214
- $headers[trim($parts[0])] = trim($parts[1]);
215
- }
216
- return $headers;
217
- }
218
-
219
- function set_header($header, $value) {
220
- parent::set_header($header, $value);
221
- if ('Plural-Forms' == $header) {
222
- list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
223
- $this->_nplurals = $nplurals;
224
- $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
225
- }
226
- }
227
- }
228
- endif;
229
-
230
- if ( !class_exists( 'NOOP_Translations' ) ):
231
- /**
232
- * Provides the same interface as Translations, but doesn't do anything
233
- */
234
- class NOOP_Translations {
235
- var $entries = array();
236
- var $headers = array();
237
-
238
- function add_entry($entry) {
239
- return true;
240
- }
241
-
242
- function set_header($header, $value) {
243
- }
244
-
245
- function set_headers($headers) {
246
- }
247
-
248
- function get_header($header) {
249
- return false;
250
- }
251
-
252
- function translate_entry(&$entry) {
253
- return false;
254
- }
255
-
256
- function translate($singular, $context=null) {
257
- return $singular;
258
- }
259
-
260
- function select_plural_form($count) {
261
- return 1 == $count? 0 : 1;
262
- }
263
-
264
- function get_plural_forms_count() {
265
- return 2;
266
- }
267
-
268
- function translate_plural($singular, $plural, $count, $context = null) {
269
- return 1 == $count? $singular : $plural;
270
- }
271
-
272
- function merge_with(&$other) {
273
- }
274
- }
275
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/pot-ext-meta.php DELETED
@@ -1,76 +0,0 @@
1
- <?php
2
- /**
3
- * Console application, which adds metadata strings from
4
- * a WordPress extension to a POT file
5
- *
6
- * @version $Id$
7
- * @package wordpress-i18n
8
- * @subpackage tools
9
- */
10
-
11
- require_once dirname( __FILE__ ) . '/pomo/po.php';
12
- require_once dirname( __FILE__ ) . '/makepot.php';
13
-
14
- class PotExtMeta {
15
-
16
- var $headers = array(
17
- 'Plugin Name',
18
- 'Theme Name',
19
- 'Plugin URI',
20
- 'Theme URI',
21
- 'Description',
22
- 'Author',
23
- 'Author URI',
24
- 'Tags',
25
- );
26
-
27
-
28
- function usage() {
29
- fwrite(STDERR, "Usage: php pot-ext-meta.php EXT POT\n");
30
- fwrite(STDERR, "Adds metadata from a WordPress theme or plugin file EXT to POT file\n");
31
- exit(1);
32
- }
33
-
34
- function load_from_file($ext_filename) {
35
- $source = MakePOT::get_first_lines($ext_filename);
36
- $pot = '';
37
- foreach($this->headers as $header) {
38
- $string = MakePOT::get_addon_header($header, $source);
39
- if (!$string) continue;
40
- $args = array(
41
- 'singular' => $string,
42
- 'extracted_comments' => $header.' of the plugin/theme',
43
- );
44
- $entry = new Translation_Entry($args);
45
- $pot .= "\n".PO::export_entry($entry)."\n";
46
- }
47
- return $pot;
48
- }
49
-
50
- function append( $ext_filename, $pot_filename, $headers = null ) {
51
- if ( $headers )
52
- $this->headers = (array) $headers;
53
- if ( is_dir( $ext_filename ) ) {
54
- $pot = implode('', array_map(array(&$this, 'load_from_file'), glob("$ext_filename/*.php")));
55
- } else {
56
- $pot = $this->load_from_file($ext_filename);
57
- }
58
- $potf = '-' == $pot_filename? STDOUT : fopen($pot_filename, 'a');
59
- if (!$potf) return false;
60
- fwrite($potf, $pot);
61
- if ('-' != $pot_filename) fclose($potf);
62
- return true;
63
- }
64
- }
65
-
66
- $included_files = get_included_files();
67
- if ($included_files[0] == __FILE__) {
68
- ini_set('display_errors', 1);
69
- $potextmeta = new PotExtMeta;
70
- if (!isset($argv[1])) {
71
- $potextmeta->usage();
72
- }
73
- $potextmeta->append( $argv[1], isset( $argv[2] ) ? $argv[2] : '-', isset( $argv[3] ) ? $argv[3] : null );
74
- }
75
-
76
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/vendor/websharks/wp-i18n-tools/setup_locale DELETED
@@ -1,40 +0,0 @@
1
- #!/bin/sh
2
- # setup_locale - Creates the directory structure for a new locale in the
3
- # wordpress-i18n repository for a new locale.
4
-
5
- # First argument is the locale. Ex: es_ES
6
- locale=$1
7
-
8
- if [ -z "$locale" ]
9
- then
10
- echo "A locale must be specified."
11
- echo Usage is: $0 locale [repository]
12
- exit
13
- fi
14
-
15
- # Second argument is the base directory of your working copy
16
- # of wordpress-i18n.
17
- base=$2
18
-
19
- if [ -z "$base" ]
20
- then
21
- base=.
22
- fi
23
-
24
- if [ ! -d "$base" ]
25
- then
26
- echo "Directory $base does not exist."
27
- echo Usage is: $0 locale [repository]
28
- exit
29
- fi
30
-
31
- cd $base
32
-
33
- svn mkdir $locale
34
- svn mkdir $locale/trunk
35
- svn mkdir $locale/branches
36
- svn mkdir $locale/tags
37
-
38
- svn mkdir $locale/trunk/dist
39
-
40
- svn commit $locale -m "$locale" --force-log