From 27715e88ab371e4f55803c0406f0bcf1faff1ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:26:31 +0100 Subject: [PATCH 1/3] Add the check for the leading and trailing spaces --- WordPress/Sniffs/WP/I18nSniff.php | 44 +++++++++++++++++++++ WordPress/Tests/WP/I18nUnitTest.1.inc | 23 +++++++++++ WordPress/Tests/WP/I18nUnitTest.1.inc.fixed | 23 +++++++++++ WordPress/Tests/WP/I18nUnitTest.php | 22 +++++++++++ 4 files changed, 112 insertions(+) diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index bf9b9936ec..7bc449a793 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -380,6 +380,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $has_content = $this->check_string_has_translatable_content( $matched_content, $param_name, $param_info ); if ( true === $has_content ) { $this->check_string_has_no_html_wrapper( $matched_content, $param_name, $param_info ); + $this->check_string_has_no_leading_trailing_spaces( $matched_content, $param_name, $param_info ); } } } @@ -804,6 +805,49 @@ private function check_string_has_no_html_wrapper( $matched_content, $param_name } } + /** + * Check if a translatable string has leading or trailing spaces. + * + * @since 3.2.0 + * + * @param string $matched_content The token content (function name) which was matched + * in lowercase. + * @param string $param_name The name of the parameter being examined. + * @param array|false $param_info Parameter info array for an individual parameter, + * as received from the PassedParameters class. + * + * @return void + */ + private function check_string_has_no_leading_trailing_spaces( $matched_content, $param_name, $param_info ) { + // Strip surrounding quotes. + $content_without_quotes = TextStrings::stripQuotes( $param_info['clean'] ); + $first_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, $param_info['start'], ( $param_info['end'] + 1 ), true ); + + if ( ltrim( $content_without_quotes ) !== $content_without_quotes ) { + $this->phpcsFile->addError( + 'Translatable string should not have leading spaces. Found: %s', + $first_non_empty, + 'NoLeadingTrailingSpaces', + array( $param_info['clean'] ) + ); + } + if ( rtrim( $content_without_quotes ) !== $content_without_quotes ) { + $this->phpcsFile->addError( + 'Translatable string should not have trailing spaces. Found: %s', + $first_non_empty, + 'NoLeadingTrailingSpaces', + array( $param_info['clean'] ) + ); + } + + if ('cadena' == $param_info['raw']) { + fwrite(STDERR, "\n" . '$matched_content: ' . print_r($matched_content, TRUE)); + fwrite(STDERR, "\n" . '$param_name: ' . print_r($param_name, TRUE)); + fwrite(STDERR, "\n" . '$param_info: ' . print_r($param_info, TRUE)); + exit(1); + } + } + /** * Check for inconsistencies in the placeholders between single and plural form of the translatable text string. * diff --git a/WordPress/Tests/WP/I18nUnitTest.1.inc b/WordPress/Tests/WP/I18nUnitTest.1.inc index 6256e6d84a..d5d80f8e70 100644 --- a/WordPress/Tests/WP/I18nUnitTest.1.inc +++ b/WordPress/Tests/WP/I18nUnitTest.1.inc @@ -317,4 +317,27 @@ esc_html_e( 'foo', '' ); // Bad: text-domain can not be empty. // PHP 8.0+: safeguard handling of newly introduced placeholders. __( 'There are %1$h monkeys in the %H', 'my-slug' ); // Bad: multiple arguments should be numbered. +__( ' string', 'my-slug' ); // Bad: leading space. +_e( 'string ', 'my-slug' ); // Bad: trailing space. +_x( ' string ', 'context', 'my-slug' ); // Bad: leading and trailing spaces. +_ex( ' string', 'context', 'my-slug' ); // Bad: leading spaces. +_n( ' There is %1$d monkey in the %2$s', 'In the %2$s there are %1$d monkeys', $number, 'my-slug' ); // Bad: leading space. +_n( 'There is %1$d monkey in the %2$s', 'In the %2$s there are %1$d monkeys ', $number, 'my-slug' ); // Bad: trailing space. +_n( ' There is %1$d monkey in the %2$s', 'In the %2$s there are %1$d monkeys ', $number, 'my-slug' ); // Bad: leading and trailing spaces. +_nx( ' I have %d cat.', 'I have %d cats.', $number, 'Not really.', 'my-slug' ); // Bad: leading spaces. +_nx( 'I have %d cat.', 'I have %d cats. ', $number, 'Not really.', 'my-slug' ); // Bad: trailing spaces. +_nx( ' I have %d cat.', 'I have %d cats. ', $number, 'Not really.', 'my-slug' ); // Bad: leading and trailing spaces. +_n_noop( ' I have %d cat.', 'I have %d cats.', 'my-slug' ); // Bad: leading space. +_n_noop( 'I have %d cat.', 'I have %d cats. ', 'my-slug' ); // Bad: trailing space. +_n_noop( ' I have %d cat.', 'I have %d cats. ', 'my-slug' ); // Bad: leading and trailing spaces. +_nx_noop( ' I have %d cat.', 'I have %d cats.', 'Not really.', 'my-slug' ); // Bad: leading spaces. +_nx_noop( 'I have %d cat.', 'I have %d cats. ', 'Not really.', 'my-slug' ); // Bad: trailing spaces. +_nx_noop( ' I have %d cat.', 'I have %d cats. ', 'Not really.', 'my-slug' ); // Bad: leading and trailing spaces. +esc_html__( ' string', 'my-slug' ); // Bad: leading space. +esc_html_e( 'string ', 'my-slug' ); // Bad: trailing space. +esc_html_x( ' string ', 'context', 'my-slug' ); // Bad: leading and trailing spaces. +esc_attr__( ' string', 'my-slug' ); // Bad: leading space. +esc_attr_e( 'string ', 'my-slug' ); // Bad: trailing space. +esc_attr_x( ' string ', 'context', 'my-slug' ); // Bad: leading and trailing spaces. + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment diff --git a/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed b/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed index b23e9b6192..c884f83963 100644 --- a/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed +++ b/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed @@ -317,4 +317,27 @@ esc_html_e( 'foo', '' ); // Bad: text-domain can not be empty. // PHP 8.0+: safeguard handling of newly introduced placeholders. __( 'There are %1$h monkeys in the %H', 'my-slug' ); // Bad: multiple arguments should be numbered. +__( ' string', 'my-slug' ); // Bad: leading space. +_e( 'string ', 'my-slug' ); // Bad: trailing space. +_x( ' string ', 'context', 'my-slug' ); // Bad: leading and trailing spaces. +_ex( ' string', 'context', 'my-slug' ); // Bad: leading spaces. +_n( ' There is %1$d monkey in the %2$s', 'In the %2$s there are %1$d monkeys', $number, 'my-slug' ); // Bad: leading space. +_n( 'There is %1$d monkey in the %2$s', 'In the %2$s there are %1$d monkeys ', $number, 'my-slug' ); // Bad: trailing space. +_n( ' There is %1$d monkey in the %2$s', 'In the %2$s there are %1$d monkeys ', $number, 'my-slug' ); // Bad: leading and trailing spaces. +_nx( ' I have %d cat.', 'I have %d cats.', $number, 'Not really.', 'my-slug' ); // Bad: leading spaces. +_nx( 'I have %d cat.', 'I have %d cats. ', $number, 'Not really.', 'my-slug' ); // Bad: trailing spaces. +_nx( ' I have %d cat.', 'I have %d cats. ', $number, 'Not really.', 'my-slug' ); // Bad: leading and trailing spaces. +_n_noop( ' I have %d cat.', 'I have %d cats.', 'my-slug' ); // Bad: leading space. +_n_noop( 'I have %d cat.', 'I have %d cats. ', 'my-slug' ); // Bad: trailing space. +_n_noop( ' I have %d cat.', 'I have %d cats. ', 'my-slug' ); // Bad: leading and trailing spaces. +_nx_noop( ' I have %d cat.', 'I have %d cats.', 'Not really.', 'my-slug' ); // Bad: leading spaces. +_nx_noop( 'I have %d cat.', 'I have %d cats. ', 'Not really.', 'my-slug' ); // Bad: trailing spaces. +_nx_noop( ' I have %d cat.', 'I have %d cats. ', 'Not really.', 'my-slug' ); // Bad: leading and trailing spaces. +esc_html__( ' string', 'my-slug' ); // Bad: leading space. +esc_html_e( 'string ', 'my-slug' ); // Bad: trailing space. +esc_html_x( ' string ', 'context', 'my-slug' ); // Bad: leading and trailing spaces. +esc_attr__( ' string', 'my-slug' ); // Bad: leading space. +esc_attr_e( 'string ', 'my-slug' ); // Bad: trailing space. +esc_attr_x( ' string ', 'context', 'my-slug' ); // Bad: leading and trailing spaces. + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment diff --git a/WordPress/Tests/WP/I18nUnitTest.php b/WordPress/Tests/WP/I18nUnitTest.php index 3834eb189f..f88102c710 100644 --- a/WordPress/Tests/WP/I18nUnitTest.php +++ b/WordPress/Tests/WP/I18nUnitTest.php @@ -148,6 +148,28 @@ public function getErrorList( $testFile = '' ) { 311 => 1, 315 => 1, 318 => 1, + 320 => 1, + 321 => 1, + 322 => 2, + 323 => 1, + 324 => 1, + 325 => 1, + 326 => 2, + 327 => 1, + 328 => 1, + 329 => 2, + 330 => 1, + 331 => 1, + 332 => 2, + 333 => 1, + 334 => 1, + 335 => 2, + 336 => 1, + 337 => 1, + 338 => 2, + 339 => 1, + 340 => 1, + 341 => 2, ); case 'I18nUnitTest.2.inc': From 436cd2506d7a21e22bff1738280a099bcd0e243c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:33:27 +0100 Subject: [PATCH 2/3] Remove a debug code --- WordPress/Sniffs/WP/I18nSniff.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 7bc449a793..268d49be93 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -839,13 +839,6 @@ private function check_string_has_no_leading_trailing_spaces( $matched_content, array( $param_info['clean'] ) ); } - - if ('cadena' == $param_info['raw']) { - fwrite(STDERR, "\n" . '$matched_content: ' . print_r($matched_content, TRUE)); - fwrite(STDERR, "\n" . '$param_name: ' . print_r($param_name, TRUE)); - fwrite(STDERR, "\n" . '$param_info: ' . print_r($param_info, TRUE)); - exit(1); - } } /** From 7f311cb55e6f5356bf55edff8aa449263bef6061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:50:33 +0100 Subject: [PATCH 3/3] Lint --- WordPress/Sniffs/WP/I18nSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 268d49be93..3d7303307b 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -821,7 +821,7 @@ private function check_string_has_no_html_wrapper( $matched_content, $param_name private function check_string_has_no_leading_trailing_spaces( $matched_content, $param_name, $param_info ) { // Strip surrounding quotes. $content_without_quotes = TextStrings::stripQuotes( $param_info['clean'] ); - $first_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, $param_info['start'], ( $param_info['end'] + 1 ), true ); + $first_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, $param_info['start'], ( $param_info['end'] + 1 ), true ); if ( ltrim( $content_without_quotes ) !== $content_without_quotes ) { $this->phpcsFile->addError(