first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,398 @@
<?php
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
abstract class WPML_Element_Translation_Job extends WPML_Translation_Job {
protected $original_del_text;
/** @var WPML_Translation_Job_Factory $job_factory */
protected $job_factory;
private $original_doc_id = false;
private $translation_id = false;
/**
* @param int $job_id
* @param null|int $batch_id
* @param null|TranslationManagement $tm_instance
* @param null|WPML_Translation_Job_Factory $job_factory
*/
function __construct( $job_id, $batch_id = null, &$tm_instance = null, &$job_factory = null ) {
parent::__construct( $job_id, $batch_id, $tm_instance );
$this->original_del_text = __( 'The original has been deleted!', 'sitepress' );
if ( ! $job_factory ) {
global $wpml_translation_job_factory;
$job_factory = &$wpml_translation_job_factory;
}
$this->job_factory = $job_factory;
}
function get_type() {
return 'Post';
}
function to_array() {
$this->maybe_load_basic_data();
$data_array = $this->basic_data_to_array( $this->basic_data );
$data_array['id'] = $this->basic_data->job_id;
$data_array['translation_id'] = $this->basic_data->translation_id;
$data_array['status'] = $this->get_status();
$data_array['translation_edit_url'] = $this->get_url();
$data_array['original_url'] = $this->get_url( true );
$data_array['post_title'] = esc_html( $this->get_title() );
return $data_array;
}
function to_xliff_file() {
$xliff = new WPML_TM_Xliff_Writer( $this->job_factory );
return $xliff->get_job_xliff_file( $this->get_id() );
}
function get_original_element_id() {
if ( ! $this->original_doc_id ) {
$this->original_doc_id = $this->get_iclt_field( 'element_id', false );
}
return $this->original_doc_id;
}
function get_translation_id() {
if ( ! $this->translation_id ) {
$translation_id = $this->get_iclt_field( 'translation_id', true );
$this->translation_id = $translation_id;
} else {
$translation_id = $this->translation_id;
}
return $translation_id;
}
/**
* Saves the job data in this object to the database (e.g. to a post)
*
* @param bool $complete whether or not to set the status
* of the target element to complete
*/
public function save_to_element( $complete = false ) {
global $wpdb, $wpml_post_translations, $wpml_term_translations;
$wpml_tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
$save_data_action = new WPML_Save_Translation_Data_Action(
array(
'job_id' => $this->get_id(),
'complete' => $complete,
'fields' => array(),
),
$wpml_tm_records
);
$save_data_action->save_translation();
}
/**
* @return int
*/
function estimate_word_count() {
$fields = $this->get_original_fields();
$combined_string = join( ' ', $fields );
$calculator = new WPML_TM_Word_Calculator( new WPML_PHP_Functions() );
return $calculator->count_words( $combined_string, $this->get_source_language_code() );
}
function get_original_fields() {
global $wpdb;
$fields = $wpdb->get_results(
$wpdb->prepare(
"SELECT field_type, field_data, field_format
FROM {$wpdb->prefix}icl_translate
WHERE job_id = %d
AND field_translate = 1",
$this->get_id()
)
);
$res = array();
foreach ( $fields as $field ) {
$res[ $field->field_type ] = base64_decode( $field->field_data );
}
return $res;
}
public function cancel() {
global $wpdb;
$deleted = false;
$rid_query = "SELECT rid FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d";
$rid_prepare = $wpdb->prepare( $rid_query, array( $this->job_id ) );
$rid = $wpdb->get_var( $rid_prepare );
$translation_id_query = "SELECT translation_id FROM {$wpdb->prefix}icl_translation_status WHERE rid=%d";
$translation_id_prepare = $wpdb->prepare( $translation_id_query, array( $rid ) );
$translation_id = $wpdb->get_var( $translation_id_prepare );
if ( $rid ) {
$wpdb->delete( $wpdb->prefix . 'icl_translate_job', array( 'job_id' => $this->job_id ) );
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'job_id' => $this->job_id ) );
$deleted = true;
}
if ( $translation_id ) {
$wpdb->delete( $wpdb->prefix . 'icl_translations', array( 'translation_id' => $translation_id ) );
if ( $rid ) {
$wpdb->delete(
$wpdb->prefix . 'icl_translation_status',
array(
'translation_id' => $translation_id,
'rid' => $rid,
)
);
}
}
return $deleted;
}
/**
* @param TranslationProxy_Project $project
* @param int $translator_id
* @param WPML_TM_CMS_ID $cms_id_helper
* @param TranslationManagement $tm_instance
* @param null|string $note
*
* @return array
*/
function send_to_tp( $project, $translator_id, &$cms_id_helper, &$tm_instance, $note = null ) {
global $wpdb;
$this->maybe_load_basic_data();
$file = $this->to_xliff_file();
$title = $this->get_title();
$cms_id = $cms_id_helper->cms_id_from_job_id( $this->get_id() );
$url = $this->get_url( true );
$word_count = $this->estimate_word_count();
$note = isset( $note ) ? $note : '';
$source_language = $this->get_source_language_code();
$target_language = $this->get_language_code();
$uuid = $this->get_uuid();
try {
$tp_job_id = $project->send_to_translation_batch_mode( $file, $title, $cms_id, $url, $source_language, $target_language, $word_count, $translator_id, $note, $uuid );
} catch ( Exception $err ) {
// The translation entry will be removed
$project->errors[] = $err;
$tp_job_id = 0;
}
$translation_id = $this->get_translation_id();
if ( $tp_job_id ) {
$tm_instance->update_translation_status(
array(
'translation_id' => $translation_id,
'translator_id' => $translator_id,
'status' => ICL_TM_IN_PROGRESS,
'needs_update' => 0,
)
);
} else {
$previous_state = $wpdb->get_var(
$wpdb->prepare(
" SELECT _prevstate
FROM {$wpdb->prefix}icl_translation_status
WHERE translation_id=%d
LIMIT 1",
$translation_id
)
);
if ( ! empty( $previous_state ) ) {
$previous_state = unserialize( $previous_state );
$data = array(
'status' => $previous_state['status'],
'translator_id' => $previous_state['translator_id'],
'needs_update' => $previous_state['needs_update'],
'md5' => $previous_state['md5'],
'translation_service' => $previous_state['translation_service'],
'translation_package' => $previous_state['translation_package'],
'timestamp' => $previous_state['timestamp'],
'links_fixed' => $previous_state['links_fixed'],
);
$data_where = array( 'translation_id' => $translation_id );
$wpdb->update( $wpdb->prefix . 'icl_translation_status', $data, $data_where );
} else {
$data = array(
'status' => ICL_TM_NOT_TRANSLATED,
'needs_update' => 0,
);
$data_where = array( 'translation_id' => $translation_id );
$wpdb->update( $wpdb->prefix . 'icl_translation_status', $data, $data_where );
}
$err = true;
}
return array( isset( $err ) ? $err : false, $project, $tp_job_id );
}
/**
* @param bool|false $original
*
* @return string
*/
abstract function get_url( $original = false );
/**
* @return WP_Post|WPML_Package|mixed
*/
abstract function get_original_document();
protected function load_status() {
$this->maybe_load_basic_data();
$this->basic_data->status = ! empty( $this->basic_data->translated ) ? ICL_TM_COMPLETE : $this->basic_data->status;
return TranslationManagement::get_job_status_string(
$this->basic_data->status,
$this->basic_data->needs_update
);
}
/**
* @param int $job_id
*
* @return bool|stdClass|WPML_Element_Translation_Job
*/
protected function load_job_data( $job_id ) {
if ( $this->job_factory ) {
return $this->job_factory->get_translation_job( $job_id, false, 1 );
}
return false;
}
protected function save_updated_assignment() {
global $wpdb;
$job_id = $this->get_id();
$service = $this->get_translation_service();
list( $prev_translator_id, $rid ) = $wpdb->get_row( $wpdb->prepare( "SELECT translator_id, rid FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $job_id ), ARRAY_N );
$translator_id = $this->get_translator_id();
$assigned_correctly = $translator_id == $prev_translator_id;
$assigned_correctly = apply_filters( 'wpml_job_assigned_to_after_assignment', $assigned_correctly, $job_id, $translator_id, $service );
if ( $assigned_correctly ) {
return true;
}
$data = array(
'translator_id' => $translator_id,
'status' => ICL_TM_WAITING_FOR_TRANSLATOR,
'translation_service' => $service,
);
$data_where = array( 'rid' => $rid );
$wpdb->update( $wpdb->prefix . 'icl_translation_status', $data, $data_where );
$wpdb->update( $wpdb->prefix . 'icl_translate_job', array( 'translator_id' => $translator_id ), array( 'job_id' => $job_id ) );
return true;
}
/**
* Retrieves the batch ID for job elements using the
* `icl_translation_status` and `icl_translate_job` tables
*/
protected function load_batch_id() {
global $wpdb;
$this->batch_id = $wpdb->get_var(
$wpdb->prepare(
"SELECT batch_id
FROM {$wpdb->prefix}icl_translation_status as ts
LEFT JOIN {$wpdb->prefix}icl_translate_job as tj ON tj.rid = ts.rid
WHERE tj.job_id = %d AND tj.revision IS NULL
LIMIT 1",
$this->job_id
)
);
}
private function get_iclt_field( $field_name, $translation ) {
global $wpdb;
$column_name = ( $translation === true ? 'i' : 'o' ) . '.' . $field_name;
$query = " SELECT {$column_name}
FROM {$wpdb->prefix}icl_translations o
JOIN {$wpdb->prefix}icl_translations i
ON i.trid = o.trid
AND i.source_language_code = o.language_code
JOIN {$wpdb->prefix}icl_translation_status s
ON s.translation_id = i.translation_id
JOIN {$wpdb->prefix}icl_translate_job j
ON j.rid = s.rid
WHERE j.job_id = %d
LIMIT 1";
$args = array( $this->get_id() );
$prepared_query = $wpdb->prepare( $query, $args );
return $wpdb->get_var( $prepared_query );
}
/**
* If the job does not have deadline date,
* we consider that the job was completed on time.
*
* @return bool
*/
public function is_completed_on_time() {
return $this->get_number_of_days_overdue() <= 0;
}
/**
* @return false|int Negative integer if the job was completed before the deadline, or positive either.
* False is the job has no deadline date
*/
public function get_number_of_days_overdue() {
$deadline = $this->get_deadline_date();
$completed = $this->get_completed_date();
if ( ! $deadline ) {
return false;
}
if ( ! $completed ) {
$completed = strtotime( 'now' );
} else {
$completed = strtotime( $completed );
}
$deadline = strtotime( $deadline );
return (int) floor( ( $completed - $deadline ) / DAY_IN_SECONDS );
}
/** @return string|null */
public function get_deadline_date() {
return $this->get_basic_data_property( 'deadline_date' );
}
/** @return string|null */
public function get_completed_date() {
return $this->get_basic_data_property( 'completed_date' );
}
/** @return string|null */
public function get_manager_id() {
return $this->get_basic_data_property( 'manager_id' );
}
/** @return string|null */
protected function get_title_from_db() {
return $this->get_basic_data_property( 'title' );
}
/** @return string|null */
protected function get_uuid() {
return $this->get_basic_data_property( 'uuid' );
}
}

View File

@@ -0,0 +1,88 @@
<?php
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
class WPML_External_Translation_Job extends WPML_Element_Translation_Job {
function get_original_document() {
return apply_filters(
'wpml_get_translatable_item',
null,
$this->get_original_element_id(),
isset( $this->basic_data->original_post_type ) ? $this->basic_data->original_post_type : null
);
}
/**
* @param bool|false $original
*
* @return string
*/
public function get_url( $original = false ) {
$url = null;
$element_id = null;
if ( $original ) {
$element_id = $this->get_original_element_id();
$url = apply_filters( 'wpml_external_item_url', '', $element_id );
}
return apply_filters( 'wpml_element_translation_job_url', $url, $original, $element_id, $this->get_original_document() );
}
/**
* @return string
*/
public function get_title() {
$title = $this->get_title_from_db();
if ( $title ) {
return $title;
}
$original_element = $this->get_original_document();
return $original_element
? apply_filters( 'wpml_tm_external_translation_job_title', $this->title_from_job_fields(), $original_element->ID )
: $this->original_del_text;
}
/**
* @return string
*/
public function get_type_title() {
$original_element = $this->get_original_document();
return $original_element->kind;
}
protected function load_resultant_element_id() {
return 0;
}
private function title_from_job_fields() {
global $wpdb;
$title_and_name = $wpdb->get_row(
$wpdb->prepare(
"
SELECT n.field_data AS name, t.field_data AS title
FROM {$wpdb->prefix}icl_translate AS n
JOIN {$wpdb->prefix}icl_translate AS t
ON n.job_id = t.job_id
WHERE n.job_id = %d
AND n.field_type = 'name'
AND t.field_type = 'title'
LIMIT 1
",
$this->get_id()
)
);
return $title_and_name !== null ? ( $title_and_name->name ?
base64_decode( $title_and_name->name )
: base64_decode( $title_and_name->title ) ) : '';
}
}

View File

@@ -0,0 +1,291 @@
<?php
use WPML\TM\Jobs\FieldId;
use WPML\TM\Jobs\TermMeta;
use WPML\FP\Lst;
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
class WPML_Post_Translation_Job extends WPML_Element_Translation_Job {
function get_original_document() {
return get_post( $this->get_original_element_id() );
}
/**
* @param bool|false $original
*
* @return string
*/
public function get_url( $original = false ) {
$url = null;
$element_id = null;
if ( $original ) {
$element_id = $this->get_original_element_id();
$url = get_permalink( $element_id );
} else {
$element_id = $this->get_resultant_element_id();
$url = get_edit_post_link( $element_id );
}
return apply_filters( 'wpml_element_translation_job_url', $url, $original, $element_id, $this->get_original_document() );
}
/**
* It checks that the post type is translatable.
*
* @return bool
*/
function is_translatable_post_type() {
$post_type = $this->get_post_type();
if ( $post_type ) {
/** @var SitePress $sitepress */
global $sitepress;
if ( $sitepress ) {
$post_types = array_keys( $sitepress->get_translatable_documents() );
return in_array( $post_type, $post_types, true );
}
}
return false;
}
function update_fields_from_post() {
global $iclTranslationManagement, $wpdb, $wpml_translation_job_factory;
$job_id = $this->get_id();
$post_id = $this->get_resultant_element_id();
$data['complete'] = 1;
$data['job_id'] = $job_id;
$job = $wpml_translation_job_factory->get_translation_job( $job_id, 1 );
$term_names = $this->get_term_field_array_for_post();
$post = get_post( $post_id );
if ( is_object( $job ) && is_array( $job->elements ) && is_object( $post ) ) {
foreach ( $job->elements as $element ) {
$field_data = '';
switch ( $element->field_type ) {
case 'title':
$field_data = $this->encode_field_data( $post->post_title);
break;
case 'body':
$field_data = $this->encode_field_data( $post->post_content);
break;
case 'excerpt':
$field_data = $this->encode_field_data( $post->post_excerpt);
break;
case 'URL':
$field_data = $this->encode_field_data( $post->post_name);
break;
default:
if ( isset( $term_names[ $element->field_type ] ) ) {
$field_data = $this->encode_field_data( $term_names[ $element->field_type ]);
}
}
if ( $field_data ) {
$wpdb->update( $wpdb->prefix . 'icl_translate',
array(
'field_data_translated' => $field_data,
'field_finished' => 1
),
array( 'tid' => $element->tid )
);
}
}
$iclTranslationManagement->mark_job_done( $job_id );
}
}
function save_terms_to_post() {
/** @var SitePress $sitepress */
global $sitepress, $wpdb;
$lang_code = $this->get_language_code();
if ( $sitepress->get_setting( 'tm_block_retranslating_terms' ) ) {
$this->load_terms_from_post_into_job( true );
}
$terms = $this->get_terms_in_job_rows();
foreach ( $terms as $term ) {
$new_term_action = new WPML_Update_Term_Action( $wpdb, $sitepress, [
'term' => base64_decode( $term->field_data_translated ),
'description' => TermMeta::getTermDescription( $this->get_id(), $term->term_taxonomy_id ),
'lang_code' => $lang_code,
'trid' => $term->trid,
'taxonomy' => $term->taxonomy
] );
$new_term = $new_term_action->execute();
foreach ( TermMeta::getTermMeta( $this->get_id(), $term->term_taxonomy_id ) as $meta ) {
update_term_meta( $new_term['term_taxonomy_id'], FieldId::getTermMetaKey( $meta->field_type ), $meta->field_data_translated );
}
}
$term_helper = wpml_get_term_translation_util();
$term_helper->sync_terms( $this->get_original_element_id(), $this->get_language_code() );
}
function load_terms_from_post_into_job( $delete = null ) {
global $sitepress;
$delete = isset( $delete ) ? $delete : $sitepress->get_setting( 'tm_block_retranslating_terms' );
$this->set_translated_term_values( $delete );
}
/**
* @return string
*/
public function get_title() {
$title = $this->get_title_from_db();
if ( $title ) {
return $title;
}
$original_post = $this->get_original_document();
return is_object( $original_post ) && isset( $original_post->post_title )
? $original_post->post_title : $this->original_del_text;
}
/**
* @return string
*/
public function get_type_title() {
$post_type = get_post_type_object( $this->get_post_type() );
return $post_type->labels->singular_name;
}
/**
* @return string
*/
public function get_post_type() {
$original_post = $this->get_original_document();
return $original_post->post_type;
}
protected function load_resultant_element_id() {
global $wpdb;
$this->maybe_load_basic_data();
return $wpdb->get_var( $wpdb->prepare( "SELECT element_id
FROM {$wpdb->prefix}icl_translations
WHERE translation_id = %d
LIMIT 1",
$this->basic_data->translation_id ) );
}
protected function get_terms_in_job_rows(){
global $wpdb;
$query_for_terms_in_job = $wpdb->prepare(" SELECT
tt.taxonomy,
tt.term_taxonomy_id,
iclt.trid,
j.field_data_translated
FROM {$wpdb->term_taxonomy} tt
JOIN {$wpdb->prefix}icl_translations iclt
ON iclt.element_id = tt.term_taxonomy_id
AND CONCAT('tax_', tt.taxonomy) = iclt.element_type
JOIN {$wpdb->prefix}icl_translate j
ON j.field_type = CONCAT('t_', tt.term_taxonomy_id)
WHERE j.job_id = %d ", $this->get_id());
return $wpdb->get_results( $query_for_terms_in_job );
}
/**
* Retrieves an array of all terms associated with a post. This array is indexed by indexes of the for {t_}{term_taxonomy_id}.
*
* @return array
*/
protected function get_term_field_array_for_post() {
global $wpdb;
$post_id = $this->get_resultant_element_id();
$query = $wpdb->prepare( "SELECT o.term_taxonomy_id, t.name
FROM {$wpdb->term_relationships} o
JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = o.term_taxonomy_id
JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
WHERE o.object_id = %d",
$post_id );
$res = $wpdb->get_results( $query );
$result = array();
foreach ( $res as $term ) {
$result[ 't_' . $term->term_taxonomy_id ] = $term->name;
}
return $result;
}
protected function set_translated_term_values( $delete ) {
global $wpdb;
$translations_table = $wpdb->prefix . 'icl_translations';
$translate_table = $wpdb->prefix . 'icl_translate';
$job_id = $this->get_id();
$get_target_terms_for_job_query = $wpdb->prepare( "
SELECT
t.name,
tt.description,
iclt_original.element_id ttid,
t.term_id tr_ttid
FROM {$wpdb->terms} t
JOIN {$wpdb->term_taxonomy} tt
ON t.term_id = tt.term_id
JOIN {$translations_table} iclt_translation
ON iclt_translation.element_id = tt.term_taxonomy_id
AND CONCAT('tax_', tt.taxonomy) = iclt_translation.element_type
JOIN {$translations_table} iclt_original
ON iclt_original.trid = iclt_translation.trid
JOIN {$translate_table} jobs
ON jobs.field_type = CONCAT('t_', iclt_original.element_id)
WHERE jobs.job_id = %d
AND iclt_translation.language_code = %s",
$job_id, $this->get_language_code() );
$term_values = $wpdb->get_results( $get_target_terms_for_job_query );
foreach ( $term_values as $term ) {
if ( $delete ) {
$conditions = [
"field_type LIKE 'tfield-%-{$term->ttid}'", // Term fields
"field_type LIKE 'tfield-%-{$term->ttid}\_%'", // Term fields as array
"field_type = 't_{$term->ttid}'",
"field_type = 'tdesc_{$term->ttid}'",
];
$wpdb->query(
"DELETE FROM {$translate_table} WHERE job_id = $job_id AND "
. "(" . Lst::join( ' OR ', $conditions ) . ")"
);
} else {
$wpdb->update(
$translate_table,
[ 'field_data_translated' => base64_encode( $term->name ), 'field_finished' => 1 ],
[ 'field_type' => 't_' . $term->ttid, 'job_id' => $job_id ]
);
$wpdb->update(
$translate_table,
[ 'field_data_translated' => base64_encode( $term->description ), 'field_finished' => 1 ],
[ 'field_type' => 'tdesc_' . $term->ttid, 'job_id' => $job_id ]
);
$meta_values = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->termmeta} WHERE term_id = {$term->tr_ttid}" );
foreach ( $meta_values as $meta ) {
$wpdb->update(
$translate_table,
[ 'field_finished' => 1, 'field_data_translated' => base64_encode( $meta->meta_value ) ],
[ 'job_id' => $job_id, 'field_type' => 'tfield-' . $meta->meta_key . '-' . $term->ttid ]
);
}
}
}
}
}

View File

@@ -0,0 +1,149 @@
<?php
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
class WPML_String_Translation_Job extends WPML_Translation_Job {
protected function load_job_data( $string_translation_id ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT st.id,
s.language AS source_language_code,
st.language AS language_code,
IF(cs.status IS NULL, st.status, cs.status) as status,
st.string_id,
s.name,
s.value,
tb.id AS batch_id,
st.translation_service,
st.translator_id,
u.display_name as translator_name,
COUNT( st.id ) as strings_count
FROM {$wpdb->prefix}icl_string_translations AS st
INNER JOIN {$wpdb->prefix}icl_strings AS s
ON st.string_id = s.id
INNER JOIN {$wpdb->prefix}icl_translation_batches AS tb
ON tb.id = st.batch_id
LEFT JOIN {$wpdb->users} u
ON st.translator_id = u.ID
LEFT JOIN {$wpdb->prefix}icl_string_status ss ON ss.string_translation_id = st.id
LEFT JOIN {$wpdb->prefix}icl_core_status cs ON cs.rid = ss.rid
WHERE st.id = %d
LIMIT 1",
$string_translation_id
);
return $wpdb->get_row( $query );
}
public function get_title() {
$this->maybe_load_basic_data();
return esc_html( $this->basic_data->value );
}
/**
* @return string
*/
public function get_id() {
return 'string|' . parent::get_id();
}
public function get_type() {
return 'String';
}
public function get_original_element_id() {
if ( ! $this->basic_data ) {
$this->maybe_load_basic_data();
}
return $this->basic_data->string_id;
}
public function cancel() {
global $WPML_String_Translation, $wpdb;
/** @var WPML_String_Translation $WPML_String_Translation */
if ( $WPML_String_Translation ) {
$rid = $wpdb->get_var(
$wpdb->prepare(
"SELECT rid
FROM {$wpdb->prefix}icl_string_status
WHERE string_translation_id = %d
LIMIT 1",
$this->job_id
)
);
if ( $rid ) {
$WPML_String_Translation->cancel_remote_translation( $rid );
}
}
}
protected function load_status() {
$this->maybe_load_basic_data();
$this->status = WPML_Remote_String_Translation::get_string_status_label( $this->basic_data->status );
return $this->status;
}
public function to_array() {
$this->maybe_load_basic_data();
$this->basic_data->value = $this->get_title();
$data_array = $this->basic_data_to_array( $this->basic_data );
$data_array['job_id'] = 'string|' . $this->job_id;
$data_array['translation_id'] = $this->basic_data->id;
$data_array['status'] = $this->get_status();
$data_array['id'] = $this->get_id();
return $data_array;
}
protected function load_resultant_element_id() {
global $wpdb;
return $wpdb->get_var(
$wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}icl_string_translations
WHERE string_id = %d AND language = %s",
$this->get_original_element_id(),
$this->get_language_code()
)
);
}
protected function save_updated_assignment() {
global $wpdb;
return $wpdb->update(
$wpdb->prefix . 'icl_string_translations',
array(
'translator_id' => $this->get_translator_id(),
'translation_service' => $this->get_translation_service(),
),
array(
'string_id' => $this->get_original_element_id(),
'language' => $this->get_language_code(),
)
);
}
/**
* Retrieves the batch ID for a string job
*/
protected function load_batch_id() {
global $wpdb;
$this->batch_id = $wpdb->get_var(
$wpdb->prepare(
"SELECT batch_id
FROM {$wpdb->prefix}icl_string_translations
WHERE id = %d
LIMIT 1",
$this->job_id
)
);
}
}

View File

@@ -0,0 +1,411 @@
<?php
abstract class WPML_Translation_Job extends WPML_Translation_Job_Helper {
protected $basic_data;
protected $element_id = - 1;
protected $status = - 1;
protected $job_id;
protected $batch_id;
/** @var WPML_TM_Blog_Translators $blog_translators */
protected $blog_translators;
/**
* @param int $job_id
* @param int|null $batch_id
* @param WPML_TM_Blog_Translators $blog_translators
*/
function __construct( $job_id, $batch_id = null, &$blog_translators = null ) {
$this->job_id = $job_id;
$batch_id = $batch_id ? $batch_id : $this->get_batch_id();
$this->batch_id = $batch_id ? $batch_id : TranslationProxy_Batch::update_translation_batch();
$this->blog_translators = $blog_translators ? $blog_translators : wpml_tm_load_blog_translators();
}
abstract public function cancel();
abstract public function get_original_element_id();
abstract public function to_array();
/**
* @return string
*/
abstract function get_title();
public function get_status() {
if ( $this->status == - 1 ) {
$this->status = $this->load_status();
}
return $this->status;
}
public function get_status_value() {
$this->maybe_load_basic_data();
return $this->basic_data->status;
}
public function get_id() {
return $this->job_id;
}
public function get_resultant_element_id( $force = false ) {
if ( $this->element_id == - 1 || $force === true ) {
$this->element_id = $this->load_resultant_element_id();
}
return $this->element_id;
}
/**
* Checks whether the input user is allowed to edit this job
*
* @param WP_User $user
*
* @return bool
*/
public function user_can_translate( $user ) {
$translator_id = $this->get_translator_id();
$user_can_take_this_job = 0 === $translator_id
|| $this->is_current_user_allowed_to_translate(
$user,
$translator_id
);
$translator_has_job_language_pairs = $this->blog_translators->is_translator(
$user->ID,
array(
'lang_from' => $this->get_source_language_code(),
'lang_to' => $this->get_language_code(),
)
);
$user_can_translate = ( $user_can_take_this_job && $translator_has_job_language_pairs )
|| user_can( $user, 'manage_options' );
return apply_filters( 'wpml_user_can_translate', $user_can_translate, $user );
}
/**
* @param WP_User $user
* @param int $translator_id
*
* @return bool
*/
private function is_current_user_allowed_to_translate( WP_User $user, $translator_id ) {
$allowed_translators = apply_filters( 'wpml_tm_allowed_translators_for_job', array(), $this );
$allowed_translators[] = $translator_id;
return in_array( (int) $user->ID, $allowed_translators, true );
}
public function get_batch_id() {
if ( ! isset( $this->batch_id ) ) {
$this->load_batch_id();
}
return $this->batch_id;
}
/**
* @param bool|false $as_name if true will return the language's display name if applicable
*
* @return bool|string
*/
public function get_language_code( $as_name = false ) {
$this->maybe_load_basic_data();
$code = isset( $this->basic_data->language_code ) ? $this->basic_data->language_code : false;
return $code && $as_name ? $this->lang_code_to_name( $code ) : $code;
}
/**
* @param bool|false $as_name if true will return the language's display name if applicable
*
* @return bool|string
*/
function get_source_language_code( $as_name = false ) {
$this->maybe_load_basic_data();
$code = isset( $this->basic_data->source_language_code ) ? $this->basic_data->source_language_code : false;
return $code && $as_name ? $this->lang_code_to_name( $code ) : $code;
}
/**
* @return string|false
*/
public function get_translator_name() {
$this->maybe_load_basic_data();
if ( $this->basic_data->translation_service == TranslationProxy::get_current_service_id() ) {
$this->basic_data->translator_name = TranslationProxy_Translator::get_translator_name( $this->basic_data->translator_id );
} else {
$this->basic_data->translator_name = false;
}
return $this->basic_data->translator_name;
}
/**
* Returns the id of the assigned translator or 0 if no translator is assigned to the job
*
* @return int
*/
public function get_translator_id() {
$this->maybe_load_basic_data();
$this->basic_data->translator_id = ! empty( $this->basic_data->translator_id )
? $this->basic_data->translator_id : 0;
return (int) $this->basic_data->translator_id;
}
public function get_basic_data() {
$this->maybe_load_basic_data();
return $this->basic_data;
}
/**
* @param int $translator_id
* @param string $service
*
* @return bool true on success false on failure
*/
public function assign_to( $translator_id, $service = 'local' ) {
$this->maybe_load_basic_data();
$prev_translator_id = $this->get_translator_id();
$prev_service = $this->get_translation_service();
if ( $translator_id == $prev_translator_id && $service = $this->get_translation_service() ) {
return true;
}
$this->basic_data->translator_id = $translator_id;
$this->basic_data->translation_service = $service;
if ( $this->save_updated_assignment() === false ) {
$this->basic_data->translator_id = $prev_translator_id;
$this->basic_data->translation_service = $prev_service;
return false;
}
$job_id = $this->get_id();
if ( $this->get_tm_setting( array( 'notification', 'resigned' ) ) == ICL_TM_NOTIFICATION_IMMEDIATELY
&& ! empty( $prev_translator_id )
&& $prev_translator_id != $translator_id
&& $job_id ) {
do_action( 'wpml_tm_remove_job_notification', $prev_translator_id, $this );
}
if ( $this->get_tm_setting( array( 'notification', 'new-job' ) ) == ICL_TM_NOTIFICATION_IMMEDIATELY ) {
if ( empty( $translator_id ) ) {
do_action( 'wpml_tm_new_job_notification', $this );
} else {
do_action( 'wpml_tm_assign_job_notification', $this, $translator_id );
}
}
return true;
}
/**
* Returns either the translation service id for the job or 'local' for local jobs
*
* @return int|string
*/
public function get_translation_service() {
$this->maybe_load_basic_data();
$this->basic_data->translation_service = ! empty( $this->basic_data->translation_service )
? $this->basic_data->translation_service : 'local';
return $this->basic_data->translation_service;
}
abstract protected function save_updated_assignment();
abstract protected function load_resultant_element_id();
abstract protected function load_status();
abstract protected function load_job_data( $id );
abstract function get_type();
protected function basic_data_to_array( $job_data ) {
$this->maybe_load_basic_data();
$data_array = (array) $job_data;
if ( isset( $data_array['post_title'] ) ) {
$data_array['post_title'] = esc_html( $data_array['post_title'] );
}
$data_array['translator_name'] = $this->get_translator_name();
$data_array['batch_id'] = $job_data->batch_id;
$data_array['source_language_code'] = $this->basic_data->source_language_code;
$data_array['language_code'] = $this->basic_data->language_code;
$data_array['translator_html'] = $this->get_translator_html( $this->basic_data );
$data_array['type'] = $this->get_type();
$data_array['lang_text'] = $this->generate_lang_text();
return $data_array;
}
protected function maybe_load_basic_data() {
if ( ! $this->basic_data ) {
$this->basic_data = $this->load_job_data( $this->job_id );
$this->basic_data = $this->basic_data ? $this->basic_data : new stdClass();
}
}
private function get_inactive_translation_service( $translation_service_id ) {
$cache_key = $translation_service_id;
$cache_group = 'get_inactive_translation_service';
$cache_found = false;
$service = wp_cache_get( $cache_key, $cache_group, false, $cache_found );
if ( ! $cache_found ) {
try {
$service = TranslationProxy_Service::get_service( $translation_service_id );
} catch ( WPMLTranslationProxyApiException $ex ) {
$service = false;
}
if ( ! $service ) {
$service = new stdClass();
$service->name = __( '(inactive and unknown service)', 'wpml-translation-management' );
}
wp_cache_set( $cache_key, $service, $cache_group );
}
return $service;
}
protected function get_translator_html( $job ) {
$job = (object) $job;
$current_service_name = TranslationProxy::get_current_service_name();
$translation_services = array( 'local', TranslationProxy::get_current_service_id() );
if ( isset( $job->translation_service ) && ! in_array( $job->translation_service, $translation_services ) ) {
$inactive_service = $this->get_inactive_translation_service( $job->translation_service );
$current_service_name = $inactive_service->name;
}
$translator = '';
if ( $job->translation_service && $job->translation_service !== 'local' ) {
try {
$project = TranslationProxy::get_current_project();
if ( $project ) {
$translator .= $current_service_name;
} else {
$translator .= esc_html( $job->translator_name );
}
} catch ( Exception $e ) {
// Just doesn't create the output
}
} elseif ( $job->status == ICL_TM_COMPLETE ) {
$translator_data = get_userdata( $job->translator_id );
$translator_name = $translator_data ? $translator_data->display_name : '';
$translator = '<span class="icl-finished-local-name">' . $translator_name . '</span>';
} else {
$translator .= '<span class="icl_tj_select_translator">';
$selected_translator = isset( $job->translator_id ) ? $job->translator_id : false;
$disabled = false;
if ( $job->translation_service
&& $job->translation_service !== 'local'
&& is_numeric( $job->translation_service ) ) {
$selected_translator = TranslationProxy_Service::get_wpml_translator_id(
$job->translation_service,
$job->translator_id
);
$disabled = true;
}
$job_id = isset( $job->job_id ) ? $job->job_id : $job->id;
$local_only = isset( $job->local_only ) ? $job->local_only : true;
$args = array(
'id' => 'icl_tj_translator_for_' . $job_id,
'name' => 'icl_tj_translator_for_' . ( $job_id ),
'from' => $job->source_language_code,
'to' => $job->language_code,
'selected' => $selected_translator,
'services' => $translation_services,
'disabled' => $disabled,
'echo' => false,
'local_only' => $local_only,
);
$translator .= wpml_tm_get_translators_dropdown()->render( $args );
$translator .= '<input type="hidden" id="icl_tj_ov_'
. $job_id
. '" value="'
. (int) $job->translator_id
. '" />';
$translator .= '<input type="hidden" id="icl_tj_ty_'
. $job_id
. '" value="'
. strtolower( $this->get_type() )
. '" />';
$translator .= '<span class="icl_tj_select_translator_controls" id="icl_tj_tc_' . ( $job_id ) . '">';
$translator .= '<input type="button" class="button-secondary icl_tj_ok" value="'
. __(
'Send',
'wpml-translation-management'
)
. '" />&nbsp;';
$translator .= '<input type="button" class="button-secondary icl_tj_cancel" value="'
. __(
'Cancel',
'wpml-translation-management'
)
. '" />';
$translator .= '</span>';
}
return $translator;
}
/**
* Retrieves the batch ID associated to the job ID
*/
abstract protected function load_batch_id();
/**
* @return string
*/
protected function generate_lang_text() {
$this->maybe_load_basic_data();
return $this->lang_code_to_name( $this->get_source_language_code() )
. html_entity_decode( ' &raquo; ' )
. $this->lang_code_to_name( $this->get_language_code() );
}
/**
* @param string $code
*
* @return string
*/
private function lang_code_to_name( $code ) {
global $sitepress;
$lang_details = $sitepress->get_language_details( $code );
return isset( $lang_details['display_name'] ) ? $lang_details['display_name'] : $code;
}
/**
* @param string $name
*
* @return mixed
*/
protected function get_basic_data_property( $name ) {
$value = null;
$this->maybe_load_basic_data();
if ( isset( $this->basic_data->{$name} ) ) {
$value = $this->basic_data->{$name};
}
return $value;
}
}