Changeset 11122
- Timestamp:
- 07/19/2021 03:13:43 AM (4 years ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc
- Files:
-
- 1 edited
- 1 copied
-
class-plugin.php (modified) (1 diff)
-
cli/class-export-json.php (copied) (copied from sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/cli/class-language-pack.php) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/class-plugin.php
r10587 r11122 429 429 WP_CLI::add_command( 'wporg-translate make-core-pot', __NAMESPACE__ . '\CLI\Make_Core_Pot' ); 430 430 WP_CLI::add_command( 'wporg-translate export', __NAMESPACE__ . '\CLI\Export' ); 431 WP_CLI::add_command( 'wporg-translate export-json', __NAMESPACE__ . '\CLI\Export_Json' ); 432 431 433 } 432 434 -
sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/cli/class-export-json.php
r11116 r11122 5 5 use GP; 6 6 use GP_Locales; 7 use stdClass;8 7 use WP_CLI; 9 use WP_CLI\Utils;10 8 use WP_CLI_Command; 11 use WP_Error; 12 13 class Language_Pack extends WP_CLI_Command { 14 15 const TMP_DIR = '/tmp/language-packs'; 16 const BUILD_DIR = '/nfs/rosetta/builds'; 17 const SVN_URL = 'https://i18n.svn.wordpress.org'; 18 const PACKAGE_THRESHOLD = 90; 19 20 /** 21 * Whether a language pack should be enforced. 22 * 23 * @var bool 24 */ 25 private $force = false; 26 27 /** 28 * Generates a language pack. 9 10 class Export_JSON extends WP_CLI_Command { 11 12 /** 13 * Export plugin/themes JSON translation files for a project into a WPLANGDIR type directory. 29 14 * 30 15 * ## OPTIONS 31 16 * 17 * <project> 18 * : The GlotPress project to export. 19 * 20 * <locale> 21 * : Locale to export json translations for. 22 * 32 23 * <type> 33 * : T ype of the language pack. 'plugin' or 'theme'.34 * 35 * < slug>36 * : Slug of the theme or plugin.37 * 38 * [--locale]39 * : Locale the language pack is for.40 * 24 * : The type of the project. 'plugin', 'theme', or 'both'. 25 * 26 * <textdomain> 27 * : The textdomain of the project. 28 * 29 * <export-directory> 30 * : The directory to export the JSON files into. Must contain `plugins` and `themes` sub-folders. 31 * 41 32 * [--locale-slug] 42 33 * : Slug of the locale. Default: 'default'. 43 * 44 * [--version] 45 * : Current version of the theme or plugin. 46 * 47 * [--force] 48 * : Generate language pack even when threshold is not reached or no updates exist. 49 */ 50 public function generate( $args, $assoc_args ) { 51 $type = $args[0]; 52 $slug = $args[1]; 53 54 $this->force = Utils\get_flag_value( $assoc_args, 'force' ); 34 * 35 * [--strip-path-prefix] 36 * : Path prefix to strip from the file prefix. Pass 'guess' to strip all plugin/theme looking prefixes. Default: false. 37 */ 38 public function __invoke( $args, $assoc_args ) { 39 $project_slug = $args[0]; 40 $locale = $args[1]; 41 $type = $args[2] === 'both' ? false : $args[2]; 42 $textdomain = $args[3]; 43 $export_dir = $args[4]; 55 44 56 45 $args = wp_parse_args( $assoc_args, [ 57 'locale' => false, 58 'locale-slug' => 'default', 59 'version' => false, 46 'locale-slug' => 'default', 47 'strip-path-prefix' => false, 60 48 ] ); 61 49 62 switch ( $type ) { 63 case 'plugin' : 64 $this->generate_plugin( $slug, $args ); 65 break; 66 case 'theme' : 67 $this->generate_theme( $slug, $args ); 68 break; 69 default : 70 WP_CLI::error( 'Invalid type.' ); 71 } 72 } 73 74 /** 75 * Generates a language pack for a plugin. 76 * 77 * Examples: 78 * wp @translate wporg-translate language-pack generate plugin nothing-much 79 * wp @translate wporg-translate language-pack generate plugin nothing-much --locale=de 80 * 81 * @param string $slug Slug of the plugin. 82 * @param array $args Extra arguments. 83 */ 84 private function generate_plugin( $slug, $args ) { 85 $gp_project = GP::$project->by_path( "wp-plugins/$slug" ); 50 $gp_project = GP::$project->by_path( $project_slug ); 86 51 if ( ! $gp_project ) { 87 WP_CLI::error( 'Invalid plugin slug.' ); 88 } 89 90 $stable_tag = $this->get_plugin_stable_tag( $slug ); 91 $branch = ( 'trunk' !== $stable_tag ) ? 'stable' : 'dev'; 92 93 $gp_project = GP::$project->by_path( "wp-plugins/$slug/$branch" ); 94 if ( ! $gp_project ) { 95 WP_CLI::error( 'Invalid plugin branch.' ); 96 } 97 98 $translation_sets = GP::$translation_set->by_project_id( $gp_project->id ); 99 if ( ! $translation_sets ) { 100 WP_CLI::error( 'No translation sets available.' ); 101 } 102 103 /** 104 * Filters the arguments passed to the WP-CLI command. 105 * 106 * @param array $args CLI arguments. 107 * @param string $slug Slug of the theme. 108 */ 109 $args = apply_filters( 'wporg_translate_language_pack_plugin_args', $args, $slug ); 110 111 if ( $args['locale'] ) { 112 $translation_sets = wp_list_filter( $translation_sets, [ 113 'locale' => $args['locale'], 114 'slug' => $args['locale-slug'], 115 ] ); 116 } 117 118 if ( ! $translation_sets ) { 119 WP_CLI::error( 'No translation sets available.' ); 120 } 121 122 $version = $args['version']; 123 if ( ! $version ) { 124 $version = $this->get_latest_plugin_version( $slug ); 125 } 126 127 if ( ! $version ) { 128 WP_CLI::error( 'No version available.' ); 129 } 130 131 $svn_command = $this->get_svn_command(); 132 $svn_checkout = self::get_temp_directory( $slug ); 133 134 $result = $this->execute_command( sprintf( 135 '%s checkout --quiet --depth=empty %s %s 2>&1', 136 $svn_command, 137 escapeshellarg( self::SVN_URL . '/plugins' ), 138 escapeshellarg( $svn_checkout ) 139 ) ); 140 141 if ( is_wp_error( $result ) ) { 142 WP_CLI::error_multi_line( $result->get_error_data() ); 143 WP_CLI::error( 'SVN export failed.' ); 144 } 145 146 $data = new stdClass(); 147 $data->type = 'plugin'; 148 $data->domain = $slug; 149 $data->version = $version; 150 $data->translation_sets = $translation_sets; 151 $data->gp_project = $gp_project; 152 $data->svn_checkout = $svn_checkout; 153 $this->build_language_packs( $data ); 154 } 155 156 /** 157 * Generates a language pack for a theme. 158 * 159 * Examples: 160 * wp @translate wporg-translate language-pack generate theme twentyeleven 161 * wp @translate wporg-translate language-pack generate theme twentyeleven --locale=de 162 * 163 * @param string $slug Slug of the theme. 164 * @param array $args Extra arguments. 165 */ 166 private function generate_theme( $slug, $args ) { 167 $gp_project = GP::$project->by_path( "wp-themes/$slug" ); 168 if ( ! $gp_project ) { 169 WP_CLI::error( 'Invalid theme slug.' ); 170 } 171 172 $translation_sets = GP::$translation_set->by_project_id( $gp_project->id ); 173 if ( ! $translation_sets ) { 174 WP_CLI::error( 'No translation sets available.' ); 175 } 176 177 /** 178 * Filters the arguments passed to the WP-CLI command. 179 * 180 * @param array $args CLI arguments. 181 * @param string $slug Slug of the theme. 182 */ 183 $args = apply_filters( 'wporg_translate_language_pack_theme_args', $args, $slug ); 184 185 if ( $args['locale'] ) { 186 $translation_sets = wp_list_filter( $translation_sets, [ 187 'locale' => $args['locale'], 188 'slug' => $args['locale-slug'], 189 ] ); 190 } 191 192 if ( ! $translation_sets ) { 193 WP_CLI::error( 'No translation sets available.' ); 194 } 195 196 $version = $args['version']; 197 if ( ! $version ) { 198 $version = $this->get_latest_theme_version( $slug ); 199 } 200 201 if ( ! $version ) { 202 WP_CLI::error( 'No version available.' ); 203 } 204 205 $svn_command = $this->get_svn_command(); 206 $svn_checkout = self::get_temp_directory( $slug ); 207 208 $result = $this->execute_command( sprintf( 209 '%s checkout --quiet --depth=empty %s %s 2>&1', 210 $svn_command, 211 escapeshellarg( self::SVN_URL . '/themes' ), 212 escapeshellarg( $svn_checkout ) 213 ) ); 214 215 if ( is_wp_error( $result ) ) { 216 WP_CLI::error_multi_line( $result->get_error_data() ); 217 WP_CLI::error( 'SVN export failed.' ); 218 } 219 220 $data = new stdClass(); 221 $data->type = 'theme'; 222 $data->domain = $slug; 223 $data->version = $version; 224 $data->translation_sets = $translation_sets; 225 $data->gp_project = $gp_project; 226 $data->svn_checkout = $svn_checkout; 227 $this->build_language_packs( $data ); 228 } 229 230 /** 231 * Creates a unique temporary directory. 232 * 233 * The temporary directory returned will be removed upon script termination. 234 * 235 * @param string $prefix Optional. The prefix for the directory, 'hello-dolly' for example. 236 * @return string The temporary directory. 237 */ 238 public static function get_temp_directory( $prefix = '' ) { 239 if ( ! is_dir( self::TMP_DIR ) ) { 240 mkdir( self::TMP_DIR, 0777 ); 241 } 242 243 // Generate a unique filename 244 $tmp_dir = tempnam( self::TMP_DIR, $prefix ); 245 246 // Replace that filename with a directory 247 unlink( $tmp_dir ); 248 mkdir( $tmp_dir, 0777 ); 249 250 // Automatically remove temporary directories on shutdown. 251 register_shutdown_function( [ __CLASS__, 'remove_temp_directory' ], $tmp_dir ); 252 253 return $tmp_dir; 254 } 255 256 /** 257 * Removes a directory. 258 * 259 * @param string $dir The directory which should be removed. 260 * @return bool False if directory is removed, false otherwise. 261 */ 262 public static function remove_temp_directory( $dir ) { 263 if ( trim( $dir, '/' ) ) { 264 exec( 'rm -rf ' . escapeshellarg( $dir ) ); 265 } 266 267 return is_dir( $dir ); 268 } 269 270 /** 271 * Retrieves the stable tag of a plugin. 272 * 273 * @param string $plugin_slug Slug of a plugin. 274 * @return false|string False on failure, stable tag on success. 275 */ 276 private function get_plugin_stable_tag( $plugin_slug ) { 277 $plugin = @file_get_contents( "https://api.wordpress.org/plugins/info/1.0/{$plugin_slug}.json?fields=stable_tag" ); 278 if ( ! $plugin ) { 279 return false; 280 } 281 282 $plugin = json_decode( $plugin ); 283 284 return $plugin->stable_tag; 285 } 286 287 /** 288 * Retrieves the current stable version of a theme. 289 * 290 * @param string $theme_slug Slug of a theme. 291 * @return false|string False on failure, version on success. 292 */ 293 private function get_latest_theme_version( $theme_slug ) { 294 $theme = @file_get_contents( "https://api.wordpress.org/themes/info/1.1/?action=theme_information&request[slug]={$theme_slug}" ); 295 if ( ! $theme ) { 296 return false; 297 } 298 299 $theme = json_decode( $theme ); 300 301 return $theme->version; 302 } 303 304 /** 305 * Retrieves the current stable version of a plugin. 306 * 307 * @param string $plugin_slug Slug of a plugin. 308 * @return false|string False on failure, version on success. 309 */ 310 private function get_latest_plugin_version( $plugin_slug ) { 311 $plugin = @file_get_contents( "https://api.wordpress.org/plugins/info/1.0/{$plugin_slug}.json" ); 312 if ( ! $plugin ) { 313 return false; 314 } 315 316 $plugin = json_decode( $plugin ); 317 318 return $plugin->version; 319 } 320 321 /** 322 * Retrieves active language packs for a theme/plugin of a version. 323 * 324 * @param string $type Type of the language pack. Supports 'plugin' or 'theme'. 325 * @param string $domain Slug of a theme/plugin. 326 * @param string $version Version of a theme/plugin. 327 * @return array Array of active language packs. 328 */ 329 private function get_active_language_packs( $type, $domain, $version ) { 330 global $wpdb; 331 332 $active_language_packs = $wpdb->get_results( $wpdb->prepare( 333 'SELECT language, updated FROM language_packs WHERE type = %s AND domain = %s AND version = %s AND active = 1', 334 $type, 335 $domain, 336 $version 337 ), OBJECT_K ); 338 339 if ( ! $active_language_packs ) { 340 return []; 341 } 342 343 return $active_language_packs; 344 } 345 346 /** 347 * Whether there's at least one active language pack for a theme/plugin of any version. 348 * 349 * @param string $type Type of the language pack. Supports 'plugin' or 'theme'. 350 * @param string $domain Slug of a theme/plugin. 351 * @param string $locale WordPress locale. 352 * @return boolean True if theme/plugin has an active language pack, false if not. 353 */ 354 private function has_active_language_pack( $type, $domain, $locale ) { 355 global $wpdb; 356 357 return (bool) $wpdb->get_var( $wpdb->prepare( 358 'SELECT updated FROM language_packs WHERE type = %s AND domain = %s AND language = %s AND active = 1 LIMIT 1', 359 $type, 360 $domain, 361 $locale 362 ) ); 363 } 364 365 /** 366 * Retrieves the basic SVN command with authentication data. 367 * 368 * @return string The SVN command. 369 */ 370 private function get_svn_command() { 371 return sprintf( 372 'svn --no-auth-cache --non-interactive --username=%s --password=%s', 373 escapeshellarg( POT_SVN_USER ), 374 escapeshellarg( POT_SVN_PASS ) 375 ); 376 } 377 378 /** 379 * Updates a SVN directory. 380 * 381 * Creates directories if they don't exist yet. 382 * 383 * @param string $svn_directory The SVN directory. 384 */ 385 private function update_svn_directory( $svn_directory ) { 386 $svn_command = $this->get_svn_command(); 387 388 // Update existing files. 389 $this->execute_command( sprintf( 390 '%s up --quiet --parents %s 2>/dev/null', 391 $svn_command, 392 escapeshellarg( $svn_directory ) 393 ) ); 394 395 // Create missing SVN directories. 396 $this->execute_command( sprintf( 397 '%s mkdir --quiet --parents %s 2>/dev/null', 398 $svn_command, 399 escapeshellarg( $svn_directory ) 400 ) ); 52 WP_CLI::error( 'Invalid project slug.' ); 53 } 54 55 if ( ! is_writable( $export_dir ) || ! is_dir( $export_dir ) ) { 56 WP_CLI::error( 'Invalid export directory.' ); 57 } 58 59 $translation_set = GP::$translation_set->by_project_id_slug_and_locale( $gp_project->id, $args['locale-slug'], $locale ); 60 if ( ! $translation_set ) { 61 WP_CLI::error( 'Invalid translation set.' ); 62 } 63 64 // Get WP locale. 65 $gp_locale = GP_Locales::by_slug( $translation_set->locale ); 66 if ( ! isset( $gp_locale->wp_locale ) ) { 67 WP_CLI::error( 'Invalid translation set.' ); 68 } 69 70 // Check if any current translations exist. 71 if ( 0 === $translation_set->current_count() ) { 72 WP_CLI::log( 'No current translations available.' ); 73 return; 74 } 75 76 $entries = GP::$translation->for_export( $gp_project, $translation_set, [ 'status' => 'current' ] ); 77 if ( ! $entries ) { 78 WP_CLI::warning( 'No current translations available.' ); 79 return; 80 } 81 82 // Build a mapping based on where the translation entries occur. 83 $plugins = $this->build_mapping( $entries, 'plugins', $type ); 84 $themes = $this->build_mapping( $entries, 'themes', $type ); 85 86 // Strip the path prefix if required. 87 if ( $args['strip-path-prefix'] ) { 88 $plugins = $this->strip_path_prefix( $plugins, $args['strip-path-prefix'] ); 89 $themes = $this->strip_path_prefix( $themes, $args['strip-path-prefix'] ); 90 } 91 92 // Create JED json files for each JS file. 93 $plugin_json_files = $this->build_json_files( $gp_project, $gp_locale, $set, $plugins, "{$export_dir}/plugins/{$textdomain}-{$gp_locale->wp_locale}" ); 94 $theme_json_files = $this->build_json_files( $gp_project, $gp_locale, $set, $themes, "{$export_dir}/themes/{$textdomain}-{$gp_locale->wp_locale}" ); 95 96 WP_CLI::success( "JSON Files for {$project_slug} {$locale} generated." ); 401 97 } 402 98 403 99 /** 404 100 * Build a mapping of JS files to translation entries occurring in those files. 405 * Translation entries occurring in other files are added to the 'po' key. 406 * 407 * @param Translation_Entry[] $entries The translation entries to map. 101 * Translation entries occurring in other files are skipped. 102 * 103 * @param Translation_Entry[] $entries The translation entries to map. 104 * @param string $type_limiter Limit to this kind of string. 'themes', 'plugins'. 105 * @param string $type The type of the project. false to guess. 408 106 * @return array The mapping of sources to translation entries. 409 107 */ 410 private function build_mapping( $entries ) {108 private function build_mapping( $entries, $type_limiter, $type ) { 411 109 $mapping = []; 412 110 … … 428 126 return $file; 429 127 } 430 return 'po'; 128 129 return false; 431 130 }, 432 131 $entry->references … … 434 133 435 134 $sources = array_unique( $sources ); 135 } 136 137 foreach ( array_filter( $sources ) as $source ) { 138 if ( $type_limiter ) { 139 $filetype = $type; 140 if ( $type ) { 141 $filetype = $type; 142 } elseif ( preg_match( '!wp-content/(themes|plugins)/!', $source, $m ) ) { 143 $filetype = $m[1]; 144 } elseif ( preg_match( '!^/?(themes|plugins)/!', $source, $m ) ) { 145 $filetype = $m[1]; 146 } 147 148 if ( $filetype !== $type_limiter ) { 149 continue; 150 } 151 } 152 153 $mapping[ $source ][] = $entry; 154 } 155 } 156 157 return $mapping; 158 } 159 160 /** 161 * Strip a leading path off the keys of the mapping array. 162 * 163 * @param array $mapping The mapping array returned by build_mapping. 164 * @param string $prefix The prefix to strip, or 'magic' to strip all plugin/theme-looking paths. 165 * @return array The $mapping object with paths striped. 166 */ 167 private function strip_path_prefix( $mapping, $prefix ) { 168 $result = []; 169 170 foreach ( $mapping as $file => $entries ) { 171 if ( 'guess' === $prefix ) { 172 $file = preg_replace( '!^(.*wp-content)?/?(plugins|themes)/[^/]+/!i', '', $file ); 436 173 } else { 437 $sources = [ 'po' ];438 }439 440 foreach ( $sources as $source ) {441 $mapping[ $source ][] = $entry; 442 }443 } 444 445 return $ mapping;174 if ( $prefix === substr( $file, 0, strlen( $prefix ) ) ) { 175 $file = substr( $file, strlen( $prefix ) ); 176 } 177 } 178 179 $result[ $file ] = $entries; 180 } 181 182 return $result; 446 183 } 447 184 … … 486 223 } 487 224 488 /**489 * Builds a PO file for translations.490 *491 * @param GP_Project $gp_project The GlotPress project.492 * @param GP_Locale $gp_locale The GlotPress locale.493 * @param GP_Translation_Set $set The translation set.494 * @param Translation_Entry[] $entries The translation entries.495 * @param string $dest Destination file name.496 * @return string|WP_Error Last updated date on success, WP_Error on failure.497 */498 private function build_po_file( $gp_project, $gp_locale, $set, $entries, $dest ) {499 $format = gp_array_get( GP::$formats, 'po' );500 $po_content = $format->print_exported_file( $gp_project, $gp_locale, $set, $entries );501 502 // Get last updated.503 preg_match( '/^"PO-Revision-Date: (.*)\+\d+\\\n/m', $po_content, $match );504 if ( empty( $match[1] ) ) {505 return new WP_Error( 'invalid_format', 'Date could not be parsed.' );506 }507 508 file_put_contents( $dest, $po_content );509 510 return $match[1];511 }512 513 /**514 * Executes a command via exec().515 *516 * @param string $command The escaped command to execute.517 * @return true|WP_Error True on success, WP_Error on failure.518 */519 private function execute_command( $command ) {520 exec( $command, $output, $return_var );521 522 if ( $return_var ) {523 return new WP_Error( $return_var, 'Error while executing the command.', $output );524 }525 526 return true;527 }528 529 /**530 * Inserts a language pack into database.531 *532 * @param string $type Type of the language pack.533 * @param string $domain Slug of the theme/plugin.534 * @param string $language Language the language pack is for.535 * @param string $version Version of the theme/plugin.536 * @param string $updated Last updated.537 * @return true|WP_Error true when language pack was updated, WP_Error on failure.538 */539 private function insert_language_pack( $type, $domain, $language, $version, $updated ) {540 global $wpdb;541 542 $existing = $wpdb->get_var( $wpdb->prepare(543 'SELECT id FROM language_packs WHERE type = %s AND domain = %s AND language = %s AND version = %s AND updated = %s AND active = 1',544 $type,545 $domain,546 $language,547 $version,548 $updated549 ) );550 551 if ( $existing ) {552 return true;553 }554 555 $now = current_time( 'mysql', 1 );556 $inserted = $wpdb->insert( 'language_packs', [557 'type' => $type,558 'domain' => $domain,559 'language' => $language,560 'version' => $version,561 'updated' => $updated,562 'active' => 1,563 'date_added' => $now,564 'date_modified' => $now,565 ] );566 567 if ( ! $inserted ) {568 return new WP_Error( 'language_pack_not_inserted', 'The language pack was not inserted.' );569 }570 571 // Mark old language packs for the same version as inactive.572 $wpdb->query( $wpdb->prepare(573 'UPDATE language_packs SET active = 0, date_modified = %s WHERE type = %s AND domain = %s AND language = %s AND version = %s AND id <> %d',574 $now,575 $type,576 $domain,577 $language,578 $version,579 $wpdb->insert_id580 ) );581 582 return true;583 }584 585 /**586 * Builds a language pack.587 *588 * @param object $data The data of a language pack.589 */590 private function build_language_packs( $data ) {591 $existing_packs = $this->get_active_language_packs( $data->type, $data->domain, $data->version );592 $svn_command = $this->get_svn_command();593 594 foreach ( $data->translation_sets as $set ) {595 // Get WP locale.596 $gp_locale = GP_Locales::by_slug( $set->locale );597 if ( ! isset( $gp_locale->wp_locale ) ) {598 continue;599 }600 601 // Change wp_locale until GlotPress returns the correct wp_locale for variants.602 $wp_locale = $gp_locale->wp_locale;603 if ( 'default' !== $set->slug ) {604 $wp_locale = $wp_locale . '_' . $set->slug;605 }606 607 // Check if any current translations exist.608 if ( 0 === $set->current_count() ) {609 WP_CLI::log( "Skip {$wp_locale}, no translations." );610 continue;611 }612 613 // Check if percent translated is above threshold for initial language pack.614 $has_existing_pack = $this->has_active_language_pack( $data->type, $data->domain, $wp_locale );615 if ( ! $has_existing_pack ) {616 $percent_translated = $set->percent_translated();617 if ( ! $this->force && $percent_translated < self::PACKAGE_THRESHOLD ) {618 WP_CLI::log( "Skip {$wp_locale}, translations below threshold ({$percent_translated}%)." );619 continue;620 }621 } else {622 WP_CLI::log( "Skipping threshold check for {$wp_locale}, has existing language pack." );623 }624 625 // Check if new translations are available since last build.626 if ( ! $this->force && isset( $existing_packs[ $wp_locale ] ) ) {627 $pack_time = strtotime( $existing_packs[ $wp_locale ]->updated );628 $glotpress_time = strtotime( $set->last_modified() );629 630 if ( $pack_time >= $glotpress_time ) {631 WP_CLI::log( "Skip {$wp_locale}, no new translations." );632 continue;633 }634 }635 636 $entries = GP::$translation->for_export( $data->gp_project, $set, [ 'status' => 'current' ] );637 if ( ! $entries ) {638 WP_CLI::warning( "No current translations available for {$wp_locale}." );639 continue;640 }641 642 $working_directory = "{$data->svn_checkout}/{$data->domain}";643 $export_directory = "{$working_directory}/{$data->version}/{$wp_locale}";644 $build_directory = self::BUILD_DIR . "/{$data->type}s/{$data->domain}/{$data->version}";645 646 $filename = "{$data->domain}-{$wp_locale}";647 $json_file_base = "{$export_directory}/{$filename}";648 $po_file = "{$export_directory}/{$filename}.po";649 $mo_file = "{$export_directory}/{$filename}.mo";650 $zip_file = "{$export_directory}/{$filename}.zip";651 $build_zip_file = "{$build_directory}/{$wp_locale}.zip";652 $build_sig_file = "{$build_zip_file}.sig";653 654 // Update/create directories.655 $this->update_svn_directory( $export_directory );656 657 // Build a mapping based on where the translation entries occur and separate the po entries.658 $mapping = $this->build_mapping( $entries );659 $po_entries = array_key_exists( 'po', $mapping ) ? $mapping['po'] : [];660 661 unset( $mapping['po'] );662 663 // Create JED json files for each JS file.664 $json_files = $this->build_json_files( $data->gp_project, $gp_locale, $set, $mapping, $json_file_base );665 666 // Create PO file.667 $last_modified = $this->build_po_file( $data->gp_project, $gp_locale, $set, $po_entries, $po_file );668 669 if ( is_wp_error( $last_modified ) ) {670 WP_CLI::warning( sprintf( "PO generation for {$wp_locale} failed: %s", $last_modified->get_error_message() ) );671 672 // Clean up.673 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );674 675 continue;676 }677 678 // Create MO file.679 $result = $this->execute_command( sprintf(680 'msgfmt %s -o %s 2>&1',681 escapeshellarg( $po_file ),682 escapeshellarg( $mo_file )683 ) );684 685 if ( is_wp_error( $result ) ) {686 WP_CLI::error_multi_line( $result->get_error_data() );687 WP_CLI::warning( "MO generation for {$wp_locale} failed." );688 689 // Clean up.690 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );691 692 continue;693 }694 695 // Create ZIP file.696 $result = $this->execute_command( sprintf(697 'zip -9 -j %s %s %s %s 2>&1',698 escapeshellarg( $zip_file ),699 escapeshellarg( $po_file ),700 escapeshellarg( $mo_file ),701 implode( ' ', array_map( 'escapeshellarg', $json_files ) )702 ) );703 704 if ( is_wp_error( $result ) ) {705 WP_CLI::error_multi_line( $result->get_error_data() );706 WP_CLI::warning( "ZIP generation for {$wp_locale} failed." );707 708 // Clean up.709 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );710 711 continue;712 }713 714 // Create build directories.715 $result = $this->execute_command( sprintf(716 'mkdir -p %s 2>&1',717 escapeshellarg( $build_directory )718 ) );719 720 if ( is_wp_error( $result ) ) {721 WP_CLI::error_multi_line( $result->get_error_data() );722 WP_CLI::warning( "Creating build directories for {$wp_locale} failed." );723 724 // Clean up.725 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );726 727 continue;728 }729 730 // Move ZIP file to build directory.731 $result = $this->execute_command( sprintf(732 'mv %s %s 2>&1',733 escapeshellarg( $zip_file ),734 escapeshellarg( $build_zip_file )735 ) );736 737 if ( is_wp_error( $result ) ) {738 WP_CLI::error_multi_line( $result->get_error_data() );739 WP_CLI::warning( "Moving ZIP file for {$wp_locale} failed." );740 741 // Clean up.742 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );743 744 continue;745 }746 747 // Generate a signature for the ZIP file.748 if ( false && function_exists( 'wporg_sign_file' ) ) {749 $signatures = wporg_sign_file( $build_zip_file, 'translation' );750 if ( $signatures ) {751 file_put_contents( $build_sig_file, implode( "\n", $signatures ) );752 }753 }754 755 // Insert language pack into database.756 $result = $this->insert_language_pack( $data->type, $data->domain, $wp_locale, $data->version, $last_modified );757 758 if ( is_wp_error( $result ) ) {759 WP_CLI::warning( sprintf( "Language pack for {$wp_locale} failed: %s", $result->get_error_message() ) );760 761 // Clean up.762 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );763 764 continue;765 }766 767 // Add PO file to SVN.768 $this->execute_command( sprintf(769 '%s add --quiet --force --parents %s 2>/dev/null',770 $svn_command,771 escapeshellarg( $po_file )772 ) );773 774 // Commit PO file.775 $result = $this->execute_command( sprintf(776 '%s commit --quiet %s -m %s 2>&1',777 $svn_command,778 escapeshellarg( $data->svn_checkout ),779 escapeshellarg( "Update PO file for {$data->type} {$data->domain} {$data->version} {$wp_locale}." )780 ) );781 782 if ( is_wp_error( $result ) ) {783 WP_CLI::error_multi_line( $result->get_error_data() );784 WP_CLI::warning( "SVN commit for {$wp_locale} failed." );785 786 // Clean up.787 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );788 789 continue;790 }791 792 // Clean up.793 $this->execute_command( sprintf( 'rm -rf %s', escapeshellarg( $working_directory ) ) );794 795 WP_CLI::success( "Language pack for {$wp_locale} generated." );796 }797 }798 225 }
Note: See TracChangeset
for help on using the changeset viewer.