WordPress.org

Making WordPress.org

Ticket #760: 760.diff

File 760.diff, 9.3 KB (added by stephdau, 6 years ago)
  • extend/plugins-plugins/svn-track/class.dotorg-plugins-tracker.php

     
    9393                                bb_set_current_user( $user->ID );
    9494                        }
    9595
    96                         if ( 1 < $argc && 'update' == $argv[1] ) {
     96                        if ( 1 < $argc && ( 'update' == $argv[1] || 'i18n' == $argv[1] ) ) {
    9797                                if ( !isset( $_SERVER['REMOTE_ADDR'] ) )
    9898                                        $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
    9999
    100100                                if ( 2 == $argc ) // php bb-load.php update
    101101                                        return $this->process_changes();
    102102
     103                                if ( 'i18n' == $argv[1] ) {
     104                                        // php bb-load.php i18n slug [dev|stable, default: dev] [code|readme|all, default: all]
     105                                        return $this->process_i18n( $argv[2], ( 'stable' === $argv[3] ) ? $argv[3] : 'dev', $argv[4] );
     106                                }
     107
    103108                                switch ( $argv[2] ) {
    104109                                case 'all' :
    105110                                        return $this->process_all();
     
    19962001                return false;
    19972002        }
    19982003
     2004        function process_i18n( $slug, $branch = 'dev', $type = 'all' ) {
     2005                if ( empty( $slug ) )
     2006                        return false;
     2007
     2008                if ( 'stable' !== $branch )
     2009                        $branch = 'dev';
     2010
     2011                if ( 'code' !== $type && 'readme' !== $type )
     2012                        $type = 'all';
     2013
     2014                $path_rel = "{$slug}/trunk/";
     2015
     2016                if ( 'stable' === $branch ) {
     2017                        if ( false == ( $stable_tag = $this->get_stable_tag_dir_using( $path_rel ) ) ) {
     2018                                // Can't get a stable tag, bail out
     2019                                return false;
     2020                        } else if ( 'trunk' == trim( $stable_tag['tag_dir'], '/' ) ) {
     2021                                // If stable is trunk, then it's really same as dev, switch to that
     2022                                $branch = 'dev';
     2023                        } else {
     2024                                // We're dealing with an actual stable tag, go for it
     2025                                $path_rel = "{$slug}/{$stable_tag['tag_dir']}"; //
     2026                        }
     2027                }
     2028
     2029                if ( 'code' === $type || 'all' === $type )
     2030                        $this->process_code_i18n( $path_rel, $branch );
     2031
     2032                if ( 'readme' === $type || 'all' === $type )
     2033                        $this->process_readme_i18n( $path_rel, $branch );
     2034
     2035                echo "Processed {$type} for {$path_rel}\n";
     2036                return true;
     2037        }
     2038
     2039        function process_code_i18n( $path_rel, $branch = 'dev' ) {
     2040                if ( false == ( $export_path = $this->create_export( $path_rel ) ) )
     2041                        return false;
     2042
     2043                $slug = preg_replace( '|^/?([^/]+)/?.+?$|', '\1', $path_rel );
     2044
     2045                if ( empty( $slug ) || empty( $export_path ) || !preg_match( '/^[a-z0-9-]+$/i', $slug ) || !is_dir( $export_path ) )
     2046                        return false;
     2047
     2048                $old_cwd = getcwd();
     2049                chdir( $export_path );
     2050
     2051                // Check for a plugin text domain declaration and loading, grep recursively, not necessarily in [slug].php
     2052                if ( ! shell_exec( 'grep -r --include "*.php" "Text Domain: ' . escapeshellarg( $slug ) . '" .' ) && ! shell_exec( 'grep -r --include "*.php" "\bload_plugin_textdomain\b" .' ) )
     2053                        return false;
     2054
     2055                if ( !class_exists( 'PotExtMeta' ) )
     2056                        require_once( __DIR__ . '/i18n-tools/pot-ext-meta.php' );
     2057
     2058                $pot_file      = "./{$slug}.pot";
     2059                $other_pot_loc = str_replace( './', './languages/', $pot_file );
     2060
     2061                if ( file_exists( $other_pot_loc ) ) {      // Some plugins have their pot file in /languages/, use it
     2062                        $pot_file = $other_pot_loc;
     2063                } else if ( ! file_exists( $pot_file ) ) {  // BuddyPress, for EG, has theirs in the root's repo, use it
     2064                        $makepot = new MakePOT;
     2065                        // Create pot file from code
     2066                        if ( ! $makepot->wp_plugin( '.', $pot_file, $slug ) || ! file_exists( $pot_file ) )
     2067                                return false;
     2068                }
     2069
     2070                // DEBUG
     2071                // system( "cat {$pot_file}" );
     2072
     2073                $this->import_to_glotpress_project( $slug, $branch, $pot_file );
     2074
     2075                chdir( $old_cwd );
     2076                return true;
     2077        }
     2078
     2079        function process_readme_i18n( $path_rel, $branch = 'dev' ) {
     2080                if ( false == ( $export_path = $this->create_export( $path_rel ) ) )
     2081                        return false;
     2082
     2083                $slug = preg_replace( '|^/?([^/]+)/?.+?$|', '\1', $path_rel );
     2084
     2085                if ( empty( $slug ) || empty( $export_path ) || !preg_match( '/^[a-z0-9-]+$/i', $slug ) || !is_dir( $export_path ) )
     2086                        return false;
     2087
     2088                $old_cwd = getcwd();
     2089                chdir( $export_path );
     2090
     2091                $readme = $this->parse_readme_in( $path_rel );
     2092
     2093                if ( !class_exists( 'PO' ) )
     2094                        require_once( __DIR__ . '/i18n-tools/pomo/po.php' );
     2095
     2096                $pot = new PO;
     2097
     2098                foreach ( array( 'name', 'license', 'short_description' ) as $key ) {
     2099                        $readme[ $key ] = trim( $readme[ $key ] ) ;
     2100                }
     2101
     2102                // If empty or "sketchy", get the plugin name form the PHP file's headers
     2103                if ( empty( $readme['name'] ) || 'Plugin Name' == trim( $readme['name'] ) ) {
     2104                        // -o in grep will make sure we don't get comments opening delimiters (//, /*) or spaces as part of string
     2105                        $name_from_php  = trim( shell_exec( 'grep -o "\bPlugin Name:.*" ' . escapeshellarg( $slug ) . '.php' ) );
     2106                        // Remove the header label
     2107                        $name_from_php  = str_replace( 'Plugin Name:', '', $name_from_php );
     2108                        // Do clean out potential comment closing delimiter (*/) out of string
     2109                        $name_from_php  = preg_replace( '|^(.+)[\s]+?\*/$|', '\1', $name_from_php );
     2110                        // Use trimmed results as plugin name
     2111                        $readme['name'] = trim( $name_from_php );
     2112                }
     2113
     2114                if ( !empty( $readme['name'] ) ) {
     2115                        $pot->add_entry( new Translation_Entry ( array(
     2116                                'singular'           => $readme['name'],
     2117                                'extracted_comments' => 'Plugin/theme name.',
     2118                        ) ) );
     2119                }
     2120
     2121                if ( !empty( $readme['license'] ) ) {
     2122                        $pot->add_entry( new Translation_Entry ( array(
     2123                                'singular'           => $readme['license'],
     2124                                'extracted_comments' => 'License.',
     2125                        ) ) );
     2126                }
     2127
     2128                if ( !empty( $readme['short_description'] ) ) {
     2129                        $pot->add_entry( new Translation_Entry ( array(
     2130                                'singular'           => $readme['short_description'],
     2131                                'extracted_comments' => 'Short description.',
     2132                        ) ) );
     2133                }
     2134
     2135                if ( !empty( $readme['screenshots'] ) ) {
     2136                        foreach ( $readme['screenshots'] as $sshot_key => $sshot_desc ) {
     2137                                $sshot_desc = trim( $sshot_desc );
     2138                                $pot->add_entry( new Translation_Entry ( array(
     2139                                        'singular'           => $sshot_desc,
     2140                                        'extracted_comments' => 'Screenshot description.',
     2141                                ) ) );
     2142                        }
     2143
     2144                }
     2145
     2146                if ( empty( $readme['sections'] ) )
     2147                        $readme['sections'] = array();
     2148
     2149                // Adding remaining content as a section so it's processed by the same loop below
     2150                if ( !empty( $readme['remaining_content'] ) )
     2151                        $readme['sections']['remaining_content'] = $readme['remaining_content'];
     2152
     2153                $strings = array();
     2154
     2155                foreach ( $readme['sections'] as $section_key => $section_text ) {
     2156                        if ( 'screenshots' == $section_key )
     2157                                continue;
     2158
     2159                        /*
     2160                         * Scanned tags based on block elements found in Automattic_Readme::filter_text() $allowed.
     2161                         * Scanning H3/4, li, p and blockquote. Other tags are ignored  in strings (a, strong, cite, etc).
     2162                         * Processing notes:
     2163                         * * Don't normalize/modify original text, will be used as a search pattern in original doc in some use-cases.
     2164                         * * Using regexes over XML parsing for performance reasons, could move to the latter for more accuracy.
     2165                         */
     2166
     2167                        if ( 'changelog' !== $section_key ) { // No need to scan non-translatable version headers in changelog
     2168                                if ( preg_match_all( '|<h[3-4]+[^>]*>(.+)</h[3-4]+>|', $section_text, $matches ) ) {
     2169                                        if ( !empty( $matches[1] ) ) {
     2170                                                foreach ( $matches[1] as $text ) {
     2171                                                        $strings = $this->handle_translator_comment( $strings, $text, "{$section_key} header" );
     2172                                                }
     2173                                        }
     2174                                }
     2175                        }
     2176
     2177                        if ( preg_match_all( '|<li>(.+)</li>|', $section_text, $matches ) ) {
     2178                                if ( !empty( $matches[1] ) ) {
     2179                                        foreach ( $matches[1] as $text ) {
     2180                                                $strings = $this->handle_translator_comment( $strings, $text, "{$section_key} list item" );
     2181                                        }
     2182                                }
     2183                        }
     2184
     2185                        if ( preg_match_all( '|<p>(.+)</p>|', $section_text, $matches ) ) {
     2186                                if ( !empty( $matches[1] ) ) {
     2187                                        foreach ( $matches[1] as $text ) {
     2188                                                $strings = $this->handle_translator_comment( $strings, $text, "{$section_key} paragraph" );
     2189                                        }
     2190                                }
     2191                        }
     2192
     2193                        if ( preg_match_all( '|<blockquote>(.+)</blockquote>|', $section_text, $matches ) ) {
     2194                                if ( !empty( $matches[1] ) ) {
     2195                                        foreach ( $matches[1] as $text ) {
     2196                                                $strings = $this->handle_translator_comment( $strings, $text, "{$section_key} block quote" );
     2197                                        }
     2198                                }
     2199                        }
     2200                }
     2201
     2202                foreach ( $strings as $text => $comments ) {
     2203                        $pot->add_entry( new Translation_Entry ( array(
     2204                                'singular'           => $text,
     2205                                'extracted_comments' => 'Found in ' . implode( $comments, ", " ) . '.',
     2206                        ) ) );
     2207                }
     2208
     2209                $pot_file = "./{$slug}-readme.pot";
     2210                $pot->export_to_file( $pot_file );
     2211
     2212                // DEBUG
     2213                // system( "cat {$pot_file}" );
     2214
     2215                // import to GlotPress, dev or stable
     2216                $this->import_to_glotpress_project( $slug, "{$branch}-readme", $pot_file );
     2217
     2218                chdir( $old_cwd );
     2219                return true;
     2220        }
     2221
     2222        function handle_translator_comment( $array, $key, $val ) {
     2223                $val = trim( preg_replace( '/[^a-z0-9]/i', ' ', $val ) ); // cleanup key names for display
     2224                if ( empty( $array[ $key ] ) ) {
     2225                        $array[ $key ] = array( $val );
     2226                } else if ( !in_array( $val, $array[ $key ] ) ) {
     2227                        $array[ $key ][] = $val;
     2228                }
     2229                return $array;
     2230        }
     2231
     2232        function import_to_glotpress_project( $project, $branch, $file ) {
     2233                $cmd = 'php ' . __DIR__ . '/../../../translate/glotpress/scripts/import-originals.php -o po -p ' . escapeshellarg( "wp-plugins/{$project }/{$branch}" ) . ' -f ' . escapeshellarg( $file );
     2234                // DEBUG
     2235                // var_dump( $cmd );
     2236                system( $cmd );
     2237                // Note: this will nly work if the GlotPress project/sub-projects exist. To be improved, or must insure they are.
     2238        }
     2239
    19992240        function get_all_roots( $via = 'local' ) {
    20002241                global $bbdb;
    20012242                $root_rels = false;