Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions features/makejson.feature
Original file line number Diff line number Diff line change
Expand Up @@ -1089,3 +1089,51 @@ Feature: Split PO files into JSON files.
"""
"source":"app.min.admin.js"
"""

Scenario: Prints validation warnings for strings with placeholders
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.js:10
msgid "Hello, %s"
msgstr "Hallo, %s"

#: foo-plugin.js:15
msgid "One Comment"
msgid_plural "%s Comments"
msgstr[0] "Ein Kommentar"
msgstr[1] "%s Kommentare"
"""

When I try `wp i18n make-json foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And STDERR should contain:
"""
Warning: The string "Hello, %s" contains placeholders but has no "translators:" comment to clarify their meaning. (foo-plugin.js:10)
"""
And STDERR should contain:
"""
Warning: Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals (foo-plugin.js:15)
"""
And the return code should be 0

48 changes: 48 additions & 0 deletions features/makemo.feature
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,51 @@ Feature: Generate MO files from PO files
JS Only Translation
"""

Scenario: Prints validation warnings for strings with placeholders
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.php:10
msgid "Hello, %s"
msgstr "Hallo, %s"

#: foo-plugin.php:15
msgid "One Comment"
msgid_plural "%s Comments"
msgstr[0] "Ein Kommentar"
msgstr[1] "%s Kommentare"
"""

When I try `wp i18n make-mo foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And STDERR should contain:
"""
Warning: The string "Hello, %s" contains placeholders but has no "translators:" comment to clarify their meaning. (foo-plugin.php:10)
"""
And STDERR should contain:
"""
Warning: Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals (foo-plugin.php:15)
"""
And the return code should be 0
And the foo-plugin/foo-plugin-de_DE.mo file should exist

59 changes: 55 additions & 4 deletions features/makephp.feature
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,16 @@ Feature: Generate PHP files from PO files
msgstr "[%s] Export personenbezogener Daten"
"""

When I run `wp i18n make-php foo-plugin`
When I try `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And the return code should be 0
And STDERR should be empty
And STDERR should contain:
"""
Warning:
"""
And the foo-plugin/foo-plugin-de_DE.l10n.php file should contain:
"""
<?php
Expand Down Expand Up @@ -194,7 +197,7 @@ Feature: Generate PHP files from PO files
msgstr[1] "Sie haben %d neue Nachrichten"
"""

When I run `wp i18n make-php foo-plugin`
When I try `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
Expand Down Expand Up @@ -249,7 +252,7 @@ Feature: Generate PHP files from PO files
msgstr[1] ""
"""

When I run `wp i18n make-php foo-plugin`
When I try `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
Expand Down Expand Up @@ -364,3 +367,51 @@ Feature: Generate PHP files from PO files
JS Only Translation
"""

Scenario: Prints validation warnings for strings with placeholders
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.php:10
msgid "Hello, %s"
msgstr "Hallo, %s"

#: foo-plugin.php:15
msgid "One Comment"
msgid_plural "%s Comments"
msgstr[0] "Ein Kommentar"
msgstr[1] "%s Kommentare"
"""

When I try `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And STDERR should contain:
"""
Warning: The string "Hello, %s" contains placeholders but has no "translators:" comment to clarify their meaning. (foo-plugin.php:10)
"""
And STDERR should contain:
"""
Warning: Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals (foo-plugin.php:15)
"""
And the return code should be 0
And the foo-plugin/foo-plugin-de_DE.l10n.php file should exist

5 changes: 5 additions & 0 deletions src/MakeJsonCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use SplFileInfo;

class MakeJsonCommand extends WP_CLI_Command {
use StringAuditTrait;

/**
* Options passed to json_encode().
*
Expand Down Expand Up @@ -220,6 +222,9 @@ protected function make_json( $source_file, $destination, $map, $domain, $extens

PoExtractor::fromFile( $source_file, $translations );

// Audit strings for potential issues.
$this->perform_string_audit( $translations );

$base_file_name = basename( $source_file, '.po' );

$domain = ( ! empty( $domain ) ) ? $domain : $translations->getDomain();
Expand Down
4 changes: 4 additions & 0 deletions src/MakeMoCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

class MakeMoCommand extends WP_CLI_Command {
use JsStringFilterTrait;
use StringAuditTrait;

/**
* Create MO files from PO files.
Expand Down Expand Up @@ -92,6 +93,9 @@ public function __invoke( $args, $assoc_args ) {

$translations = Translations::fromPoFile( $file->getPathname() );

// Audit strings for potential issues.
$this->perform_string_audit( $translations );

// Remove JS-only strings from MO files to keep them small.
$this->remove_js_only_strings( $translations );

Expand Down
4 changes: 4 additions & 0 deletions src/MakePhpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

class MakePhpCommand extends WP_CLI_Command {
use JsStringFilterTrait;
use StringAuditTrait;

/**
* Create PHP files from PO files.
Expand Down Expand Up @@ -86,6 +87,9 @@ public function __invoke( $args, $assoc_args ) {

$translations = Translations::fromPoFile( $file->getPathname() );

// Audit strings for potential issues.
$this->perform_string_audit( $translations );

// Remove JS-only strings from PHP files to keep them small.
$this->remove_js_only_strings( $translations );

Expand Down
131 changes: 4 additions & 127 deletions src/MakePotCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use IteratorIterator;

class MakePotCommand extends WP_CLI_Command {
use StringAuditTrait;

/**
* @var string
*/
Expand Down Expand Up @@ -780,133 +782,8 @@ protected function extract_strings() {
* @param Translations $translations Translations object.
*/
protected function audit_strings( $translations ) {
foreach ( $translations as $translation ) {
/** @var Translation $translation */

$references = $translation->getReferences();

// File headers don't have any file references.
$location = $translation->hasReferences() ? '(' . implode( ':', $references[0] ) . ')' : '';

// Check 1: Flag strings with placeholders that should have translator comments.
if (
! $translation->hasExtractedComments() &&
preg_match( self::SPRINTF_PLACEHOLDER_REGEX, $translation->getOriginal(), $placeholders ) >= 1
) {
$message = sprintf(
'The string "%1$s" contains placeholders but has no "translators:" comment to clarify their meaning. %2$s',
$translation->getOriginal(),
$location
);
WP_CLI::warning( $message );
}

// Check 2: Flag strings with different translator comments.
if ( $translation->hasExtractedComments() ) {
$comments = $translation->getExtractedComments();

// Remove plugin header information from comments.
$comments = array_filter(
$comments,
function ( $comment ) {
/** @var ParsedComment|string $comment */
/** @var string $file_header */
foreach ( $this->get_file_headers( $this->project_type ) as $file_header ) {
if ( 0 === strpos( ( $comment instanceof ParsedComment ? $comment->getComment() : $comment ), $file_header ) ) {
return null;
}
}

return $comment;
}
);

$unique_comments = array();

// Remove duplicate comments.
$comments = array_filter(
$comments,
function ( $comment ) use ( &$unique_comments ) {
/** @var ParsedComment|string $comment */
if ( in_array( ( $comment instanceof ParsedComment ? $comment->getComment() : $comment ), $unique_comments, true ) ) {
return null;
}

$unique_comments[] = ( $comment instanceof ParsedComment ? $comment->getComment() : $comment );

return $comment;
}
);

$comments_count = count( $comments );

if ( $comments_count > 1 ) {
$message = sprintf(
"The string \"%1\$s\" has %2\$d different translator comments. %3\$s\n%4\$s",
$translation->getOriginal(),
$comments_count,
$location,
implode( "\n", $unique_comments )
);
WP_CLI::warning( $message );
}
}

$non_placeholder_content = trim( preg_replace( '`^([\'"])(.*)\1$`Ds', '$2', $translation->getOriginal() ) );
$non_placeholder_content = preg_replace( self::SPRINTF_PLACEHOLDER_REGEX, '', $non_placeholder_content );

// Check 3: Flag empty strings without any translatable content.
if ( '' === $non_placeholder_content ) {
$message = sprintf(
'Found string without translatable content. %s',
$location
);
WP_CLI::warning( $message );
}

// Check 4: Flag strings with multiple unordered placeholders (%s %s %s vs. %1$s %2$s %3$s).
$unordered_matches_count = preg_match_all( self::UNORDERED_SPRINTF_PLACEHOLDER_REGEX, $translation->getOriginal(), $unordered_matches );
$unordered_matches = $unordered_matches[0];

if ( $unordered_matches_count >= 2 ) {
$message = sprintf(
'Multiple placeholders should be ordered. %s',
$location
);
WP_CLI::warning( $message );
}

if ( $translation->hasPlural() ) {
preg_match_all( self::SPRINTF_PLACEHOLDER_REGEX, $translation->getOriginal(), $single_placeholders );
$single_placeholders = $single_placeholders[0];

preg_match_all( self::SPRINTF_PLACEHOLDER_REGEX, $translation->getPlural(), $plural_placeholders );
$plural_placeholders = $plural_placeholders[0];

// see https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals
if ( count( $single_placeholders ) < count( $plural_placeholders ) ) {
// Check 5: Flag things like _n( 'One comment', '%s Comments' )
$message = sprintf(
'Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals %s',
$location
);
WP_CLI::warning( $message );
} else {
// Reordering is fine, but mismatched placeholders is probably wrong.
sort( $single_placeholders );
sort( $plural_placeholders );

// Check 6: Flag things like _n( '%s Comment (%d)', '%s Comments (%s)' )
if ( $single_placeholders !== $plural_placeholders ) {
$message = sprintf(
'Mismatched placeholders for singular and plural string. %s',
$location
);
WP_CLI::warning( $message );
}
}
}
}
// Call the trait's perform_string_audit method with the appropriate file headers.
$this->perform_string_audit( $translations, $this->get_file_headers( $this->project_type ) );
}

/**
Expand Down
Loading