i18n-tools: Respect the coding standards when adding textdomains with add-textdomain.php.

Props GaryJ, groovecoder.
Fixes #21616.

git-svn-id: https://develop.svn.wordpress.org/trunk@36603 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Dominik Schilling (ocean90) 2016-02-20 21:43:51 +00:00
parent 2ba684e7e4
commit 78ed4e109a
4 changed files with 106 additions and 44 deletions

View File

@ -17,40 +17,78 @@ class AddTextdomain {
/**
* Constructor.
*/
function __construct() {
public function __construct() {
$makepot = new MakePOT;
$this->funcs = array_keys( $makepot->rules );
$this->funcs[] = 'translate_nooped_plural';
}
function usage() {
/**
* Prints CLI usage.
*/
public function usage() {
$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";
fwrite(STDERR, $usage);
exit(1);
}
function process_token($token_text, $inplace) {
if ($inplace)
$this->modified_contents .= $token_text;
else
echo $token_text;
/**
* Adds textdomain to a single file.
*
* @see AddTextdomain::process_string()
*
* @param string $domain Text domain.
* @param string $source_filename Filename with optional path.
* @param bool $inplace True to modifies the PHP file in place. False to print to standard output.
*/
public function process_file( $domain, $source_filename, $inplace ) {
$new_source = $this->process_string( $domain, file_get_contents( $source_filename ) );
if ( $inplace ) {
$f = fopen( $source_filename, 'w' );
fwrite( $f, $new_source );
fclose( $f );
} else {
echo $new_source;
}
}
/**
* Adds textdomain to a string of PHP.
*
* Functions calls should be wrapped in opening and closing PHP delimiters as usual.
*
* @see AddTextdomain::process_tokens()
*
* @param string $domain Text domain.
* @param string $string PHP code to parse.
* @return string Modified source.
*/
public function process_string( $domain, $string ) {
$tokens = token_get_all( $string );
return $this->process_tokens( $domain, $tokens );
}
function process_file($domain, $source_filename, $inplace) {
/**
* Adds textdomain to a set of PHP tokens.
*
* @param string $domain Text domain.
* @param array $tokens PHP tokens. An array of token identifiers. Each individual token identifier is either a
* single character (i.e.: ;, ., >, !, etc.), or a three element array containing the token
* index in element 0, the string content of the original token in element 1 and the line
* number in element 2.
* @return string Modified source.
*/
public function process_tokens( $domain, $tokens ) {
$this->modified_contents = '';
$domain = addslashes($domain);
$source = file_get_contents($source_filename);
$tokens = token_get_all($source);
$domain = addslashes( $domain );
$in_func = false;
$args_started = false;
$parens_balance = 0;
$found_domain = false;
foreach($tokens as $token) {
foreach($tokens as $index => $token) {
$string_success = false;
if (is_array($token)) {
list($id, $text) = $token;
@ -71,26 +109,28 @@ class AddTextdomain {
} elseif (')' == $token) {
--$parens_balance;
if ($in_func && 0 == $parens_balance) {
$token = $found_domain? ')' : ", '$domain')";
if ( ! $found_domain ) {
$token = ", '$domain'";
if ( T_WHITESPACE == $tokens[ $index - 1 ][0] ) {
$token .= ' '; // Maintain code standards if previously present
// Remove previous whitespace token to account for it.
$this->modified_contents = trim( $this->modified_contents );
}
$token .= ')';
}
$in_func = false;
$args_started = false;
$found_domain = false;
}
}
$this->process_token($token, $inplace);
$this->modified_contents .= $token;
}
if ($inplace) {
$f = fopen($source_filename, 'w');
fwrite($f, $this->modified_contents);
fclose($f);
}
return $this->modified_contents;
}
}
// run the CLI only if the file
// wasn't included
// Run the CLI only if the file wasn't included.
$included_files = get_included_files();
if ($included_files[0] == __FILE__) {
$adddomain = new AddTextdomain();

View File

@ -10,15 +10,37 @@ require_once dirname( dirname( __FILE__ ) ) . '/add-textdomain.php';
class AddTextDomainTest extends PHPUnit_Framework_TestCase {
function __construct() {
$this->atd = new AddTextdomain;
function setUp() {
parent::setUp();
$this->atd = new AddTextdomain();
}
function test_add() {
# copy to a new file, so that we don't corrupt the old one
// Copy to a new file, so that we don't corrupt the old one.
copy( 'data/add-textdomain-0.php', 'data/add-textdomain-0-work.php' );
$this->atd->process_file( 'test-domain', 'data/add-textdomain-0-work.php', true );
$this->assertEquals( file_get_contents( 'data/add-textdomain-0-result.php' ), file_get_contents( 'data/add-textdomain-0-work.php' ) );
unlink( 'data/add-textdomain-0-work.php' );
}
/**
* @dataProvider data_textdomain_sources
*/
function test_basic_add_textdomain( $source, $expected ) {
$tokens = token_get_all( $source );
$result = $this->atd->process_tokens( 'foo', $tokens );
$this->assertEquals( $expected, $result );
}
function data_textdomain_sources() {
return array(
array( "<?php __('string'); ?>", "<?php __('string', 'foo'); ?>" ), // Simple single quotes
array( '<?php __("string"); ?>', "<?php __(\"string\", 'foo'); ?>" ), // Simple double quotes
array( "<?php __( 'string' ); ?>", "<?php __( 'string', 'foo' ); ?>" ), // Simple single quotes CS
array( '<?php __( "string" ); ?>', "<?php __( \"string\", 'foo' ); ?>" ), // Simple double quotes CS
array( "<?php __( 'string', 'string2' ); ?>", "<?php __( 'string', 'string2', 'foo' ); ?>" ), // Multiple string args
array( '<?php __( \'string\', $var ); ?>', '<?php __( \'string\', $var, \'foo\' ); ?>' ), // Multiple string / var args
array( "<?php __( 'string', 'foo' ); ?>", "<?php __( 'string', 'foo' ); ?>" ), // Existing textdomain
);
}
}

View File

@ -1,18 +1,18 @@
<?php
function call_some_i18n_methods() {
__( 'Hello World' , 'test-domain');
_e( 'Hello World' , 'test-domain');
_n( 'Single', 'Plural', 1 , 'test-domain');
_n_noop( 'Single Noop', 'Plural Noop', 1 , 'test-domain');
_x( 'Hello World', 'Testing' , 'test-domain');
_ex( 'Hello World', 'Testing' , 'test-domain');
_nx( 'Hello World', 'Testing' , 'test-domain');
_nx_noop( 'Hello World Noop', 'Testing' , 'test-domain');
esc_attr__( 'Attribute' , 'test-domain');
esc_html__( 'HTML' , 'test-domain');
esc_attr_e( 'Attribute' , 'test-domain');
esc_html_e( 'HTML' , 'test-domain');
esc_attr_x( 'Attribute', 'Testing' , 'test-domain');
esc_html_x( 'HTML', 'Testing' , 'test-domain');
translate_nooped_plural( 'Plural Noop', 2 , 'test-domain');
}
__( 'Hello World', 'test-domain' );
_e( 'Hello World', 'test-domain' );
_n( 'Single', 'Plural', 1, 'test-domain' );
_n_noop( 'Single Noop', 'Plural Noop', 1, 'test-domain' );
_x( 'Hello World', 'Testing', 'test-domain' );
_ex( 'Hello World', 'Testing', 'test-domain' );
_nx( 'Hello World', 'Testing', 'test-domain' );
_nx_noop( 'Hello World Noop', 'Testing', 'test-domain' );
esc_attr__( 'Attribute', 'test-domain' );
esc_html__( 'HTML', 'test-domain' );
esc_attr_e( 'Attribute', 'test-domain' );
esc_html_e( 'HTML', 'test-domain' );
esc_attr_x( 'Attribute', 'Testing', 'test-domain' );
esc_html_x( 'HTML', 'Testing', 'test-domain' );
translate_nooped_plural( 'Plural Noop', 2, 'test-domain' );
}

View File

@ -15,4 +15,4 @@ function call_some_i18n_methods() {
esc_attr_x( 'Attribute', 'Testing' );
esc_html_x( 'HTML', 'Testing' );
translate_nooped_plural( 'Plural Noop', 2 );
}
}