Postie - Version 1.6.3

Version Description

(2014.10.03) = * Added postie_filter_email2 filter which includes To and Reply-To headers * Added postie_author filter * Revised help/support page

Download this release

Release Info

Developer WayneAllen
Plugin Icon 128x128 Postie
Version 1.6.3
Comparing to
See all releases

Code changes from version 1.6.2 to 1.6.3

config_form.php CHANGED
@@ -121,7 +121,7 @@
121
  <li id="simpleTabs-nav-4"><?php _e('Image', 'postie') ?></li>
122
  <li id="simpleTabs-nav-5"><?php _e('Video and Audio', 'postie') ?></li>
123
  <li id="simpleTabs-nav-6"><?php _e('Attachments', 'postie') ?></li>
124
- <li id="simpleTabs-nav-7"><?php _e('Help', 'postie') ?></li>
125
  </ul>
126
  </div>
127
  <div id="simpleTabs-content-1" class="simpleTabs-content">
@@ -829,11 +829,25 @@
829
  </table>
830
  </div>
831
  <div id="simpleTabs-content-7" class="simpleTabs-content">
832
- Visit <a href="http://postieplugin.com/" target="_blank">PostiePlugin.com</a> for lots of information and assistance.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
833
  </div>
834
 
835
 
836
- <p class="submit">
837
  <input type="hidden" name="action" value="update" />
838
  <input type="hidden" name="page_options" value="postie-settings" />
839
  <input type="submit" name="Submit" value="<?php _e('Save Changes') ?>" class="button button-primary" />
@@ -855,7 +869,29 @@
855
  autoNav: "false", // @param : true or false
856
  closeTabs: "false" // @param : true or false;
857
  });
858
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
859
  });
860
 
861
  function changeIconSet(selectBox, size) {
121
  <li id="simpleTabs-nav-4"><?php _e('Image', 'postie') ?></li>
122
  <li id="simpleTabs-nav-5"><?php _e('Video and Audio', 'postie') ?></li>
123
  <li id="simpleTabs-nav-6"><?php _e('Attachments', 'postie') ?></li>
124
+ <li id="simpleTabs-nav-7"><?php _e('Support', 'postie') ?></li>
125
  </ul>
126
  </div>
127
  <div id="simpleTabs-content-1" class="simpleTabs-content">
829
  </table>
830
  </div>
831
  <div id="simpleTabs-content-7" class="simpleTabs-content">
832
+ <div style="">
833
+ <h3>Postie Support</h3>
834
+ <p>Please use the Postie <a href="https://wordpress.org/support/plugin/postie" target="_blank">support forums</a></p>
835
+ <h3>More Postie info</h3>
836
+ <p>Visit <a href="http://postieplugin.com/" target="_blank">PostiePlugin.com</a> for lots of information and assistance
837
+ including information for developers wanting to leverage/extend Postie.</p>
838
+ </div>
839
+ <div>
840
+ <h3>Postie AddOns</h3>
841
+ <p>There are a number of different AddOns available to extend Postie's functionality.
842
+ See <a href='http://postieplugin.com/add-ons/' target='_blank'>the list</a> for more information.</p>
843
+ <div>
844
+ <div id='postie-addons'></div>
845
+ </div>
846
+ </div>
847
  </div>
848
 
849
 
850
+ <p class="submit" style="clear: both;">
851
  <input type="hidden" name="action" value="update" />
852
  <input type="hidden" name="page_options" value="postie-settings" />
853
  <input type="submit" name="Submit" value="<?php _e('Save Changes') ?>" class="button button-primary" />
869
  autoNav: "false", // @param : true or false
870
  closeTabs: "false" // @param : true or false;
871
  });
872
+ jQuery("#simpleTabs-nav-7").click(function () {
873
+ jQuery.get('http://postieplugin.com/feed/?post_type=download', function (data) {
874
+ console.log(data);
875
+ var h = '';
876
+ jQuery(data).find("item").each(function () {
877
+ var t = jQuery(this).find("title").text();
878
+ if (t != 'Donation') {
879
+ h += "<div style='float: left; width: 300px;'>";
880
+ h += "<h4 class='title'><a href='" + jQuery(this).find("link").text() + "' target='_blank'>" + t + "</a></h4>";
881
+ var d = jQuery(this).find("description").text();
882
+ if ((i = d.indexOf('<p class="more')) != -1) {
883
+ d = d.substring(0, i);
884
+ }
885
+ else if ((i = d.indexOf('<p>The post <a')) != -1) {
886
+ d = d.substring(0, i);
887
+ }
888
+ h += "<div>" + d + "</div>";
889
+ h += "</div>";
890
+ }
891
+ });
892
+ jQuery("#postie-addons").html(h);
893
+ });
894
+ });
895
  });
896
 
897
  function changeIconSet(selectBox, size) {
docs/Changes.txt CHANGED
@@ -27,6 +27,11 @@ All script, style and body tags are stripped from html emails.
27
  Attachments are now processed in the order they were attached.
28
 
29
  == CHANGELOG ==
 
 
 
 
 
30
  = 1.6.2 (2014.09.22) =
31
  * Moved FAQ and Help to PostiePlugin.com
32
  * Fixed file type issue with wp_handle_upload_prefilter()
27
  Attachments are now processed in the order they were attached.
28
 
29
  == CHANGELOG ==
30
+ = 1.6.3 (2014.10.03) =
31
+ * Added postie_filter_email2 filter which includes To and Reply-To headers
32
+ * Added postie_author filter
33
+ * Revised help/support page
34
+
35
  = 1.6.2 (2014.09.22) =
36
  * Moved FAQ and Help to PostiePlugin.com
37
  * Fixed file type issue with wp_handle_upload_prefilter()
docs/Postie.txt CHANGED
@@ -6,7 +6,7 @@ Plugin URI: http://PostiePlugin.com/
6
  Tags: e-mail, email, post-by-email
7
  Requires at least: 3.0
8
  Tested up to: 4.0
9
- Stable tag: 1.6.2
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
6
  Tags: e-mail, email, post-by-email
7
  Requires at least: 3.0
8
  Tested up to: 4.0
9
+ Stable tag: 1.6.3
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
docs/TODO.txt CHANGED
@@ -1,3 +1,7 @@
 
 
 
 
1
  automatically create category if it doesn't exist. new option to allow this feature?
2
  Add setting for category detection. I.e. checkboxes for [], -- and : styles. Default to all on.
3
  Add setting to not remove category text from subject/title
@@ -23,9 +27,6 @@ add hooks for post meta data change
23
  excerpt
24
  tags
25
  author
26
- add hook for email address extraction
27
- author found - allows plugins to change who the author is, filter need access to message to extract from body or headers
28
- to email - allows plugins to change category/tags based on the TO address (allows CC & BCC to be Postie mailbox)
29
  add hooks for content changes
30
  attachment template
31
  subject/title
1
+ Add Message-ID header value to custom field (postie_message_id?) to both posts and comments.
2
+ Use In-Reply-To header value as a better way to detect replies
3
+ Verify that {TITLE} is doing the right thing.
4
+ Automatic updates for AddOns: https://github.com/seedprod/sellwp-updater
5
  automatically create category if it doesn't exist. new option to allow this feature?
6
  Add setting for category detection. I.e. checkboxes for [], -- and : styles. Default to all on.
7
  Add setting to not remove category text from subject/title
27
  excerpt
28
  tags
29
  author
 
 
 
30
  add hooks for content changes
31
  attachment template
32
  subject/title
postie-functions.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- $Id: postie-functions.php 993640 2014-09-19 23:45:30Z WayneAllen $
4
  */
5
 
6
  //to turn on debug output add the following line to wp-config.php
@@ -618,13 +618,7 @@ function make_links($text) {
618
  function getPostAuthorDetails(&$subject, &$content, &$mimeDecodedEmail) {
619
 
620
  $theDate = $mimeDecodedEmail->headers['date'];
621
-
622
- $theEmail = $mimeDecodedEmail->headers["from"];
623
- DebugEcho("getPostAuthorDetails: pre email filter $theEmail");
624
- $theEmail = apply_filters("postie_filter_email", $theEmail);
625
- DebugEcho("getPostAuthorDetails: post email filter $theEmail");
626
-
627
- $theEmail = RemoveExtraCharactersInEmailAddress($theEmail);
628
 
629
  $regAuthor = get_user_by('email', $theEmail);
630
  if ($regAuthor) {
@@ -938,7 +932,7 @@ function PostToDB($details, $isReply, $customImageField, $postmodifiers) {
938
 
939
  $postmodifiers->apply($post_ID);
940
 
941
- apply_filters('postie_post_after', $details);
942
  }
943
  }
944
 
@@ -1362,7 +1356,20 @@ function ValidatePoster(&$mimeDecodedEmail, $config) {
1362
  if (property_exists($mimeDecodedEmail, "headers") && array_key_exists('from', $mimeDecodedEmail->headers)) {
1363
  $from = RemoveExtraCharactersInEmailAddress(trim($mimeDecodedEmail->headers["from"]));
1364
  $from = apply_filters("postie_filter_email", $from);
1365
- DebugEcho("ValidatePoster: post email filter $from");
 
 
 
 
 
 
 
 
 
 
 
 
 
1366
  } else {
1367
  DebugEcho("No 'from' header found");
1368
  DebugDump($mimeDecodedEmail->headers);
@@ -1387,7 +1394,10 @@ function ValidatePoster(&$mimeDecodedEmail, $config) {
1387
  if ($user->has_cap("post_via_postie")) {
1388
  DebugEcho("$user_ID has 'post_via_postie' permissions");
1389
  $poster = $user_ID;
1390
- DebugEcho("posting as user $poster");
 
 
 
1391
  } else {
1392
  DebugEcho("$user_ID does not have 'post_via_postie' permissions");
1393
  $user_ID = "";
@@ -1401,6 +1411,9 @@ function ValidatePoster(&$mimeDecodedEmail, $config) {
1401
  $poster = 1;
1402
  } else {
1403
  $poster = $user->ID;
 
 
 
1404
  }
1405
  DebugEcho("ValidatePoster: found user '$poster'");
1406
  }
1
  <?php
2
  /*
3
+ $Id: postie-functions.php 994962 2014-09-22 20:19:08Z WayneAllen $
4
  */
5
 
6
  //to turn on debug output add the following line to wp-config.php
618
  function getPostAuthorDetails(&$subject, &$content, &$mimeDecodedEmail) {
619
 
620
  $theDate = $mimeDecodedEmail->headers['date'];
621
+ $theEmail = RemoveExtraCharactersInEmailAddress($mimeDecodedEmail->headers["from"]);
 
 
 
 
 
 
622
 
623
  $regAuthor = get_user_by('email', $theEmail);
624
  if ($regAuthor) {
932
 
933
  $postmodifiers->apply($post_ID);
934
 
935
+ do_action('postie_post_after', $details);
936
  }
937
  }
938
 
1356
  if (property_exists($mimeDecodedEmail, "headers") && array_key_exists('from', $mimeDecodedEmail->headers)) {
1357
  $from = RemoveExtraCharactersInEmailAddress(trim($mimeDecodedEmail->headers["from"]));
1358
  $from = apply_filters("postie_filter_email", $from);
1359
+ DebugEcho("ValidatePoster: post postie_filter_email $from");
1360
+
1361
+ $toEmail = '';
1362
+ if (isset($mimeDecodedEmail->headers["to"])) {
1363
+ $toEmail = $mimeDecodedEmail->headers["to"];
1364
+ }
1365
+
1366
+ $replytoEmail = '';
1367
+ if (isset($mimeDecodedEmail->headers["reply-to"])) {
1368
+ $replytoEmail = $mimeDecodedEmail->headers["reply-to"];
1369
+ }
1370
+
1371
+ $from = apply_filters("postie_filter_email2", $from, $toEmail, $replytoEmail);
1372
+ DebugEcho("ValidatePoster: post postie_filter_email2 $from");
1373
  } else {
1374
  DebugEcho("No 'from' header found");
1375
  DebugDump($mimeDecodedEmail->headers);
1394
  if ($user->has_cap("post_via_postie")) {
1395
  DebugEcho("$user_ID has 'post_via_postie' permissions");
1396
  $poster = $user_ID;
1397
+
1398
+ DebugEcho("ValidatePoster: pre postie_author $poster");
1399
+ $poster = apply_filters("postie_author", $poster);
1400
+ DebugEcho("ValidatePoster: post postie_author $poster");
1401
  } else {
1402
  DebugEcho("$user_ID does not have 'post_via_postie' permissions");
1403
  $user_ID = "";
1411
  $poster = 1;
1412
  } else {
1413
  $poster = $user->ID;
1414
+ DebugEcho("ValidatePoster: pre postie_author (default) $poster");
1415
+ $poster = apply_filters("postie_author", $poster);
1416
+ DebugEcho("ValidatePoster: post postie_author (default) $poster");
1417
  }
1418
  DebugEcho("ValidatePoster: found user '$poster'");
1419
  }
postie.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Postie
5
  Plugin URI: http://PostiePlugin.com/
6
  Description: Create posts via email. Signifigantly upgrades the Post by Email features of Word Press.
7
- Version: 1.6.2
8
  Author: Wayne Allen
9
  Author URI: http://allens-home.com/
10
  License: GPL2
@@ -27,11 +27,11 @@
27
  */
28
 
29
  /*
30
- $Id: postie.php 994866 2014-09-22 17:19:43Z WayneAllen $
31
  */
32
  require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . "postie-functions.php");
33
 
34
- define('POSTIE_VERSION', '1.6.2');
35
  define("POSTIE_ROOT", dirname(__FILE__));
36
  define("POSTIE_URL", WP_PLUGIN_URL . '/' . basename(dirname(__FILE__)));
37
 
4
  Plugin Name: Postie
5
  Plugin URI: http://PostiePlugin.com/
6
  Description: Create posts via email. Signifigantly upgrades the Post by Email features of Word Press.
7
+ Version: 1.6.3
8
  Author: Wayne Allen
9
  Author URI: http://allens-home.com/
10
  License: GPL2
27
  */
28
 
29
  /*
30
+ $Id: postie.php 1001517 2014-10-03 22:02:02Z WayneAllen $
31
  */
32
  require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . "postie-functions.php");
33
 
34
+ define('POSTIE_VERSION', '1.6.3');
35
  define("POSTIE_ROOT", dirname(__FILE__));
36
  define("POSTIE_URL", WP_PLUGIN_URL . '/' . basename(dirname(__FILE__)));
37
 
readme.txt CHANGED
@@ -6,7 +6,7 @@ Plugin URI: http://PostiePlugin.com/
6
  Tags: e-mail, email, post-by-email
7
  Requires at least: 3.0
8
  Tested up to: 4.0
9
- Stable tag: 1.6.2
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
@@ -238,6 +238,11 @@ All script, style and body tags are stripped from html emails.
238
  Attachments are now processed in the order they were attached.
239
 
240
  == CHANGELOG ==
 
 
 
 
 
241
  = 1.6.2 (2014.09.22) =
242
  * Moved FAQ and Help to PostiePlugin.com
243
  * Fixed file type issue with wp_handle_upload_prefilter()
6
  Tags: e-mail, email, post-by-email
7
  Requires at least: 3.0
8
  Tested up to: 4.0
9
+ Stable tag: 1.6.3
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
238
  Attachments are now processed in the order they were attached.
239
 
240
  == CHANGELOG ==
241
+ = 1.6.3 (2014.10.03) =
242
+ * Added postie_filter_email2 filter which includes To and Reply-To headers
243
+ * Added postie_author filter
244
+ * Revised help/support page
245
+
246
  = 1.6.2 (2014.09.22) =
247
  * Moved FAQ and Help to PostiePlugin.com
248
  * Fixed file type issue with wp_handle_upload_prefilter()
templates/video1_templates.php CHANGED
@@ -80,4 +80,3 @@ $simple_link = '<a href="{FILELINK}">{FILENAME}</a>';
80
 
81
  $custom = isset($config) ? (array_key_exists('VIDEO1TEMPLATE', $config) ? $config['VIDEO1TEMPLATE'] : "") : "";
82
  $video1Templates = compact('simple_link', 'small', 'medium', 'medium_widescreen', 'large', 'large_widescreen', 'custom');
83
- ?>
80
 
81
  $custom = isset($config) ? (array_key_exists('VIDEO1TEMPLATE', $config) ? $config['VIDEO1TEMPLATE'] : "") : "";
82
  $video1Templates = compact('simple_link', 'small', 'medium', 'medium_widescreen', 'large', 'large_widescreen', 'custom');
 
templates/video2_templates.php CHANGED
@@ -81,4 +81,3 @@ $simple_link = '<a href="{FILELINK}">{FILENAME}</a>';
81
 
82
  $custom = isset($config) ? (array_key_exists('VIDEO2TEMPLATE', $config) ? $config['VIDEO2TEMPLATE'] : "") : "";
83
  $video2Templates = compact('simple_link', 'small', 'medium', 'medium_widescreen', 'large', 'large_widescreen', 'flv_embed', 'custom');
84
- ?>
81
 
82
  $custom = isset($config) ? (array_key_exists('VIDEO2TEMPLATE', $config) ? $config['VIDEO2TEMPLATE'] : "") : "";
83
  $video2Templates = compact('simple_link', 'small', 'medium', 'medium_widescreen', 'large', 'large_widescreen', 'flv_embed', 'custom');
 
util/wp-i18n/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: add-textdomain.php 15618 2011-01-15 15:23:34Z nbachiyski $
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
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/extract/ExtractTest.php DELETED
@@ -1,154 +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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/extract/TODO DELETED
@@ -1 +0,0 @@
1
- * php-format
 
util/wp-i18n/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$/', $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 === strpos( $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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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 ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/makepot.php DELETED
@@ -1,561 +0,0 @@
1
- <?php
2
- require_once dirname( __FILE__ ) . '/not-gettexted.php';
3
- require_once dirname( __FILE__ ) . '/pot-ext-meta.php';
4
- require_once dirname( __FILE__ ) . '/extract/extract.php';
5
-
6
- if ( !defined( 'STDERR' ) ) {
7
- define( 'STDERR', fopen( 'php://stderr', 'w' ) );
8
- }
9
-
10
- class MakePOT {
11
- var $max_header_lines = 30;
12
-
13
- var $projects = array(
14
- 'generic',
15
- 'wp-frontend',
16
- 'wp-admin',
17
- 'wp-network-admin',
18
- 'wp-core',
19
- 'wp-ms',
20
- 'wp-tz',
21
- 'wp-plugin',
22
- 'wp-theme',
23
- 'bb',
24
- 'mu',
25
- 'bp',
26
- 'rosetta',
27
- 'wporg-bb-forums',
28
- );
29
-
30
- var $rules = array(
31
- '_' => array('string'),
32
- '__' => array('string'),
33
- '_e' => array('string'),
34
- '_c' => array('string'),
35
- '_n' => array('singular', 'plural'),
36
- '_n_noop' => array('singular', 'plural'),
37
- '_nc' => array('singular', 'plural'),
38
- '__ngettext' => array('singular', 'plural'),
39
- '__ngettext_noop' => array('singular', 'plural'),
40
- '_x' => array('string', 'context'),
41
- '_ex' => array('string', 'context'),
42
- '_nx' => array('singular', 'plural', null, 'context'),
43
- '_nx_noop' => array('singular', 'plural', 'context'),
44
- '_n_js' => array('singular', 'plural'),
45
- '_nx_js' => array('singular', 'plural', 'context'),
46
- 'esc_attr__' => array('string'),
47
- 'esc_html__' => array('string'),
48
- 'esc_attr_e' => array('string'),
49
- 'esc_html_e' => array('string'),
50
- 'esc_attr_x' => array('string', 'context'),
51
- 'esc_html_x' => array('string', 'context'),
52
- 'comments_number_link' => array('string', 'singular', 'plural'),
53
- );
54
-
55
- 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.*' );
56
-
57
- var $temp_files = array();
58
-
59
- var $meta = array(
60
- 'default' => array(
61
- 'from-code' => 'utf-8',
62
- 'msgid-bugs-address' => 'http://wppolyglots.wordpress.com',
63
- 'language' => 'php',
64
- 'add-comments' => 'translators',
65
- 'comments' => "Copyright (C) {year} {package-name}\nThis file is distributed under the same license as the {package-name} package.",
66
- ),
67
- 'generic' => array(),
68
- 'wp-frontend' => array(
69
- 'description' => 'Translation of frontend strings in WordPress {version}',
70
- 'copyright-holder' => 'WordPress',
71
- 'package-name' => 'WordPress',
72
- 'package-version' => '{version}',
73
- ),
74
- 'wp-admin' => array(
75
- 'description' => 'Translation of site admin strings in WordPress {version}',
76
- 'copyright-holder' => 'WordPress',
77
- 'package-name' => 'WordPress',
78
- 'package-version' => '{version}',
79
- ),
80
- 'wp-network-admin' => array(
81
- 'description' => 'Translation of network admin strings in WordPress {version}',
82
- 'copyright-holder' => 'WordPress',
83
- 'package-name' => 'WordPress',
84
- 'package-version' => '{version}',
85
- ),
86
- 'wp-core' => array(
87
- 'description' => 'Translation of WordPress {version}',
88
- 'copyright-holder' => 'WordPress',
89
- 'package-name' => 'WordPress',
90
- 'package-version' => '{version}',
91
- ),
92
- 'wp-ms' => array(
93
- 'description' => 'Translation of multisite strings in WordPress {version}',
94
- 'copyright-holder' => 'WordPress',
95
- 'package-name' => 'WordPress',
96
- 'package-version' => '{version}',
97
- ),
98
- 'wp-tz' => array(
99
- 'description' => 'Translation of timezone strings in WordPress {version}',
100
- 'copyright-holder' => 'WordPress',
101
- 'package-name' => 'WordPress',
102
- 'package-version' => '{version}',
103
- ),
104
- 'bb' => array(
105
- 'description' => 'Translation of bbPress',
106
- 'copyright-holder' => 'bbPress',
107
- 'package-name' => 'bbPress',
108
- ),
109
- 'wp-plugin' => array(
110
- 'description' => 'Translation of the WordPress plugin {name} {version} by {author}',
111
- 'msgid-bugs-address' => 'http://wordpress.org/tag/{slug}',
112
- 'copyright-holder' => '{author}',
113
- 'package-name' => '{name}',
114
- 'package-version' => '{version}',
115
- ),
116
- 'wp-theme' => array(
117
- 'description' => 'Translation of the WordPress theme {name} {version} by {author}',
118
- 'msgid-bugs-address' => 'http://wordpress.org/tags/{slug}',
119
- 'copyright-holder' => '{author}',
120
- 'package-name' => '{name}',
121
- 'package-version' => '{version}',
122
- 'comments' => 'Copyright (C) {year} {author}\nThis file is distributed under the same license as the {package-name} package.',
123
- ),
124
- 'bp' => array(
125
- 'description' => 'Translation of BuddyPress',
126
- 'copyright-holder' => 'BuddyPress',
127
- 'package-name' => 'BuddyPress',
128
- ),
129
- 'wporg-bb-forums' => array(
130
- 'description' => 'WordPress.org International Forums',
131
- 'copyright-holder' => 'WordPress',
132
- 'package-name' => 'WordPress.org International Forums',
133
- ),
134
- 'rosetta' => array(
135
- 'description' => 'Rosetta (.wordpress.org locale sites)',
136
- 'copyright-holder' => 'WordPress',
137
- 'package-name' => 'Rosetta',
138
- ),
139
- );
140
-
141
- function __construct($deprecated = true) {
142
- $this->extractor = new StringExtractor( $this->rules );
143
- }
144
-
145
- function __destruct() {
146
- foreach ( $this->temp_files as $temp_file )
147
- unlink( $temp_file );
148
- }
149
-
150
- function tempnam( $file ) {
151
- $tempnam = tempnam( sys_get_temp_dir(), $file );
152
- $this->temp_files[] = $tempnam;
153
- return $tempnam;
154
- }
155
-
156
- function realpath_missing($path) {
157
- return realpath(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
158
- }
159
-
160
- function xgettext($project, $dir, $output_file, $placeholders = array(), $excludes = array(), $includes = array()) {
161
- $meta = array_merge( $this->meta['default'], $this->meta[$project] );
162
- $placeholders = array_merge( $meta, $placeholders );
163
- $meta['output'] = $this->realpath_missing( $output_file );
164
- $placeholders['year'] = date( 'Y' );
165
- $placeholder_keys = array_map( create_function( '$x', 'return "{".$x."}";' ), array_keys( $placeholders ) );
166
- $placeholder_values = array_values( $placeholders );
167
- foreach($meta as $key => $value) {
168
- $meta[$key] = str_replace($placeholder_keys, $placeholder_values, $value);
169
- }
170
-
171
- $originals = $this->extractor->extract_from_directory( $dir, $excludes, $includes );
172
- $pot = new PO;
173
- $pot->entries = $originals->entries;
174
-
175
- $pot->set_header( 'Project-Id-Version', $meta['package-name'].' '.$meta['package-version'] );
176
- $pot->set_header( 'Report-Msgid-Bugs-To', $meta['msgid-bugs-address'] );
177
- $pot->set_header( 'POT-Creation-Date', gmdate( 'Y-m-d H:i:s+00:00' ) );
178
- $pot->set_header( 'MIME-Version', '1.0' );
179
- $pot->set_header( 'Content-Type', 'text/plain; charset=UTF-8' );
180
- $pot->set_header( 'Content-Transfer-Encoding', '8bit' );
181
- $pot->set_header( 'PO-Revision-Date', date( 'Y') . '-MO-DA HO:MI+ZONE' );
182
- $pot->set_header( 'Last-Translator', 'FULL NAME <EMAIL@ADDRESS>' );
183
- $pot->set_header( 'Language-Team', 'LANGUAGE <LL@li.org>' );
184
- $pot->set_comment_before_headers( $meta['comments'] );
185
- $pot->export_to_file( $output_file );
186
- return true;
187
- }
188
-
189
- function wp_generic($dir, $args) {
190
- $defaults = array(
191
- 'project' => 'wp-core',
192
- 'output' => null,
193
- 'default_output' => 'wordpress.pot',
194
- 'includes' => array(),
195
- 'excludes' => array_merge(
196
- array('wp-admin/includes/continents-cities\.php', 'wp-content/themes/twenty.*', ),
197
- $this->ms_files
198
- ),
199
- 'extract_not_gettexted' => false,
200
- 'not_gettexted_files_filter' => false,
201
- );
202
- $args = array_merge( $defaults, $args );
203
- extract( $args );
204
- $placeholders = array();
205
- if ( $wp_version = $this->wp_version( $dir ) )
206
- $placeholders['version'] = $wp_version;
207
- else
208
- return false;
209
- $output = is_null( $output )? $default_output : $output;
210
- $res = $this->xgettext( $project, $dir, $output, $placeholders, $excludes, $includes );
211
- if ( !$res ) return false;
212
-
213
- if ( $extract_not_gettexted ) {
214
- $old_dir = getcwd();
215
- $output = realpath( $output );
216
- chdir( $dir );
217
- $php_files = NotGettexted::list_php_files('.');
218
- $php_files = array_filter( $php_files, $not_gettexted_files_filter );
219
- $not_gettexted = new NotGettexted;
220
- $res = $not_gettexted->command_extract( $output, $php_files );
221
- chdir( $old_dir );
222
- /* Adding non-gettexted strings can repeat some phrases */
223
- $output_shell = escapeshellarg( $output );
224
- system( "msguniq --use-first $output_shell -o $output_shell" );
225
- }
226
- return $res;
227
- }
228
-
229
- function wp_core($dir, $output) {
230
- if ( file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
231
-
232
- return $this->wp_generic( $dir, array(
233
- 'project' => 'wp-core', 'output' => $output,
234
- 'extract_not_gettexted' => true,
235
- 'not_gettexted_files_filter' => array( &$this, 'is_not_ms_file' ),
236
- ) );
237
- }
238
-
239
- function wp_frontend($dir, $output) {
240
- if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
241
-
242
- return $this->wp_generic( $dir, array(
243
- 'project' => 'wp-frontend', 'output' => $output,
244
- 'includes' => array(), 'excludes' => array( 'wp-admin/.*', 'wp-content/themes/.*' ),
245
- 'default_output' => 'wordpress.pot',
246
- ) );
247
- }
248
-
249
- function wp_admin($dir, $output) {
250
- if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
251
-
252
- $frontend_pot = $this->tempnam( 'frontend.pot' );
253
- if ( false === $frontend_pot ) return false;
254
-
255
- $frontend_result = $this->wp_frontend( $dir, $frontend_pot );
256
- if ( ! $frontend_result )
257
- return false;
258
-
259
- $result = $this->wp_generic( $dir, array(
260
- 'project' => 'wp-admin', 'output' => $output,
261
- 'includes' => array( 'wp-admin/.*' ), 'excludes' => array( 'wp-admin/includes/continents-cities\.php', 'wp-admin/network/.*', 'wp-admin/network.php' ),
262
- 'default_output' => 'wordpress-admin.pot',
263
- ) );
264
-
265
- if ( ! $result )
266
- return false;
267
-
268
- $potextmeta = new PotExtMeta;
269
- $result = $potextmeta->append( "$dir/wp-content/plugins/akismet/akismet.php", $output );
270
- if ( ! $result )
271
- return false;
272
- $result = $potextmeta->append( "$dir/wp-content/plugins/hello.php", $output );
273
- if ( ! $result )
274
- return false;
275
- /* Adding non-gettexted strings can repeat some phrases */
276
- $output_shell = escapeshellarg($output);
277
- system("msguniq $output_shell -o $output_shell");
278
-
279
- $common_pot = $this->tempnam( 'common.pot' );
280
- if ( ! $common_pot )
281
- return false;
282
- $admin_pot = realpath( is_null( $output ) ? 'wordpress-admin.pot' : $output );
283
- system( "msgcat --more-than=1 --use-first $frontend_pot $admin_pot > $common_pot" );
284
- system( "msgcat -u --use-first $admin_pot $common_pot -o $admin_pot" );
285
- return true;
286
- }
287
-
288
- function wp_network_admin($dir, $output) {
289
- if ( ! file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
290
-
291
- $frontend_pot = $this->tempnam( 'frontend.pot' );
292
- if ( false === $frontend_pot ) return false;
293
-
294
- $frontend_result = $this->wp_frontend( $dir, $frontend_pot );
295
- if ( ! $frontend_result )
296
- return false;
297
-
298
- $admin_pot = $this->tempnam( 'admin.pot' );
299
- if ( false === $admin_pot ) return false;
300
-
301
- $admin_result = $this->wp_admin( $dir, $admin_pot );
302
- if ( ! $admin_result )
303
- return false;
304
-
305
- $result = $this->wp_generic( $dir, array(
306
- 'project' => 'wp-network-admin', 'output' => $output,
307
- 'includes' => array( 'wp-admin/network/.*', 'wp-admin/network.php' ), 'excludes' => array(),
308
- 'default_output' => 'wordpress-admin-network.pot',
309
- ) );
310
-
311
- if ( ! $result ) {
312
- return false;
313
- }
314
-
315
- $common_pot = $this->tempnam( 'common.pot' );
316
- if ( ! $common_pot )
317
- return false;
318
-
319
- $net_admin_pot = realpath( is_null( $output ) ? 'wordpress-network-admin.pot' : $output );
320
- system( "msgcat --more-than=1 --use-first $frontend_pot $admin_pot $net_admin_pot > $common_pot" );
321
- system( "msgcat -u --use-first $net_admin_pot $common_pot -o $net_admin_pot" );
322
- return true;
323
- }
324
-
325
- function wp_ms($dir, $output) {
326
- if ( file_exists( "$dir/wp-admin/user/about.php" ) ) return false;
327
- if ( !is_file("$dir/wp-admin/ms-users.php") ) return false;
328
- $core_pot = $this->tempnam( 'wordpress.pot' );
329
- if ( false === $core_pot ) return false;
330
- $core_result = $this->wp_core( $dir, $core_pot );
331
- if ( ! $core_result )
332
- return false;
333
- $ms_result = $this->wp_generic( $dir, array(
334
- 'project' => 'wp-ms', 'output' => $output,
335
- 'includes' => $this->ms_files, 'excludes' => array(),
336
- 'default_output' => 'wordpress-ms.pot',
337
- 'extract_not_gettexted' => true,
338
- 'not_gettexted_files_filter' => array( &$this, 'is_ms_file' ),
339
- ) );
340
- if ( !$ms_result ) {
341
- return false;
342
- }
343
- $common_pot = $this->tempnam( 'common.pot' );
344
- if ( ! $common_pot )
345
- return false;
346
- $ms_pot = realpath( is_null( $output )? 'wordpress-ms.pot' : $output );
347
- system( "msgcat --more-than=1 --use-first $core_pot $ms_pot > $common_pot" );
348
- system( "msgcat -u --use-first $ms_pot $common_pot -o $ms_pot" );
349
- return true;
350
- }
351
-
352
- function wp_tz($dir, $output) {
353
- $continents_path = 'wp-admin/includes/continents-cities.php';
354
- if ( !file_exists( "$dir/$continents_path" ) ) return false;
355
- return $this->wp_generic( $dir, array(
356
- 'project' => 'wp-tz', 'output' => $output,
357
- 'includes' => array($continents_path), 'excludes' => array(),
358
- 'default_output' => 'wordpress-continents-cities.pot',
359
- ) );
360
- }
361
-
362
- function wp_version($dir) {
363
- $version_php = $dir.'/wp-includes/version.php';
364
- if ( !is_readable( $version_php ) ) return false;
365
- return preg_match( '/\$wp_version\s*=\s*\'(.*?)\';/', file_get_contents( $version_php ), $matches )? $matches[1] : false;
366
- }
367
-
368
-
369
- function mu($dir, $output) {
370
- $placeholders = array();
371
- if (preg_match('/\$wpmu_version\s*=\s*\'(.*?)\';/', file_get_contents($dir.'/wp-includes/version.php'), $matches)) {
372
- $placeholders['version'] = $matches[1];
373
- }
374
- $output = is_null($output)? 'wordpress.pot' : $output;
375
- return $this->xgettext('wp', $dir, $output, $placeholders);
376
- }
377
-
378
-
379
- function bb($dir, $output) {
380
- $placeholders = array();
381
- $output = is_null($output)? 'bbpress.pot' : $output;
382
- return $this->xgettext('bb', $dir, $output, $placeholders);
383
-
384
- }
385
-
386
- function get_first_lines($filename, $lines = 30) {
387
- $extf = fopen($filename, 'r');
388
- if (!$extf) return false;
389
- $first_lines = '';
390
- foreach(range(1, $lines) as $x) {
391
- $line = fgets($extf);
392
- if (feof($extf)) break;
393
- if (false === $line) {
394
- return false;
395
- }
396
- $first_lines .= $line;
397
- }
398
- return $first_lines;
399
- }
400
-
401
-
402
- function get_addon_header($header, &$source) {
403
- if (preg_match('|'.$header.':(.*)$|mi', $source, $matches))
404
- return trim($matches[1]);
405
- else
406
- return false;
407
- }
408
-
409
- function generic($dir, $output) {
410
- $output = is_null($output)? "generic.pot" : $output;
411
- return $this->xgettext('generic', $dir, $output, array());
412
- }
413
-
414
- function guess_plugin_slug($dir) {
415
- if ('trunk' == basename($dir)) {
416
- $slug = basename(dirname($dir));
417
- } elseif (in_array(basename(dirname($dir)), array('branches', 'tags'))) {
418
- $slug = basename(dirname(dirname($dir)));
419
- } else {
420
- $slug = basename($dir);
421
- }
422
- return $slug;
423
- }
424
-
425
- function wp_plugin($dir, $output, $slug = null) {
426
- $placeholders = array();
427
- // guess plugin slug
428
- if (is_null($slug)) {
429
- $slug = $this->guess_plugin_slug($dir);
430
- }
431
- $main_file = $dir.'/'.$slug.'.php';
432
- $source = $this->get_first_lines($main_file, $this->max_header_lines);
433
-
434
- $placeholders['version'] = $this->get_addon_header('Version', $source);
435
- $placeholders['author'] = $this->get_addon_header('Author', $source);
436
- $placeholders['name'] = $this->get_addon_header('Plugin Name', $source);
437
- $placeholders['slug'] = $slug;
438
-
439
- $output = is_null($output)? "$slug.pot" : $output;
440
- $res = $this->xgettext('wp-plugin', $dir, $output, $placeholders);
441
- if (!$res) return false;
442
- $potextmeta = new PotExtMeta;
443
- $res = $potextmeta->append($main_file, $output);
444
- /* Adding non-gettexted strings can repeat some phrases */
445
- $output_shell = escapeshellarg($output);
446
- system("msguniq $output_shell -o $output_shell");
447
- return $res;
448
- }
449
-
450
- function wp_theme($dir, $output, $slug = null) {
451
- $placeholders = array();
452
- // guess plugin slug
453
- if (is_null($slug)) {
454
- $slug = $this->guess_plugin_slug($dir);
455
- }
456
- $main_file = $dir.'/style.css';
457
- $source = $this->get_first_lines($main_file, $this->max_header_lines);
458
-
459
- $placeholders['version'] = $this->get_addon_header('Version', $source);
460
- $placeholders['author'] = $this->get_addon_header('Author', $source);
461
- $placeholders['name'] = $this->get_addon_header('Theme Name', $source);
462
- $placeholders['slug'] = $slug;
463
-
464
- $license = $this->get_addon_header( 'License', $source );
465
- if ( $license )
466
- $this->meta['wp-theme']['comments'] = "Copyright (C) {year} {author}\nThis file is distributed under the {$license}.";
467
- else
468
- $this->meta['wp-theme']['comments'] = "Copyright (C) {year} {author}\nThis file is distributed under the same license as the {package-name} package.";
469
-
470
- $output = is_null($output)? "$slug.pot" : $output;
471
- $res = $this->xgettext('wp-theme', $dir, $output, $placeholders);
472
- if (! $res )
473
- return false;
474
- $potextmeta = new PotExtMeta;
475
- $res = $potextmeta->append( $main_file, $output, array( 'Theme Name', 'Theme URI', 'Description', 'Author', 'Author URI' ) );
476
- if ( ! $res )
477
- return false;
478
- // If we're dealing with a pre-3.4 default theme, don't extract page templates before 3.4.
479
- $extract_templates = ! in_array( $slug, array( 'twentyten', 'twentyeleven', 'default', 'classic' ) );
480
- if ( ! $extract_templates ) {
481
- $wp_dir = dirname( dirname( dirname( $dir ) ) );
482
- $extract_templates = file_exists( "$wp_dir/wp-admin/user/about.php" ) || ! file_exists( "$wp_dir/wp-load.php" );
483
- }
484
- if ( $extract_templates ) {
485
- $res = $potextmeta->append( $dir, $output, array( 'Template Name' ) );
486
- if ( ! $res )
487
- return false;
488
- $files = scandir( $dir );
489
- foreach ( $files as $file ) {
490
- if ( '.' == $file[0] || 'CVS' == $file )
491
- continue;
492
- if ( is_dir( $dir . '/' . $file ) ) {
493
- $res = $potextmeta->append( $dir . '/' . $file, $output, array( 'Template Name' ) );
494
- if ( ! $res )
495
- return false;
496
- }
497
- }
498
- }
499
- /* Adding non-gettexted strings can repeat some phrases */
500
- $output_shell = escapeshellarg($output);
501
- system("msguniq $output_shell -o $output_shell");
502
- return $res;
503
- }
504
-
505
- function bp($dir, $output) {
506
- $output = is_null($output)? "buddypress.pot" : $output;
507
- return $this->xgettext('bp', $dir, $output, array(), array('bp-forums/bbpress/.*'));
508
- }
509
-
510
- function wporg_bb_forums( $dir, $output ) {
511
- $output = is_null( $output ) ? 'wporg.pot' : $output;
512
- return $this->xgettext( 'wporg-bb-forums', $dir, $output, array(), array(
513
- 'bb-plugins/elfakismet/.*',
514
- 'bb-plugins/support-forum/.*',
515
- ) );
516
- }
517
-
518
- function rosetta( $dir, $output ) {
519
- $output = is_null( $output )? 'rosetta.pot' : $output;
520
- return $this->xgettext( 'rosetta', $dir, $output, array(), array(), array(
521
- 'mu-plugins/rosetta.*\.php',
522
- 'mu-plugins/rosetta/[^/]+\.php',
523
- 'mu-plugins/rosetta/tmpl/.*\.php',
524
- 'themes/rosetta/.*\.php',
525
- ) );
526
- }
527
-
528
- function is_ms_file( $file_name ) {
529
- $is_ms_file = false;
530
- $prefix = substr( $file_name, 0, 2 ) === './'? '\./' : '';
531
- foreach( $this->ms_files as $ms_file )
532
- if ( preg_match( '|^'.$prefix.$ms_file.'$|', $file_name ) ) {
533
- $is_ms_file = true;
534
- break;
535
- }
536
- return $is_ms_file;
537
- }
538
-
539
- function is_not_ms_file( $file_name ) {
540
- return !$this->is_ms_file( $file_name );
541
- }
542
- }
543
-
544
- // run the CLI only if the file
545
- // wasn't included
546
- $included_files = get_included_files();
547
- if ($included_files[0] == __FILE__) {
548
- $makepot = new MakePOT;
549
- if ((3 == count($argv) || 4 == count($argv)) && in_array($method = str_replace('-', '_', $argv[1]), get_class_methods($makepot))) {
550
- $res = call_user_func(array(&$makepot, $method), realpath($argv[2]), isset($argv[3])? $argv[3] : null);
551
- if (false === $res) {
552
- fwrite(STDERR, "Couldn't generate POT file!\n");
553
- }
554
- } else {
555
- $usage = "Usage: php makepot.php PROJECT DIRECTORY [OUTPUT]\n\n";
556
- $usage .= "Generate POT file from the files in DIRECTORY [OUTPUT]\n";
557
- $usage .= "Available projects: ".implode(', ', $makepot->projects)."\n";
558
- fwrite(STDERR, $usage);
559
- exit(1);
560
- }
561
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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: not-gettexted.php 19275 2012-02-10 17:47:42Z nacin $
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
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/mo.php DELETED
@@ -1,257 +0,0 @@
1
- <?php
2
- /**
3
- * Class for working with MO files
4
- *
5
- * @version $Id: mo.php 718 2012-10-31 00:32:02Z nbachiyski $
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
- $this->set_headers($this->make_headers($translation));
211
- } else {
212
- $entry = &$this->make_entry($original, $translation);
213
- $this->entries[$entry->key()] = &$entry;
214
- }
215
- }
216
- return true;
217
- }
218
-
219
- /**
220
- * Build a Translation_Entry from original string and translation strings,
221
- * found in a MO file
222
- *
223
- * @static
224
- * @param string $original original string to translate from MO file. Might contain
225
- * 0x04 as context separator or 0x00 as singular/plural separator
226
- * @param string $translation translation string from MO file. Might contain
227
- * 0x00 as a plural translations separator
228
- */
229
- function &make_entry($original, $translation) {
230
- $entry = new Translation_Entry();
231
- // look for context
232
- $parts = explode(chr(4), $original);
233
- if (isset($parts[1])) {
234
- $original = $parts[1];
235
- $entry->context = $parts[0];
236
- }
237
- // look for plural original
238
- $parts = explode(chr(0), $original);
239
- $entry->singular = $parts[0];
240
- if (isset($parts[1])) {
241
- $entry->is_plural = true;
242
- $entry->plural = $parts[1];
243
- }
244
- // plural translations are also separated by \0
245
- $entry->translations = explode(chr(0), $translation);
246
- return $entry;
247
- }
248
-
249
- function select_plural_form($count) {
250
- return $this->gettext_select_plural_form($count);
251
- }
252
-
253
- function get_plural_forms_count() {
254
- return $this->_nplurals;
255
- }
256
- }
257
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/po.php DELETED
@@ -1,384 +0,0 @@
1
- <?php
2
- /**
3
- * Class for working with PO files
4
- *
5
- * @version $Id: po.php 718 2012-10-31 00:32:02Z nbachiyski $
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
- 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
- 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
- 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
- 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
- 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
- $this->set_headers($this->make_headers($res['entry']->translations[0]));
227
- } else {
228
- $this->add_entry($res['entry']);
229
- }
230
- }
231
- PO::read_line($f, 'clear');
232
- if ( false === $res ) {
233
- return false;
234
- }
235
- if ( ! $this->headers && ! $this->entries ) {
236
- return false;
237
- }
238
- return true;
239
- }
240
-
241
- function read_entry($f, $lineno = 0) {
242
- $entry = new Translation_Entry();
243
- // where were we in the last step
244
- // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
245
- $context = '';
246
- $msgstr_index = 0;
247
- $is_final = create_function('$context', 'return $context == "msgstr" || $context == "msgstr_plural";');
248
- while (true) {
249
- $lineno++;
250
- $line = PO::read_line($f);
251
- if (!$line) {
252
- if (feof($f)) {
253
- if ($is_final($context))
254
- break;
255
- elseif (!$context) // we haven't read a line and eof came
256
- return null;
257
- else
258
- return false;
259
- } else {
260
- return false;
261
- }
262
- }
263
- if ($line == "\n") continue;
264
- $line = trim($line);
265
- if (preg_match('/^#/', $line, $m)) {
266
- // the comment is the start of a new entry
267
- if ($is_final($context)) {
268
- PO::read_line($f, 'put-back');
269
- $lineno--;
270
- break;
271
- }
272
- // comments have to be at the beginning
273
- if ($context && $context != 'comment') {
274
- return false;
275
- }
276
- // add comment
277
- $this->add_comment_to_entry($entry, $line);;
278
- } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
279
- if ($is_final($context)) {
280
- PO::read_line($f, 'put-back');
281
- $lineno--;
282
- break;
283
- }
284
- if ($context && $context != 'comment') {
285
- return false;
286
- }
287
- $context = 'msgctxt';
288
- $entry->context .= PO::unpoify($m[1]);
289
- } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
290
- if ($is_final($context)) {
291
- PO::read_line($f, 'put-back');
292
- $lineno--;
293
- break;
294
- }
295
- if ($context && $context != 'msgctxt' && $context != 'comment') {
296
- return false;
297
- }
298
- $context = 'msgid';
299
- $entry->singular .= PO::unpoify($m[1]);
300
- } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
301
- if ($context != 'msgid') {
302
- return false;
303
- }
304
- $context = 'msgid_plural';
305
- $entry->is_plural = true;
306
- $entry->plural .= PO::unpoify($m[1]);
307
- } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
308
- if ($context != 'msgid') {
309
- return false;
310
- }
311
- $context = 'msgstr';
312
- $entry->translations = array(PO::unpoify($m[1]));
313
- } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
314
- if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
315
- return false;
316
- }
317
- $context = 'msgstr_plural';
318
- $msgstr_index = $m[1];
319
- $entry->translations[$m[1]] = PO::unpoify($m[2]);
320
- } elseif (preg_match('/^".*"$/', $line)) {
321
- $unpoified = PO::unpoify($line);
322
- switch ($context) {
323
- case 'msgid':
324
- $entry->singular .= $unpoified; break;
325
- case 'msgctxt':
326
- $entry->context .= $unpoified; break;
327
- case 'msgid_plural':
328
- $entry->plural .= $unpoified; break;
329
- case 'msgstr':
330
- $entry->translations[0] .= $unpoified; break;
331
- case 'msgstr_plural':
332
- $entry->translations[$msgstr_index] .= $unpoified; break;
333
- default:
334
- return false;
335
- }
336
- } else {
337
- return false;
338
- }
339
- }
340
- if (array() == array_filter($entry->translations, create_function('$t', 'return $t || "0" === $t;'))) {
341
- $entry->translations = array();
342
- }
343
- return array('entry' => $entry, 'lineno' => $lineno);
344
- }
345
-
346
- function read_line($f, $action = 'read') {
347
- static $last_line = '';
348
- static $use_last_line = false;
349
- if ('clear' == $action) {
350
- $last_line = '';
351
- return true;
352
- }
353
- if ('put-back' == $action) {
354
- $use_last_line = true;
355
- return true;
356
- }
357
- $line = $use_last_line? $last_line : fgets($f);
358
- $line = gp_endswith( $line, "\r\n" )? rtrim( $line, "\r\n" ) . "\n" : $line;
359
- $last_line = $line;
360
- $use_last_line = false;
361
- return $line;
362
- }
363
-
364
- function add_comment_to_entry(&$entry, $po_comment_line) {
365
- $first_two = substr($po_comment_line, 0, 2);
366
- $comment = trim(substr($po_comment_line, 2));
367
- if ('#:' == $first_two) {
368
- $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
369
- } elseif ('#.' == $first_two) {
370
- $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
371
- } elseif ('#,' == $first_two) {
372
- $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
373
- } else {
374
- $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
375
- }
376
- }
377
-
378
- function trim_quotes($s) {
379
- if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
380
- if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
381
- return $s;
382
- }
383
- }
384
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/sample/app.php DELETED
@@ -1,63 +0,0 @@
1
- <?php
2
-
3
- require_once '../translations.php';
4
- require_once '../mo.php';
5
-
6
-
7
- function __($text, $domain = 'default') {
8
- $translations = &get_translations($domain);
9
- return $translations->translate($text);
10
- }
11
-
12
- function _e($text, $domain = 'default') {
13
- $translations = &get_translations($domain);
14
- echo $translations->translate($text);
15
- }
16
-
17
- function __n($singular, $plural, $count, $domain = 'default') {
18
- $translations = &get_translations($domain);
19
- return $translations->translate_plural($singular, $plural, $count);
20
- }
21
-
22
- function &load_translations($mo_filename) {
23
- if (is_readable($mo_filename)) {
24
- $translations = new MO();
25
- $translations->import_from_file($mo_filename);
26
- } else {
27
- $translations = new Translations();
28
- }
29
- return $translations;
30
- }
31
-
32
- // get the locale from somewhere: subomain, config, GET var, etc.
33
- // it can be safely empty
34
- $locale = 'bg';
35
- $translations = array();
36
- $empty_translations = & new Translations();
37
-
38
- function load_textdomain($domain, $mofile) {
39
- global $translations;
40
- $translations[$domain] = &load_translations($mofile);
41
- }
42
-
43
- function &get_translations($domain) {
44
- global $translations, $empty_translations;
45
- return isset($translations[$domain])? $translations[$domain] : $empty_translations;
46
- }
47
-
48
- // load the translations
49
- load_textdomain('default', "languages/$locale.mo");
50
- load_textdomain('side', "languages/$locale-side.mo");
51
-
52
- //here comes the real app
53
- $user = 'apok';
54
- $messages = rand(0, 2);
55
-
56
- printf(__('Welcome %s!')."\n", $user);
57
-
58
- printf(__n('You have one new message.', 'You have %s new messages.', $messages)."\n", $messages);
59
-
60
- echo __("A string with low priority!", 'side')."\n";
61
-
62
- _e("Bye\n");
63
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/sample/languages/app-side.pot DELETED
@@ -1,21 +0,0 @@
1
- # SOME DESCRIPTIVE TITLE.
2
- # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
- # This file is distributed under the same license as the PACKAGE package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
6
- #, fuzzy
7
- msgid ""
8
- msgstr ""
9
- "Project-Id-Version: PACKAGE VERSION\n"
10
- "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n"
11
- "POT-Creation-Date: 2008-06-06 23:10+0300\n"
12
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "MIME-Version: 1.0\n"
16
- "Content-Type: text/plain; charset=CHARSET\n"
17
- "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
19
-
20
- msgid "A string with low priority!"
21
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/sample/languages/app.pot DELETED
@@ -1,34 +0,0 @@
1
- # SOME DESCRIPTIVE TITLE.
2
- # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
- # This file is distributed under the same license as the PACKAGE package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
6
- #, fuzzy
7
- msgid ""
8
- msgstr ""
9
- "Project-Id-Version: PACKAGE VERSION\n"
10
- "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n"
11
- "POT-Creation-Date: 2008-06-06 23:10+0300\n"
12
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "MIME-Version: 1.0\n"
16
- "Content-Type: text/plain; charset=CHARSET\n"
17
- "Content-Transfer-Encoding: 8bit\n"
18
- "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
19
-
20
- #: app.php:46
21
- #, php-format
22
- msgid "Welcome %s!"
23
- msgstr ""
24
-
25
- #: app.php:48
26
- #, php-format
27
- msgid "You have one new message."
28
- msgid_plural "You have %s new messages."
29
- msgstr[0] ""
30
- msgstr[1] ""
31
-
32
- #: app.php:50
33
- msgid "Bye\n"
34
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/sample/languages/bg-side.mo DELETED
Binary file
util/wp-i18n/pomo/sample/languages/bg-side.po DELETED
@@ -1,19 +0,0 @@
1
- # Bulgarian translations for PACKAGE package.
2
- # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
3
- # This file is distributed under the same license as the PACKAGE package.
4
- # Nikolay Bachiyski <nb@nikolay.bg>, 2008.
5
- #
6
- msgid ""
7
- msgstr ""
8
- "Project-Id-Version: PACKAGE VERSION\n"
9
- "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n"
10
- "POT-Creation-Date: 2008-06-06 23:10+0300\n"
11
- "PO-Revision-Date: 2008-06-06 22:54+0300\n"
12
- "Last-Translator: Nikolay Bachiyski <nb@nikolay.bg>\n"
13
- "Language-Team: Bulgarian\n"
14
- "MIME-Version: 1.0\n"
15
- "Content-Type: text/plain; charset=UTF-8\n"
16
- "Content-Transfer-Encoding: 8bit\n"
17
-
18
- msgid "A string with low priority!"
19
- msgstr "Смотан низ!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/pomo/sample/languages/bg.mo DELETED
Binary file
util/wp-i18n/pomo/sample/languages/bg.po DELETED
@@ -1,32 +0,0 @@
1
- # Bulgarian translations for PACKAGE package.
2
- # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
3
- # This file is distributed under the same license as the PACKAGE package.
4
- # Nikolay Bachiyski <nb@nikolay.bg>, 2008.
5
- #
6
- msgid ""
7
- msgstr ""
8
- "Project-Id-Version: PACKAGE VERSION\n"
9
- "Report-Msgid-Bugs-To: wp-polyglots@lists.automattic.com\n"
10
- "POT-Creation-Date: 2008-06-06 23:10+0300\n"
11
- "PO-Revision-Date: 2008-06-06 22:54+0300\n"
12
- "Last-Translator: Nikolay Bachiyski <nb@nikolay.bg>\n"
13
- "Language-Team: Bulgarian\n"
14
- "MIME-Version: 1.0\n"
15
- "Content-Type: text/plain; charset=UTF-8\n"
16
- "Content-Transfer-Encoding: 8bit\n"
17
-
18
- #: app.php:46
19
- #, php-format
20
- msgid "Welcome %s!"
21
- msgstr "Добре дошъл, %s!"
22
-
23
- #: app.php:48
24
- #, php-format
25
- msgid "You have one new message."
26
- msgid_plural "You have %s new messages."
27
- msgstr[0] "Имате едно ново съобщение."
28
- msgstr[1] "Имате %s нови съобщения."
29
-
30
- #: app.php:50
31
- msgid "Bye\n"
32
- msgstr "Чао\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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 718 2012-10-31 00:32:02Z nbachiyski $
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 commong logic for English is implmented:
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 implmentation 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;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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: pot-ext-meta.php 19937 2012-05-21 21:40:14Z nacin $
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
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/t/data/not-gettexted-0-result.php DELETED
@@ -1,24 +0,0 @@
1
- <?php
2
-
3
- if (! isset($wp_did_header)):
4
- if ( !file_exists( dirname(__FILE__) . '/wp-config.php') ) {
5
- if (strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false) $path = '';
6
- else $path = 'wp-admin/';
7
-
8
- require_once( dirname(__FILE__) . '/wp-includes/classes.php');
9
- require_once( dirname(__FILE__) . '/wp-includes/functions.php');
10
- require_once( dirname(__FILE__) . '/wp-includes/plugin.php');
11
- wp_die( sprintf(/*WP_I18N_CONFIG*/'Translation: There doesn\'t seem to be a <code>wp-config.php</code> file. I need this before we can get started. Need more help? <a href=\'http://codex.wordpress.org/Editing_wp-config.php\'>We got it</a>. You can create a <code>wp-config.php</code> file through a web interface, but this doesn\'t work for all server setups. The safest way is to manually create the file.</p><p><a href=\'%s\' class=\'button\'>Create a Configuration File</a>' /*/WP_I18N_CONFIG*/, $path.'setup-config.php'), /*WP_I18N_ERROR*/ 'Translation: WordPress &rsaquo; Error' /*/WP_I18N_ERROR*/);
12
- }
13
-
14
- $wp_did_header = true;
15
-
16
- require_once( dirname(__FILE__) . '/wp-config.php');
17
-
18
- wp();
19
-
20
- require_once(ABSPATH . WPINC . '/template-loader.php');
21
-
22
- endif;
23
-
24
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/t/data/not-gettexted-0-work.php DELETED
@@ -1,24 +0,0 @@
1
- <?php
2
-
3
- if (! isset($wp_did_header)):
4
- if ( !file_exists( dirname(__FILE__) . '/wp-config.php') ) {
5
- if (strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false) $path = '';
6
- else $path = 'wp-admin/';
7
-
8
- require_once( dirname(__FILE__) . '/wp-includes/classes.php');
9
- require_once( dirname(__FILE__) . '/wp-includes/functions.php');
10
- require_once( dirname(__FILE__) . '/wp-includes/plugin.php');
11
- wp_die( sprintf(/*WP_I18N_CONFIG*/'Translation: There doesn\'t seem to be a <code>wp-config.php</code> file. I need this before we can get started. Need more help? <a href=\'http://codex.wordpress.org/Editing_wp-config.php\'>We got it</a>. You can create a <code>wp-config.php</code> file through a web interface, but this doesn\'t work for all server setups. The safest way is to manually create the file.</p><p><a href=\'%s\' class=\'button\'>Create a Configuration File</a>' /*/WP_I18N_CONFIG*/, $path.'setup-config.php'), /*WP_I18N_ERROR*/ 'Translation: WordPress &rsaquo; Error' /*/WP_I18N_ERROR*/);
12
- }
13
-
14
- $wp_did_header = true;
15
-
16
- require_once( dirname(__FILE__) . '/wp-config.php');
17
-
18
- wp();
19
-
20
- require_once(ABSPATH . WPINC . '/template-loader.php');
21
-
22
- endif;
23
-
24
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/t/data/not-gettexted-0.mo DELETED
Binary file
util/wp-i18n/t/data/not-gettexted-0.php DELETED
@@ -1,24 +0,0 @@
1
- <?php
2
-
3
- if (! isset($wp_did_header)):
4
- if ( !file_exists( dirname(__FILE__) . '/wp-config.php') ) {
5
- if (strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false) $path = '';
6
- else $path = 'wp-admin/';
7
-
8
- require_once( dirname(__FILE__) . '/wp-includes/classes.php');
9
- require_once( dirname(__FILE__) . '/wp-includes/functions.php');
10
- require_once( dirname(__FILE__) . '/wp-includes/plugin.php');
11
- wp_die( sprintf(/*WP_I18N_CONFIG*/" There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started. Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>. You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file.</p><p><a href='%s' class='button'>Create a Configuration File</a>" /*/WP_I18N_CONFIG*/, $path.'setup-config.php'), /*WP_I18N_ERROR*/ "WordPress &rsaquo; Error" /*/WP_I18N_ERROR*/);
12
- }
13
-
14
- $wp_did_header = true;
15
-
16
- require_once( dirname(__FILE__) . '/wp-config.php');
17
-
18
- wp();
19
-
20
- require_once(ABSPATH . WPINC . '/template-loader.php');
21
-
22
- endif;
23
-
24
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/t/data/not-gettexted-0.po DELETED
@@ -1,21 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Project-Id-Version: \n"
4
- "POT-Creation-Date: \n"
5
- "PO-Revision-Date: 2008-04-22 19:23+0200\n"
6
- "Last-Translator: \n"
7
- "Language-Team: \n"
8
- "MIME-Version: 1.0\n"
9
- "Content-Type: text/plain; charset=iso-8859-1\n"
10
- "Content-Transfer-Encoding: 8bit\n"
11
-
12
- #. Not gettexted string WP_I18N_CONFIG
13
- #: not-gettext-0.php:11
14
- msgid " There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started. Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>. You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file.</p><p><a href='%s' class='button'>Create a Configuration File</a>"
15
- msgstr "Translation: There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started. Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>. You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file.</p><p><a href='%s' class='button'>Create a Configuration File</a>"
16
-
17
- #. Not gettexted string WP_I18N_ERROR
18
- #: not-gettext-0.php:11
19
- msgid "WordPress &rsaquo; Error"
20
- msgstr "Translation: WordPress &rsaquo; Error"
21
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/wp-i18n/t/run.sh DELETED
@@ -1,2 +0,0 @@
1
- #!/bin/sh
2
- phpunit Test_Not_Gettexted test_not-gettexted.php
 
 
util/wp-i18n/t/test_not-gettexted.php DELETED
@@ -1,50 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Tests for not-gettexted.php
5
- *
6
- * @version $Id: test_not-gettexted.php 19937 2012-05-21 21:40:14Z nacin $
7
- * @package wordpress-i18n
8
- * @subpackage tools
9
- */
10
- error_reporting(E_ALL);
11
- require_once 'PHPUnit/Framework.php';
12
- require_once dirname(__FILE__) . '/../not-gettexted.php';
13
-
14
- class Test_Not_Gettexted extends PHPUnit_Framework_TestCase {
15
-
16
- function __construct() {
17
- $this->ng = new NotGettexted;
18
- }
19
-
20
- function test_make_string_aggregator() {
21
- global $baba;
22
- $f = $this->ng->make_string_aggregator('baba', 'baba.php');
23
- call_user_func($f, 'x', 'y', 'z');
24
- call_user_func($f, 'a', 'b', 'c');
25
- $this->assertEquals(array(array('x', 'y', 'baba.php', 'z'), array('a', 'b', 'baba.php', 'c')), $baba);
26
- }
27
-
28
- function test_walk() {
29
- $code = '
30
- <?php
31
- $s = 8;
32
- echo /* WP_I18N_GUGU*/ "yes" /* /WP_I18N_UGU */;
33
- if ($x == "18181") { wp_die(sprintf(/*WP_I18N_DIE*/\'We died %d times!\'/*WP_I18N_DIE*/)); }
34
- ?>';
35
- $tokens = token_get_all($code);
36
- $this->assertEquals('', $this->ng->walk_tokens($tokens, array(&$this->ng, 'ignore_token'), array(&$this->ng, 'ignore_token')));
37
- $this->assertEquals('"yes"\'We died %d times!\'', $this->ng->walk_tokens($tokens, array(&$this->ng, 'unchanged_token'), array(&$this->ng, 'ignore_token')));
38
- $this->assertEquals($code, $this->ng->walk_tokens($tokens, array(&$this->ng, 'unchanged_token'), array(&$this->ng, 'unchanged_token')));
39
- $this->assertEquals($code, $this->ng->walk_tokens($tokens, array(&$this->ng, 'unchanged_token'), array(&$this->ng, 'unchanged_token')));
40
- }
41
-
42
- function test_replace() {
43
- # copy to a new file, so that we don't corrupt the old one
44
- copy('data/not-gettexted-0.php', 'data/not-gettexted-0-work.php');
45
- $this->ng->command_replace('data/not-gettexted-0.mo', 'data/not-gettexted-0-work.php');
46
- $this->assertEquals(file_get_contents('data/not-gettexted-0-result.php'), file_get_contents('data/not-gettexted-0-work.php'));
47
- unlink('data/not-gettexted-0-work.php');
48
- }
49
-
50
- }