sitepress */ private $sitepress; private $export_archive_name; private $late_init_priority = 9999; /** * WPML_TM_Xliff_Frontend constructor. * * @param WPML_Translation_Job_Factory $job_factory * @param SitePress $sitepress */ public function __construct( &$job_factory, &$sitepress ) { parent::__construct( $job_factory ); $this->sitepress = &$sitepress; } /** * @return array */ function get_available_xliff_versions() { return array( "10" => "1.0", "11" => "1.1", "12" => "1.2" ); } /** * @return int */ public function get_init_priority() { return isset( $_POST['xliff_upload'] ) || ( isset( $_GET['wpml_xliff_action'] ) && $_GET['wpml_xliff_action'] === 'download' ) || isset( $_POST['wpml_xliff_export_all_filtered'] ) ? $this->get_late_init_priority() : 10; } /** * @return int */ public function get_late_init_priority() { return $this->late_init_priority; } /** * @return bool */ function init() { $this->attachments = array(); $this->error = null; if ( $this->sitepress->get_wp_api()->is_admin() ) { add_action( 'admin_head', array( $this, 'js_scripts' ) ); add_action( 'wp_ajax_set_xliff_options', array( $this, 'ajax_set_xliff_options' ), 10, 2 ); if ( ! $this->sitepress->get_setting( 'xliff_newlines' ) ) { $this->sitepress->set_setting( 'xliff_newlines', WPML_XLIFF_TM_NEWLINES_REPLACE, true ); } if ( ! $this->sitepress->get_setting( 'tm_xliff_version' ) ) { $this->sitepress->set_setting( 'tm_xliff_version', '12', true ); } if ( 1 < count( $this->sitepress->get_languages( false, true ) ) ) { add_filter( 'wpml_translation_queue_actions', array( $this, 'translation_queue_add_actions' ) ); add_action( 'wpml_xliff_select_actions', array( $this, 'translation_queue_xliff_select_actions' ), 10, 2 ); add_action( 'wpml_translation_queue_do_actions_export_xliff', array( $this, 'translation_queue_do_actions_export_xliff' ), 10, 2 ); add_action( 'wpml_translation_queue_after_display', array( $this, 'translation_queue_after_display' ), 10, 2 ); add_action( 'wpml_translator_notification', array( $this, 'translator_notification' ), 10, 0 ); add_filter( 'wpml_new_job_notification', array( $this, 'new_job_notification' ), 10, 2 ); add_filter( 'wpml_new_job_notification_attachments', array( $this, 'new_job_notification_attachments' ) ); } if ( isset( $_GET['wpml_xliff_action'] ) && $_GET['wpml_xliff_action'] === 'download' && wp_verify_nonce( $_GET['nonce'], 'xliff-export' ) ) { $archive = $this->get_xliff_archive( $_GET["xliff_version"] ); $this->stream_xliff_archive( $archive ); } if ( isset( $_POST['wpml_xliff_export_all_filtered'] ) && wp_verify_nonce( $_POST['nonce'], 'xliff-export-all-filtered' ) ) { $job_ids = $this->get_all_filtered_job_ids(); $archive = $this->get_xliff_archive( $_POST["xliff_version"], $job_ids ); $this->stream_xliff_archive( $archive ); } if ( isset( $_POST['xliff_upload'] ) ) { $this->import_xliff( $_FILES['import'] ); if ( is_wp_error( $this->error ) ) { add_action( 'admin_notices', array( $this, '_error' ) ); } } } return true; } function ajax_set_xliff_options() { check_ajax_referer( 'icl_xliff_options_form_nonce', 'security' ); $newlines = (int) $_POST['icl_xliff_newlines']; $this->sitepress->set_setting( "xliff_newlines", $newlines, true ); $version = (int) $_POST['icl_xliff_version']; $this->sitepress->set_setting( "tm_xliff_version", $version, true ); wp_send_json_success( array( 'message' => 'OK', 'newlines_saved' => $newlines, 'version_saved' => $version ) ); } /** * @param array $mail * @param int $job_id * * @return array */ function new_job_notification( $mail, $job_id ) { $tm_settings = $this->sitepress->get_setting( 'translation-management', array() ); if ( isset( $tm_settings['notification']['include_xliff'] ) && $tm_settings['notification']['include_xliff'] ) { $xliff_version = $this->get_user_xliff_version(); $xliff_file = $this->get_xliff_file( $job_id, $xliff_version ); $temp_dir = get_temp_dir(); $file_name = $temp_dir . get_bloginfo( 'name' ) . '-translation-job-' . $job_id . '.xliff'; $fh = fopen( $file_name, 'w' ); if ( $fh ) { fwrite( $fh, $xliff_file ); fclose( $fh ); $mail['attachment'] = $file_name; $this->attachments[ $job_id ] = $file_name; $mail['body'] .= __( ' - A xliff file is attached.', 'wpml-translation-management' ); } } return $mail; } /** * @param $job_ids * * @return string */ private function _get_zip_name_from_jobs( $job_ids ) { $min_job = min( $job_ids ); $max_job = max( $job_ids ); if ( $max_job == $min_job ) { return get_bloginfo( 'name' ) . '-translation-job-' . $max_job . '.zip'; } else { return get_bloginfo( 'name' ) . '-translation-job-' . $min_job . '-' . $max_job . '.zip'; } } /** * @param $attachments * * @return array */ function new_job_notification_attachments( $attachments ) { $found = false; $archive = new wpml_zip(); foreach ( $attachments as $index => $attachment ) { if ( in_array( $attachment, $this->attachments ) ) { $fh = fopen( $attachment, 'r' ); $xliff_file = fread( $fh, filesize( $attachment ) ); fclose( $fh ); $archive->addFile( $xliff_file, basename( $attachment ) ); unset( $attachments[ $index ] ); $found = true; } } if ( $found ) { // add the zip file to the attachments. $archive_data = $archive->getZipData(); $temp_dir = get_temp_dir(); $file_name = $temp_dir . $this->_get_zip_name_from_jobs( array_keys( $this->attachments ) ); $fh = fopen( $file_name, 'w' ); fwrite( $fh, $archive_data ); fclose( $fh ); $attachments[] = $file_name; } return $attachments; } /** * @param int $job_id * @param string $xliff_version * * @return string */ private function get_xliff_file( $job_id, $xliff_version = WPML_XLIFF_DEFAULT_VERSION ) { $xliff = new WPML_TM_Xliff_Writer( $this->job_factory, $xliff_version ); return $xliff->generate_job_xliff( $job_id ); } /** * @param string $xliff_version * @param array|null $job_ids * * @return wpml_zip * * @throws Exception */ function get_xliff_archive( $xliff_version, $job_ids = array() ) { global $wpdb, $current_user; if ( empty( $job_ids ) && isset( $_GET['xliff_export_data'] ) ) { $data = json_decode( base64_decode( $_GET['xliff_export_data'] ) ); $job_ids = isset( $data->job ) ? array_keys( (array) $data->job ) : array(); } $archive = new wpml_zip(); foreach ( $job_ids as $job_id ) { $xliff_file = $this->get_xliff_file( $job_id, $xliff_version ); // assign the job to this translator $rid = $wpdb->get_var( $wpdb->prepare( "SELECT rid FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d ", $job_id ) ); $data_value = array( 'translator_id' => $current_user->ID ); $data_where = array( 'job_id' => $job_id ); $wpdb->update( $wpdb->prefix . 'icl_translate_job', $data_value, $data_where ); $data_where = array( 'rid' => $rid ); $wpdb->update( $wpdb->prefix . 'icl_translation_status', $data_value, $data_where ); $archive->addFile( $xliff_file, get_bloginfo( 'name' ) . '-translation-job-' . $job_id . '.xliff' ); } $this->export_archive_name = $this->_get_zip_name_from_jobs( $job_ids ); $archive->finalize(); return $archive; } /** * @param wpml_zip $archive */ private function stream_xliff_archive( $archive ) { if ( is_a( $archive, 'wpml_zip' ) ) { $archive->sendZip( $this->export_archive_name ); } exit; } /** * @return array */ public function get_all_filtered_job_ids() { /** * @var TranslationManagement $iclTranslationManagement * @var WPML_Translation_Job_Factory $wpml_translation_job_factory */ global $iclTranslationManagement, $wpml_translation_job_factory; $job_ids = array(); $current_translator = $iclTranslationManagement->get_current_translator(); $can_translate = $current_translator && $current_translator->ID > 0 && $current_translator->language_pairs; if( $can_translate ) { if ( isset( $_SESSION['translation_ujobs_filter'] ) ) { $icl_translation_filter = $_SESSION['translation_ujobs_filter']; } $icl_translation_filter['translator_id'] = $current_translator->ID; $icl_translation_filter['include_unassigned'] = true; $translation_jobs = $wpml_translation_job_factory->get_translation_jobs( (array) $icl_translation_filter, true ); $job_ids = wp_list_pluck( $translation_jobs, 'job_id' ); } return $job_ids; } /** * Stops any redirects from happening when we call the * translation manager to save the translations. * * @param $location * * @return null */ function _stop_redirect( $location ) { return null; } /** * @param array $file * * @return bool|WP_Error */ private function import_xliff( $file ) { global $current_user; // We don't want any redirects happening when we save the translation add_filter( 'wp_redirect', array( $this, '_stop_redirect' ) ); $this->success = array(); $contents = array(); if ( 0 === (int) $file['size'] ) { $this->error = new WP_Error( 'empty_file', __( 'You are trying to import an empty file.', 'wpml-translation-management' ) ); return false; } elseif ( isset( $file['tmp_name'] ) && $file['tmp_name'] ) { $fh = fopen( $file['tmp_name'], 'r' ); $data = fread( $fh, 4 ); fclose( $fh ); if ( $data[0] == 'P' && $data[1] == 'K' && $data[2] == chr( 03 ) && $data[3] == chr( 04 ) ) { if ( class_exists( 'ZipArchive' ) ) { $z = new ZipArchive(); $zopen = $z->open( $file['tmp_name'], 4 ); if ( true !== $zopen ) { $this->error = new WP_Error( 'incompatible_archive', __( 'Incompatible Archive.', 'wpml-translation-management' ) ); return false; } $empty_files = array(); for ( $i = 0; $i < $z->numFiles; $i ++ ) { if ( ! $info = $z->statIndex( $i ) ) { $this->error = new WP_Error( 'stat_failed', __( 'Could not retrieve file from archive.', 'wpml-translation-management' ) ); return false; } $content = $z->getFromIndex( $i ); if ( false === (bool) $content ) { $empty_files[] = $info['name']; } $contents[ $info['name'] ] = $content; } if ( $empty_files ) { $this->error = new WP_Error( 'extract_failed', __( 'The archive contains one or more empty files.', 'wpml-translation-management' ), $empty_files ); return false; } } else { require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' ); $archive = new PclZip( $file['tmp_name'] ); // Is the archive valid? if ( false == ( $archive_files = $archive->extract( PCLZIP_OPT_EXTRACT_AS_STRING ) ) ) { $this->error = new WP_Error( 'incompatible_archive', __( 'You are trying to import an incompatible Archive.', 'wpml-translation-management' ), $archive->errorInfo( true ) ); return false; } if ( 0 == count( $archive_files ) ) { $this->error = new WP_Error( 'empty_archive', __( 'You are trying to import an empty archive.', 'wpml-translation-management' ) ); return false; } $empty_files = array(); foreach ( $archive_files as $content ) { if ( false === (bool) $content['content'] ) { $empty_files[] = $content['filename']; } $contents[ $content['filename'] ] = $content['content']; } if ( $empty_files ) { $this->error = new WP_Error( 'extract_failed', __( 'The archive contains one or more empty files.', 'wpml-translation-management' ), $empty_files ); return false; } } } else { $fh = fopen( $file['tmp_name'], 'r' ); $data = fread( $fh, $file['size'] ); fclose( $fh ); $contents[ $file['name'] ] = $data; } foreach ( $contents as $name => $content ) { if( $this->validate_file_name( $name ) ) { list( $job, $job_data ) = $this->validate_file( $name, $content, $current_user ); if ( null !== $this->error ) { return $job_data; } kses_remove_filters(); wpml_tm_save_data( $job_data ); kses_init(); $this->success[] = sprintf( __( 'Translation of job %s has been uploaded and completed.', 'wpml-translation-management' ), $job->job_id ); } } if ( count( $this->success ) ) { add_action( 'admin_notices', array( $this, '_success' ) ); return true; } } return false; } /** * @param $actions * @param $action_name */ function translation_queue_xliff_select_actions( $actions, $action_name ) { if ( sizeof( $actions ) > 0 ): $user_version = $this->get_user_xliff_version(); ?>