|
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 ) { |
|
|
|
|
|
|
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 ) { |
|
|
|
|
|
|
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[] = 'https://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
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.