| | 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 | |