first commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
function translation_service_details( $service, $show_project = false ) {
|
||||
$service_details = '';
|
||||
if ( defined( 'OTG_SANDBOX_DEBUG' ) && OTG_SANDBOX_DEBUG ) {
|
||||
$service_details .= '<h3>Service details:</h3>' . PHP_EOL;
|
||||
$service_details .= '<pre>' . PHP_EOL;
|
||||
$service_details .= print_r( $service, true );
|
||||
$service_details .= '</pre>' . PHP_EOL;
|
||||
|
||||
if ( $show_project ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
echo '<pre>$project' . PHP_EOL;
|
||||
echo print_r( $project, true );
|
||||
echo '</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
return $service_details;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'object_to_array' ) ) {
|
||||
function object_to_array( $obj ) {
|
||||
if ( is_object( $obj ) ) {
|
||||
$obj = (array) $obj;
|
||||
}
|
||||
if ( is_array( $obj ) ) {
|
||||
$new = array();
|
||||
foreach ( $obj as $key => $val ) {
|
||||
$new[ $key ] = object_to_array( $val );
|
||||
}
|
||||
} else {
|
||||
$new = $obj;
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
if( class_exists( 'TranslationProxy_Api' ) ) {
|
||||
// Workaround for UnitTests.
|
||||
return;
|
||||
}
|
||||
|
||||
class TranslationProxy_Api {
|
||||
const API_VERSION = 1.1;
|
||||
|
||||
public static function proxy_request(
|
||||
$path,
|
||||
$params = array(),
|
||||
$method = 'GET',
|
||||
$multi_part = false,
|
||||
$has_return_value = true
|
||||
) {
|
||||
|
||||
return wpml_tm_load_tp_networking()->send_request(
|
||||
OTG_TRANSLATION_PROXY_URL . $path,
|
||||
$params,
|
||||
$method,
|
||||
$has_return_value
|
||||
);
|
||||
}
|
||||
|
||||
public static function proxy_download( $path, $params ) {
|
||||
|
||||
return wpml_tm_load_tp_networking()->send_request(
|
||||
OTG_TRANSLATION_PROXY_URL . $path,
|
||||
$params,
|
||||
'GET',
|
||||
true,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static function service_request(
|
||||
$url,
|
||||
$params = array(),
|
||||
$method = 'GET',
|
||||
$has_return_value = true,
|
||||
$json_response = false,
|
||||
$has_api_response = false
|
||||
) {
|
||||
|
||||
return wpml_tm_load_tp_networking()->send_request(
|
||||
$url,
|
||||
$params,
|
||||
$method,
|
||||
$has_return_value,
|
||||
$json_response,
|
||||
$has_api_response
|
||||
);
|
||||
}
|
||||
|
||||
public static function add_parameters_to_url( $url, $params ) {
|
||||
if ( preg_match_all( '/\{.+?\}/', $url, $symbs ) ) {
|
||||
foreach ( $symbs[0] as $symb ) {
|
||||
$without_braces = preg_replace( '/\{|\}/', '', $symb );
|
||||
if ( preg_match_all( '/\w+/', $without_braces, $indexes ) ) {
|
||||
foreach ( $indexes[0] as $index ) {
|
||||
if ( isset( $params[ $index ] ) ) {
|
||||
$value = $params[ $index ];
|
||||
$url = preg_replace( preg_quote( "/$symb/" ), $value, $url );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'gzdecode' ) ) {
|
||||
/**
|
||||
* Inflates a string enriched with gzip headers. Counterpart to gzencode().
|
||||
* Extracted from upgradephp
|
||||
* http://include-once.org/p/upgradephp/
|
||||
*
|
||||
* officially available by default in php @since 5.4.
|
||||
*/
|
||||
function gzdecode( $gzdata, $maxlen = null ) {
|
||||
|
||||
// -- decode header
|
||||
$len = strlen( $gzdata );
|
||||
if ( $len < 20 ) {
|
||||
return;
|
||||
}
|
||||
$head = substr( $gzdata, 0, 10 );
|
||||
$head = unpack( 'n1id/C1cm/C1flg/V1mtime/C1xfl/C1os', $head );
|
||||
list( $ID, $CM, $FLG, $MTIME, $XFL, $OS ) = array_values( $head );
|
||||
$FTEXT = 1 << 0;
|
||||
$FHCRC = 1 << 1;
|
||||
$FEXTRA = 1 << 2;
|
||||
$FNAME = 1 << 3;
|
||||
$FCOMMENT = 1 << 4;
|
||||
$head = unpack( 'V1crc/V1isize', substr( $gzdata, $len - 8, 8 ) );
|
||||
list( $CRC32, $ISIZE ) = array_values( $head );
|
||||
|
||||
// -- check gzip stream identifier
|
||||
if ( $ID != 0x1f8b ) {
|
||||
trigger_error( 'gzdecode: not in gzip format', E_USER_WARNING );
|
||||
|
||||
return;
|
||||
}
|
||||
// -- check for deflate algorithm
|
||||
if ( $CM != 8 ) {
|
||||
trigger_error( 'gzdecode: cannot decode anything but deflated streams', E_USER_WARNING );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// -- start of data, skip bonus fields
|
||||
$s = 10;
|
||||
if ( $FLG & $FEXTRA ) {
|
||||
$s += $XFL;
|
||||
}
|
||||
if ( $FLG & $FNAME ) {
|
||||
$s = strpos( $gzdata, "\000", $s ) + 1;
|
||||
}
|
||||
if ( $FLG & $FCOMMENT ) {
|
||||
$s = strpos( $gzdata, "\000", $s ) + 1;
|
||||
}
|
||||
if ( $FLG & $FHCRC ) {
|
||||
$s += 2; // cannot check
|
||||
}
|
||||
|
||||
// -- get data, uncompress
|
||||
$gzdata = substr( $gzdata, $s, $len - $s );
|
||||
if ( $maxlen ) {
|
||||
$gzdata = gzinflate( $gzdata, $maxlen );
|
||||
|
||||
return ( $gzdata ); // no checks(?!)
|
||||
} else {
|
||||
$gzdata = gzinflate( $gzdata );
|
||||
}
|
||||
|
||||
// -- check+fin
|
||||
$chk = crc32( $gzdata );
|
||||
if ( $CRC32 != $chk ) {
|
||||
trigger_error( "gzdecode: checksum failed (real$chk != comp$CRC32)", E_USER_WARNING );
|
||||
} elseif ( $ISIZE != strlen( $gzdata ) ) {
|
||||
trigger_error( 'gzdecode: stream size mismatch', E_USER_WARNING );
|
||||
} else {
|
||||
return ( $gzdata );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,927 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
use WPML\TM\API\Jobs;
|
||||
|
||||
if ( ! class_exists( 'TranslationProxy_Basket' ) ) {
|
||||
/**
|
||||
* TranslationProxy_basket collects all static methods to operate on
|
||||
* translations basket (cart)
|
||||
*/
|
||||
class TranslationProxy_Basket {
|
||||
private static $messages;
|
||||
private static $dashboard_select;
|
||||
|
||||
private static $basket;
|
||||
|
||||
// The name of the option stored in wp_options table and that
|
||||
// stores all the basket items
|
||||
const ICL_TRANSLATION_JOBS_BASKET = 'icl_translation_jobs_basket';
|
||||
private static $posts_ids;
|
||||
private static $translate_from;
|
||||
private static $translation_action;
|
||||
|
||||
public static function add_message( $array ) {
|
||||
self::$messages[] = $array;
|
||||
}
|
||||
|
||||
public static function remove_message( $text ) {
|
||||
if ( is_array( self::$messages ) ) {
|
||||
foreach ( self::$messages as $key => $message ) {
|
||||
if ( array_key_exists( 'text', $message ) && $message['text'] === $text ) {
|
||||
unset( self::$messages[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_basket( $force = false ) {
|
||||
if ( ! isset( self::$basket ) || $force ) {
|
||||
self::$basket = get_option( self::ICL_TRANSLATION_JOBS_BASKET, [] );
|
||||
}
|
||||
|
||||
return self::$basket;
|
||||
}
|
||||
|
||||
public static function update_basket( $basket_portion = array() ) {
|
||||
if ( ! empty( $basket_portion ) ) {
|
||||
if ( ! self::$basket || self::get_basket_items_count() == 0 ) {
|
||||
self::$basket = $basket_portion;
|
||||
} else {
|
||||
self::$basket = self::merge_baskets( self::$basket, $basket_portion );
|
||||
}
|
||||
}
|
||||
if ( self::get_basket_items_count( true ) == 0 ) {
|
||||
self::$basket = [];
|
||||
}
|
||||
self::sync_target_languages();
|
||||
self::update_basket_option( self::$basket );
|
||||
self::update_basket_notifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $basket
|
||||
*/
|
||||
private static function update_basket_option( $basket ) {
|
||||
update_option( self::ICL_TRANSLATION_JOBS_BASKET, $basket, false );
|
||||
}
|
||||
|
||||
private static function merge_baskets( $from, $to ) {
|
||||
if ( function_exists( 'array_replace_recursive' ) ) {
|
||||
return array_replace_recursive( $from, $to );
|
||||
} else {
|
||||
return self::array_replace_recursive( $from, $to );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of items in translation basket by key
|
||||
*
|
||||
* @param string $type
|
||||
* @param bool $skip_cache
|
||||
*
|
||||
* @return int number of items in translation basket
|
||||
*/
|
||||
public static function get_basket_items_type_count( $type, $skip_cache = false ) {
|
||||
|
||||
$cache_key = $type;
|
||||
$cache_group = 'get_basket_items_type_count';
|
||||
$cache_found = false;
|
||||
|
||||
if ( ! $skip_cache ) {
|
||||
$basket_items_number = (int) wp_cache_get( $cache_key, $cache_group, false, $cache_found );
|
||||
} else {
|
||||
$basket_items_number = 0;
|
||||
}
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $basket_items_number;
|
||||
}
|
||||
|
||||
self::get_basket();
|
||||
|
||||
if ( self::$basket ) {
|
||||
if ( isset( self::$basket[ $type ] ) ) {
|
||||
$posts = self::$basket[ $type ];
|
||||
$basket_items_number += count( $posts );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $skip_cache ) {
|
||||
wp_cache_set( $cache_key, $basket_items_number, $cache_group );
|
||||
}
|
||||
|
||||
return $basket_items_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of items in translation basket
|
||||
*
|
||||
* @param bool $skip_cache
|
||||
*
|
||||
* @return int number of items in translation basket
|
||||
*/
|
||||
public static function get_basket_items_count( $skip_cache = false ) {
|
||||
|
||||
$basket_items_number = 0;
|
||||
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
$basket_items_number += self::get_basket_items_type_count( $item_type_name, $skip_cache );
|
||||
}
|
||||
|
||||
return $basket_items_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register notification with number of items in basket and link to basket
|
||||
*/
|
||||
public static function update_basket_notifications() {
|
||||
$positions = self::get_basket_notification_positions();
|
||||
$basket_link = 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=basket';
|
||||
|
||||
foreach ( $positions as $position => $group ) {
|
||||
ICL_AdminNotifier::remove_message_group( $position );
|
||||
}
|
||||
|
||||
self::get_basket();
|
||||
$basket_items_count = self::get_basket_items_count( true );
|
||||
|
||||
$limit_to_page = array();
|
||||
if ( defined( 'WPML_ST_FOLDER' ) ) {
|
||||
$limit_to_page[] = WPML_ST_FOLDER . '/menu/string-translation.php';
|
||||
}
|
||||
|
||||
// if we have something in the basket
|
||||
if ( self::is_st_page() && $basket_items_count > 0 && ( ! isset( $_GET['clear_basket'] ) || $_GET['clear_basket'] != 1 ) && ( ! isset( $_GET['action'] ) || $_GET['action'] != 'delete' ) ) {
|
||||
|
||||
$text = __( 'The items you have selected are now in the translation basket –', 'wpml-translation-management' );
|
||||
$text .= ' ' . sprintf( __( '<a href="%s">Send to translation »</a>', 'wpml-translation-management' ), $basket_link );
|
||||
|
||||
// translation management pages
|
||||
$message_args = array(
|
||||
'id' => $positions['tm_dashboard_top'],
|
||||
'text' => $text,
|
||||
'classes' => 'small',
|
||||
'type' => 'information small',
|
||||
'group' => $positions['tm_dashboard_top'],
|
||||
'admin_notice' => false,
|
||||
'hide_per_user' => false,
|
||||
'dismiss_per_user' => false,
|
||||
'limit_to_page' => $limit_to_page,
|
||||
'capability' => 'manage_translations',
|
||||
);
|
||||
ICL_AdminNotifier::add_message( $message_args );
|
||||
|
||||
} else {
|
||||
ICL_AdminNotifier::remove_message( $positions['tm_dashboard_top'] );
|
||||
}
|
||||
|
||||
$admin_basket_message_id = $positions['admin_notice'];
|
||||
if ( ( self::$messages || $basket_items_count > 0 ) && self::is_st_page() ) {
|
||||
|
||||
$additional_messages = array();
|
||||
if ( isset( self::$messages ) && is_array( self::$messages ) ) {
|
||||
foreach ( self::$messages as $message ) {
|
||||
$additional_messages[] = $message['text'];
|
||||
}
|
||||
}
|
||||
$additional_messages_text = '';
|
||||
if ( count( $additional_messages ) > 0 ) {
|
||||
$additional_messages_text = '<ul><li>' . implode( '</li><li>', $additional_messages ) . '</li></ul>';
|
||||
}
|
||||
|
||||
$message_args = array(
|
||||
'id' => $admin_basket_message_id,
|
||||
'text' => $additional_messages_text,
|
||||
'classes' => 'small',
|
||||
'type' => 'information',
|
||||
'group' => $admin_basket_message_id,
|
||||
'admin_notice' => true,
|
||||
'hide_per_user' => false,
|
||||
'dismiss_per_user' => false,
|
||||
'limit_to_page' => $limit_to_page,
|
||||
'show_once' => true,
|
||||
);
|
||||
|
||||
if ( trim( $additional_messages_text ) != '' ) {
|
||||
ICL_AdminNotifier::add_message( $message_args );
|
||||
}
|
||||
} else {
|
||||
ICL_AdminNotifier::remove_message( $admin_basket_message_id );
|
||||
}
|
||||
}
|
||||
|
||||
private static function is_st_page() {
|
||||
return defined( 'WPML_ST_FOLDER' ) && array_key_exists( 'page', $_GET ) && false !== strpos( $_GET['page'], WPML_ST_FOLDER );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays div with number of items in basket and link to basket
|
||||
* Removes notification if basket is empty
|
||||
*/
|
||||
public static function display_basket_items_notification() {
|
||||
ICL_AdminNotifier::display_messages( 'translation-basket-notification' );
|
||||
}
|
||||
|
||||
public static function is_in_basket( $post_id, $source_language, $target_language, $item_type = 'post' ) {
|
||||
self::get_basket();
|
||||
|
||||
if ( ! self::$basket || ! isset( self::$basket[ $item_type ][ $post_id ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$basket_item = self::$basket[ $item_type ][ $post_id ];
|
||||
|
||||
return $basket_item['from_lang'] == $source_language && isset( $basket_item['to_langs'][ $target_language ] ) && $basket_item['to_langs'][ $target_language ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if post with ID $post_id is in the basket for any language
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param string $element_type
|
||||
* @param array $check_in_languages
|
||||
* @param bool $original_language_code
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function anywhere_in_basket( $post_id, $element_type = 'post', $check_in_languages = array(), $original_language_code = false ) {
|
||||
$basket = self::get_basket();
|
||||
|
||||
if ( $post_id && isset( $basket[ $element_type ][ $post_id ] ) ) {
|
||||
if ( $check_in_languages ) {
|
||||
if ( ! $original_language_code ) {
|
||||
$original_language_code = $basket['source_language'];
|
||||
}
|
||||
foreach ( $check_in_languages as $language_code => $language_data ) {
|
||||
if ( $language_code != $original_language_code && isset( $basket[ $element_type ][ $post_id ]['to_langs'][ $language_code ] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function is_string_in_basket_anywhere( $string_id ) {
|
||||
return self::anywhere_in_basket( $string_id, 'string' );
|
||||
}
|
||||
|
||||
public static function has_any_string() {
|
||||
return self::has_any_item_type( 'string' );
|
||||
}
|
||||
|
||||
public static function has_any_item_type( $item_type ) {
|
||||
self::get_basket();
|
||||
return isset( self::$basket[ $item_type ] ) && count( self::$basket[ $item_type ] );
|
||||
}
|
||||
|
||||
/**** adding items to basket ****/
|
||||
|
||||
/**
|
||||
* Serves Translation Dashboard form submission and adds posts to basket
|
||||
*
|
||||
* @param array $data data submitted from form
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function add_posts_to_basket( $data ) {
|
||||
self::get_basket();
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
$wpml_translation_job_factory = wpml_tm_load_job_factory();
|
||||
|
||||
extract( $data, EXTR_OVERWRITE );
|
||||
|
||||
ICL_AdminNotifier::remove_message( 'the_basket_items_notification' );
|
||||
|
||||
self::$translation_action = null;
|
||||
if ( isset( $data['tr_action'] ) ) { // adapt new format
|
||||
self::$translation_action = $data['tr_action'];
|
||||
}
|
||||
if ( ! isset( $data['tr_action'] ) && isset( $data['translate_to'] ) ) { // adapt new format
|
||||
$data['tr_action'] = $data['translate_to'];
|
||||
self::$translation_action = $data['tr_action'];
|
||||
unset( $data['translate_to'] );
|
||||
}
|
||||
|
||||
self::$posts_ids = self::get_elements_ids( $data, 'post' );
|
||||
|
||||
self::$translate_from = $data ['translate_from']; // language of the submitted posts transported by hidden field
|
||||
|
||||
$data_is_valid = self::validate_data( $data );
|
||||
|
||||
if ( ! $data_is_valid ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check tr_action and do what user decided
|
||||
foreach ( self::$translation_action as $language_code => $status ) {
|
||||
|
||||
$language_name = $sitepress->get_display_language_name( $language_code );
|
||||
// if he decided duplicate or not to translate for this particular language,
|
||||
// try to remove it from wp_options
|
||||
|
||||
$basket_item_type = 'post';
|
||||
|
||||
if ( $status == 2 ) {
|
||||
// iterate posts ids, check if they are in wp_options
|
||||
// if they are set to translate for this particular language
|
||||
// end then remove it
|
||||
foreach ( self::$posts_ids as $id ) {
|
||||
if ( isset( self::$basket[ $basket_item_type ][ $id ]['to_langs'][ $language_code ] ) ) {
|
||||
unset( self::$basket[ $basket_item_type ][ $id ]['to_langs'][ $language_code ] );
|
||||
}
|
||||
// if user want to duplicate this post, lets do this
|
||||
if ( $status == 2 ) {
|
||||
$iclTranslationManagement->make_duplicate( $id, $language_code );
|
||||
}
|
||||
}
|
||||
} elseif ( $status == 1 ) {
|
||||
foreach ( self::$posts_ids as $id ) {
|
||||
|
||||
$send_to_basket = true;
|
||||
|
||||
$post = self::get_post( $id );
|
||||
|
||||
$post_type = $post->post_type;
|
||||
$messages = new \WPML\TM\Jobs\Dispatch\Messages();
|
||||
global $wpdb;
|
||||
$source_language_code = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
" SELECT source_language_code
|
||||
FROM {$wpdb->prefix}icl_translations
|
||||
WHERE element_type LIKE 'post_%%'
|
||||
AND element_id = %d",
|
||||
$post->ID
|
||||
)
|
||||
);
|
||||
|
||||
if ( $source_language_code != $language_code ) {
|
||||
$job = Jobs::getPostJob( $id, $post_type, $language_code );
|
||||
if ( $job && ICL_TM_IN_PROGRESS === $job->status && ! $job->needs_update ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => $messages->ignoreInProgressPostMessage( $post, $language_name ),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
} else {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => $messages->ignoreOriginalPostMessage( $post, $language_name ),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
|
||||
if ( $send_to_basket ) {
|
||||
self::$basket[ $basket_item_type ][ $id ]['from_lang'] = self::$translate_from;
|
||||
self::$basket[ $basket_item_type ][ $id ]['to_langs'][ $language_code ] = 1;
|
||||
// set basket language if not already set
|
||||
if ( ! isset( self::$basket['source_language'] ) ) {
|
||||
self::$basket['source_language'] = self::$translate_from;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_basket();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves WPML > String translation form submission and adds strings to basket
|
||||
*
|
||||
* @param array $string_ids identifiers of strings
|
||||
* @param $source_language
|
||||
* @param array $target_languages selected target languages
|
||||
* @return bool
|
||||
* @todo: [WPML 3.3] move to ST and handle with hooks
|
||||
*/
|
||||
public static function add_strings_to_basket( $string_ids, $source_language, $target_languages ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
self::get_basket();
|
||||
ICL_AdminNotifier::remove_message( 'the_basket_items_notification' );
|
||||
|
||||
/*
|
||||
structure of cart in get_option:
|
||||
* [posts]
|
||||
* [element_id]
|
||||
* [to_langs]
|
||||
* [language_code] fr | pl | de ... with value 1
|
||||
* [strings]
|
||||
* [string_id]
|
||||
* [to_langs]
|
||||
* [language_code]
|
||||
*/
|
||||
|
||||
// no post selected ?
|
||||
if ( empty( $string_ids ) ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one document to translate.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::update_basket();
|
||||
return false;
|
||||
}
|
||||
|
||||
// no language selected ?
|
||||
if ( empty( $target_languages ) ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one language to translate into.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::update_basket();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self::get_basket() && self::get_source_language() ) {
|
||||
/*
|
||||
we do not add items that are not in the source language of the current basket
|
||||
we cannot yet set its source language though since update_basket would set the basket
|
||||
to false oso long as we do not have any elements in the basket*/
|
||||
if ( $source_language != self::get_source_language() ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => __(
|
||||
'You cannot add strings in this language to the basket since it already contains posts or strings of another source language!
|
||||
Either submit the current basket and then add the post or delete the posts of differing language in the current basket',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
);
|
||||
self::update_basket();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $target_languages as $target_language => $selected ) {
|
||||
if ( $target_language == $source_language ) {
|
||||
continue;
|
||||
}
|
||||
$target_language_name = $sitepress->get_display_language_name( $target_language );
|
||||
|
||||
foreach ( $string_ids as $id ) {
|
||||
|
||||
$send_to_basket = true;
|
||||
$query = " SELECT {$wpdb->prefix}icl_string_translations.status,
|
||||
{$wpdb->prefix}icl_strings.value
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
INNER JOIN {$wpdb->prefix}icl_strings
|
||||
ON {$wpdb->prefix}icl_string_translations.string_id = {$wpdb->prefix}icl_strings.id
|
||||
WHERE {$wpdb->prefix}icl_string_translations.string_id=%d
|
||||
AND {$wpdb->prefix}icl_string_translations.language=%s";
|
||||
|
||||
$string_translation = $wpdb->get_row( $wpdb->prepare( $query, $id, $target_language ) );
|
||||
|
||||
if ( ! is_null( $string_translation ) && $string_translation->status == ICL_TM_WAITING_FOR_TRANSLATOR ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => sprintf(
|
||||
__(
|
||||
'String "%1$s" will be ignored for %2$s, because translation is already waiting for translator.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$string_translation->value,
|
||||
$target_language_name
|
||||
),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
|
||||
if ( $send_to_basket ) {
|
||||
self::$basket['string'][ $id ]['from_lang'] = $source_language;
|
||||
self::$basket['string'][ $id ]['to_langs'][ $target_language ] = 1;
|
||||
// set basket language if not already set
|
||||
if ( ! isset( self::$basket['source_language'] ) ) {
|
||||
self::$basket['source_language'] = $source_language;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_basket();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves deletion of items from basket, triggered from WPML TM > Translation
|
||||
* Jobs
|
||||
*
|
||||
* @param array $items Array of items ids, in two separate parts: ['post']
|
||||
* and ['string']
|
||||
*/
|
||||
public static function delete_items_from_basket( $items ) {
|
||||
self::get_basket();
|
||||
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
if ( ! empty( $items[ $item_type_name ] ) ) {
|
||||
foreach ( $items[ $item_type_name ] as $id ) {
|
||||
self::delete_item_from_basket( $id, $item_type_name, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one item from basket
|
||||
*
|
||||
* @param int $id Item ID
|
||||
* @param string $type Item type (strings | posts | ...)
|
||||
* @param bool $update_option do update_option('icl_translation_jobs_cart' ?
|
||||
*/
|
||||
public static function delete_item_from_basket( $id, $type = 'post', $update_option = true ) {
|
||||
self::get_basket();
|
||||
|
||||
if ( isset( self::$basket[ $type ][ $id ] ) ) {
|
||||
unset( self::$basket[ $type ][ $id ] );
|
||||
if ( count( self::$basket[ $type ] ) == 0 ) {
|
||||
unset( self::$basket[ $type ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( self::get_basket_items_count( true ) == 0 ) {
|
||||
self::$basket = array();
|
||||
}
|
||||
|
||||
if ( $update_option ) {
|
||||
self::update_basket( self::$basket );
|
||||
} else {
|
||||
self::update_basket_notifications();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [WPML 3.3] implement this in the troubleshooting page
|
||||
public static function delete_all_items_from_basket() {
|
||||
self::$basket = [];
|
||||
delete_option( self::ICL_TRANSLATION_JOBS_BASKET );
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TP_Batch|null $batch
|
||||
*/
|
||||
public static function set_batch_data( $batch ) {
|
||||
self::get_basket();
|
||||
self::$basket['batch'] = $batch;
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|null|WPML_TP_Batch
|
||||
*/
|
||||
public static function get_batch_data() {
|
||||
self::get_basket();
|
||||
return isset( self::$basket['batch'] ) ? self::$basket['batch'] : false;
|
||||
}
|
||||
|
||||
public static function set_basket_name( $basket_name ) {
|
||||
self::get_basket();
|
||||
self::$basket['name'] = $basket_name;
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
public static function get_basket_name() {
|
||||
self::get_basket();
|
||||
|
||||
return isset( self::$basket['name'] ) ? self::$basket['name'] : false;
|
||||
}
|
||||
|
||||
public static function set_options( array $options ) {
|
||||
self::$basket['options'] = $options;
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public static function get_options() {
|
||||
return isset( self::$basket['options'] ) ? self::$basket['options'] : array();
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields() {
|
||||
if ( isset( $_REQUEST['extra_fields'] ) ) {
|
||||
$extra_fields_string = urldecode( $_REQUEST['extra_fields'] );
|
||||
if ( strlen( $extra_fields_string ) > 0 ) {
|
||||
$extra_fields_rows = explode( '|', $extra_fields_string );
|
||||
$result = array();
|
||||
foreach ( $extra_fields_rows as $row ) {
|
||||
$row_data = explode( ':', $row );
|
||||
if ( count( $row_data ) == 2 ) {
|
||||
$result[ $row_data[0] ] = $row_data[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $result ) && count( $result ) > 0 ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function array_replace_recursive( $array, $array1 ) {
|
||||
if ( function_exists( 'array_replace_recursive' ) ) {
|
||||
$array = array_replace_recursive( $array, $array1 );
|
||||
} else {
|
||||
// handle the arguments, merge one by one
|
||||
$args = func_get_args();
|
||||
$array = $args[0];
|
||||
if ( ! is_array( $array ) ) {
|
||||
return $array;
|
||||
}
|
||||
for ( $i = 1; $i < count( $args ); $i ++ ) {
|
||||
if ( is_array( $args[ $i ] ) ) {
|
||||
$array = self::recurse( $array, $args[ $i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
private static function recurse( $array, $array1 ) {
|
||||
foreach ( $array1 as $key => $value ) {
|
||||
// create new key in $array, if it is empty or not an array
|
||||
if ( ! isset( $array[ $key ] ) || ( isset( $array[ $key ] ) && ! is_array( $array[ $key ] ) ) ) {
|
||||
$array[ $key ] = array();
|
||||
}
|
||||
|
||||
// overwrite the value in the base array
|
||||
if ( is_array( $value ) ) {
|
||||
$value = self::recurse( $array[ $key ], $value );
|
||||
}
|
||||
$array[ $key ] = $value;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public static function get_basket_items_types() {
|
||||
return apply_filters(
|
||||
'wpml_tm_basket_items_types',
|
||||
[
|
||||
'string' => 'core',
|
||||
'post' => 'core',
|
||||
'package' => 'custom',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post_id
|
||||
*
|
||||
* @return mixed|null|void|WP_Post
|
||||
*/
|
||||
private static function get_post( $post_id ) {
|
||||
if ( is_string( $post_id ) && strcmp( substr( $post_id, 0, strlen( 'external_' ) ), 'external_' ) === 0 ) {
|
||||
$item = apply_filters( 'wpml_get_translatable_item', null, $post_id );
|
||||
} else {
|
||||
$item = get_post( $post_id );
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $selected_elements
|
||||
*
|
||||
* @param bool|string $type
|
||||
* @return array[]|int[]
|
||||
*/
|
||||
public static function get_elements_ids( $selected_elements, $type = false ) {
|
||||
$element_ids = array();
|
||||
$legal_item_types = $type ? array( $type ) : array_keys( self::get_basket_items_types() );
|
||||
foreach ( $legal_item_types as $item_type ) {
|
||||
if ( ! isset( $selected_elements[ $item_type ] ) ) {
|
||||
continue;
|
||||
}
|
||||
$element_ids[ $item_type ] = isset( $element_ids[ $item_type ] ) ? $element_ids[ $item_type ] : array();
|
||||
$items = $selected_elements[ $item_type ];
|
||||
foreach ( $items as $element_id => $action_data ) {
|
||||
if ( isset( $action_data['checked'] ) && $action_data['checked'] ) {
|
||||
$element_ids[ $item_type ][] = $element_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $type && isset( $element_ids[ $type ] ) ? $element_ids[ $type ] : $element_ids;
|
||||
}
|
||||
|
||||
public static function get_source_language() {
|
||||
self::get_basket();
|
||||
return isset( self::$basket['source_language'] ) ? self::$basket['source_language'] : false;
|
||||
}
|
||||
|
||||
private static function sync_target_languages() {
|
||||
self::get_basket();
|
||||
if ( ! isset( self::$basket['target_languages'] ) ) {
|
||||
self::$basket['target_languages'] = array();
|
||||
}
|
||||
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
if ( isset( self::$basket[ $item_type_name ] ) ) {
|
||||
$posts_in_basket = self::$basket[ $item_type_name ];
|
||||
foreach ( (array) $posts_in_basket as $post_in_basket ) {
|
||||
foreach ( (array) $post_in_basket['to_langs'] as $key => $target_language ) {
|
||||
if ( $target_language && ! in_array( $key, self::$basket['target_languages'] ) ) {
|
||||
self::$basket['target_languages'] [] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function get_target_languages() {
|
||||
self::get_basket();
|
||||
self::sync_target_languages();
|
||||
return isset( self::$basket['target_languages'] ) ? self::$basket['target_languages'] : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets target languages for remote service
|
||||
*
|
||||
* @param $remote_target_languages
|
||||
*/
|
||||
public static function set_remote_target_languages( $remote_target_languages ) {
|
||||
self::get_basket();
|
||||
self::$basket['remote_target_languages'] = $remote_target_languages;
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get target languages for remote service
|
||||
*
|
||||
* @return array | false
|
||||
*/
|
||||
public static function get_remote_target_languages() {
|
||||
self::get_basket();
|
||||
if ( isset( self::$basket['remote_target_languages'] ) ) {
|
||||
return self::$basket['remote_target_languages'];
|
||||
} else {
|
||||
return self::get_target_languages();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_basket_notification_positions() {
|
||||
return array(
|
||||
'admin_notice' => 'basket_status_update',
|
||||
'tm_dashboard_top' => 'translation-basket-notification',
|
||||
'st_dashboard_top' => 'string-translation-top',
|
||||
'st_dashboard_bottom' => 'string-translation-under',
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields_section() {
|
||||
$extra_fields = TranslationProxy::get_extra_fields_local();
|
||||
|
||||
$html = '';
|
||||
|
||||
if ( $extra_fields ) {
|
||||
|
||||
$html .= '<h3>3. ' . __( 'Select additional options', 'wpml-translation-management' ) . ' <a href="#" id="basket_extra_fields_refresh">(' . __( 'Refresh', 'wpml-translation-management' ) . ')</a></h3>';
|
||||
|
||||
$html .= '<div id="basket_extra_fields_list">';
|
||||
|
||||
$html .= self::get_basket_extra_fields_inputs( $extra_fields, false );
|
||||
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields_inputs( array $extra_fields = array(), $force_refresh = false ) {
|
||||
if ( ! $extra_fields ) {
|
||||
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
||||
$force_refresh = true;
|
||||
}
|
||||
$extra_fields = self::get_basket_extra_fields_array( $force_refresh );
|
||||
}
|
||||
|
||||
return self::extra_fields_build_inputs( $extra_fields );
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields_array( $force_refresh = false ) {
|
||||
if ( $force_refresh ) {
|
||||
$networking = wpml_tm_load_tp_networking();
|
||||
$project = TranslationProxy::get_current_project();
|
||||
$extra_fields = $networking->get_extra_fields_remote( $project );
|
||||
TranslationProxy::save_extra_fields( $extra_fields );
|
||||
} else {
|
||||
$extra_fields = TranslationProxy::get_extra_fields_local();
|
||||
}
|
||||
|
||||
return TranslationProxy::maybe_convert_extra_fields( $extra_fields );
|
||||
}
|
||||
|
||||
public static function extra_fields_build_inputs( array $extra_fields ) {
|
||||
if ( ! $extra_fields ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
/** @var WPML_TP_Extra_Field $field */
|
||||
$field_diplay = new WPML_TP_Extra_Field_Display();
|
||||
foreach ( $extra_fields as $field ) {
|
||||
$rows[] = $field_diplay->render( $field );
|
||||
}
|
||||
|
||||
$rows = array_filter( $rows );
|
||||
|
||||
$html = '';
|
||||
if ( $rows ) {
|
||||
$html = '<table class="form-table">';
|
||||
$html .= '<tbody>';
|
||||
$html .= implode( PHP_EOL, $rows );
|
||||
$html .= '</tbody>';
|
||||
$html .= '</table>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function validate_data( $data ) {
|
||||
$data_is_valid = true;
|
||||
if ( self::get_basket() && self::get_source_language() ) {
|
||||
/*
|
||||
we do not add items that are not in the source language of the current basket
|
||||
we cannot yet set its source language though since update_basket would set the basket
|
||||
to false as long as we do not have any elements in the basket*/
|
||||
if ( self::$translate_from != self::get_source_language() ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => __(
|
||||
'You cannot add posts in this language to the basket since it already contains posts or strings of another source language!
|
||||
Either submit the current basket and then add the post or delete the posts of differing language in the current basket',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
);
|
||||
self::update_basket();
|
||||
|
||||
$data_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// no language selected ?
|
||||
if ( ! isset( self::$translation_action ) || empty( self::$translation_action ) ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one language to translate into.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::$dashboard_select = $data; // pre fill dashboard
|
||||
$data_is_valid = false;
|
||||
}
|
||||
|
||||
if ( $data_is_valid ) {
|
||||
$data_is_valid = false;
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
// nothing selected ?
|
||||
foreach ( $basket_items_types as $basket_items_type => $basket_type ) {
|
||||
if ( isset( $data[ $basket_items_type ] ) && $data[ $basket_items_type ] ) {
|
||||
$data_is_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $data_is_valid ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one document to translate.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::$dashboard_select = $data; // pre-populate dashboard
|
||||
$data_is_valid = false;
|
||||
|
||||
return $data_is_valid;
|
||||
}
|
||||
|
||||
return $data_is_valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
use \WPML\Collect\Support\Traits\Macroable;
|
||||
use function \WPML\FP\curryN;
|
||||
use \WPML\LIB\WP\Cache;
|
||||
use \WPML\FP\Logic;
|
||||
|
||||
/**
|
||||
* Class TranslationProxy_Batch
|
||||
*
|
||||
* @method static callable|int getBatchId( ...$name ) :: string → int
|
||||
*/
|
||||
class TranslationProxy_Batch {
|
||||
|
||||
use Macroable;
|
||||
|
||||
public static function update_translation_batch(
|
||||
$batch_name = false,
|
||||
$tp_id = false
|
||||
) {
|
||||
$batch_name = $batch_name
|
||||
? $batch_name
|
||||
: ( ( (bool) $tp_id === false || $tp_id === 'local' )
|
||||
? self::get_generic_batch_name() : TranslationProxy_Basket::get_basket_name() );
|
||||
if ( ! $batch_name ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$getBatchId = function( $batch_name, $tp_id ) {
|
||||
$batch_id = self::getBatchId( $batch_name );
|
||||
|
||||
return $batch_id ? $batch_id : self::createBatchRecord( $batch_name, $tp_id );
|
||||
};
|
||||
|
||||
$cache = Cache::memorizeWithCheck( 'update_translation_batch', Logic::isNotNull(), $getBatchId );
|
||||
return $cache( $batch_name, $tp_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the name of a generic batch
|
||||
* name is built based on the current's date
|
||||
*
|
||||
* @param bool $isAuto
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_generic_batch_name( $isAuto = false ) {
|
||||
return ( $isAuto ? 'Automatic Translations from ' : 'Manual Translations from ' ) . date( 'F \t\h\e jS\, Y' );
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the id of a generic batch
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function create_generic_batch() {
|
||||
$batch_name = self::get_generic_batch_name();
|
||||
$batch_id = self::update_translation_batch( $batch_name );
|
||||
|
||||
return $batch_id;
|
||||
}
|
||||
|
||||
public static function maybe_assign_generic_batch( $data ) {
|
||||
global $wpdb;
|
||||
|
||||
$batch_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT batch_id
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_id=%d",
|
||||
$data['translation_id']
|
||||
)
|
||||
);
|
||||
|
||||
// if the batch id is smaller than 1 we assign the translation to the generic manual translations batch for today if the translation_service is local
|
||||
if ( ( $batch_id < 1 ) && isset( $data ['translation_service'] ) && $data ['translation_service'] == 'local' ) {
|
||||
// first we retrieve the batch id for today's generic translation batch
|
||||
$batch_id = self::create_generic_batch();
|
||||
// then we update the entry in the icl_translation_status table accordingly
|
||||
$data_where = array( 'rid' => $data['rid'] );
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translation_status',
|
||||
array( 'batch_id' => $batch_id ),
|
||||
$data_where
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $batch_name
|
||||
* @param $tp_id
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function createBatchRecord( $batch_name, $tp_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$data = [
|
||||
'batch_name' => $batch_name,
|
||||
'last_update' => date( 'Y-m-d H:i:s' ),
|
||||
];
|
||||
if ( $tp_id ) {
|
||||
$data['tp_id'] = $tp_id === 'local' ? 0 : $tp_id;
|
||||
}
|
||||
$wpdb->insert( $wpdb->prefix . 'icl_translation_batches', $data );
|
||||
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $batch_name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
TranslationProxy_Batch::macro(
|
||||
'getBatchId',
|
||||
curryN(
|
||||
1,
|
||||
function( $batch_name ) {
|
||||
global $wpdb;
|
||||
|
||||
$batch_id_sql = "SELECT id FROM {$wpdb->prefix}icl_translation_batches WHERE batch_name=%s";
|
||||
$batch_id_prepared = $wpdb->prepare( $batch_id_sql, $batch_name );
|
||||
return $wpdb->get_var( $batch_id_prepared );
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
class TranslationProxy_Popup {
|
||||
|
||||
public static function display() {
|
||||
include_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-popup.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function get_link( $link, $args = array(), $just_url = false ) {
|
||||
|
||||
$defaults = array(
|
||||
'title' => null,
|
||||
'class' => '',
|
||||
'id' => '',
|
||||
'ar' => 0, // auto_resize
|
||||
'unload_cb' => false, // onunload callback
|
||||
);
|
||||
|
||||
$args = array_merge($defaults, $args);
|
||||
|
||||
/**
|
||||
* @var title string
|
||||
*/
|
||||
$title = $args['title'];
|
||||
/**
|
||||
* @var $class string
|
||||
*/
|
||||
$class = $args['class'];
|
||||
/**
|
||||
* @var $id int
|
||||
*/
|
||||
$id = $args['id'];
|
||||
/**
|
||||
* @var $ar int
|
||||
*/
|
||||
$ar = $args['ar'];
|
||||
/**
|
||||
* @var $unload_cb bool
|
||||
*/
|
||||
$unload_cb = $args['unload_cb'];
|
||||
|
||||
if ( !empty( $ar ) ) {
|
||||
$auto_resize = '&auto_resize=1';
|
||||
} else {
|
||||
$auto_resize = '';
|
||||
}
|
||||
|
||||
$unload_cb = isset( $unload_cb ) ? '&unload_cb=' . $unload_cb : '';
|
||||
|
||||
$url_glue = false !== strpos( $link, '?' ) ? '&' : '?';
|
||||
$link .= $url_glue . 'compact=1';
|
||||
|
||||
$nonce_snippet = '&_icl_nonce=' . wp_create_nonce( 'reminder_popup_nonce' );
|
||||
$action_and_nonce = 'admin.php?page=' . ICL_PLUGIN_FOLDER
|
||||
. "/menu/languages.php&icl_action=reminder_popup{$nonce_snippet}{$auto_resize}{$unload_cb}"
|
||||
. "&target=" . urlencode( $link );
|
||||
if ( ! empty( $id ) ) {
|
||||
$id = ' id="' . $id . '"';
|
||||
}
|
||||
if ( ! $just_url ) {
|
||||
return '<a class="icl_thickbox ' . $class . '" title="' . $title . '" href="' . $action_and_nonce . '"' . $id . '>';
|
||||
} else {
|
||||
if ( ! $just_url ) {
|
||||
return '<a class="icl_thickbox ' . $class . '" href="' . $action_and_nonce . '"' . $id . '>';
|
||||
} else {
|
||||
return $action_and_nonce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
define( 'ICL_LANGUAGE_NOT_SUPPORTED', 3 );
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$target = filter_input( INPUT_GET, 'target', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
$auto_resize = filter_input( INPUT_GET, 'auto_resize', FILTER_VALIDATE_BOOLEAN | FILTER_NULL_ON_FAILURE );
|
||||
$unload_cb = filter_input( INPUT_GET, 'unload_cb', FILTER_SANITIZE_FULL_SPECIAL_CHARS | FILTER_NULL_ON_FAILURE );
|
||||
|
||||
// Adding a translator
|
||||
if ( preg_match( '|^@select-translators;([^;]+);([^;]+)@|', $target, $matches ) ) {
|
||||
$source_language = $matches[1];
|
||||
$target_language = $matches[2];
|
||||
$project = TranslationProxy::get_current_project();
|
||||
try {
|
||||
$lp_setting_index = 'language_pairs';
|
||||
$language_pairs = $sitepress->get_setting( $lp_setting_index, array() );
|
||||
if ( ! isset( $language_pairs[ $source_language ][ $target_language ] ) || $language_pairs[ $source_language ][ $target_language ] == 0 ) {
|
||||
$language_pairs[ $source_language ][ $target_language ] = 1;
|
||||
TranslationProxy_Translator::update_language_pairs( $project, $language_pairs );
|
||||
$sitepress->set_setting( $lp_setting_index, $language_pairs, true );
|
||||
}
|
||||
$target = $project->select_translator_iframe_url( $source_language, $target_language );
|
||||
} catch ( Exception $e ) {
|
||||
if ( $e->getCode() == ICL_LANGUAGE_NOT_SUPPORTED ) {
|
||||
printf( __( '<p>Requested languages are not supported by the translation service (%s). Please <a%s>contact us</a> for support. </p>', 'wpml-translation-management' ), $e->getMessage(), ' target="_blank" href="http://wpml.org/?page_id=5255"' );
|
||||
} else {
|
||||
printf( __( '<p>Could not add the requested languages. Please <a%s>contact us</a> for support. </p><p>Show <a%s>debug information</a>.</p>', 'wpml-translation-management' ), ' target="_blank" href="http://wpml.org/?page_id=5255"',
|
||||
' a href="admin.php?page=' .
|
||||
ICL_PLUGIN_FOLDER .
|
||||
'/menu/troubleshooting.php&icl_action=icl-connection-test' .
|
||||
'#icl-connection-test"' );
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$target .= ( strpos( $target, '?' ) === false ) ? '?' : '&';
|
||||
$target .= "lc=" . $sitepress->get_admin_language();
|
||||
?>
|
||||
|
||||
<iframe src="<?php echo $target; ?>" style="width:100%; height:92%" onload=" var TB_window = jQuery('#TB_window');
|
||||
<?php if ( $auto_resize ): ?>
|
||||
TB_window.css('width','90%').css('margin-left', '-45%');
|
||||
<?php endif; ?>
|
||||
<?php if ( $unload_cb ){
|
||||
$unload_cb = esc_js($unload_cb);
|
||||
?>
|
||||
TB_window.unbind('unload').bind('tb_unload', function(){<?php echo $unload_cb; ?>});
|
||||
<?php } ?>
|
||||
">
|
||||
@@ -0,0 +1,513 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
if( class_exists( 'TranslationProxy_Project' ) ) {
|
||||
// Workaround for UnitTests.
|
||||
return;
|
||||
}
|
||||
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-api.class.php';
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-service.class.php';
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-batch.class.php';
|
||||
|
||||
/**
|
||||
* Class TranslationProxy_Project
|
||||
*/
|
||||
class TranslationProxy_Project {
|
||||
|
||||
public $id;
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* `access_key` used when sending **any request** to TP
|
||||
*/
|
||||
public $access_key;
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* `ts_id` (aka `website_id`) is used **exclusively** when sending request directly to ICL
|
||||
*/
|
||||
public $ts_id;
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* `ts_access_key` is used **exclusively** when sending request directly to ICL
|
||||
*/
|
||||
public $ts_access_key;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
public $service;
|
||||
|
||||
/** @var WPML_TP_Client $tp_client */
|
||||
public $tp_client;
|
||||
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @param TranslationProxy_Service $service
|
||||
* @param string $delivery
|
||||
* @param WPML_TP_Client $tp_client
|
||||
*/
|
||||
public function __construct( $service, $delivery, WPML_TP_Client $tp_client ) {
|
||||
$this->service = $service;
|
||||
$this->tp_client = $tp_client;
|
||||
|
||||
$icl_translation_projects = TranslationProxy::get_translation_projects();
|
||||
$project_index = self::generate_service_index( $service );
|
||||
|
||||
if ( $project_index && $icl_translation_projects && isset( $icl_translation_projects [ $project_index ] ) ) {
|
||||
$project = $icl_translation_projects[ $project_index ];
|
||||
$this->id = $project['id'];
|
||||
$this->access_key = $project['access_key'];
|
||||
$this->ts_id = $project['ts_id'];
|
||||
$this->ts_access_key = $project['ts_access_key'];
|
||||
|
||||
$this->service->delivery_method = $delivery;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TranslationProxy_Service
|
||||
*/
|
||||
public function service() {
|
||||
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index by which a translation service can be found in the array returned by
|
||||
* \TranslationProxy::get_translation_projects
|
||||
*
|
||||
* @param $service object
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function generate_service_index( $service ) {
|
||||
$index = false;
|
||||
if ( $service ) {
|
||||
$service->custom_fields_data = isset( $service->custom_fields_data ) ? $service->custom_fields_data : array();
|
||||
if ( isset( $service->id ) ) {
|
||||
$index = md5( $service->id . serialize( $service->custom_fields_data ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert WPML language code to service language
|
||||
*
|
||||
* @param $language string
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function service_language( $language ) {
|
||||
return TranslationProxy_Service::get_language( $this->service, $language );
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Get information about the project (Translation Service)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
public function custom_text( $location, $locale = 'en' ) {
|
||||
$response = '';
|
||||
if ( ! $this->ts_id || ! $this->ts_access_key ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Sending Translation Service (ts_) id and access_key, as we are talking directly to the Translation Service
|
||||
// Todo: use project->id and project->access_key once this call is moved to TP
|
||||
$params = array(
|
||||
'project_id' => $this->ts_id,
|
||||
'accesskey' => $this->ts_access_key,
|
||||
'location' => $location,
|
||||
'lc' => $locale,
|
||||
);
|
||||
|
||||
if ( $this->service->custom_text_url ) {
|
||||
try {
|
||||
$response = TranslationProxy_Api::service_request(
|
||||
$this->service->custom_text_url,
|
||||
$params,
|
||||
'GET',
|
||||
true,
|
||||
true,
|
||||
true
|
||||
);
|
||||
} catch ( Exception $e ) {
|
||||
throw new RuntimeException(
|
||||
'error getting custom text from Translation Service: ' . serialize( $params ) . ' url: ' . $this->service->custom_text_url,
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function current_service_name() {
|
||||
|
||||
return TranslationProxy::get_current_service_name();
|
||||
}
|
||||
|
||||
function current_service() {
|
||||
return TranslationProxy::get_current_service();
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* IFrames to display project info (Translation Service)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
public function select_translator_iframe_url( $source_language, $target_language ) {
|
||||
// Sending Translation Service (ts_) id and access_key, as we are talking directly to the Translation Service
|
||||
$params['project_id'] = $this->ts_id;
|
||||
$params['accesskey'] = $this->ts_access_key;
|
||||
$params['source_language'] = $this->service_language( $source_language );
|
||||
$params['target_language'] = $this->service_language( $target_language );
|
||||
$params['compact'] = 1;
|
||||
|
||||
return $this->_create_iframe_url( $this->service->select_translator_iframe_url, $params );
|
||||
}
|
||||
|
||||
public function translator_contact_iframe_url( $translator_id ) {
|
||||
// Sending Translation Service (ts_) id and access_key, as we are talking directly to the Translation Service
|
||||
$params['project_id'] = $this->ts_id;
|
||||
$params['accesskey'] = $this->ts_access_key;
|
||||
$params['translator_id'] = $translator_id;
|
||||
$params['compact'] = 1;
|
||||
if ( $this->service->translator_contact_iframe_url ) {
|
||||
return $this->_create_iframe_url( $this->service->translator_contact_iframe_url, $params );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function _create_iframe_url( $url, $params ) {
|
||||
if ( $params ) {
|
||||
$url = TranslationProxy_Api::add_parameters_to_url( $url, $params );
|
||||
$url .= '?' . http_build_query( $params );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Jobs handling (Translation Proxy)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/**
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @param bool $source_language
|
||||
* @param bool $target_languages
|
||||
*
|
||||
* @internal param bool $name
|
||||
* @return false|WPML_TP_Batch
|
||||
*/
|
||||
function get_batch_job(
|
||||
$source_language = false,
|
||||
$target_languages = false
|
||||
) {
|
||||
$batch_data = TranslationProxy_Basket::get_batch_data();
|
||||
|
||||
if ( ! $batch_data ) {
|
||||
if ( ! $source_language ) {
|
||||
$source_language = TranslationProxy_Basket::get_source_language();
|
||||
}
|
||||
if ( ! $target_languages ) {
|
||||
$target_languages = TranslationProxy_Basket::get_remote_target_languages();
|
||||
}
|
||||
|
||||
if ( ! $source_language || ! $target_languages ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$batch_data = $this->create_batch_job( $source_language, $target_languages );
|
||||
|
||||
if ( $batch_data ) {
|
||||
TranslationProxy_Basket::set_batch_data( $batch_data );
|
||||
}
|
||||
}
|
||||
|
||||
return $batch_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
function get_batch_job_id() {
|
||||
$ret = false;
|
||||
$batch_data = $this->get_batch_job();
|
||||
|
||||
if ( $batch_data ) {
|
||||
$ret = $batch_data->get_id();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @param bool $source_language
|
||||
* @param $target_languages
|
||||
*
|
||||
* @internal param bool $name
|
||||
* @return false|WPML_TP_Batch
|
||||
*/
|
||||
public function create_batch_job( $source_language, $target_languages ) {
|
||||
$batch_name = TranslationProxy_Basket::get_basket_name();
|
||||
$batch_options = TranslationProxy_Basket::get_options();
|
||||
$extra_fields = TranslationProxy_Basket::get_basket_extra_fields();
|
||||
|
||||
$batch_data = array(
|
||||
'source_language' => $source_language,
|
||||
'target_languages' => $target_languages,
|
||||
'name' => $batch_name,
|
||||
);
|
||||
|
||||
if ( ! $batch_data['source_language'] ) {
|
||||
$batch_data['source_language'] = TranslationProxy_Basket::get_source_language();
|
||||
}
|
||||
|
||||
if ( ! $batch_data['target_languages'] ) {
|
||||
$batch_data['target_languages'] = TranslationProxy_Basket::get_remote_target_languages();
|
||||
}
|
||||
|
||||
if ( ! $batch_data['source_language'] || ! $batch_data['target_languages'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $batch_data['name'] ) {
|
||||
$batch_data['name'] = sprintf(
|
||||
__(
|
||||
'%s: WPML Translation Jobs',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
get_option( 'blogname' )
|
||||
);
|
||||
}
|
||||
|
||||
TranslationProxy_Basket::set_basket_name( $batch_data['name'] );
|
||||
|
||||
if ( isset( $batch_options['deadline_date'] ) ) {
|
||||
$batch_data['deadline'] = strtotime( $batch_options['deadline_date'] );
|
||||
}
|
||||
|
||||
return $this->tp_client->batches()->create( $batch_data, $extra_fields );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add Files Batch Job
|
||||
*
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $title
|
||||
* @param string $cms_id
|
||||
* @param string $url
|
||||
* @param string $source_language
|
||||
* @param string $target_language
|
||||
* @param int $word_count
|
||||
* @param int $translator_id
|
||||
* @param string $note
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
public function send_to_translation_batch_mode(
|
||||
$file,
|
||||
$title,
|
||||
$cms_id,
|
||||
$url,
|
||||
$source_language,
|
||||
$target_language,
|
||||
$word_count,
|
||||
$translator_id = 0,
|
||||
$note = '',
|
||||
$uuid = null
|
||||
) {
|
||||
|
||||
$batch_id = $this->get_batch_job_id();
|
||||
|
||||
if ( ! $batch_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$job_data = array(
|
||||
'file' => $file,
|
||||
'word_count' => $word_count,
|
||||
'title' => $title,
|
||||
'cms_id' => $cms_id,
|
||||
'udid' => $uuid,
|
||||
'url' => $url,
|
||||
'translator_id' => $translator_id,
|
||||
'note' => $note,
|
||||
'source_language' => $source_language,
|
||||
'target_language' => $target_language,
|
||||
);
|
||||
|
||||
$tp_job = $this->tp_client->batches()->add_job( $batch_id, $job_data );
|
||||
|
||||
return $tp_job ? $tp_job->get_id() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|int $tp_batch_id
|
||||
*
|
||||
* @link http://git.icanlocalize.com/onthego/translation_proxy/wikis/commit_batch_job
|
||||
*
|
||||
* @return array|bool|mixed|null|stdClass|string
|
||||
*/
|
||||
function commit_batch_job( $tp_batch_id = false ) {
|
||||
$tp_batch_id = $tp_batch_id ? $tp_batch_id : $this->get_batch_job_id();
|
||||
|
||||
if ( ! $tp_batch_id ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'api_version' => TranslationProxy_Api::API_VERSION,
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'batch_id' => $tp_batch_id,
|
||||
);
|
||||
|
||||
$response = TranslationProxy_Api::proxy_request( '/batches/{batch_id}/commit.json', $params, 'PUT', false );
|
||||
$basket_name = TranslationProxy_Basket::get_basket_name();
|
||||
if ( $basket_name ) {
|
||||
global $wpdb;
|
||||
|
||||
$batch_id_sql = "SELECT id FROM {$wpdb->prefix}icl_translation_batches WHERE batch_name=%s";
|
||||
$batch_id_prepared = $wpdb->prepare(
|
||||
$batch_id_sql,
|
||||
array( $basket_name )
|
||||
);
|
||||
$batch_id = $wpdb->get_var( $batch_id_prepared );
|
||||
|
||||
$batch_data = array(
|
||||
'batch_name' => $basket_name,
|
||||
'tp_id' => $tp_batch_id,
|
||||
'last_update' => date( 'Y-m-d H:i:s' ),
|
||||
);
|
||||
if ( isset( $response ) && $response ) {
|
||||
$batch_data['ts_url'] = serialize( $response );
|
||||
}
|
||||
|
||||
if ( ! $batch_id ) {
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'icl_translation_batches',
|
||||
$batch_data
|
||||
);
|
||||
} else {
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translation_batches',
|
||||
$batch_data,
|
||||
array( 'id' => $batch_id )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return isset( $response ) ? $response : false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public function jobs() {
|
||||
|
||||
return $this->get_jobs( 'any' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object[]
|
||||
*/
|
||||
public function finished_jobs() {
|
||||
|
||||
return $this->get_jobs( 'translation_ready' );
|
||||
}
|
||||
|
||||
public function set_delivery_method( $method ) {
|
||||
$params = array(
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'project' => array( 'delivery_method' => $method ),
|
||||
);
|
||||
TranslationProxy_Api::proxy_request( '/projects.json', $params, 'put' );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fetch_translation( $job_id ) {
|
||||
$params = array(
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'job_id' => $job_id,
|
||||
);
|
||||
|
||||
return TranslationProxy_Api::proxy_download(
|
||||
'/jobs/{job_id}/xliff.json',
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
public function update_job( $job_id, $url = null, $state = 'delivered' ) {
|
||||
$params = array(
|
||||
'job_id' => $job_id,
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'job' => array(
|
||||
'state' => $state,
|
||||
),
|
||||
);
|
||||
if ( $url ) {
|
||||
$params['job']['url'] = $url;
|
||||
}
|
||||
|
||||
TranslationProxy_Api::proxy_request(
|
||||
'/jobs/{job_id}.json',
|
||||
$params,
|
||||
'PUT'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function get_jobs( $state = 'any' ) {
|
||||
$batch = TranslationProxy_Basket::get_batch_data();
|
||||
|
||||
$params = array(
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'state' => $state,
|
||||
);
|
||||
|
||||
if ( $batch ) {
|
||||
$params['batch_id'] = $batch ? $batch->get_id() : false;
|
||||
|
||||
return TranslationProxy_Api::proxy_request(
|
||||
'/batches/{batch_id}/jobs.json',
|
||||
$params
|
||||
);
|
||||
} else {
|
||||
// FIXME: remove this once TP will accept the TP Project ID: https://icanlocalize.basecamphq.com/projects/11113143-translation-proxy/todo_items/182251206/comments
|
||||
$params['project_id'] = $this->id;
|
||||
}
|
||||
|
||||
return TranslationProxy_Api::proxy_request( '/jobs.json', $params );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-api.class.php';
|
||||
|
||||
class TranslationProxy_Service {
|
||||
|
||||
public $id;
|
||||
public $name;
|
||||
public $description;
|
||||
public $default_service;
|
||||
public $has_translator_selection = true; // Todo: read this from service properties
|
||||
public $delivery_method;
|
||||
public $project_details_url;
|
||||
public $custom_text_url;
|
||||
public $has_language_pairs;
|
||||
public $languages_map;
|
||||
public $url;
|
||||
public $logo_url;
|
||||
public $create_project_url;
|
||||
public $add_language_pair_url;
|
||||
public $new_job_url;
|
||||
public $custom_fields;
|
||||
public $custom_fields_data;
|
||||
public $select_translator_iframe_url;
|
||||
public $translator_contact_iframe_url;
|
||||
public $quote_iframe_url;
|
||||
public $batch_name_max_length;
|
||||
|
||||
public static function is_authenticated( $service ) {
|
||||
|
||||
// for services that do not require authentication return true by default
|
||||
if ( ! TranslationProxy::service_requires_authentication( $service ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isset( $service->custom_fields_data ) && $service->custom_fields_data ? true : false;
|
||||
}
|
||||
|
||||
public static function list_services() {
|
||||
return TranslationProxy_Api::proxy_request( '/services.json' );
|
||||
}
|
||||
|
||||
public static function get_service( $service_id ) {
|
||||
$service = TranslationProxy_Api::proxy_request( "/services/$service_id.json" );
|
||||
$service->languages_map = self::languages_map( $service );
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
public static function get_service_by_suid( $suid ) {
|
||||
$service = TranslationProxy_Api::proxy_request( "/services/$suid.json" );
|
||||
$service->languages_map = self::languages_map( $service );
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
public static function languages_map( $service ) {
|
||||
$languages_map = array();
|
||||
$languages = TranslationProxy_Api::proxy_request( "/services/{$service->id}/language_identifiers.json" );
|
||||
foreach ( $languages as $language ) {
|
||||
$languages_map[ $language->iso_code ] = $language->value;
|
||||
}
|
||||
|
||||
return $languages_map;
|
||||
}
|
||||
|
||||
public static function get_language( $service, $language ) {
|
||||
if ( ! empty( $service->languages_map ) and array_key_exists( $language, $service->languages_map ) ) {
|
||||
$language = $service->languages_map[ $language ];
|
||||
}
|
||||
|
||||
return $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a WPML readable string that allows to tell translation service and translator id
|
||||
* (typically used for translators dropdowns)
|
||||
*
|
||||
* @param int|bool $translation_service_id
|
||||
* @param int|bool $translator_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_wpml_translator_id( $translation_service_id = false, $translator_id = false ) {
|
||||
if ( $translation_service_id === false ) {
|
||||
$translation_service_id = TranslationProxy::get_current_service_id();
|
||||
}
|
||||
$result = 'ts-' . $translation_service_id;
|
||||
if ( $translator_id !== false ) {
|
||||
$result .= '-' . $translator_id;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $translator_id
|
||||
*
|
||||
* @return array Returns a two elements array, respectively containing translation_service and translator_id
|
||||
*/
|
||||
public static function get_translator_data_from_wpml( $translator_id ) {
|
||||
$result = array();
|
||||
if ( is_numeric( $translator_id ) ) {
|
||||
$result['translation_service'] = 'local';
|
||||
$result['translator_id'] = $translator_id;
|
||||
} else {
|
||||
$translator_data = explode( '-', $translator_id );
|
||||
$result = array();
|
||||
$result['translation_service'] = $translator_data[1];
|
||||
$result['translator_id'] = isset( $translator_data[2] ) ? $translator_data[2] : 0;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
class TranslationProxy_Translator {
|
||||
/**
|
||||
* Get information about translators from current project. Works only for ICL as a Translation Service
|
||||
*
|
||||
* @param bool $force
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function get_icl_translator_status( $force = false ) {
|
||||
/** @var SitePress $sitepress */
|
||||
/** @var WPML_Pro_Translation $ICL_Pro_Translation */
|
||||
global $sitepress, $ICL_Pro_Translation;
|
||||
|
||||
if ( ! $ICL_Pro_Translation ) {
|
||||
$job_factory = wpml_tm_load_job_factory();
|
||||
$ICL_Pro_Translation = new WPML_Pro_Translation( $job_factory );
|
||||
}
|
||||
|
||||
if ( ! TranslationProxy::translator_selection_available() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
if ( ! $project ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$cache_key = md5( serialize( $project ) );
|
||||
$cache_group = 'get_icl_translator_status';
|
||||
|
||||
$found = false;
|
||||
$result = wp_cache_get( $cache_key, $cache_group, false, $found );
|
||||
|
||||
if ( $found ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$translator_status = array();
|
||||
$website_details = self::get_website_details(
|
||||
new TranslationProxy_Project( TranslationProxy::get_current_service(), 'xmlrpc', TranslationProxy::get_tp_client() ),
|
||||
$force
|
||||
);
|
||||
|
||||
if ( false === (bool) $website_details ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$language_pairs = array();
|
||||
if ( isset( $website_details['translation_languages']['translation_language'] ) ) {
|
||||
|
||||
$translation_languages = $website_details['translation_languages']['translation_language'];
|
||||
if ( ! isset( $translation_languages[0] ) ) {
|
||||
$buf = $translation_languages;
|
||||
$translation_languages = array( 0 => $buf );
|
||||
}
|
||||
|
||||
foreach ( $translation_languages as $lang ) {
|
||||
$translators = $_tr = array();
|
||||
$max_rate = false;
|
||||
if ( isset( $lang['translators'], $lang['translators']['translator'] ) && ! empty( $lang['translators'] ) ) {
|
||||
if ( ! isset( $lang['translators']['translator'][0] ) ) {
|
||||
$_tr[0] = $lang['translators']['translator'];
|
||||
} else {
|
||||
$_tr = $lang['translators']['translator'];
|
||||
}
|
||||
foreach ( $_tr as $t ) {
|
||||
if ( false === $max_rate || $t['attr']['amount'] > $max_rate ) {
|
||||
$max_rate = $t['attr']['amount'];
|
||||
}
|
||||
$translators[] = array(
|
||||
'id' => $t['attr']['id'],
|
||||
'nickname' => $t['attr']['nickname'],
|
||||
'contract_id' => $t['attr']['contract_id'],
|
||||
);
|
||||
}
|
||||
}
|
||||
$language_pairs[] = array(
|
||||
'from' => $sitepress->get_language_code( $ICL_Pro_Translation->server_languages_map( $lang['attr']['from_language_name'], true ) ),
|
||||
'to' => $sitepress->get_language_code( $ICL_Pro_Translation->server_languages_map( $lang['attr']['to_language_name'], true ) ),
|
||||
'have_translators' => $lang['attr']['have_translators'],
|
||||
'available_translators' => $lang['attr']['available_translators'],
|
||||
'applications' => $lang['attr']['applications'],
|
||||
'contract_id' => $lang['attr']['contract_id'],
|
||||
'id' => $lang['attr']['id'],
|
||||
'translators' => $translators,
|
||||
'max_rate' => $max_rate,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$translator_status['icl_lang_status'] = $language_pairs;
|
||||
|
||||
$translator_status['icl_support_ticket_id'] = null;
|
||||
|
||||
wp_cache_set( $cache_key, $translator_status, $cache_group );
|
||||
|
||||
return $translator_status;
|
||||
}
|
||||
|
||||
private static function get_popup_link( $matches ) {
|
||||
global $sitepress;
|
||||
|
||||
return TranslationProxy_Popup::get_link( $matches[2] );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get information about language pairs (including translators). Works only for ICL as a Translation Service
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_language_pairs() {
|
||||
global $sitepress;
|
||||
|
||||
$icl_lang_status = $sitepress->get_setting( 'icl_lang_status', array() );
|
||||
if ( ! empty( $icl_lang_status ) ) {
|
||||
$missing_translators = false;
|
||||
foreach ( $icl_lang_status as $lang ) {
|
||||
if ( empty( $lang['translators'] ) ) {
|
||||
$missing_translators = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! $missing_translators ) {
|
||||
$icl_lang_sub_status = $icl_lang_status;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset( $icl_lang_sub_status ) ) {
|
||||
$translator_status = self::get_icl_translator_status();
|
||||
$icl_lang_sub_status = isset( $translator_status['icl_lang_status'] )
|
||||
? $translator_status['icl_lang_status'] : array();
|
||||
}
|
||||
foreach ( $icl_lang_sub_status as $key => $status ) {
|
||||
if ( ! isset( $status['from'] ) ) {
|
||||
unset( $icl_lang_sub_status[ $key ] );
|
||||
}
|
||||
}
|
||||
array_filter( $icl_lang_sub_status );
|
||||
|
||||
return $icl_lang_sub_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to ICL to get website details (including language pairs)
|
||||
*
|
||||
* @param TranslationProxy_Project $project
|
||||
* @param bool $force
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_website_details( $project, $force = false ) {
|
||||
|
||||
require_once ICL_PLUGIN_PATH . '/inc/utilities/xml2array.php';
|
||||
require_once ICL_PLUGIN_PATH . '/lib/icl_api.php';
|
||||
|
||||
$site_id = $project->ts_id;
|
||||
$access_key = $project->ts_access_key;
|
||||
|
||||
$default = array();
|
||||
|
||||
if ( ! $site_id ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$icl_query = new ICanLocalizeQuery( $site_id, $access_key );
|
||||
|
||||
return $icl_query->get_website_details( $force );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $translator_id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function get_translator_name( $translator_id ) {
|
||||
if ( TranslationProxy::translator_selection_available() ) {
|
||||
$lang_status = self::get_language_pairs();
|
||||
if ( $lang_status ) {
|
||||
foreach ( $lang_status as $lp ) {
|
||||
$lp_trans = ! empty( $lp['translators'] ) ? $lp['translators'] : array();
|
||||
foreach ( $lp_trans as $tr ) {
|
||||
$translators[ $tr['id'] ] = $tr['nickname'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isset( $translators[ $translator_id ] ) ? $translators[ $translator_id ] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes language pairs with ICL
|
||||
*
|
||||
* @global object $sitepress
|
||||
*
|
||||
* @param $project
|
||||
* @param $language_pairs
|
||||
*/
|
||||
public static function update_language_pairs( $project, $language_pairs ) {
|
||||
/** @var WPML_Pro_Translation $ICL_Pro_Translation */
|
||||
global $sitepress, $ICL_Pro_Translation;
|
||||
|
||||
$params = array(
|
||||
'site_id' => $project->ts_id,
|
||||
'accesskey' => $project->ts_access_key,
|
||||
'create_account' => 0,
|
||||
);
|
||||
|
||||
$lang_server = array();
|
||||
foreach ( $sitepress->get_active_languages() as $lang ) {
|
||||
$lang_server[ $lang['code'] ] = $ICL_Pro_Translation->server_languages_map( $lang['english_name'] );
|
||||
}
|
||||
|
||||
// update account - add language pair
|
||||
$incr = 0;
|
||||
foreach ( $language_pairs as $k => $v ) {
|
||||
if ( ! array_key_exists( $k, $lang_server ) ) {
|
||||
unset( $language_pairs[ $k ] );
|
||||
continue;
|
||||
}
|
||||
foreach ( $v as $k2 => $v2 ) {
|
||||
if ( ! array_key_exists( $k2, $lang_server ) ) {
|
||||
unset( $language_pairs[ $k ][ $k2 ] );
|
||||
if ( (bool) $language_pairs[ $k ] === false ) {
|
||||
unset( $language_pairs[ $k ] );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
$incr ++;
|
||||
$params[ 'from_language' . $incr ] = $lang_server[ $k ];
|
||||
$params[ 'to_language' . $incr ] = $lang_server[ $k2 ];
|
||||
}
|
||||
}
|
||||
|
||||
require_once ICL_PLUGIN_PATH . '/inc/utilities/xml2array.php';
|
||||
require_once ICL_PLUGIN_PATH . '/lib/icl_api.php';
|
||||
$icl_query = new ICanLocalizeQuery();
|
||||
$icl_query->updateAccount( $params );
|
||||
}
|
||||
|
||||
public static function flush_website_details_cache() {
|
||||
delete_transient( WEBSITE_DETAILS_TRANSIENT_KEY );
|
||||
}
|
||||
|
||||
public static function flush_website_details_cache_action() {
|
||||
$nonce = array_key_exists( 'nonce', $_POST ) ? $_POST['nonce'] : null;
|
||||
$action = array_key_exists( 'action', $_POST ) ? $_POST['action'] : null;
|
||||
$nonce_is_valid = wp_verify_nonce( $nonce, $action );
|
||||
|
||||
if ( $nonce_is_valid ) {
|
||||
self::flush_website_details_cache();
|
||||
$query_args = array(
|
||||
'page' => urlencode( WPML_TM_FOLDER . '/menu/main.php' ),
|
||||
'sm' => urlencode( 'translators' ),
|
||||
);
|
||||
$link_url = add_query_arg( $query_args, get_admin_url( null, 'admin.php' ) );
|
||||
wp_send_json_success( array( 'redirectTo' => $link_url ) );
|
||||
} else {
|
||||
wp_send_json_error( 'Nonce is not valid.' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
use WPML\TM\TranslationProxy\Services\AuthorizationFactory;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/functions.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-basket.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-api.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-project.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-service.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-popup.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-translator.class.php';
|
||||
|
||||
define( 'CUSTOM_TEXT_MAX_LENGTH', 1000 );
|
||||
|
||||
class TranslationProxy {
|
||||
private static $tp_client;
|
||||
|
||||
/**
|
||||
* @param bool $reload
|
||||
*
|
||||
* @return WPML_TP_Service[]
|
||||
*/
|
||||
public static function services( $reload = true ) {
|
||||
return self::get_tp_client()->services()->get_all( $reload );
|
||||
}
|
||||
|
||||
public static function get_tp_default_suid() {
|
||||
if ( defined( 'WPML_TP_DEFAULT_SUID' ) ) {
|
||||
return WPML_TP_DEFAULT_SUID;
|
||||
}
|
||||
|
||||
return self::get_preferred_translation_service() ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $suid
|
||||
* @return 'wpml_list'|'config'|'account'
|
||||
*/
|
||||
public static function get_service_linked_by_suid( $suid ) {
|
||||
if ( defined( 'WPML_TP_DEFAULT_SUID' ) && WPML_TP_DEFAULT_SUID === $suid ) {
|
||||
return 'config';
|
||||
}
|
||||
if ( self::get_preferred_translation_service() === $suid ) {
|
||||
return 'account';
|
||||
}
|
||||
return 'wpml_list';
|
||||
}
|
||||
|
||||
public static function has_preferred_translation_service() {
|
||||
return self::get_tp_default_suid() !== false;
|
||||
}
|
||||
|
||||
public static function clear_preferred_translation_service() {
|
||||
WP_Installer_API::set_preferred_ts( 'clear' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $service_id
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public static function get_service( $service_id ) {
|
||||
// @todo: implement usage of WPML_TP_Service for the active service
|
||||
return (object) (array) self::get_tp_client()->services()->get_service( $service_id, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $service_id
|
||||
*
|
||||
* @return TranslationProxy_Project|WP_Error
|
||||
* @throws \WPMLTranslationProxyApiException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function select_service( $service_id, $credentials = null ) {
|
||||
global $sitepress;
|
||||
|
||||
$service_selected = false;
|
||||
$error = false;
|
||||
|
||||
/** @var TranslationProxy_Service $service */
|
||||
$service = self::get_service( $service_id );
|
||||
|
||||
if ( $service ) {
|
||||
self::deselect_active_service();
|
||||
|
||||
$service = self::build_and_store_active_translation_service( $service, $credentials );
|
||||
$result = $service;
|
||||
$service_selected = true;
|
||||
|
||||
// Force authentication if no user input is needed
|
||||
if ( ! self::service_requires_authentication( $service ) ) {
|
||||
( new AuthorizationFactory() )->create()->authorize( new \stdClass() );
|
||||
}
|
||||
} else {
|
||||
$result = new WP_Error(
|
||||
'0',
|
||||
'No service selected',
|
||||
array( 'service_id' => $service_id )
|
||||
);
|
||||
}
|
||||
|
||||
// Do not store selected service if this operation failed;
|
||||
if ( $error || ! $service_selected ) {
|
||||
$sitepress->set_setting( 'translation_service', false, true );
|
||||
}
|
||||
$sitepress->save_settings();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function deselect_active_service() {
|
||||
global $sitepress;
|
||||
|
||||
$sitepress->set_setting( 'translation_service', false );
|
||||
$sitepress->set_setting( 'translator_choice', false );
|
||||
$sitepress->set_setting( 'icl_lang_status', false );
|
||||
$sitepress->set_setting( 'icl_html_status', false );
|
||||
$sitepress->set_setting( 'icl_current_session', false );
|
||||
$sitepress->set_setting( 'last_icl_reminder_fetch', false );
|
||||
$sitepress->set_setting( 'translators_management_info', false );
|
||||
$sitepress->set_setting( 'language_pairs', false );
|
||||
$sitepress->save_settings();
|
||||
|
||||
do_action( 'wpml_tp_service_dectivated', self::get_current_service() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $service
|
||||
* @param bool $custom_fields_data
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \WPMLTranslationProxyApiException
|
||||
*/
|
||||
public static function build_and_store_active_translation_service( $service, $custom_fields_data = false ) {
|
||||
global $sitepress;
|
||||
|
||||
// set language map
|
||||
$service->languages_map = self::languages_map( $service );
|
||||
|
||||
// set information about custom fields
|
||||
$service->custom_fields = self::get_custom_fields( $service->id, true );
|
||||
$service->custom_fields_data = $custom_fields_data;
|
||||
|
||||
$service->last_refresh = time();
|
||||
|
||||
$sitepress->set_setting( 'translation_service', $service, true );
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|TranslationProxy_Project
|
||||
*/
|
||||
public static function get_current_project() {
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service ) {
|
||||
return new TranslationProxy_Project( $translation_service, 'xmlrpc', self::get_tp_client() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_current_service_info( array $info = array() ) {
|
||||
global $sitepress;
|
||||
if ( ! $sitepress->get_setting( 'translation_service' ) ) {
|
||||
$sitepress->set_setting( 'translation_service', false, true );
|
||||
}
|
||||
$service = self::get_current_service();
|
||||
if ( $service ) {
|
||||
$service_info = array();
|
||||
if ( icl_do_not_promote() ) {
|
||||
$service_info['name'] = __( 'Translation Service', 'wpml-translation-management' );
|
||||
$service_info['logo'] = false;
|
||||
$service_info['header'] = __( 'Translation Service', 'wpml-translation-management' );
|
||||
$service_info['description'] = false;
|
||||
$service_info['contact_url'] = false;
|
||||
} else {
|
||||
$service_info['name'] = $service->name;
|
||||
$service_info['logo'] = $service->logo_url;
|
||||
$service_info['header'] = $service->name;
|
||||
$service_info['description'] = $service->description;
|
||||
$service_info['contact_url'] = $service->url;
|
||||
}
|
||||
$service_info['setup_url'] = TranslationProxy_Popup::get_link( '@select-translators;from_replace;to_replace@', array( 'ar' => 1 ), true );
|
||||
$service_info['has_quote'] = $service->quote_iframe_url !== '';
|
||||
$service_info['has_translator_selection'] = $service->has_translator_selection;
|
||||
|
||||
$info[ $service->id ] = $service_info;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public static function get_service_promo() {
|
||||
global $sitepress;
|
||||
|
||||
if ( icl_do_not_promote() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cache_key = 'get_service_promo';
|
||||
$cache_found = false;
|
||||
|
||||
$output = wp_cache_get( $cache_key, '', false, $cache_found );
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
$icl_translation_services = apply_filters( 'icl_translation_services', array() );
|
||||
$icl_translation_services = array_merge( $icl_translation_services, self::get_current_service_info() );
|
||||
|
||||
$output = '';
|
||||
|
||||
if ( ! empty( $icl_translation_services ) ) {
|
||||
|
||||
$sitepress_settings = $sitepress->get_settings();
|
||||
$icl_dashboard_settings = isset( $sitepress_settings['dashboard'] ) ? $sitepress_settings['dashboard'] : array();
|
||||
|
||||
if ( empty( $icl_dashboard_settings['hide_icl_promo'] ) ) {
|
||||
$exp_hidden = '';
|
||||
$col_hidden = ' hidden';
|
||||
} else {
|
||||
$exp_hidden = ' hidden';
|
||||
$col_hidden = '';
|
||||
}
|
||||
|
||||
$output .= '<div class="icl-translation-services' . $exp_hidden . '">';
|
||||
foreach ( $icl_translation_services as $service ) {
|
||||
$output .= '<div class="icl-translation-services-inner">';
|
||||
$output .= '<p class="icl-translation-services-logo"><span><img src="' . $service['logo'] . '" alt="' . $service['name'] . '" /></span></p>';
|
||||
$output .= '<h3 class="icl-translation-services-header"> ' . $service['header'] . '</h3>';
|
||||
$output .= '<div class="icl-translation-desc"> ' . $service['description'] . '</div>';
|
||||
$output .= '</div>';
|
||||
$output .= '<p class="icl-translation-links">';
|
||||
$output .= '<a class="icl-mail-ico" href="' . $service['contact_url'] . '" target="_blank">' . __( 'Contact', 'wpml-translation-management' ) . " {$service['name']}</a>";
|
||||
$output .= '<a id="icl_hide_promo" href="#">' . __( 'Hide this', 'wpml-translation-management' ) . '</a>';
|
||||
$output .= '</p>';
|
||||
}
|
||||
$output .= '</div>';
|
||||
|
||||
$output .= '<a class="' . $col_hidden . '" id="icl_show_promo" href="#">' . __( 'Need translators?', 'wpml-translation-management' ) . '</a>';
|
||||
}
|
||||
|
||||
wp_cache_set( $cache_key, $output );
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function get_service_dashboard_info() {
|
||||
global $sitepress;
|
||||
|
||||
return self::get_custom_html(
|
||||
'dashboard',
|
||||
$sitepress->get_current_language(),
|
||||
array(
|
||||
'TranslationProxy_Popup',
|
||||
'get_link',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_service_translators_info() {
|
||||
global $sitepress;
|
||||
|
||||
return self::get_custom_html(
|
||||
'translators',
|
||||
$sitepress->get_current_language(),
|
||||
array(
|
||||
'TranslationProxy_Popup',
|
||||
'get_link',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $location
|
||||
* @param string $locale
|
||||
* @param callable $popup_link_callback
|
||||
* @param int $max_count
|
||||
* @param bool $paragraph
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_custom_html(
|
||||
$location,
|
||||
$locale,
|
||||
$popup_link_callback,
|
||||
$max_count = 1000,
|
||||
$paragraph = true
|
||||
) {
|
||||
/** @var $project TranslationProxy_Project */
|
||||
$project = self::get_current_project();
|
||||
|
||||
if ( ! $project ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cache_key = $project->id . ':' . md5(
|
||||
serialize(
|
||||
array(
|
||||
$location,
|
||||
$locale,
|
||||
serialize( $popup_link_callback ),
|
||||
$max_count,
|
||||
$paragraph,
|
||||
)
|
||||
)
|
||||
);
|
||||
$cache_group = 'get_custom_html';
|
||||
$cache_found = false;
|
||||
|
||||
$output = wp_cache_get( $cache_key, $cache_group, false, $cache_found );
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
try {
|
||||
$text = $project->custom_text( $location, $locale );
|
||||
} catch ( Exception $e ) {
|
||||
|
||||
return 'Error getting custom text from Translation Service: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
if ( $text ) {
|
||||
foreach ( $text as $string ) {
|
||||
$format_string = self::sanitize_custom_text( $string->format_string );
|
||||
|
||||
if ( $paragraph ) {
|
||||
$format = '<p>' . $format_string . '</p>';
|
||||
} else {
|
||||
$format = '<div>' . $format_string . '</div>';
|
||||
}
|
||||
$links = array();
|
||||
/** @var array $string_links */
|
||||
$string_links = $string->links;
|
||||
foreach ( $string_links as $link ) {
|
||||
$url = self::sanitize_custom_text( $link->url );
|
||||
$text = self::sanitize_custom_text( $link->text );
|
||||
if ( isset( $link->dismiss ) && (int) $link->dismiss === 1 ) {
|
||||
$links[] = '<a href="' . $url . '" class="wpml_tp_custom_dismiss_able">' . $text . '</a>';
|
||||
} else {
|
||||
$links[] = call_user_func(
|
||||
$popup_link_callback,
|
||||
$url
|
||||
) . $text . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$output .= vsprintf( $format, $links );
|
||||
|
||||
$count ++;
|
||||
if ( $count >= $max_count ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function get_current_service_name() {
|
||||
|
||||
if ( icl_do_not_promote() ) {
|
||||
return __( 'Translation Service', 'wpml-translation-management' );
|
||||
}
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service ) {
|
||||
return $translation_service->name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_current_service_id() {
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service ) {
|
||||
return $translation_service->id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_current_service_batch_name_max_length() {
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service && isset( $translation_service->batch_name_max_length )
|
||||
&& null
|
||||
!== $translation_service->batch_name_max_length ) {
|
||||
return $translation_service->batch_name_max_length;
|
||||
}
|
||||
|
||||
return 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|TranslationProxy_Service|WP_Error $service
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \WPMLTranslationProxyApiException
|
||||
*/
|
||||
public static function service_requires_authentication( $service = false ) {
|
||||
if ( ! $service ) {
|
||||
$service = self::get_current_service();
|
||||
}
|
||||
|
||||
$custom_fields = false;
|
||||
if ( false !== (bool) $service ) {
|
||||
$custom_fields = self::get_custom_fields( $service->id );
|
||||
}
|
||||
|
||||
return $custom_fields && isset( $custom_fields->custom_fields ) && count( $custom_fields->custom_fields ) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if $service has been successfully authenticated
|
||||
* Services that do not require authentication are by default authenticated
|
||||
*
|
||||
* @param bool|WP_Error|TranslationProxy_Service $service
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function is_service_authenticated( $service = false ) {
|
||||
if ( ! $service ) {
|
||||
$service = self::get_current_service();
|
||||
}
|
||||
|
||||
if ( ! $service ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! self::service_requires_authentication( $service ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$has_custom_fields = self::has_custom_fields();
|
||||
$custom_fields_data = self::get_custom_fields_data();
|
||||
|
||||
return $has_custom_fields && $custom_fields_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|TranslationProxy_Service|WP_Error
|
||||
*/
|
||||
public static function get_current_service() {
|
||||
global $sitepress;
|
||||
|
||||
/** @var TranslationProxy_Service $ts */
|
||||
$ts = $sitepress->get_setting( 'translation_service' );
|
||||
|
||||
if ( is_array( $ts ) ) {
|
||||
return new WP_Error( 'translation-proxy-service-misconfiguration', 'translation_service is stored as array!', $ts );
|
||||
}
|
||||
|
||||
return $ts;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function is_current_service_active_and_authenticated() {
|
||||
$active_service = self::get_current_service();
|
||||
|
||||
return $active_service && TranslationProxy_Service::is_authenticated( $active_service );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_translation_projects() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_setting( 'icl_translation_projects', null );
|
||||
}
|
||||
|
||||
public static function get_service_name( $service_id = false ) {
|
||||
if ( $service_id ) {
|
||||
$name = false;
|
||||
$services = self::services( false );
|
||||
|
||||
foreach ( $services as $service ) {
|
||||
if ( $service->id === $service_id ) {
|
||||
$name = $service->name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$name = self::get_current_service_name();
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public static function has_custom_fields( $service_id = false ) {
|
||||
$custom_fields = self::get_custom_fields( $service_id );
|
||||
|
||||
if ( $custom_fields ) {
|
||||
return isset( $custom_fields->custom_fields ) && is_array( $custom_fields->custom_fields ) && count( $custom_fields->custom_fields );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|bool $service_id If not given, will use the current service ID (if any)
|
||||
* @param bool $force_reload Force reload custom fields from Translation Service
|
||||
*
|
||||
* @throws WPMLTranslationProxyApiException
|
||||
* @throws InvalidArgumentException
|
||||
* @return array|mixed|null|string
|
||||
*/
|
||||
public static function get_custom_fields( $service_id = false, $force_reload = false ) {
|
||||
|
||||
if ( ! $service_id ) {
|
||||
$service_id = self::get_current_service_id();
|
||||
}
|
||||
if ( ! $service_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
if ( $translation_service && ! $force_reload ) {
|
||||
return $translation_service->custom_fields ?: false;
|
||||
}
|
||||
|
||||
return self::get_tp_client()->services()->get_custom_fields( $service_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_extra_fields_local() {
|
||||
global $sitepress;
|
||||
$service = self::get_current_service();
|
||||
$icl_translation_projects = $sitepress->get_setting( 'icl_translation_projects' );
|
||||
|
||||
if ( isset( $icl_translation_projects[ TranslationProxy_Project::generate_service_index( $service ) ]['extra_fields'] ) && ! empty( $icl_translation_projects[ TranslationProxy_Project::generate_service_index( $service ) ]['extra_fields'] ) ) {
|
||||
return $icl_translation_projects[ TranslationProxy_Project::generate_service_index( $service ) ]['extra_fields'];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $extra_fields
|
||||
*/
|
||||
public static function save_extra_fields( $extra_fields ) {
|
||||
global $sitepress;
|
||||
$service = self::get_current_service();
|
||||
$icl_translation_projects = $sitepress->get_setting( 'icl_translation_projects' );
|
||||
$icl_translation_project_id = TranslationProxy_Project::generate_service_index( $service );
|
||||
|
||||
if ( is_array( Obj::prop( $icl_translation_project_id, $icl_translation_projects ) ) ) {
|
||||
$icl_translation_projects[ $icl_translation_project_id ]['extra_fields'] = $extra_fields;
|
||||
$sitepress->set_setting( 'icl_translation_projects', $icl_translation_projects );
|
||||
$sitepress->save_settings();
|
||||
}
|
||||
}
|
||||
|
||||
public static function maybe_convert_extra_fields( $extra_fields ) {
|
||||
$extra_fields_typed = array();
|
||||
|
||||
if ( $extra_fields && is_array( $extra_fields ) ) {
|
||||
/** @var array $extra_fields */
|
||||
/** @var stdClass $extra_field */
|
||||
foreach ( $extra_fields as $extra_field ) {
|
||||
if ( $extra_field instanceof WPML_TP_Extra_Field ) {
|
||||
$extra_field_typed = $extra_field;
|
||||
} else {
|
||||
$extra_field_typed = new WPML_TP_Extra_Field();
|
||||
if ( isset( $extra_field->type ) ) {
|
||||
$extra_field_typed->type = $extra_field->type;
|
||||
}
|
||||
if ( isset( $extra_field->label ) ) {
|
||||
$extra_field_typed->label = $extra_field->label;
|
||||
}
|
||||
if ( isset( $extra_field->name ) ) {
|
||||
$extra_field_typed->name = $extra_field->name;
|
||||
}
|
||||
if ( isset( $extra_field->items ) ) {
|
||||
$extra_field_typed->items = $extra_field->items;
|
||||
}
|
||||
}
|
||||
$extra_fields_typed[] = $extra_field_typed;
|
||||
}
|
||||
}
|
||||
|
||||
return $extra_fields_typed;
|
||||
}
|
||||
|
||||
public static function get_custom_fields_data() {
|
||||
$service = self::get_current_service();
|
||||
|
||||
return null !== $service->custom_fields_data ? $service->custom_fields_data : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if the current translation service allows selection of specific translators
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function translator_selection_available() {
|
||||
$res = false;
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
if ( $translation_service && $translation_service->has_translator_selection && self::is_service_authenticated() ) {
|
||||
$res = true;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private static function sanitize_custom_text( $text ) {
|
||||
$text = substr( $text, 0, CUSTOM_TEXT_MAX_LENGTH );
|
||||
$text = esc_html( $text );
|
||||
|
||||
// Service sends html tags as [tag]
|
||||
$text = str_replace( array( '[', ']' ), array( '<', '>' ), $text );
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function languages_map( $service ) {
|
||||
$languages_map = array();
|
||||
$languages = self::get_tp_client()->services()->get_languages_map( $service->id );
|
||||
if ( ! empty( $languages ) ) {
|
||||
foreach ( $languages as $language ) {
|
||||
$languages_map[ $language->iso_code ] = $language->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $languages_map;
|
||||
}
|
||||
|
||||
private static function get_preferred_translation_service() {
|
||||
$tp_default_suid = false;
|
||||
$preferred_translation_service_from_installer = self::get_preferred_translation_service_from_installer();
|
||||
if ( 'clear' !== $preferred_translation_service_from_installer ) {
|
||||
$tp_default_suid = $preferred_translation_service_from_installer;
|
||||
}
|
||||
|
||||
return $tp_default_suid;
|
||||
}
|
||||
|
||||
private static function get_preferred_translation_service_from_installer() {
|
||||
|
||||
return WP_Installer_API::get_preferred_ts();
|
||||
}
|
||||
|
||||
public static function get_tp_client() {
|
||||
if ( ! self::$tp_client ) {
|
||||
$tp_api_factory = new WPML_TP_Client_Factory();
|
||||
self::$tp_client = $tp_api_factory->create();
|
||||
}
|
||||
|
||||
return self::$tp_client;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,611 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @package wpml-core-pro-translation
|
||||
*/
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Str;
|
||||
use function WPML\Container\make;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
/**
|
||||
* Class WPML_Pro_Translation
|
||||
*/
|
||||
class WPML_Pro_Translation extends WPML_TM_Job_Factory_User {
|
||||
|
||||
public $errors = array();
|
||||
/** @var TranslationManagement $tmg */
|
||||
private $tmg;
|
||||
|
||||
/** @var WPML_TM_CMS_ID $cms_id_helper */
|
||||
private $cms_id_helper;
|
||||
|
||||
/** @var WPML_TM_Xliff_Reader_Factory $xliff_reader_factory */
|
||||
private $xliff_reader_factory;
|
||||
|
||||
|
||||
private $sitepress;
|
||||
|
||||
private $update_pm;
|
||||
|
||||
/**
|
||||
* WPML_Pro_Translation constructor.
|
||||
*
|
||||
* @param WPML_Translation_Job_Factory $job_factory
|
||||
*/
|
||||
function __construct( &$job_factory ) {
|
||||
parent::__construct( $job_factory );
|
||||
global $iclTranslationManagement, $wpdb, $sitepress, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
$this->tmg =& $iclTranslationManagement;
|
||||
$this->xliff_reader_factory = new WPML_TM_Xliff_Reader_Factory( $this->job_factory );
|
||||
$wpml_tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$this->cms_id_helper = new WPML_TM_CMS_ID( $wpml_tm_records, $job_factory );
|
||||
$this->sitepress = $sitepress;
|
||||
|
||||
add_filter( 'xmlrpc_methods', array( $this, 'custom_xmlrpc_methods' ) );
|
||||
add_action(
|
||||
'post_submitbox_start',
|
||||
array(
|
||||
$this,
|
||||
'post_submitbox_start',
|
||||
)
|
||||
);
|
||||
add_action(
|
||||
'icl_ajx_custom_call',
|
||||
array(
|
||||
$this,
|
||||
'ajax_calls',
|
||||
),
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_action( 'wpml_minor_edit_for_gutenberg', array( $this, 'gutenberg_minor_edit' ), 10, 0 );
|
||||
|
||||
$this->update_pm = new WPML_Update_PickUp_Method( $this->sitepress );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_CMS_ID
|
||||
*/
|
||||
public function &get_cms_id_helper() {
|
||||
return $this->cms_id_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $call
|
||||
* @param array $data
|
||||
*/
|
||||
function ajax_calls( $call, $data ) {
|
||||
switch ( $call ) {
|
||||
case 'set_pickup_mode':
|
||||
$response = $this->update_pm->update_pickup_method( $data, $this->get_current_project() );
|
||||
if ( 'no-ts' === $response ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Please activate translation service first.', 'wpml-translation-management' ) ) );
|
||||
}
|
||||
if ( 'cant-update' === $response ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Could not update the translation pickup mode.', 'wpml-translation-management' ) ) );
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'message' => __( 'Ok', 'wpml-translation-management' ) ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_current_project() {
|
||||
return TranslationProxy::get_current_project();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post|WPML_Package $post
|
||||
* @param array $target_languages
|
||||
* @param int $translator_id
|
||||
* @param int $job_id
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
function send_post( $post, $target_languages, $translator_id, $job_id ) {
|
||||
/** @var TranslationManagement $iclTranslationManagement */
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
$this->maybe_init_translation_management( $iclTranslationManagement );
|
||||
|
||||
if ( is_numeric( $post ) ) {
|
||||
$post = get_post( $post );
|
||||
}
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post_id = $post->ID;
|
||||
$post_type = $post->post_type;
|
||||
$element_type_prefix = $iclTranslationManagement->get_element_type_prefix_from_job_id( $job_id );
|
||||
$element_type = $element_type_prefix . '_' . $post_type;
|
||||
|
||||
$note = WPML_TM_Translator_Note::get( $post_id );
|
||||
if ( ! $note ) {
|
||||
$note = null;
|
||||
}
|
||||
$err = false;
|
||||
$tp_job_id = false;
|
||||
$source_language = $sitepress->get_language_for_element( $post_id, $element_type );
|
||||
$target_language = is_array( $target_languages ) ? end( $target_languages ) : $target_languages;
|
||||
if ( empty( $target_language ) || $target_language === $source_language ) {
|
||||
return false;
|
||||
}
|
||||
$translation = $this->tmg->get_element_translation( $post_id, $target_language, $element_type );
|
||||
if ( ! $translation ) { // translated the first time
|
||||
$err = true;
|
||||
}
|
||||
if ( ! $err && ( $translation->needs_update || $translation->status == ICL_TM_NOT_TRANSLATED || $translation->status == ICL_TM_WAITING_FOR_TRANSLATOR ) ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
if ( $iclTranslationManagement->is_external_type( $element_type_prefix ) ) {
|
||||
$job_object = new WPML_External_Translation_Job( $job_id );
|
||||
} else {
|
||||
$job_object = new WPML_Post_Translation_Job( $job_id );
|
||||
$job_object->load_terms_from_post_into_job();
|
||||
}
|
||||
|
||||
list( $err, $project, $tp_job_id ) = $job_object->send_to_tp( $project, $translator_id, $this->cms_id_helper, $this->tmg, $note );
|
||||
if ( $err ) {
|
||||
$this->enqueue_project_errors( $project );
|
||||
}
|
||||
}
|
||||
|
||||
return $err ? false : $tp_job_id; // last $ret
|
||||
}
|
||||
|
||||
function server_languages_map( $language_name, $server2plugin = false ) {
|
||||
if ( is_array( $language_name ) ) {
|
||||
return array_map( array( $this, 'server_languages_map' ), $language_name );
|
||||
}
|
||||
$map = array(
|
||||
'Norwegian Bokmål' => 'Norwegian',
|
||||
'Portuguese, Brazil' => 'Portuguese',
|
||||
'Portuguese, Portugal' => 'Portugal Portuguese',
|
||||
);
|
||||
|
||||
$map = $server2plugin ? array_flip( $map ) : $map;
|
||||
|
||||
return isset( $map[ $language_name ] ) ? $map[ $language_name ] : $language_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $methods
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function custom_xmlrpc_methods( $methods ) {
|
||||
$icl_methods['translationproxy.test_xmlrpc'] = '__return_true';
|
||||
$icl_methods['translationproxy.updated_job_status'] = array(
|
||||
$this,
|
||||
'xmlrpc_updated_job_status',
|
||||
);
|
||||
|
||||
$methods = array_merge( $methods, $icl_methods );
|
||||
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && preg_match( '#<methodName>([^<]+)</methodName>#i', $this->sitepress->get_wp_api()->get_raw_post_data(), $matches ) ) {
|
||||
$method = $matches[1];
|
||||
if ( array_key_exists( $method, $icl_methods ) ) {
|
||||
set_error_handler( array( $this, 'translation_error_handler' ), E_ERROR | E_USER_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
*
|
||||
* @return int|IXR_Error
|
||||
*/
|
||||
public function xmlrpc_updated_job_status( $args ) {
|
||||
global $wpdb;
|
||||
|
||||
$tp_id = isset( $args[0] ) ? $args[0] : 0;
|
||||
$cms_id = isset( $args[1] ) ? $args[1] : 0;
|
||||
$status = isset( $args[2] ) ? $args[2] : '';
|
||||
$signature = isset( $args[3] ) ? $args[3] : '';
|
||||
|
||||
if ( ! $this->authenticate_request( $tp_id, $cms_id, $status, $signature ) ) {
|
||||
return new IXR_Error( 401, 'Wrong signature' );
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
/** @var WPML_TM_Jobs_Repository $jobs_repository */
|
||||
$jobs_repository = wpml_tm_get_jobs_repository();
|
||||
|
||||
$job_match = $jobs_repository->get(
|
||||
new WPML_TM_Jobs_Search_Params(
|
||||
array(
|
||||
'scope' => 'remote',
|
||||
'tp_id' => $tp_id,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( $job_match ) {
|
||||
$jobs_array = $job_match->toArray();
|
||||
$job = $jobs_array[0];
|
||||
$job->set_status( WPML_TP_Job_States::map_tp_state_to_local( $status ) );
|
||||
|
||||
$tp_sync_updated_job = new WPML_TP_Sync_Update_Job( $wpdb, $this->sitepress );
|
||||
$job_updated = $tp_sync_updated_job->update_state( $job );
|
||||
|
||||
if ( $job_updated && WPML_TP_Job_States::CANCELLED !== $status ) {
|
||||
$apply_tp_translation = new WPML_TP_Apply_Single_Job(
|
||||
wpml_tm_get_tp_translations_repository(),
|
||||
new WPML_TP_Apply_Translation_Strategies( $wpdb )
|
||||
);
|
||||
$apply_tp_translation->apply( $job );
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
return new IXR_Error( $e->getCode(), $e->getMessage() );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function authenticate_request( $tp_id, $cms_id, $status, $signature ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
return sha1( $project->id . $project->access_key . $tp_id . $cms_id . $status ) === $signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_WP_API
|
||||
*/
|
||||
function get_wpml_wp_api() {
|
||||
return $this->sitepress->get_wp_api();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Cancel translation for given cms_id
|
||||
*
|
||||
* @param $rid
|
||||
* @param $cms_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function cancel_translation( $rid, $cms_id ) {
|
||||
/**
|
||||
* @var WPML_String_Translation|null $WPML_String_Translation
|
||||
* @var TranslationManagement $iclTranslationManagement
|
||||
*/
|
||||
global $WPML_String_Translation, $iclTranslationManagement;
|
||||
|
||||
$res = false;
|
||||
if ( empty( $cms_id ) ) { // it's a string
|
||||
if ( $WPML_String_Translation ) {
|
||||
$res = $WPML_String_Translation->cancel_remote_translation( $rid );
|
||||
}
|
||||
} else {
|
||||
$translation_id = $this->cms_id_helper->get_translation_id( $cms_id );
|
||||
|
||||
if ( $translation_id ) {
|
||||
$iclTranslationManagement->cancel_translation_request( $translation_id );
|
||||
$res = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Downloads translation from TP and updates its document
|
||||
*
|
||||
* @param $translation_proxy_job_id
|
||||
* @param $cms_id
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function download_and_process_translation( $translation_proxy_job_id, $cms_id ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $cms_id ) ) { // it's a string
|
||||
// TODO: [WPML 3.3] this should be handled as any other element type in 3.3
|
||||
$target = $wpdb->get_var( $wpdb->prepare( "SELECT target FROM {$wpdb->prefix}icl_core_status WHERE rid=%d", $translation_proxy_job_id ) );
|
||||
|
||||
return $this->process_translated_string( $translation_proxy_job_id, $target );
|
||||
} else {
|
||||
$translation_id = $this->cms_id_helper->get_translation_id( $cms_id, TranslationProxy::get_current_service() );
|
||||
|
||||
return ! empty( $translation_id ) && $this->add_translated_document( $translation_id, $translation_proxy_job_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $translation_id
|
||||
* @param int $translation_proxy_job_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function add_translated_document( $translation_id, $translation_proxy_job_id ) {
|
||||
global $wpdb, $sitepress;
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
$translation_info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}icl_translations WHERE translation_id=%d", $translation_id ) );
|
||||
$translation = $project->fetch_translation( $translation_proxy_job_id );
|
||||
if ( ! $translation ) {
|
||||
$this->errors = array_merge( $this->errors, $project->errors );
|
||||
} else {
|
||||
$translation = apply_filters( 'icl_data_from_pro_translation', $translation );
|
||||
}
|
||||
$ret = true;
|
||||
|
||||
if ( ! empty( $translation ) && strpos( $translation, 'xliff' ) !== false ) {
|
||||
try {
|
||||
/** @var $job_xliff_translation WP_Error|array */
|
||||
$job_xliff_translation = $this->xliff_reader_factory
|
||||
->general_xliff_import()->import( $translation, $translation_id );
|
||||
if ( is_wp_error( $job_xliff_translation ) ) {
|
||||
$this->add_error( $job_xliff_translation->get_error_message() );
|
||||
|
||||
return false;
|
||||
}
|
||||
kses_remove_filters();
|
||||
wpml_tm_save_data( $job_xliff_translation );
|
||||
kses_init();
|
||||
|
||||
$translations = $sitepress->get_element_translations( $translation_info->trid, $translation_info->element_type, false, true, true );
|
||||
if ( isset( $translations[ $translation_info->language_code ] ) ) {
|
||||
$translation = $translations[ $translation_info->language_code ];
|
||||
if ( isset( $translation->element_id ) && $translation->element_id ) {
|
||||
$translation_post_type_prepared = $wpdb->prepare( "SELECT post_type FROM $wpdb->posts WHERE ID=%d", array( $translation->element_id ) );
|
||||
$translation_post_type = $wpdb->get_var( $translation_post_type_prepared );
|
||||
} else {
|
||||
$translation_post_type = implode( '_', array_slice( explode( '_', $translation_info->element_type ), 1 ) );
|
||||
}
|
||||
if ( $translation_post_type == 'page' ) {
|
||||
$url = get_option( 'home' ) . '?page_id=' . $translation->element_id;
|
||||
} else {
|
||||
$url = get_option( 'home' ) . '?p=' . $translation->element_id;
|
||||
}
|
||||
$project->update_job( $translation_proxy_job_id, $url );
|
||||
} else {
|
||||
$project->update_job( $translation_proxy_job_id );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private static function content_get_link_paths( $body ) {
|
||||
|
||||
$regexp_links = array(
|
||||
"/<a[^>]*href\s*=\s*([\"\']??)([^\"^>]+)[\"\']??([^>]*)>/i",
|
||||
);
|
||||
|
||||
$links = array();
|
||||
|
||||
foreach ( $regexp_links as $regexp ) {
|
||||
if ( preg_match_all( $regexp, $body, $matches, PREG_SET_ORDER ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$links[] = $match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
public function fix_links_to_translated_content( $element_id, $target_lang_code, $element_type = 'post' ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$sitepress->switch_lang( $target_lang_code );
|
||||
|
||||
$wpml_element_type = $element_type;
|
||||
$body = false;
|
||||
$string_type = null;
|
||||
if ( strpos( $element_type, 'post' ) === 0 ) {
|
||||
$post_prepared = $wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE ID=%d", array( $element_id ) );
|
||||
$post = $wpdb->get_row( $post_prepared );
|
||||
$body = $post->post_content;
|
||||
$wpml_element_type = 'post_' . $post->post_type;
|
||||
} elseif ( $element_type == 'string' ) {
|
||||
$string_prepared = $wpdb->prepare( "SELECT string_id, value FROM {$wpdb->prefix}icl_string_translations WHERE id=%d", array( $element_id ) );
|
||||
$data = $wpdb->get_row( $string_prepared );
|
||||
$body = $data->value;
|
||||
$original_string_id = $data->string_id;
|
||||
$string_type = $wpdb->get_var( $wpdb->prepare( "SELECT type FROM {$wpdb->prefix}icl_strings WHERE id=%d", $original_string_id ) );
|
||||
if ( 'LINK' === $string_type ) {
|
||||
$body = '<a href="' . $body . '">removeit</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$translate_link_targets = make( 'WPML_Translate_Link_Targets' );
|
||||
$absolute_links = make( 'AbsoluteLinks' );
|
||||
|
||||
$getTranslatedLink = function ( $link ) use ( $translate_link_targets, $absolute_links, $element_type, $target_lang_code ) {
|
||||
if ( $absolute_links->is_home( $link[2] ) ) {
|
||||
$translatedLink = $absolute_links->convert_url( $link[2], $target_lang_code );
|
||||
$translatedLink = Str::replace( $link[2], $translatedLink, $link[0] );
|
||||
} else {
|
||||
add_filter( 'wpml_force_translated_permalink', '__return_true' );
|
||||
$translatedLink = $translate_link_targets->convert_text( $link[0] );
|
||||
remove_filter( 'wpml_force_translated_permalink', '__return_true' );
|
||||
if ( self::should_links_be_converted_back_to_sticky( $element_type ) ) {
|
||||
$translatedLink = $absolute_links->convert_text( $translatedLink );
|
||||
}
|
||||
}
|
||||
|
||||
return $translatedLink !== $link[0]
|
||||
? [
|
||||
'from' => $link[0],
|
||||
'to' => $translatedLink,
|
||||
]
|
||||
: null;
|
||||
};
|
||||
|
||||
$getTranslatedLinks = pipe(
|
||||
Fns::map( $getTranslatedLink ),
|
||||
Fns::filter( Fns::identity() )
|
||||
);
|
||||
|
||||
$links = self::content_get_link_paths( $body );
|
||||
|
||||
$translatedLinks = $getTranslatedLinks( $links );
|
||||
|
||||
$replaceLink = function ( $body, $link ) {
|
||||
return str_replace( $link['from'], $link['to'], $body );
|
||||
};
|
||||
|
||||
$new_body = Fns::reduce( $replaceLink, $body, $translatedLinks );
|
||||
|
||||
if ( $new_body != $body ) {
|
||||
if ( strpos( $element_type, 'post' ) === 0 ) {
|
||||
$wpdb->update( $wpdb->posts, array( 'post_content' => $new_body ), array( 'ID' => $element_id ) );
|
||||
} elseif ( $element_type == 'string' ) {
|
||||
if ( 'LINK' === $string_type ) {
|
||||
$new_body = str_replace( array( '<a href="', '">removeit</a>' ), array( '', '' ), $new_body );
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'value' => $new_body,
|
||||
'status' => ICL_TM_COMPLETE,
|
||||
),
|
||||
array( 'id' => $element_id )
|
||||
);
|
||||
do_action( 'icl_st_add_string_translation', $element_id );
|
||||
} else {
|
||||
$wpdb->update( $wpdb->prefix . 'icl_string_translations', array( 'value' => $new_body ), array( 'id' => $element_id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$links_fixed_status_factory = new WPML_Links_Fixed_Status_Factory( $wpdb, new WPML_WP_API() );
|
||||
$links_fixed_status = $links_fixed_status_factory->create( $element_id, $wpml_element_type );
|
||||
$links_fixed_status->set( Lst::length( $links ) === Lst::length( $translatedLinks ) );
|
||||
|
||||
$sitepress->switch_lang();
|
||||
|
||||
return sizeof( $translatedLinks );
|
||||
|
||||
}
|
||||
|
||||
function translation_error_handler( $error_number, $error_string, $error_file, $error_line ) {
|
||||
switch ( $error_number ) {
|
||||
case E_ERROR:
|
||||
case E_USER_ERROR:
|
||||
throw new Exception( $error_string . ' [code:e' . $error_number . '] in ' . $error_file . ':' . $error_line );
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function should_links_be_converted_back_to_sticky( $element_type ) {
|
||||
return 'string' !== $element_type && ! empty( $GLOBALS['WPML_Sticky_Links'] );
|
||||
}
|
||||
|
||||
function post_submitbox_start() {
|
||||
$show_box_style = $this->get_show_minor_edit_style();
|
||||
if ( false !== $show_box_style ) {
|
||||
?>
|
||||
<p id="icl_minor_change_box" style="float:left;padding:0;margin:3px;<?php echo $show_box_style; ?>">
|
||||
<label><input type="checkbox" name="icl_minor_edit" value="1" style="min-width:15px;"/>
|
||||
<?php esc_html_e( 'Minor edit - don\'t update translation', 'wpml-translation-management' ); ?>
|
||||
</label>
|
||||
<br clear="all"/>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
public function gutenberg_minor_edit() {
|
||||
$show_box_style = $this->get_show_minor_edit_style();
|
||||
if ( false !== $show_box_style ) {
|
||||
?>
|
||||
<div id="icl_minor_change_box" style="<?php echo $show_box_style; ?>" class="icl_box_paragraph">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Minor edit', 'wpml-translation-management' ); ?></strong>
|
||||
</p>
|
||||
<label><input type="checkbox" name="icl_minor_edit" value="1" style="min-width:15px;"/>
|
||||
<?php esc_html_e( "Don't update translation", 'wpml-translation-management' ); ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
private function get_show_minor_edit_style() {
|
||||
global $post, $iclTranslationManagement;
|
||||
if ( empty( $post ) || ! $post->ID ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$translations = $iclTranslationManagement->get_element_translations( $post->ID, 'post_' . $post->post_type );
|
||||
$show_box_style = 'display:none';
|
||||
foreach ( $translations as $t ) {
|
||||
if ( $t->element_id == $post->ID ) {
|
||||
return false;
|
||||
}
|
||||
if ( $t->status == ICL_TM_COMPLETE && ! $t->needs_update ) {
|
||||
$show_box_style = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $show_box_style;
|
||||
}
|
||||
|
||||
private function process_translated_string( $translation_proxy_job_id, $language ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
$translation = $project->fetch_translation( $translation_proxy_job_id );
|
||||
$translation = apply_filters( 'icl_data_from_pro_translation', $translation );
|
||||
$ret = false;
|
||||
$translation = $this->xliff_reader_factory->string_xliff_reader()->get_data( $translation );
|
||||
if ( $translation ) {
|
||||
$ret = icl_translation_add_string_translation( $translation_proxy_job_id, $translation, $language );
|
||||
if ( $ret ) {
|
||||
$project->update_job( $translation_proxy_job_id );
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function add_error( $project_error ) {
|
||||
$this->errors[] = $project_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $project TranslationProxy_Project
|
||||
*/
|
||||
function enqueue_project_errors( $project ) {
|
||||
if ( isset( $project ) && isset( $project->errors ) && $project->errors ) {
|
||||
foreach ( $project->errors as $project_error ) {
|
||||
$this->add_error( $project_error );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TranslationManagement $iclTranslationManagement
|
||||
*/
|
||||
private function maybe_init_translation_management( $iclTranslationManagement ) {
|
||||
if ( empty( $this->tmg->settings ) ) {
|
||||
$iclTranslationManagement->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
use WPML\LIB\WP\Cache;
|
||||
use \WPML\Collect\Support\Traits\Macroable;
|
||||
use WPML\FP\Str;
|
||||
use function \WPML\FP\System\sanitizeString;
|
||||
use function \WPML\FP\pipe;
|
||||
use function \WPML\FP\curryN;
|
||||
|
||||
/**
|
||||
* @method static int get_batch_id_from_name( string $basket_name )
|
||||
*/
|
||||
class WPML_Translation_Basket {
|
||||
|
||||
use Macroable;
|
||||
|
||||
/** @var wpdb $wpdb */
|
||||
private $wpdb;
|
||||
|
||||
public function __construct( \wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the current translation basket
|
||||
*
|
||||
* @param bool|false $force if true reloads the baskets contents from the database
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_basket( $force = false ) {
|
||||
$basket = TranslationProxy_Basket::get_basket( $force );
|
||||
$basket = $basket ? $basket : array();
|
||||
|
||||
return $basket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|TranslationProxy_Project
|
||||
*/
|
||||
public function get_project() {
|
||||
|
||||
return TranslationProxy::get_current_project();
|
||||
}
|
||||
|
||||
function get_item_types() {
|
||||
|
||||
return TranslationProxy_Basket::get_basket_items_types();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a batch instance by basket- or batch-name
|
||||
*
|
||||
* @param string $basket_name
|
||||
*
|
||||
* @return WPML_Translation_Batch
|
||||
*/
|
||||
function get_basket_batch( $basket_name ) {
|
||||
|
||||
return new WPML_Translation_Batch( $this->wpdb, self::get_batch_id_from_name( $basket_name ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the remote target languages before committing the basket to a translation service.
|
||||
*
|
||||
* @param array $remote_languages
|
||||
*/
|
||||
function set_remote_target_languages( $remote_languages ) {
|
||||
|
||||
TranslationProxy_Basket::set_remote_target_languages( $remote_languages );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all items from the current translation basket.
|
||||
*/
|
||||
function delete_all_items() {
|
||||
|
||||
TranslationProxy_Basket::delete_all_items_from_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the current translation basket.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function get_name() {
|
||||
|
||||
return TranslationProxy_Basket::get_basket_name();
|
||||
}
|
||||
|
||||
function set_name( $basket_name ) {
|
||||
|
||||
TranslationProxy_Basket::set_basket_name( $basket_name );
|
||||
}
|
||||
|
||||
function set_options( array $batch_options ) {
|
||||
TranslationProxy_Basket::set_options( $batch_options );
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
function get_options() {
|
||||
return TranslationProxy_Basket::get_options();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $basket_name
|
||||
* @param int $basket_name_max_length
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_basket_name( $basket_name, $basket_name_max_length ) {
|
||||
|
||||
$result = array(
|
||||
'modified' => false,
|
||||
'valid' => true,
|
||||
'message' => '',
|
||||
'new_value' => '',
|
||||
);
|
||||
$old_value = $basket_name;
|
||||
$basket_name = strip_tags( $basket_name );
|
||||
|
||||
if ( mb_strlen( $basket_name ) > $basket_name_max_length ) {
|
||||
$result['valid'] = true;
|
||||
$result['message'] = sprintf(
|
||||
__( 'The length of the batch name exceeds the maximum length of %s', 'wpml-translation-management' ),
|
||||
$basket_name_max_length
|
||||
);
|
||||
$result['new_value'] = $this->get_unique_basket_name( $basket_name, $basket_name_max_length );
|
||||
} elseif ( self::get_batch_id_from_name( $basket_name ) ) {
|
||||
$result['valid'] = true;
|
||||
$result['new_value'] = $this->get_unique_basket_name( $basket_name, $basket_name_max_length );
|
||||
$result['message'] = __(
|
||||
'This batch name already exists and was modified to ensure unique naming',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
} elseif ( count( $basket_name_array = explode( '|', $basket_name ) ) === 1 ) {
|
||||
$result['valid'] = true;
|
||||
$result['new_value'] = $this->get_unique_basket_name( $basket_name, $basket_name_max_length );
|
||||
$result['message'] = __(
|
||||
'The batch name was appended with the source language of its elements.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
}
|
||||
$result['modified'] = $result['new_value'] !== '' && $result['new_value'] !== $old_value;
|
||||
$result['message'] = $result['modified'] || ! $result['valid'] ? $result['message'] : '';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique name derived from an input name for a Translation Proxy Basket
|
||||
*
|
||||
* @param bool $name
|
||||
* @param bool|int $max_length
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function get_unique_basket_name( $name, $max_length ) {
|
||||
$basket_name_array = explode( '|', $name );
|
||||
$name = count( $basket_name_array ) === 1
|
||||
|| ( ! is_numeric( $basket_name_array[ count( $basket_name_array ) - 1 ] )
|
||||
&& $basket_name_array[ count( $basket_name_array ) - 1 ] !== $this->get_source_language() )
|
||||
|| ( is_numeric( $basket_name_array[ count( $basket_name_array ) - 1 ] )
|
||||
&& $basket_name_array[ count( $basket_name_array ) - 2 ] !== $this->get_source_language() )
|
||||
? $name . '|' . $this->get_source_language() : $name;
|
||||
|
||||
$name = mb_strlen( $name ) > $max_length
|
||||
? $this->sanitize_basket_name( $name, $max_length ) : $name;
|
||||
|
||||
if ( self::get_batch_id_from_name( $name ) ) {
|
||||
$suffix = 2;
|
||||
$name = $this->sanitize_basket_name( $name, $max_length - mb_strlen( (string) $suffix ) - 1 );
|
||||
while ( self::get_batch_id_from_name( $name . '|' . $suffix ) ) {
|
||||
$suffix ++;
|
||||
$name = $this->sanitize_basket_name( $name, $max_length - mb_strlen( (string) $suffix ) - 1 );
|
||||
}
|
||||
$name .= '|' . $suffix;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_source_language() {
|
||||
|
||||
return TranslationProxy_Basket::get_source_language();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
*/
|
||||
public function remove_package( $package_id ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket( $package_id, 'package' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $kind
|
||||
*/
|
||||
public function remove_item( $id, $kind ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket( $id, $kind );
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the basket portion with the saved basket
|
||||
*
|
||||
* @param array $basket_portion
|
||||
*/
|
||||
public function update_basket( $basket_portion = array() ) {
|
||||
TranslationProxy_Basket::update_basket( $basket_portion );
|
||||
}
|
||||
|
||||
private function sanitize_basket_name( $basket_name, $max_length ) {
|
||||
// input basket name is separated by pipes so we explode it
|
||||
$to_trim = mb_strlen( $basket_name ) - $max_length;
|
||||
if ( $to_trim <= 0 ) {
|
||||
return $basket_name;
|
||||
}
|
||||
$basket_name_array = explode( '|', $basket_name );
|
||||
$wpml_flag = count( $basket_name_array ) < 3;
|
||||
|
||||
if ( $wpml_flag === false && count( $basket_name_array ) < 2 ) {
|
||||
|
||||
return mb_substr( $basket_name, $max_length - 1 );
|
||||
}
|
||||
|
||||
// first we trim the middle part holding the "WPML"
|
||||
if ( $wpml_flag ) {
|
||||
list( $basket_name_array, $to_trim ) = $this->shorten_basket_name( $basket_name_array, 1, $to_trim );
|
||||
}
|
||||
// then trim the site name first, if that's not enough move the array index and also trim the language
|
||||
for ( $i = 0; $i <= 1; $i ++ ) {
|
||||
if ( $to_trim > 0 ) {
|
||||
list( $basket_name_array, $to_trim ) = $this->shorten_basket_name( $basket_name_array, 0, $to_trim );
|
||||
$basket_name_array = array_filter( $basket_name_array );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$basket_name_array = array_filter( $basket_name_array );
|
||||
|
||||
return implode( '|', $basket_name_array );
|
||||
}
|
||||
|
||||
private function shorten_basket_name( $name_array, $index, $to_trim ) {
|
||||
if ( mb_strlen( $name_array [ $index ] ) > $to_trim ) {
|
||||
$name_array[ $index ] = mb_substr( $name_array[ $index ], 0, mb_strlen( $name_array [ $index ] ) - $to_trim - 1 );
|
||||
$name_array = array_filter( $name_array );
|
||||
$to_trim = 0;
|
||||
} else {
|
||||
$to_trim = $to_trim - mb_strlen( $name_array [ $index ] ) - 1; // subtract one here since we lose a downstroke
|
||||
unset( $name_array [ $index ] );
|
||||
}
|
||||
|
||||
return array( $name_array, $to_trim );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the batch id for a given basket or batch name
|
||||
*
|
||||
* @param string $basket_name
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
WPML_Translation_Basket::macro(
|
||||
'get_batch_id_from_name',
|
||||
curryN(
|
||||
1,
|
||||
Cache::memorize(
|
||||
'get_batch_id_from_name',
|
||||
pipe(
|
||||
Str::replace( '"', '\\"' ),
|
||||
sanitizeString(),
|
||||
TranslationProxy_Batch::getBatchId()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Translation_Proxy_Basket_Networking
|
||||
*/
|
||||
class WPML_Translation_Proxy_Basket_Networking {
|
||||
|
||||
/** @var WPML_Translation_Basket $basket */
|
||||
private $basket;
|
||||
|
||||
/** @var TranslationManagement $tm_instance */
|
||||
private $tm_instance;
|
||||
|
||||
/**
|
||||
* @param WPML_Translation_Basket $basket
|
||||
* @param TranslationManagement $tm_instance
|
||||
*/
|
||||
function __construct( $basket, &$tm_instance ) {
|
||||
$this->basket = $basket;
|
||||
$this->tm_instance = $tm_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TM_Translation_Batch $batch
|
||||
*
|
||||
* @uses \WPML_Translation_Basket::get_basket Gets the array representation of the translation basket
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::generate_batch generates the batch in case no chunk was given for the commit from the basket
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::get_batch_name
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::send_all_jobs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function commit_basket_chunk( WPML_TM_Translation_Batch $batch ) {
|
||||
$result = $this->send_all_jobs( $batch );
|
||||
$error_messages = $this->tm_instance->messages_by_type( 'error' );
|
||||
if ( ( $has_error = (bool) $error_messages ) === true ) {
|
||||
\WPML\TM\API\Batch::rollback( $batch->get_basket_name() );
|
||||
$result['message'] = '';
|
||||
$result['additional_messages'] = $error_messages;
|
||||
}
|
||||
|
||||
return array( $has_error, $result, $error_messages );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an array of translators has any remote translators in it.
|
||||
*
|
||||
* @param array $translators
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function contains_remote_translators( array $translators ) {
|
||||
|
||||
return count( array_filter( $translators, 'is_numeric' ) ) < count( $translators );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends all jobs from basket in batch mode to translation proxy
|
||||
*
|
||||
* @param WPML_TM_Translation_Batch $batch
|
||||
* @param array $translators
|
||||
* @param array $batch_options
|
||||
*
|
||||
* @return bool false in case of errors (read from TranslationManagement::get_messages('error') to get errors details)
|
||||
*/
|
||||
private function send_all_jobs( WPML_TM_Translation_Batch $batch ) {
|
||||
$this->basket->set_options( $batch->get_batch_options() );
|
||||
$this->basket->set_name( $batch->get_basket_name() );
|
||||
|
||||
$this->basket->set_remote_target_languages( $batch->get_remote_target_languages() );
|
||||
$basket_items_types = $this->basket->get_item_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
do_action(
|
||||
'wpml_tm_send_' . $item_type_name . '_jobs',
|
||||
$batch,
|
||||
$item_type_name,
|
||||
\WPML\TM\API\Jobs::SENT_VIA_BASKET
|
||||
);
|
||||
}
|
||||
|
||||
// check if there were no errors
|
||||
return ! $this->tm_instance->messages_by_type( 'error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the batch array for posts in the basket.
|
||||
*
|
||||
* @param array $basket
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function generate_batch( array $basket ) {
|
||||
$batch = array();
|
||||
|
||||
$posts = isset( $basket['post'] ) ? $basket['post'] : array();
|
||||
foreach ( $posts as $post_id => $post ) {
|
||||
$batch[] = array(
|
||||
'type' => 'post',
|
||||
'post_id' => $post_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the batch that contains the given post_id.
|
||||
*
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_batch_name( $post_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$name = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
" SELECT b.batch_name
|
||||
FROM {$wpdb->prefix}icl_translation_batches b
|
||||
JOIN {$wpdb->prefix}icl_translation_status s
|
||||
ON s.batch_id = b.id
|
||||
JOIN {$wpdb->prefix}icl_translations t
|
||||
ON t.translation_id = s.translation_id
|
||||
JOIN {$wpdb->prefix}icl_translations o
|
||||
ON o.trid = t.trid
|
||||
AND o.language_code = t.source_language_code
|
||||
JOIN {$wpdb->posts} p
|
||||
ON o.element_id = p.ID
|
||||
AND o.element_type = CONCAT('post_', p.post_type)
|
||||
WHERE o.element_id = %d
|
||||
ORDER BY b.id
|
||||
LIMIT 1",
|
||||
$post_id
|
||||
)
|
||||
);
|
||||
$this->basket->set_name( $name );
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user