439 lines
14 KiB
PHP
439 lines
14 KiB
PHP
<?php
|
|
|
|
class WPML_ST_MO_Downloader {
|
|
const LOCALES_XML_FILE = 'http://d2pf4b3z51hfy8.cloudfront.net/wp-locales.xml.gz';
|
|
|
|
const CONTEXT = 'WordPress';
|
|
private $settings;
|
|
private $xml;
|
|
private $translation_files = array();
|
|
/**
|
|
* @var string[string]
|
|
*/
|
|
private $lang_map;
|
|
/**
|
|
* @var string[string]
|
|
*/
|
|
private $lang_map_rev;
|
|
|
|
|
|
function __construct() {
|
|
global $wp_version;
|
|
|
|
// requires Sitepress
|
|
if ( ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE ) {
|
|
return;
|
|
}
|
|
|
|
$wpversion = preg_replace( '#-(.+)$#', '', $wp_version );
|
|
|
|
$this->settings = get_option( 'icl_adl_settings' );
|
|
|
|
if ( empty( $this->settings['wp_version'] ) || version_compare( $wpversion, $this->settings['wp_version'], '>' ) ) {
|
|
try {
|
|
$this->updates_check( array( 'trigger' => 'wp-update' ) );
|
|
} catch ( Exception $e ) {
|
|
// do nothing - this is automated request for updates
|
|
}
|
|
}
|
|
|
|
if ( get_transient( 'WPML_ST_MO_Downloader_lang_map' ) === false ) {
|
|
$this->set_lang_map_from_csv();
|
|
}
|
|
$this->lang_map = get_transient( 'WPML_ST_MO_Downloader_lang_map' );
|
|
$this->lang_map_rev = array_flip( $this->lang_map );
|
|
|
|
add_action( 'wp_ajax_icl_adm_updates_check', array( $this, 'show_updates' ) );
|
|
add_action( 'wp_ajax_icl_adm_save_preferences', array( $this, 'save_preferences' ) );
|
|
|
|
}
|
|
|
|
function set_lang_map_from_csv() {
|
|
$fh = fopen( WPML_ST_PATH . '/inc/lang-map.csv', 'r' );
|
|
while ( list($locale, $code) = fgetcsv( $fh ) ) {
|
|
$this->lang_map[ $locale ] = $code;
|
|
}
|
|
|
|
if ( isset( $this->lang_map ) && is_array( $this->lang_map ) ) {
|
|
set_transient( 'WPML_ST_MO_Downloader_lang_map', $this->lang_map );
|
|
}
|
|
|
|
}
|
|
|
|
function updates_check( $args = array() ) {
|
|
global $wp_version, $sitepress;
|
|
|
|
$wpversion = preg_replace( '#-(.+)$#', '', $wp_version );
|
|
$trigger = 'manual';
|
|
extract( $args, EXTR_OVERWRITE );
|
|
|
|
$active_languages = $sitepress->get_active_languages();
|
|
$default_language = $sitepress->get_default_language();
|
|
$this->load_xml();
|
|
$this->get_translation_files();
|
|
$updates = array();
|
|
|
|
foreach ( $active_languages as $language ) {
|
|
if ( $language != $default_language ) {
|
|
if ( isset( $this->translation_files[ $language['code'] ] ) ) {
|
|
foreach ( $this->translation_files[ $language['code'] ] as $project => $info ) {
|
|
$this->settings['translations'][ $language['code'] ][ $project ]['available'] = $info['signature'];
|
|
if ( empty( $this->settings['translations'][ $language['code'] ][ $project ]['installed'] ) ||
|
|
( isset( $info['available'] ) && $this->settings['translations'][ $language['code'] ][ $project ]['installed'] != $info['available'] )
|
|
) {
|
|
$updates['languages'][ $language['code'] ][ $project ] = $this->settings['translations'][ $language['code'] ][ $project ]['available'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->settings['wp_version'] = $wpversion;
|
|
$this->settings['last_time_xml_check'] = time();
|
|
$this->settings['last_time_xml_check_trigger'] = $trigger;
|
|
$this->save_settings();
|
|
|
|
return $updates;
|
|
|
|
}
|
|
|
|
function show_updates() {
|
|
global $sitepress;
|
|
|
|
$html = '';
|
|
|
|
try {
|
|
$updates = $this->updates_check();
|
|
// filter only core( & admin)
|
|
$updates_core = array();
|
|
if ( array_key_exists( 'languages', $updates ) && ! empty( $updates['languages'] ) ) {
|
|
foreach ( $updates['languages'] as $k => $v ) {
|
|
if ( ! empty( $v['core'] ) ) {
|
|
$updates_core['languages'][ $k ]['core'] = $v['core'];
|
|
}
|
|
if ( ! empty( $v['admin'] ) ) {
|
|
$updates_core['languages'][ $k ]['admin'] = $v['admin'];
|
|
}
|
|
}
|
|
}
|
|
$updates = $updates_core;
|
|
if ( ! empty( $updates ) ) {
|
|
$html .= '<table>';
|
|
|
|
foreach ( $updates['languages'] as $language => $projects ) {
|
|
$l = $sitepress->get_language_details( $language );
|
|
|
|
if ( ! empty( $projects['core'] ) || ! empty( $projects['admin'] ) ) {
|
|
|
|
$vkeys = array();
|
|
foreach ( $projects as $key => $value ) {
|
|
$vkeys[] = $key . '|' . $value;
|
|
}
|
|
$version_key = join( ';', $vkeys );
|
|
|
|
$html .= '<tr>';
|
|
$html .= '<td>' . sprintf(
|
|
__( 'Updated %s translation is available', 'wpml-string-translation' ),
|
|
'<strong>' . $l['display_name'] . '</strong>'
|
|
) . '</td>';
|
|
$html .= '<td align="right">';
|
|
$html .= '<a href="' . admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&download_mo=' . $language . '&version=' . $version_key ) . '" class="button-secondary">' . __( 'Review changes and update', 'wpml-string-translation' ) . '</a>';
|
|
$html .= '</td>';
|
|
$html .= '<tr>';
|
|
$html .= '</tr>';
|
|
}
|
|
}
|
|
|
|
$html .= '</table>';
|
|
} else {
|
|
$html .= __( 'No updates found.', 'wpml-string-translation' );
|
|
}
|
|
} catch ( Exception $error ) {
|
|
$html .= '<span style="color:#f00" >' . $error->getMessage() . '</span>';
|
|
}
|
|
|
|
echo json_encode( array( 'html' => $html ) );
|
|
exit;
|
|
}
|
|
|
|
function save_preferences() {
|
|
global $sitepress;
|
|
|
|
$iclsettings['st']['auto_download_mo'] = @intval( $_POST['auto_download_mo'] );
|
|
$iclsettings['hide_upgrade_notice'] = implode( '.', array_slice( explode( '.', ICL_SITEPRESS_VERSION ), 0, 3 ) );
|
|
$sitepress->save_settings( $iclsettings );
|
|
if ( $iclsettings['st']['auto_download_mo'] ) {
|
|
try {
|
|
$this->updates_check( array( 'trigger' => 'setting-changed' ) );
|
|
} catch ( Exception $e ) {
|
|
}
|
|
}
|
|
wp_send_json_success( array( 'enabled' => $iclsettings['st']['auto_download_mo'] ) );
|
|
}
|
|
|
|
function save_settings() {
|
|
update_option( 'icl_adl_settings', $this->settings );
|
|
}
|
|
|
|
function get_option( $name ) {
|
|
return isset( $this->settings[ $name ] ) ? $this->settings[ $name ] : null;
|
|
}
|
|
|
|
function load_xml() {
|
|
if ( ! class_exists( 'WP_Http' ) ) {
|
|
include_once ABSPATH . WPINC . '/class-http.php';
|
|
}
|
|
$client = new WP_Http();
|
|
$response = $client->request(
|
|
self::LOCALES_XML_FILE,
|
|
array(
|
|
'timeout' => 15,
|
|
'decompress' => false,
|
|
)
|
|
);
|
|
|
|
if ( is_wp_error( $response ) || ! in_array( $response['response']['code'], array( 200, 301, 300 ) ) ) {
|
|
$load_xml_error_message = '';
|
|
if ( isset( $response->errors ) ) {
|
|
$errors = '';
|
|
foreach ( $response->errors as $error => $error_messages ) {
|
|
$errors .= $error . '<br/>';
|
|
foreach ( $error_messages as $error_message ) {
|
|
$errors .= '- ' . $error_message . '<br/>';
|
|
}
|
|
}
|
|
$load_xml_error_message .= sprintf( __( 'Failed downloading the language information file.', 'wpml-string-translation' ), $errors );
|
|
$load_xml_error_message .= '<br/>' . sprintf( __( 'Errors: %s', 'wpml-string-translation' ), $errors );
|
|
} else {
|
|
$load_xml_error_message .= __( 'Failed downloading the language information file. Please go back and try a little later.', 'wpml-string-translation' );
|
|
}
|
|
|
|
if ( ! is_wp_error( $response ) && isset( $response['response'] ) ) {
|
|
$load_xml_error_message .= '<br/>Response: ' . $response['response']['code'] . ' (' . $response['response']['message'] . ').';
|
|
}
|
|
|
|
$this->xml = false;
|
|
|
|
throw new Exception( $load_xml_error_message );
|
|
} elseif ( $response['response']['code'] == 200 ) {
|
|
require_once ICL_PLUGIN_PATH . '/lib/icl_api.php';
|
|
$this->xml = new SimpleXMLElement( icl_gzdecode( $response['body'] ) );
|
|
}
|
|
}
|
|
|
|
function get_mo_file_urls( $wplocale ) {
|
|
if ( ! $this->xml ) {
|
|
return false;
|
|
}
|
|
|
|
global $wp_version;
|
|
|
|
$wpversion = preg_replace( '#-(.+)$#', '', $wp_version );
|
|
$wpversion = join( '.', array_slice( explode( '.', $wpversion ), 0, 2 ) ) . '.x';
|
|
|
|
$exp = explode( '-', $wplocale );
|
|
$language = $exp[0];
|
|
$locale = isset( $exp[1] ) ? $wplocale : $language;
|
|
|
|
$mo_files = array();
|
|
|
|
$projects = $this->xml->xpath( $language . '/' . $locale );
|
|
if ( ! empty( $projects ) ) {
|
|
|
|
$project_names = array();
|
|
foreach ( $projects[0] as $project_name => $data ) {
|
|
// subprojects
|
|
if ( empty( $data->versions ) ) {
|
|
$subprojects = $this->xml->xpath( $language . '/' . $locale . '/' . $project_name );
|
|
if ( ! empty( $subprojects ) ) {
|
|
foreach ( $subprojects[0] as $sub_project_name => $sdata ) {
|
|
$project_names[] = $project_name . '/' . $sub_project_name;
|
|
}
|
|
}
|
|
} else {
|
|
$project_names[] = $project_name;
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $project_names ) ) {
|
|
foreach ( $project_names as $project_name ) {
|
|
// try to get the corresponding version
|
|
$locv_path = $this->xml->xpath( "{$language}/{$locale}/{$project_name}/versions/version[@number=\"" . $wpversion . '"]' );
|
|
// try to get the dev recent version
|
|
if ( empty( $locv_path ) ) {
|
|
$locv_path = $this->xml->xpath( "{$language}/{$locale}/{$project_name}/versions/version[@number=\"dev\"]" );
|
|
}
|
|
if ( ! empty( $locv_path ) ) {
|
|
$mo_files[ $project_name ]['url'] = (string) $locv_path[0]->url;
|
|
$mo_files[ $project_name ]['signature'] = (string) $locv_path[0]['signature'];
|
|
$mo_files[ $project_name ]['translated'] = (string) $locv_path[0]['translated'];
|
|
$mo_files[ $project_name ]['untranslated'] = (string) $locv_path[0]['untranslated'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $mo_files;
|
|
}
|
|
|
|
function get_translation_files() {
|
|
global $sitepress;
|
|
|
|
$active_languages = $sitepress->get_active_languages();
|
|
|
|
foreach ( $active_languages as $language ) {
|
|
$locale = $sitepress->get_locale( $language['code'] );
|
|
if ( ! isset( $this->lang_map[ $locale ] ) ) {
|
|
continue;
|
|
}
|
|
$wplocale = $this->lang_map[ $locale ];
|
|
|
|
$urls = $this->get_mo_file_urls( $wplocale );
|
|
|
|
if ( ! empty( $urls ) ) {
|
|
$this->translation_files[ $language['code'] ] = $urls;
|
|
}
|
|
}
|
|
|
|
return $this->translation_files;
|
|
}
|
|
|
|
function get_translations( $language, $args = array() ) {
|
|
global $wpdb;
|
|
|
|
$translations = array();
|
|
$types = array( 'core' );
|
|
|
|
extract( $args, EXTR_OVERWRITE );
|
|
|
|
if ( ! class_exists( 'WP_Http' ) ) {
|
|
include_once ABSPATH . WPINC . '/class-http.php';
|
|
}
|
|
$client = new WP_Http();
|
|
|
|
foreach ( $types as $type ) {
|
|
|
|
if ( isset( $this->translation_files[ $language ][ $type ]['url'] ) ) {
|
|
|
|
$response = $client->request( $this->translation_files[ $language ][ $type ]['url'], array( 'timeout' => 15 ) );
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
$err = __( 'Error getting the translation file. Please go back and try again.', 'wordpress-language' );
|
|
if ( isset( $response->errors['http_request_failed'][0] ) ) {
|
|
$err .= '<br />' . $response->errors['http_request_failed'][0];
|
|
}
|
|
echo '<div class="error"><p>' . $err . '</p></div>';
|
|
return false;
|
|
|
|
}
|
|
|
|
$mo = new MO();
|
|
$pomo_reader = new POMO_StringReader( $response['body'] );
|
|
$mo->import_from_reader( $pomo_reader );
|
|
$data = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"
|
|
SELECT st.value, s.name, s.gettext_context
|
|
FROM {$wpdb->prefix}icl_string_translations st
|
|
JOIN {$wpdb->prefix}icl_strings s ON st.string_id = s.id
|
|
WHERE s.context = %s AND st.language = %s
|
|
",
|
|
self::CONTEXT,
|
|
$language
|
|
)
|
|
);
|
|
$string_existing = array();
|
|
foreach ( $data as $row ) {
|
|
$string_existing[ md5( $row->name . $row->gettext_context ) ] = $row->value;
|
|
}
|
|
|
|
foreach ( $mo->entries as $key => $v ) {
|
|
|
|
$tpairs = array();
|
|
$v->singular = str_replace( "\n", '\n', $v->singular );
|
|
$tpairs[] = array(
|
|
'string' => $v->singular,
|
|
'translation' => $v->translations[0],
|
|
'name' => md5( $v->singular ),
|
|
'gettext_context' => $v->context,
|
|
);
|
|
|
|
if ( $v->is_plural ) {
|
|
$v->plural = str_replace( "\n", '\n', $v->plural );
|
|
$tpairs[] = array(
|
|
'string' => $v->plural,
|
|
'translation' => ! empty( $v->translations[1] ) ? $v->translations[1] : $v->translations[0],
|
|
'name' => md5( $v->plural ),
|
|
'gettext_context' => $v->context,
|
|
);
|
|
}
|
|
|
|
foreach ( $tpairs as $pair ) {
|
|
$key = md5( $pair['name'] . $pair['gettext_context'] );
|
|
$existing_translation = isset( $string_existing[ $key ] ) ? $string_existing[ $key ] : null;
|
|
|
|
if ( empty( $existing_translation ) ) {
|
|
$translations['new'][] = array(
|
|
'string' => $pair['string'],
|
|
'translation' => '',
|
|
'new' => $pair['translation'],
|
|
'name' => $pair['name'],
|
|
'gettext_context' => $pair['gettext_context'],
|
|
);
|
|
} else {
|
|
|
|
if ( strcmp( $existing_translation, $pair['translation'] ) !== 0 ) {
|
|
$translations['updated'][] = array(
|
|
'string' => $pair['string'],
|
|
'translation' => $existing_translation,
|
|
'new' => $pair['translation'],
|
|
'name' => $pair['name'],
|
|
'gettext_context' => $pair['gettext_context'],
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $translations;
|
|
}
|
|
|
|
function save_translations( $data, $language, $version = false ) {
|
|
|
|
set_time_limit( 0 );
|
|
|
|
if ( false === $version ) {
|
|
global $wp_version;
|
|
$version = preg_replace( '#-(.+)$#', '', $wp_version );
|
|
}
|
|
|
|
foreach ( $data as $key => $string ) {
|
|
if ( $string['gettext_context'] ) {
|
|
$string_context = array(
|
|
'domain' => self::CONTEXT,
|
|
'context' => $string['gettext_context'],
|
|
);
|
|
} else {
|
|
$string_context = self::CONTEXT;
|
|
}
|
|
$string_id = icl_register_string( $string_context, $string['name'], $string['string'] );
|
|
if ( $string_id ) {
|
|
icl_add_string_translation( $string_id, $language, $string['translation'], ICL_TM_COMPLETE );
|
|
}
|
|
}
|
|
|
|
$version_projects = explode( ';', $version );
|
|
foreach ( $version_projects as $project ) {
|
|
$exp = explode( '|', $project );
|
|
$this->settings['translations'][ $language ][ $exp[0] ]['time'] = time();
|
|
$this->settings['translations'][ $language ][ $exp[0] ]['installed'] = $exp[1];
|
|
}
|
|
|
|
$this->save_settings();
|
|
|
|
}
|
|
|
|
}
|