Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /* |
||
| 4 | * Imports translations from one or multiple WordPress.com GlotPress project to another |
||
| 5 | * |
||
| 6 | * php import-translations.php DESTINATION_URL SOURCE_URL [SOURCE_URL ...] |
||
| 7 | */ |
||
| 8 | |||
| 9 | /** |
||
| 10 | * Terminates script. Prints help and message to STDERR |
||
| 11 | * |
||
| 12 | * @param string $message |
||
| 13 | */ |
||
| 14 | View Code Duplication | function die_error( $message ) { |
|
|
0 ignored issues
–
show
|
|||
| 15 | global $argv; |
||
| 16 | |||
| 17 | fwrite( STDERR, "php $argv[0] DESTINATION_URL SOURCE_URL [SOURCE_URL ...]\n" ); |
||
| 18 | fwrite( STDERR, "$message\n" ); |
||
| 19 | exit( 1 ); |
||
| 20 | } |
||
| 21 | |||
| 22 | /** |
||
| 23 | * Converts GlotPress URL into a GlotPress API URL |
||
| 24 | * |
||
| 25 | * @param sring $url URL |
||
| 26 | * @return sstring API URL |
||
| 27 | */ |
||
| 28 | View Code Duplication | function apize_url( $url ) { |
|
|
0 ignored issues
–
show
The function
apize_url() has been defined more than once; this definition is ignored, only the first definition in tools/export-translations.php (L34-42) is considered.
This check looks for functions that have already been defined in other files. Some Codebases, like WordPress, make a practice of defining functions multiple times. This
may lead to problems with the detection of function parameters and types. If you really
need to do this, you can mark the duplicate definition with the /**
* @ignore
*/
function getUser() {
}
function getUser($id, $realm) {
}
See also the PhpDoc documentation for @ignore. Loading history...
|
|||
| 29 | if ( false !== strpos( $url, '/api' ) ) { |
||
| 30 | return $url; |
||
| 31 | } |
||
| 32 | |||
| 33 | $host = preg_quote( parse_url( $url, PHP_URL_HOST ) ); |
||
| 34 | |||
| 35 | return preg_replace( "#^https?://$host#", '\\0/api', $url ); |
||
| 36 | } |
||
| 37 | |||
| 38 | if ( empty( $argv[1] ) ) { |
||
| 39 | die_error( 'No DESTINATION_URL specified' ); |
||
| 40 | } |
||
| 41 | |||
| 42 | $destination_url = apize_url( rtrim( $argv[1], '/' ) ); |
||
| 43 | $destination = json_decode( file_get_contents( $destination_url ) ); |
||
| 44 | |||
| 45 | $destination_locales = array(); |
||
| 46 | foreach ( $destination->translation_sets as $translation_set ) { |
||
| 47 | $destination_locales[$translation_set->locale] = sprintf( '%s/%s', $translation_set->locale, $translation_set->slug ); |
||
| 48 | } |
||
| 49 | |||
| 50 | if ( isset( $argv[2] ) ) { |
||
| 51 | $origin_urls = array_map( 'apize_url', array_slice( $argv, 2 ) ); |
||
| 52 | } else { |
||
| 53 | /* |
||
| 54 | // Imports all siblings into destination |
||
| 55 | $origin_urls = array(); |
||
| 56 | $destination_parent_url = rtrim( dirname( $destination_url ), '/' ); |
||
| 57 | $destination_parent = json_decode( file_get_contents( $destination_parent_url ) ); |
||
| 58 | foreach ( $destination_parent->sub_projects as $sub_project ) { |
||
| 59 | $origin_url = sprintf( '%s/%s', $destination_parent_url, $sub_project->slug ); |
||
| 60 | if ( $origin_url == $destination_url ) { |
||
| 61 | continue; |
||
| 62 | } |
||
| 63 | $origin_urls[] = $origin_url; |
||
| 64 | } |
||
| 65 | |||
| 66 | $origin_urls[] = 'http://translate.wordpress.com/api/projects/wpcom'; |
||
| 67 | */ |
||
| 68 | die_error( 'No SOURCE_URLs specified' ); |
||
| 69 | } |
||
| 70 | |||
| 71 | sort( $origin_urls ); |
||
| 72 | |||
| 73 | // Log in |
||
| 74 | echo "WordPress.com Username: "; |
||
| 75 | $user_login = trim( fgets( STDIN ) ); |
||
| 76 | |||
| 77 | echo "WordPress.com Password: "; |
||
| 78 | $user_pass = shell_exec( 'read -rs secret_password && echo $secret_password' ); |
||
| 79 | $user_pass = substr( $user_pass, 0, -1 ); |
||
| 80 | echo "\n"; |
||
| 81 | |||
| 82 | $cookie_jar = tmpfile(); // handle |
||
| 83 | $cookie_jar_meta = stream_get_meta_data( $cookie_jar ); // file meta data |
||
| 84 | $cookie_jar_file = $cookie_jar_meta['uri']; // file |
||
| 85 | |||
| 86 | $login = curl_init( 'https://translate.wordpress.com/login' ); |
||
| 87 | $login_error = false; |
||
| 88 | |||
| 89 | curl_setopt_array( $login, array( |
||
| 90 | CURLOPT_POSTFIELDS => compact( 'user_login', 'user_pass' ), |
||
| 91 | CURLOPT_COOKIEJAR => $cookie_jar_file, // write cookies |
||
| 92 | CURLOPT_RETURNTRANSFER => true, |
||
| 93 | CURLOPT_HEADER => false, |
||
| 94 | View Code Duplication | CURLOPT_HEADERFUNCTION => function( $curl, $header_line ) use ( &$login_error ) { |
|
| 95 | if ( preg_match( '/_gp_notice_error=/', $header_line, $matches ) ) { |
||
| 96 | $login_error = true; |
||
| 97 | } |
||
| 98 | return strlen( $header_line ); |
||
| 99 | }, |
||
| 100 | ) ); |
||
| 101 | |||
| 102 | curl_exec( $login ); |
||
| 103 | curl_close( $login ); // Now our cookies are stored in $cookie_jar_file |
||
| 104 | |||
| 105 | if ( $login_error ) { |
||
| 106 | die_error( 'Invalid username/password' ); |
||
| 107 | } |
||
| 108 | |||
| 109 | foreach ( $destination_locales as $locale => $locale_url_suffix ) { |
||
| 110 | echo "$locale: "; |
||
| 111 | |||
| 112 | $destination_locale_url = sprintf( '%s/%s', $destination_url, $locale_url_suffix ); |
||
| 113 | $destination_locale_export_url = sprintf( '%s/%s/%s', $destination_url, $locale_url_suffix, 'export-translations?format=po' ); |
||
| 114 | $destination_locale_import_url = sprintf( '%s/%s/%s', $destination_url, $locale_url_suffix, 'import-translations' ); |
||
| 115 | |||
| 116 | $destination_locale_po = tmpfile(); // handle |
||
| 117 | $destination_locale_po_meta = stream_get_meta_data( $destination_locale_po ); // file meta data |
||
| 118 | $destination_locale_po_file = $destination_locale_po_meta['uri']; // file |
||
| 119 | $destination_locale_po_data = @file_get_contents( $destination_locale_export_url ); // file contents |
||
| 120 | fwrite( $destination_locale_po, $destination_locale_po_data ); |
||
| 121 | |||
| 122 | $total_strings = preg_match_all( '/^msgstr/m', $destination_locale_po_data, $m ); |
||
| 123 | $untranslated_strings = preg_match_all( '/^msgstr(\[\d+\])? ""/m', $destination_locale_po_data, $m ); |
||
| 124 | |||
| 125 | echo "TOTAL: $total_strings; UNTRANSLATED: $untranslated_strings\n"; |
||
| 126 | |||
| 127 | foreach ( $origin_urls as $origin_url ) { |
||
| 128 | $origin_locale_url = sprintf( '%s/%s', $origin_url, $locale_url_suffix ); |
||
| 129 | $origin_locale_export_url = sprintf( '%s/%s/%s', $origin_url, $locale_url_suffix, 'export-translations?format=po' ); |
||
| 130 | |||
| 131 | $origin_locale_po = tmpfile(); // handle |
||
| 132 | $origin_locale_po_meta = stream_get_meta_data( $origin_locale_po ); // file meta data |
||
| 133 | $origin_locale_po_file = $origin_locale_po_meta['uri']; // file |
||
| 134 | $origin_locale_po_data = @file_get_contents( $origin_locale_export_url ); // file contents |
||
| 135 | |||
| 136 | $translations_added = 0; |
||
| 137 | |||
| 138 | if ( $origin_locale_po_data ) { |
||
| 139 | fwrite( $origin_locale_po, $origin_locale_po_data ); |
||
| 140 | |||
| 141 | $translations_added = upload_translation( $destination_locale_import_url, $origin_locale_po_file ); |
||
| 142 | } |
||
| 143 | |||
| 144 | fclose( $origin_locale_po ); |
||
| 145 | |||
| 146 | printf( "%s: %d\n", $origin_locale_url, $translations_added ); |
||
| 147 | } |
||
| 148 | |||
| 149 | $translations_added = upload_translation( $destination_locale_import_url, $destination_locale_po_file ); |
||
| 150 | printf( "%s: %d\n", $destination_locale_url, $translations_added ); |
||
| 151 | |||
| 152 | fclose( $destination_locale_po ); |
||
| 153 | |||
| 154 | echo "\n"; |
||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | * Upload file to URL using Cookie Authentication |
||
| 159 | * |
||
| 160 | * @param string $import_url |
||
| 161 | * @param string $file |
||
| 162 | */ |
||
| 163 | function upload_translation( $import_url, $file ) { |
||
| 164 | global $cookie_jar_file; |
||
| 165 | |||
| 166 | $import = curl_init( $import_url ); |
||
| 167 | |||
| 168 | $translations_added = 0; |
||
| 169 | |||
| 170 | curl_setopt_array( $import, array( |
||
| 171 | CURLOPT_COOKIEFILE => $cookie_jar_file, // read cookies |
||
| 172 | CURLOPT_POSTFIELDS => array( |
||
| 173 | 'format' => 'po', |
||
| 174 | 'import-file' => sprintf( '@%s', $file ), |
||
| 175 | ), |
||
| 176 | CURLOPT_RETURNTRANSFER => true, |
||
| 177 | CURLOPT_HEADER => false, |
||
| 178 | View Code Duplication | CURLOPT_HEADERFUNCTION => function( $curl, $header_line ) use ( &$translations_added ) { |
|
| 179 | if ( preg_match( '/_gp_notice_notice=(\d+)/', $header_line, $matches ) ) { |
||
| 180 | $translations_added = (int) $matches[1]; |
||
| 181 | } |
||
| 182 | return strlen( $header_line ); |
||
| 183 | }, |
||
| 184 | ) ); |
||
| 185 | |||
| 186 | curl_exec( $import ); |
||
| 187 | |||
| 188 | return $translations_added; |
||
| 189 | } |
||
| 190 |
This check looks for functions that have already been defined in other files.
Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the
@ignoreannotation.See also the PhpDoc documentation for @ignore.