diff --git a/features/language-core.feature b/features/language-core.feature index b3d9b56a..ecab9c70 100644 --- a/features/language-core.feature +++ b/features/language-core.feature @@ -477,6 +477,77 @@ Feature: Manage core translation files for a WordPress install | nl_NL | installed | And STDERR should be empty + @require-wp-4.0 + Scenario: Core translation update with format flag + Given a WP install + And an empty cache + + When I run `wp language core update --format=json` + Then STDOUT should be: + """ + [] + """ + And STDERR should be empty + + When I run `wp language core update --format=csv` + Then STDOUT should be empty + And STDERR should be empty + + When I run `wp language core update --format=summary` + Then STDOUT should contain: + """ + Success: Translations are up to date. + """ + And STDERR should be empty + + @require-wp-6.0 @require-php-7.2 + Scenario Outline: Core translation update with dry-run and format flag + Given an empty directory + And WP files + And a database + And I run `wp core download --version= --force` + And wp-config.php + And I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` + + When I run `wp language core install en_CA ja` + Then STDERR should be empty + + Given I try `wp core download --version= --force` + Then the return code should be 0 + And I run `wp core update-db` + + When I run `wp language core list --fields=language,status,update` + Then STDOUT should be a table containing rows: + | language | status | update | + | en_CA | installed | available | + | ja | installed | available | + + When I run `wp language core update --dry-run --format=json` + Then STDOUT should be JSON containing: + """ + [{"Type":"Core","Name":"WordPress","Version":""}] + """ + And STDERR should be empty + + When I run `wp language core update --dry-run --format=csv` + Then STDOUT should contain: + """ + Type,Name,Version,Language + """ + And STDOUT should contain: + """ + Core,WordPress, + """ + And STDERR should be empty + + When I run `wp language core update --dry-run --format=summary` + Then STDOUT should be empty + And STDERR should be empty + + Examples: + | original | update | + | 6.5 | 6.6 | + @require-wp-4.0 Scenario: Install languages with different output formats Given a WP install diff --git a/features/language-plugin.feature b/features/language-plugin.feature index e24a4df2..b738af15 100644 --- a/features/language-plugin.feature +++ b/features/language-plugin.feature @@ -443,6 +443,119 @@ Feature: Manage plugin translation files for a WordPress install And STDERR should be empty @require-wp-4.0 + Scenario: Plugin translation update with format flag + Given a WP install + + When I run `wp plugin install hello-dolly --force` + Then STDERR should be empty + + When I run `wp language plugin update hello-dolly --format=json` + Then STDOUT should be: + """ + [] + """ + And STDERR should be empty + + When I run `wp language plugin update --all --format=csv` + Then STDOUT should be empty + And STDERR should be empty + + When I run `wp language plugin update --all --format=summary` + Then STDOUT should contain: + """ + Success: Translations are up to date. + """ + And STDERR should be empty + + @require-wp-4.0 + Scenario: Plugin translation update with format flag and actual updates + Given a WP install + And an empty cache + + When I run `wp plugin install akismet --version=3.2 --force` + Then STDERR should be empty + + When I run `wp language plugin install akismet de_DE` + Then STDERR should be empty + + When I run `wp plugin install akismet --version=4.0 --force` + And I run `wp language plugin list akismet --fields=plugin,language,update,status` + Then STDOUT should be a table containing rows: + | plugin | language | update | status | + | akismet | de_DE | available | installed | + + When I run `wp language plugin update akismet --format=json` + Then STDOUT should be JSON containing: + """ + [{"slug":"akismet","language":"de_DE","status":"updated"}] + """ + And STDERR should be empty + + When I run `wp language plugin uninstall akismet de_DE` + And I run `wp plugin install akismet --version=3.2 --force` + And I run `wp language plugin install akismet de_DE` + And I run `wp plugin install akismet --version=4.0 --force` + And I run `wp language plugin update akismet --format=csv` + Then STDOUT should contain: + """ + slug,language,status + """ + And STDOUT should contain: + """ + akismet,de_DE,updated + """ + And STDERR should be empty + + When I run `wp language plugin uninstall akismet de_DE` + And I run `wp plugin install akismet --version=3.2 --force` + And I run `wp language plugin install akismet de_DE` + And I run `wp plugin install akismet --version=4.0 --force` + And I run `wp language plugin update akismet --format=summary` + Then STDOUT should contain: + """ + Success: Updated 1/1 translation. + """ + And STDERR should be empty + + @require-wp-4.0 + Scenario: Plugin translation update with dry-run and format flag + Given a WP install + And an empty cache + + When I run `wp plugin install akismet --version=3.2 --force` + Then STDERR should be empty + + When I run `wp language plugin install akismet de_DE` + Then STDERR should be empty + + When I run `wp plugin install akismet --version=4.0 --force` + And I run `wp language plugin list akismet --fields=plugin,language,update,status` + Then STDOUT should be a table containing rows: + | plugin | language | update | status | + | akismet | de_DE | available | installed | + + When I run `wp language plugin update akismet --dry-run --format=json` + Then STDOUT should contain: + """ + "Type":"Plugin" + """ + And STDERR should be empty + + When I run `wp language plugin update akismet --dry-run --format=csv` + Then STDOUT should contain: + """ + Type,Name,Version,Language + """ + And STDOUT should contain: + """ + Plugin,"Akismet + """ + And STDERR should be empty + + When I run `wp language plugin update akismet --dry-run --format=summary` + Then STDOUT should be empty + And STDERR should be empty + Scenario: Handle plugins with text domain different from slug Given a WP install And an empty cache diff --git a/features/language-theme.feature b/features/language-theme.feature index 3739e18e..cb58ea17 100644 --- a/features/language-theme.feature +++ b/features/language-theme.feature @@ -327,6 +327,119 @@ Feature: Manage theme translation files for a WordPress install And STDERR should be empty @require-wp-4.0 + Scenario: Theme translation update with format flag + Given a WP install + + When I try `wp theme install twentyten` + Then STDOUT should not be empty + + When I run `wp language theme update twentyten --format=json` + Then STDOUT should be: + """ + [] + """ + And STDERR should be empty + + When I run `wp language theme update --all --format=csv` + Then STDOUT should be empty + And STDERR should be empty + + When I run `wp language theme update --all --format=summary` + Then STDOUT should contain: + """ + Success: Translations are up to date. + """ + And STDERR should be empty + + @require-wp-4.0 + Scenario: Theme translation update with format flag and actual updates + Given a WP install + And an empty cache + + When I run `wp theme install twentyfifteen --version=2.0 --force` + Then STDERR should be empty + + When I run `wp language theme install twentyfifteen de_DE` + Then STDERR should be empty + + When I run `wp theme install twentyfifteen --version=2.5 --force` + And I run `wp language theme list twentyfifteen --fields=theme,language,update,status` + Then STDOUT should be a table containing rows: + | theme | language | update | status | + | twentyfifteen | de_DE | available | installed | + + When I run `wp language theme update twentyfifteen --format=json` + Then STDOUT should be JSON containing: + """ + [{"slug":"twentyfifteen","language":"de_DE","status":"updated"}] + """ + And STDERR should be empty + + When I run `wp language theme uninstall twentyfifteen de_DE` + And I run `wp theme install twentyfifteen --version=2.0 --force` + And I run `wp language theme install twentyfifteen de_DE` + And I run `wp theme install twentyfifteen --version=2.5 --force` + And I run `wp language theme update twentyfifteen --format=csv` + Then STDOUT should contain: + """ + slug,language,status + """ + And STDOUT should contain: + """ + twentyfifteen,de_DE,updated + """ + And STDERR should be empty + + When I run `wp language theme uninstall twentyfifteen de_DE` + And I run `wp theme install twentyfifteen --version=2.0 --force` + And I run `wp language theme install twentyfifteen de_DE` + And I run `wp theme install twentyfifteen --version=2.5 --force` + And I run `wp language theme update twentyfifteen --format=summary` + Then STDOUT should contain: + """ + Success: Updated 1/1 translation. + """ + And STDERR should be empty + + @require-wp-4.0 + Scenario: Theme translation update with dry-run and format flag + Given a WP install + And an empty cache + + When I run `wp theme install twentyfifteen --version=2.0 --force` + Then STDERR should be empty + + When I run `wp language theme install twentyfifteen de_DE` + Then STDERR should be empty + + When I run `wp theme install twentyfifteen --version=2.5 --force` + And I run `wp language theme list twentyfifteen --fields=theme,language,update,status` + Then STDOUT should be a table containing rows: + | theme | language | update | status | + | twentyfifteen | de_DE | available | installed | + + When I run `wp language theme update twentyfifteen --dry-run --format=json` + Then STDOUT should be JSON containing: + """ + [{"Type":"Theme","Name":"Twenty Fifteen"}] + """ + And STDERR should be empty + + When I run `wp language theme update twentyfifteen --dry-run --format=csv` + Then STDOUT should contain: + """ + Type,Name,Version,Language + """ + And STDOUT should contain: + """ + Theme,"Twenty Fifteen" + """ + And STDERR should be empty + + When I run `wp language theme update twentyfifteen --dry-run --format=summary` + Then STDOUT should be empty + And STDERR should be empty + Scenario: Handle themes with text domain different from slug Given a WP install And an empty cache diff --git a/src/Core_Language_Command.php b/src/Core_Language_Command.php index a2f5ac8c..16347599 100644 --- a/src/Core_Language_Command.php +++ b/src/Core_Language_Command.php @@ -389,6 +389,18 @@ public function uninstall( $args ) { * [--dry-run] * : Preview which translations would be updated. * + * [--format=] + * : Render output in a particular format. When not specified, updates show + * progress messages and success/warning/error messages. When specified, + * the output format changes based on the selected format. + * --- + * options: + * - table + * - csv + * - json + * - summary + * --- + * * ## EXAMPLES * * # Update installed core languages packs. @@ -401,7 +413,7 @@ public function uninstall( $args ) { * @subcommand update * * @param string[] $args Positional arguments. - * @param array{'dry-run'?: bool} $assoc_args Associative arguments. + * @param array{'dry-run'?: bool, format?: string} $assoc_args Associative arguments. */ public function update( $args, $assoc_args ) { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found -- Overruling the documentation, so not useless ;-). parent::update( $args, $assoc_args ); diff --git a/src/Plugin_Language_Command.php b/src/Plugin_Language_Command.php index a9bc5039..e6f10d3e 100644 --- a/src/Plugin_Language_Command.php +++ b/src/Plugin_Language_Command.php @@ -591,6 +591,18 @@ public function uninstall( $args, $assoc_args ) { * [--dry-run] * : Preview which translations would be updated. * + * [--format=] + * : Render output in a particular format. When not specified, updates show + * progress messages and success/warning/error messages. When specified, + * the output format changes based on the selected format. + * --- + * options: + * - table + * - csv + * - json + * - summary + * --- + * * ## EXAMPLES * * # Update all installed language packs for all plugins. @@ -603,7 +615,7 @@ public function uninstall( $args, $assoc_args ) { * @subcommand update * * @param string[] $args Positional arguments. - * @param array{'dry-run'?: bool, all?: bool} $assoc_args Associative arguments. + * @param array{'dry-run'?: bool, all?: bool, format?: string} $assoc_args Associative arguments. */ public function update( $args, $assoc_args ) { $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); diff --git a/src/Theme_Language_Command.php b/src/Theme_Language_Command.php index fd0548ac..7e5bce13 100644 --- a/src/Theme_Language_Command.php +++ b/src/Theme_Language_Command.php @@ -610,6 +610,18 @@ public function uninstall( $args, $assoc_args ) { * [--dry-run] * : Preview which translations would be updated. * + * [--format=] + * : Render output in a particular format. When not specified, updates show + * progress messages and success/warning/error messages. When specified, + * the output format changes based on the selected format. + * --- + * options: + * - table + * - csv + * - json + * - summary + * --- + * * ## EXAMPLES * * # Update all installed language packs for all themes. @@ -622,7 +634,7 @@ public function uninstall( $args, $assoc_args ) { * @subcommand update * * @param string[] $args Positional arguments. - * @param array{'dry-run'?: bool, all?: bool} $assoc_args Associative arguments. + * @param array{'dry-run'?: bool, all?: bool, format?: string} $assoc_args Associative arguments. */ public function update( $args, $assoc_args ) { $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); diff --git a/src/WP_CLI/CommandWithTranslation.php b/src/WP_CLI/CommandWithTranslation.php index 02213f18..dc2d1da3 100644 --- a/src/WP_CLI/CommandWithTranslation.php +++ b/src/WP_CLI/CommandWithTranslation.php @@ -35,13 +35,20 @@ protected function sort_translations_callback( $a, $b ) { * Updates installed languages for the current object type. * * @param string[] $args Positional arguments. - * @param array{'dry-run'?: bool, all?: bool} $assoc_args Associative arguments. + * @param array{'dry-run'?: bool, all?: bool, format?: string} $assoc_args Associative arguments. */ public function update( $args, $assoc_args ) { $updates = $this->get_translation_updates(); + $format = Utils\get_flag_value( $assoc_args, 'format' ); if ( empty( $updates ) ) { - WP_CLI::success( 'Translations are up to date.' ); + if ( $format && in_array( $format, array( 'json', 'csv' ), true ) ) { + Utils\format_items( $format, array(), array() ); + } + + if ( ! $format || in_array( $format, array( 'table', 'summary' ), true ) ) { + WP_CLI::success( 'Translations are up to date.' ); + } return; } @@ -50,9 +57,17 @@ public function update( $args, $assoc_args ) { $args = array( null ); // Used for core. } + if ( $format && in_array( $format, array( 'json', 'csv' ), true ) ) { + $logger = new \WP_CLI\Loggers\Quiet(); + WP_CLI::set_logger( $logger ); + } + $upgrader = 'WP_CLI\\LanguagePackUpgrader'; $results = array(); + $results_data = array(); $num_to_update = 0; + $obj_type = rtrim( $this->obj_type, 's' ); + $slug_key = 'core' === $obj_type ? 'version' : 'slug'; foreach ( $args as $slug ) { // Gets a list of all languages. @@ -105,7 +120,6 @@ public function update( $args, $assoc_args ) { $updates_per_type[ $update->type ][] = $update; } - $obj_type = rtrim( $this->obj_type, 's' ); $available_updates = isset( $updates_per_type[ $obj_type ] ) ? $updates_per_type[ $obj_type ] : null; if ( ! is_array( $available_updates ) ) { @@ -117,7 +131,7 @@ public function update( $args, $assoc_args ) { if ( ! Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { // Update translations. foreach ( $available_updates as $update ) { - WP_CLI::line( "Updating '{$update->Language}' translation for {$update->Name} {$update->Version}..." ); + WP_CLI::log( "Updating '{$update->Language}' translation for {$update->Name} {$update->Version}..." ); /** * @var \WP_CLI\LanguagePackUpgrader $upgrader_instance @@ -129,6 +143,16 @@ public function update( $args, $assoc_args ) { $result = $upgrader_instance->upgrade( $update ); $results[] = $result; + + // Capture data for formatted output (skip for summary format). + if ( $format && 'summary' !== $format ) { + $slug_value = 'version' === $slug_key ? $update->Version : $update->slug; + $results_data[] = array( + $slug_key => $slug_value, + 'language' => $update->language, + 'status' => $result ? 'updated' : 'failed', + ); + } } } } @@ -137,29 +161,43 @@ public function update( $args, $assoc_args ) { if ( Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { $update_count = count( $updates ); - WP_CLI::line( - sprintf( - 'Found %d translation %s that would be processed:', - $update_count, - WP_CLI\Utils\pluralize( 'update', $update_count ) - ) - ); - - Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); + if ( $format && in_array( $format, array( 'json', 'csv' ), true ) ) { + // For json/csv formats, just output the formatted data without the message + Utils\format_items( $format, $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); + } elseif ( ! $format || 'table' === $format ) { + // For table or no format, show the message and table + WP_CLI::line( + sprintf( + 'Found %d translation %s that would be processed:', + $update_count, + WP_CLI\Utils\pluralize( 'update', $update_count ) + ) + ); + + Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); + } + // For 'summary' format, do nothing (no output for dry-run mode) return; } $num_updated = count( array_filter( $results ) ); - $line = sprintf( "Updated $num_updated/$num_to_update %s.", WP_CLI\Utils\pluralize( 'translation', $num_updated ) ); + // Format output if --format is specified. + if ( $format && 'summary' !== $format ) { + Utils\format_items( $format, $results_data, array( $slug_key, 'language', 'status' ) ); + } + + if ( ! $format || in_array( $format, array( 'table', 'summary' ), true ) ) { + $line = sprintf( "Updated $num_updated/$num_to_update %s.", WP_CLI\Utils\pluralize( 'translation', $num_updated ) ); - if ( $num_to_update === $num_updated ) { - WP_CLI::success( $line ); - } elseif ( $num_updated > 0 ) { - WP_CLI::warning( $line ); - } else { - WP_CLI::error( $line ); + if ( $num_to_update === $num_updated ) { + WP_CLI::success( $line ); + } elseif ( $num_updated > 0 ) { + WP_CLI::warning( $line ); + } else { + WP_CLI::error( $line ); + } } }