diff --git a/features/updatepo.feature b/features/updatepo.feature index 789f4652..4dad894c 100644 --- a/features/updatepo.feature +++ b/features/updatepo.feature @@ -516,7 +516,7 @@ Feature: Update existing PO files from a POT file When I run `wp i18n update-po foo-plugin/foo-plugin.pot` Then STDOUT should be: """ - Success: Updated 1 file. + Success: Updated 0 files. 1 file unchanged. """ And STDERR should be empty And the foo-plugin/foo-plugin-de_DE.po file should contain: @@ -527,3 +527,142 @@ Feature: Update existing PO files from a POT file """ "PO-Revision-Date: 2018-05-02T22:06:24+00:00\n" """ + + Scenario: Reports unchanged files when POT hasn't changed + Given an empty foo-plugin directory + And a foo-plugin/foo-plugin.pot 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 \n" + "Language-Team: LANGUAGE \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" + + #: foo-plugin.php:1 + msgid "Some string" + msgstr "" + """ + 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 \n" + "Language-Team: LANGUAGE \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:1 + msgid "Some string" + msgstr "Some translated string" + """ + + When I run `wp i18n update-po foo-plugin/foo-plugin.pot` + Then STDOUT should be: + """ + Success: Updated 0 files. 1 file unchanged. + """ + And STDERR should be empty + + Scenario: Reports both updated and unchanged files + Given an empty foo-plugin directory + And a foo-plugin/foo-plugin.pot 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 \n" + "Language-Team: LANGUAGE \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" + + #: foo-plugin.php:1 + msgid "Some string" + msgstr "" + + #: foo-plugin.php:15 + msgid "Another new string" + msgstr "" + """ + 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 \n" + "Language-Team: LANGUAGE \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 "Some string" + msgstr "Some translated string" + """ + And a foo-plugin/foo-plugin-es_ES.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 \n" + "Language-Team: LANGUAGE \n" + "Language: es_ES\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:1 + msgid "Some string" + msgstr "Some translated string" + + #: foo-plugin.php:15 + msgid "Another new string" + msgstr "Otra nueva cadena" + """ + + When I run `wp i18n update-po foo-plugin/foo-plugin.pot` + Then STDOUT should be: + """ + Success: Updated 1 file. 1 file unchanged. + """ + And STDERR should be empty diff --git a/src/UpdatePoCommand.php b/src/UpdatePoCommand.php index 4fec1706..51d801ab 100644 --- a/src/UpdatePoCommand.php +++ b/src/UpdatePoCommand.php @@ -41,6 +41,10 @@ class UpdatePoCommand extends WP_CLI_Command { * $ wp i18n update-po example-plugin.pot languages * Success: Updated 2 files. * + * # Shows message when some files don't need updating. + * $ wp i18n update-po example-plugin.pot languages + * Success: Updated 2 files. 1 file unchanged. + * * @when before_wp_load * * @throws WP_CLI\ExitException @@ -69,7 +73,8 @@ public function __invoke( $args, $assoc_args ) { $pot_translations = Translations::fromPoFile( $source ); - $result_count = 0; + $updated_count = 0; + $unchanged_count = 0; /** @var DirectoryIterator $file */ foreach ( $files as $file ) { if ( 'po' !== $file->getExtension() ) { @@ -81,12 +86,17 @@ public function __invoke( $args, $assoc_args ) { continue; } - $po_translations = Translations::fromPoFile( $file->getPathname() ); + $po_translations = Translations::fromPoFile( $file->getPathname() ); + $original_translations = clone $po_translations; + $po_translations->mergeWith( $pot_translations, Merge::ADD | Merge::REMOVE | Merge::COMMENTS_THEIRS | Merge::EXTRACTED_COMMENTS_THEIRS | Merge::REFERENCES_THEIRS | Merge::DOMAIN_OVERRIDE ); + // Check if the translations actually changed by comparing the objects. + $has_changes = $this->translations_differ( $original_translations, $po_translations ); + // Update PO-Revision-Date to current date and time in UTC. // Uses gmdate() for consistency across different server timezones. $po_translations->setHeader( 'PO-Revision-Date', gmdate( 'Y-m-d\TH:i:sP' ) ); @@ -96,9 +106,95 @@ public function __invoke( $args, $assoc_args ) { continue; } - ++$result_count; + if ( $has_changes ) { + ++$updated_count; + } else { + ++$unchanged_count; + } + } + + // Build the success message. + $message_parts = array(); + $message_parts[] = sprintf( 'Updated %d %s', $updated_count, Utils\pluralize( 'file', $updated_count ) ); + if ( $unchanged_count > 0 ) { + $message_parts[] = sprintf( '%d %s unchanged', $unchanged_count, Utils\pluralize( 'file', $unchanged_count ) ); + } + + WP_CLI::success( implode( '. ', $message_parts ) . '.' ); + } + + /** + * Check if two Translations objects differ. + * + * @param Translations $original Original translations. + * @param Translations $updated Updated translations. + * @return bool True if translations differ, false otherwise. + */ + private function translations_differ( Translations $original, Translations $updated ) { + // Quick check: if counts differ, they're different. + if ( count( $original ) !== count( $updated ) ) { + return true; + } + + // Compare each translation entry. + foreach ( $original as $translation ) { + $context = $translation->getContext(); + $original_str = $translation->getOriginal(); + + // Find the corresponding translation in the updated set. + $updated_translation = $updated->find( $context, $original_str ); + + // If translation doesn't exist in updated set, they differ. + if ( ! $updated_translation ) { + return true; + } + + // Compare translation strings. + if ( $translation->getTranslation() !== $updated_translation->getTranslation() ) { + return true; + } + + // Compare plural translations if they exist. + $original_plurals = $translation->getPluralTranslations(); + $updated_plurals = $updated_translation->getPluralTranslations(); + + if ( $original_plurals !== $updated_plurals ) { + return true; + } + + // Compare references (source code locations). + $original_refs = $translation->getReferences(); + $updated_refs = $updated_translation->getReferences(); + + sort( $original_refs ); + sort( $updated_refs ); + + if ( $original_refs !== $updated_refs ) { + return true; + } + + // Compare comments. + if ( $translation->getExtractedComments() !== $updated_translation->getExtractedComments() ) { + return true; + } + + if ( $translation->getComments() !== $updated_translation->getComments() ) { + return true; + } + } + + // Check if updated has any translations not in original. + foreach ( $updated as $translation ) { + $context = $translation->getContext(); + $original_str = $translation->getOriginal(); + + $original_translation = $original->find( $context, $original_str ); + + if ( ! $original_translation ) { + return true; + } } - WP_CLI::success( sprintf( 'Updated %d %s.', $result_count, Utils\pluralize( 'file', $result_count ) ) ); + return false; } }