Completed
Push — add/staging-display ( f17340...7d47df )
by
unknown
11:26
created

tools/import-translations.php (2 issues)

Upgrade to new PHP Analysis Engine

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
The function die_error() has been defined more than once; this definition is ignored, only the first definition in tools/export-translations.php (L20-26) 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 annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
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 annotation.

/**
 * @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