Completed
Push — update/add_release_post_to_upd... ( 716ce6...83935e )
by
unknown
70:54 queued 60:39
created

import-translations.php ➔ upload_translation()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 27

Duplication

Lines 6
Ratio 22.22 %

Importance

Changes 0
Metric Value
cc 2
nc 1
nop 2
dl 6
loc 27
rs 9.488
c 0
b 0
f 0
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
Duplication introduced by
This function seems to be duplicated in your project.

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.

Loading history...
Best Practice introduced by
The function die_error() has been defined more than once; this definition is ignored, only the first definition in tools/export-translations.php (L16-22) 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
0 ignored issues
show
Documentation introduced by
Should the type for parameter $url not be string?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
26
 * @return sstring API URL
27
 */
28 View Code Duplication
function apize_url( $url ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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.

Loading history...
Best Practice introduced by
The function apize_url() has been defined more than once; this definition is ignored, only the first definition in tools/export-translations.php (L31-39) 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[] = '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