first commit
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Ajax\ST\AdminText;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use WPML\FP\Either;
|
||||
use WPML\FP\Fns;
|
||||
use function WPML\FP\partial;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
class Register implements IHandler {
|
||||
|
||||
/** @var \WPML_Admin_Texts */
|
||||
private $adminTexts;
|
||||
|
||||
public function __construct( \WPML_Admin_Texts $adminTexts ) {
|
||||
$this->adminTexts = $adminTexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers or Unregisters an option for translation depending
|
||||
* on the `state` data.
|
||||
*
|
||||
* @param Collection $data
|
||||
*
|
||||
* @return Either
|
||||
*/
|
||||
public function run( Collection $data ) {
|
||||
$state = $data->get( 'state' ) ? 'on' : '';
|
||||
$applyState = partial( [ self::class, 'flatToHierarchical' ], $state );
|
||||
|
||||
$register = pipe(
|
||||
'wpml_collect',
|
||||
Fns::map( $applyState ),
|
||||
Fns::reduce( 'array_replace_recursive', [] ),
|
||||
[ $this->adminTexts, 'icl_register_admin_options' ]
|
||||
);
|
||||
|
||||
$register( $data->get( 'selected', [] ) );
|
||||
|
||||
return Either::right( true );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* string $state -> string [key1][key2][name] -> array [ key1 => [ key2 => [ name => $state ] ] ]
|
||||
*
|
||||
* @param string $state
|
||||
* @param string $option
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function flatToHierarchical( $state, $option ) {
|
||||
|
||||
// string $value -> mixed $key -> array [ $key => $value ]
|
||||
$makeArrayWithStringKey = function ( $value, $key ) {
|
||||
return [ (string) $key => $value ];
|
||||
};
|
||||
|
||||
return \WPML_Admin_Texts::getKeysParts( $option )
|
||||
->reverse()
|
||||
->reduce( $makeArrayWithStringKey, $state );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\AdminTexts;
|
||||
|
||||
use WPML\Ajax\ST\AdminText\Register;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Fns;
|
||||
use WPML\ST\WP\App\Resources;
|
||||
use function WPML\Container\make;
|
||||
use WPML\LIB\WP\Hooks as WPHooks;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
class UI implements \IWPML_Backend_Action_Loader {
|
||||
|
||||
// shouldShow :: Collection -> bool
|
||||
public static function shouldShow( Collection $data ) {
|
||||
return $data->get( 'page' ) === WPML_ST_FOLDER . '/menu/string-translation.php' &&
|
||||
(int) $data->get( 'trop' ) === 1;
|
||||
}
|
||||
|
||||
|
||||
public static function localize( Collection $model ) {
|
||||
$esc_value = Obj::over( Obj::lensProp( 'value' ), 'esc_js' );
|
||||
|
||||
return [
|
||||
'name' => 'wpml_admin_strings',
|
||||
'data' => [
|
||||
'model' => $model->map( $esc_value )->toArray(),
|
||||
'endpoint' => Register::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable|null
|
||||
*/
|
||||
public function create() {
|
||||
if ( self::shouldShow( wpml_collect( $_GET ) ) ) {
|
||||
|
||||
return function() {
|
||||
WPHooks::onAction( 'admin_enqueue_scripts' )
|
||||
->then( [ make( \WPML_Admin_Texts::class ), 'getModelForRender' ] )
|
||||
->then( [ self::class, 'localize' ] )
|
||||
->then( Resources::enqueueApp( 'admin-strings' ) );
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
require_once dirname( __FILE__ ) . '/wpml-admin-text-functionality.class.php';
|
||||
|
||||
class WPML_Admin_Text_Configuration extends WPML_Admin_Text_Functionality {
|
||||
|
||||
/** @var array $config */
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param string|stdClass $file_or_object
|
||||
*/
|
||||
function __construct( $file_or_object = '' ) {
|
||||
if ( is_object( $file_or_object ) ) {
|
||||
$config = $file_or_object->config;
|
||||
$type = $file_or_object->type;
|
||||
$admin_text_context = $file_or_object->admin_text_context;
|
||||
} elseif ( $this->can_handle_custom_xml( $file_or_object ) ) {
|
||||
$validate = new WPML_XML_Config_Validate( WPML_PLUGIN_PATH . '/res/xsd/wpml-config.xsd' );
|
||||
$transform = new WPML_XML2Array();
|
||||
$xml_config_file = new WPML_XML_Config_Read_File( $file_or_object, $validate, $transform );
|
||||
$config = $xml_config_file->get();
|
||||
$type = ( dirname( $file_or_object ) === get_template_directory() || dirname( $file_or_object ) === get_stylesheet_directory() ) ? 'theme' : 'plugin';
|
||||
$admin_text_context = basename( dirname( $file_or_object ) );
|
||||
}
|
||||
|
||||
$admin_text_config = isset( $config['wpml-config']['admin-texts'] ) ? $config['wpml-config']['admin-texts'] : array();
|
||||
$wpml_config_all = array();
|
||||
if ( isset( $type, $admin_text_context, $admin_text_config['key'] ) ) {
|
||||
if ( isset( $admin_text_config['key']['attr'] ) ) { // single
|
||||
$admin_text_config['key']['type'] = $type;
|
||||
$admin_text_config['key']['context'] = $admin_text_context;
|
||||
$wpml_config_all[] = $admin_text_config['key'];
|
||||
} else {
|
||||
foreach ( (array) $admin_text_config['key'] as $cf ) {
|
||||
$cf['type'] = $type;
|
||||
$cf['context'] = $admin_text_context;
|
||||
$wpml_config_all[] = $cf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->config = $this->fill_wildcards( $wpml_config_all );
|
||||
}
|
||||
|
||||
function get_config_array() {
|
||||
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
private function fill_wildcards( array $config_array ) {
|
||||
|
||||
return ( ! isset( $config_array['attr']['name'] ) || $config_array['attr']['name'] !== '*' )
|
||||
&& ( ! isset( $config_array[0]['attr']['name'] ) || $config_array[0]['attr']['name'] !== '*' )
|
||||
? $this->remove_unmatched(
|
||||
$config_array,
|
||||
$this->all_strings_array( $this->get_top_level_filters( $config_array ) )
|
||||
)
|
||||
: array();
|
||||
}
|
||||
|
||||
private function get_top_level_filters( array $config_array ) {
|
||||
$ret = array();
|
||||
$config_array = isset( $config_array['attr']['name'] ) ? array( $config_array ) : $config_array;
|
||||
foreach ( $config_array as $option ) {
|
||||
if ( isset( $option['attr']['name'] ) ) {
|
||||
$ret[] = $option['attr']['name'];
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function remove_unmatched( array $input, array $all_possibilities ) {
|
||||
$ret = array();
|
||||
$input = isset( $input['attr'] ) ? array( $input ) : $input;
|
||||
foreach ( $input as $val ) {
|
||||
$name_matcher = $this->wildcard_to_matcher( $val['attr']['name'] );
|
||||
foreach ( $all_possibilities as $a_val ) {
|
||||
if ( preg_match( $name_matcher, $a_val['attr']['name'] ) === 1 ) {
|
||||
$match = $val;
|
||||
$match['attr']['name'] = $a_val['attr']['name'];
|
||||
$has_sub_filter = ! empty( $val['key'] );
|
||||
$match['key'] = $has_sub_filter
|
||||
? $this->remove_unmatched( $val['key'], $a_val['key'] )
|
||||
: $a_val['key'];
|
||||
if ( $has_sub_filter === false || ! empty( $match['key'] ) ) {
|
||||
$ret[] = $match;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a regex matcher from a wildcard string name definition
|
||||
*
|
||||
* @param string $wildcard
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function wildcard_to_matcher( $wildcard ) {
|
||||
|
||||
return '#^' . str_replace( '\*', '.+', preg_quote( $wildcard, '#' ) ) . '$#';
|
||||
}
|
||||
|
||||
private function all_strings_array( array $top_level_filters ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( (bool) $top_level_filters === false ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
foreach ( $top_level_filters as $key => $filter ) {
|
||||
$like = strpos( $filter, '*' ) !== false;
|
||||
$comparator = $like ? ' LIKE ' : '=';
|
||||
$top_level_filters[ $key ] = $wpdb->prepare(
|
||||
' option_name ' . $comparator . ' %s ',
|
||||
$like
|
||||
? str_replace( '*', '%', $wpdb->esc_like( $filter ) )
|
||||
: $filter
|
||||
);
|
||||
}
|
||||
|
||||
$where = ' AND ( ' . join( ' OR ', $top_level_filters ) . ' )';
|
||||
|
||||
$strings = $wpdb->get_results(
|
||||
"SELECT option_name, option_value
|
||||
FROM {$wpdb->options}
|
||||
WHERE option_name NOT LIKE '_transient%'
|
||||
AND option_name NOT LIKE '_site_transient%' {$where}
|
||||
AND LENGTH(option_value) < 1000000"
|
||||
);
|
||||
$all_options = array();
|
||||
foreach ( $strings as $data_pair ) {
|
||||
if ( $this->is_blacklisted( $data_pair->option_name ) === false ) {
|
||||
$all_options[ $data_pair->option_name ] = maybe_unserialize( $data_pair->option_value );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->reformat_array( $all_options );
|
||||
}
|
||||
|
||||
private function reformat_array( $option_value ) {
|
||||
$ret = array();
|
||||
if ( is_array( $option_value ) ) {
|
||||
foreach ( $option_value as $key => $value ) {
|
||||
$ret[] = array(
|
||||
'attr' => array( 'name' => $key ),
|
||||
'key' => $this->reformat_array( $value ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file_path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function can_handle_custom_xml( $file_path ) {
|
||||
return is_string( $file_path ) && '' !== $file_path && file_exists( $file_path ) && class_exists( 'WPML_XML_Config_Validate' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
abstract class WPML_Admin_Text_Functionality {
|
||||
|
||||
final public function is_blacklisted( $option_name ) {
|
||||
global $wp_taxonomies;
|
||||
|
||||
$black_list = array_fill_keys(
|
||||
array(
|
||||
'active_plugins',
|
||||
'wp_user_roles',
|
||||
'_wpml_media',
|
||||
'users_can_register',
|
||||
'admin_email',
|
||||
'start_of_week',
|
||||
'use_balanceTags',
|
||||
'use_smilies',
|
||||
'require_name_email',
|
||||
'comments_notify',
|
||||
'posts_per_rss',
|
||||
'sticky_posts',
|
||||
'page_for_post',
|
||||
'_wcml_settings',
|
||||
'_wcml_version',
|
||||
'page_on_front',
|
||||
'default_post_format',
|
||||
'link_manager_enabled',
|
||||
'icl_sitepress_settings',
|
||||
'wpml_config_index',
|
||||
'wpml_config_index_updated',
|
||||
'wpml_config_files_arr',
|
||||
'icl_admin_messages',
|
||||
'wpml-package-translation-db-updates-run',
|
||||
'wpml_media',
|
||||
'wpml_ta_settings',
|
||||
'_icl_admin_option_names',
|
||||
'_icl_cache',
|
||||
'icl_sitepress_version',
|
||||
'rewrite_rules',
|
||||
'recently_activated',
|
||||
'wpml_tm_version',
|
||||
'wp_installer_settings',
|
||||
'icl_adl_settings',
|
||||
'rss_use_excerpt',
|
||||
'template',
|
||||
'stylesheet',
|
||||
'comment_whitelist',
|
||||
'comment_registration',
|
||||
'html_type',
|
||||
'use_trackback',
|
||||
'default_role',
|
||||
'db_version',
|
||||
'siteurl',
|
||||
'home',
|
||||
'blogname',
|
||||
'blogdescription',
|
||||
'mailserver_url',
|
||||
'mailserver_login',
|
||||
'mailserver_pass',
|
||||
'mailserver_port',
|
||||
'default_category',
|
||||
'default_comment_status',
|
||||
'default_ping_status',
|
||||
'default_pingback_flag',
|
||||
'comment_moderation',
|
||||
'moderation_notify',
|
||||
'permalink_structure',
|
||||
'gzipcompression',
|
||||
'hack_file',
|
||||
'blog_charset',
|
||||
'ping_sites',
|
||||
'advanced_edit',
|
||||
'comment_max_links',
|
||||
'gmt_offset',
|
||||
'default_email_category',
|
||||
'uploads_use_yearmonth_folders',
|
||||
'upload_path',
|
||||
'blog_public',
|
||||
'default_link_category',
|
||||
'tag_base',
|
||||
'show_avatars',
|
||||
'avatar_rating',
|
||||
'WPLANG',
|
||||
'wp_icl_translators_cached',
|
||||
'cron',
|
||||
'_transient_WPML_ST_MO_Downloader_lang_map',
|
||||
'icl_translation_jobs_basket',
|
||||
),
|
||||
1
|
||||
);
|
||||
|
||||
$tax_prefixes = array_keys( $wp_taxonomies );
|
||||
foreach ( $tax_prefixes as &$tax_name ) {
|
||||
$tax_name .= '_children';
|
||||
}
|
||||
$blacklist_prefixes = array_merge(
|
||||
$tax_prefixes,
|
||||
array( '_transient_', '_site_transient_' )
|
||||
);
|
||||
$matcher = '#^' . join( '|^', $blacklist_prefixes ) . '#';
|
||||
|
||||
return array_key_exists( $option_name, $black_list )
|
||||
|| preg_match( $matcher, $option_name ) === 1;
|
||||
}
|
||||
|
||||
protected function read_admin_texts_recursive( $keys, $admin_text_context, $type, &$arr_context, &$arr_type ) {
|
||||
$keys = ! empty( $keys ) && isset( $keys ['attr']['name'] ) ? array( $keys ) : $keys;
|
||||
foreach ( $keys as $key ) {
|
||||
$key_name = $key['attr']['name'];
|
||||
if ( ! empty( $key['key'] ) ) {
|
||||
$arr[ $key_name ] = $this->read_admin_texts_recursive(
|
||||
$key['key'],
|
||||
$admin_text_context,
|
||||
$type,
|
||||
$arr_context,
|
||||
$arr_type
|
||||
);
|
||||
} else {
|
||||
$arr[ $key_name ] = 1;
|
||||
$arr_context[ $key_name ] = $admin_text_context;
|
||||
$arr_type[ $key_name ] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
return isset( $arr ) ? $arr : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key Name of option to retrieve. Expected to not be SQL-escaped.
|
||||
* @param mixed $default Value to return in case the string does not exists
|
||||
*
|
||||
* @return mixed Value set for the option.
|
||||
*/
|
||||
public function get_option_without_filtering( $key, $default = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$value = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT option_value
|
||||
FROM {$wpdb->options}
|
||||
WHERE option_name = %s
|
||||
LIMIT 1",
|
||||
$key
|
||||
)
|
||||
);
|
||||
|
||||
return isset( $value ) ? $value : $default;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
require_once dirname( __FILE__ ) . '/wpml-admin-text-configuration.php';
|
||||
require_once dirname( __FILE__ ) . '/wpml-admin-text-functionality.class.php';
|
||||
|
||||
class WPML_Admin_Text_Import extends WPML_Admin_Text_Functionality {
|
||||
|
||||
/** @var WPML_ST_Records $st_records */
|
||||
private $st_records;
|
||||
|
||||
/** @var WPML_WP_API $wp_api */
|
||||
private $wp_api;
|
||||
|
||||
function __construct( WPML_ST_Records $st_records, WPML_WP_API $wp_api ) {
|
||||
$this->st_records = $st_records;
|
||||
$this->wp_api = $wp_api;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $admin_texts
|
||||
* @param string $config_handler_hash
|
||||
*/
|
||||
function parse_config( array $admin_texts, $config_handler_hash ) {
|
||||
|
||||
$admin_texts_hash = md5( serialize( $admin_texts ) );
|
||||
$transient_name = 'wpml_admin_text_import:parse_config:' . $config_handler_hash;
|
||||
|
||||
if ( $this->wp_api->is_string_translation_page() || get_transient( $transient_name ) !== $admin_texts_hash ) {
|
||||
global $iclTranslationManagement, $sitepress;
|
||||
foreach ( $admin_texts as $a ) {
|
||||
$type = isset( $a['type'] ) ? $a['type'] : 'plugin';
|
||||
$admin_text_context = isset( $a['context'] ) ? $a['context'] : '';
|
||||
$admin_string_name = $a['attr']['name'];
|
||||
if ( $this->is_blacklisted( $admin_string_name ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! empty( $a['key'] ) ) {
|
||||
foreach ( $a['key'] as $key ) {
|
||||
$arr[ $admin_string_name ][ $key['attr']['name'] ] = isset( $key['key'] )
|
||||
? $this->read_admin_texts_recursive( $key['key'],
|
||||
$admin_text_context,
|
||||
$type,
|
||||
$arr_context,
|
||||
$arr_type )
|
||||
: 1;
|
||||
$arr_context[ $admin_string_name ] = $admin_text_context;
|
||||
$arr_type[ $admin_string_name ] = $type;
|
||||
}
|
||||
} else {
|
||||
$arr[ $admin_string_name ] = 1;
|
||||
$arr_context[ $admin_string_name ] = $admin_text_context;
|
||||
$arr_type[ $admin_string_name ] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $arr ) ) {
|
||||
$iclTranslationManagement->admin_texts_to_translate = array_merge( $iclTranslationManagement->admin_texts_to_translate,
|
||||
$arr );
|
||||
}
|
||||
|
||||
$_icl_admin_option_names = get_option( '_icl_admin_option_names' );
|
||||
|
||||
$arr_options = array();
|
||||
if ( isset( $arr ) && is_array( $arr ) ) {
|
||||
foreach ( $arr as $key => $v ) {
|
||||
$value = maybe_unserialize( $this->get_option_without_filtering( $key ) );
|
||||
$value = is_array( $value ) && is_array( $v ) ? array_intersect_key( $value, $v ) : $value;
|
||||
$admin_text_context = isset( $arr_context[ $key ] ) ? $arr_context[ $key ] : '';
|
||||
$type = isset( $arr_type[ $key ] ) ? $arr_type[ $key ] : '';
|
||||
|
||||
$req_upgrade = ! $sitepress->get_setting( 'admin_text_3_2_migration_complete_' . $admin_texts_hash, false );
|
||||
if ( (bool) $value === true ) {
|
||||
$this->register_string_recursive( $key,
|
||||
$value,
|
||||
$arr[ $key ],
|
||||
'',
|
||||
$key,
|
||||
$req_upgrade,
|
||||
$type,
|
||||
$admin_text_context );
|
||||
}
|
||||
$arr_options[ $key ] = $v;
|
||||
}
|
||||
|
||||
$_icl_admin_option_names = is_array( $_icl_admin_option_names )
|
||||
? array_replace_recursive( $_icl_admin_option_names, $arr_options ) : $arr_options;
|
||||
}
|
||||
|
||||
update_option( '_icl_admin_option_names', $_icl_admin_option_names, 'no' );
|
||||
|
||||
set_transient( $transient_name, $admin_texts_hash );
|
||||
$sitepress->set_setting( 'admin_text_3_2_migration_complete_' . $admin_texts_hash, true, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function register_string_recursive( $key, $value, $arr, $prefix, $suffix, $requires_upgrade, $type, $admin_text_context_old ) {
|
||||
if ( is_scalar( $value ) ) {
|
||||
icl_register_string( WPML_Admin_Texts::DOMAIN_NAME_PREFIX . $suffix, $prefix . $key, $value, true );
|
||||
if ( $requires_upgrade ) {
|
||||
$this->migrate_3_2( $type, $admin_text_context_old, $suffix, $prefix . $key );
|
||||
}
|
||||
} elseif ( ! is_null( $value ) ) {
|
||||
foreach ( $value as $sub_key => $sub_value ) {
|
||||
if ( isset( $arr[ $sub_key ] ) ) {
|
||||
$this->register_string_recursive( $sub_key,
|
||||
$sub_value,
|
||||
$arr[ $sub_key ],
|
||||
$prefix . '[' . $key . ']',
|
||||
$suffix,
|
||||
$requires_upgrade,
|
||||
$type,
|
||||
$admin_text_context_old );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function migrate_3_2( $type, $old_admin_text_context, $new_admin_text_context, $key ) {
|
||||
global $wpdb;
|
||||
|
||||
$old_string_id = icl_st_is_registered_string( WPML_Admin_Texts::DOMAIN_NAME_PREFIX . $type . '_' . $old_admin_text_context, $key );
|
||||
if ( $old_string_id ) {
|
||||
$new_string_id = icl_st_is_registered_string( WPML_Admin_Texts::DOMAIN_NAME_PREFIX . $new_admin_text_context, $key );
|
||||
if ( $new_string_id ) {
|
||||
$wpdb->update( $wpdb->prefix . 'icl_string_translations', array( 'string_id' => $new_string_id ), array( 'string_id' => $old_string_id ) );
|
||||
$this->st_records->icl_strings_by_string_id( $new_string_id )
|
||||
->update(
|
||||
array(
|
||||
'status' => $this->st_records
|
||||
->icl_strings_by_string_id( $old_string_id )
|
||||
->status()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
<?php
|
||||
|
||||
use WPML\Collect\Support\Collection;
|
||||
use WPML\FP\Either;
|
||||
use \WPML\FP\Obj;
|
||||
use function WPML\Container\make;
|
||||
use function \WPML\FP\partial;
|
||||
use function \WPML\FP\invoke;
|
||||
use function \WPML\FP\flip;
|
||||
|
||||
class WPML_Admin_Texts extends WPML_Admin_Text_Functionality {
|
||||
const DOMAIN_NAME_PREFIX = 'admin_texts_';
|
||||
|
||||
/** @var array $cache - A cache for each option translation */
|
||||
private $cache = [];
|
||||
|
||||
/** @var array $option_names - The option names from Admin texts settings */
|
||||
private $option_names = [];
|
||||
|
||||
/** @var TranslationManagement $tm_instance */
|
||||
private $tm_instance;
|
||||
|
||||
/** @var WPML_String_Translation $st_instance */
|
||||
private $st_instance;
|
||||
|
||||
/** @var bool $lock */
|
||||
private $lock = false;
|
||||
|
||||
/**
|
||||
* @param TranslationManagement $tm_instance
|
||||
* @param WPML_String_Translation $st_instance
|
||||
*/
|
||||
function __construct( &$tm_instance, &$st_instance ) {
|
||||
add_action( 'plugins_loaded', [ $this, 'icl_st_set_admin_options_filters' ], 10 );
|
||||
add_filter( 'wpml_unfiltered_admin_string', flip( [ $this, 'get_option_without_filtering' ] ), 10, 2 );
|
||||
add_action( 'wpml_st_force_translate_admin_options', [ $this, 'force_translate_admin_options' ] );
|
||||
$this->tm_instance = &$tm_instance;
|
||||
$this->st_instance = &$st_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array|mixed|object
|
||||
*/
|
||||
private static function object_to_array( $value ) {
|
||||
return is_object( $value ) ? object_to_array( $value ) : $value;
|
||||
}
|
||||
|
||||
function icl_register_admin_options( $array, $key = '', $option = array() ) {
|
||||
$option = self::object_to_array( $option );
|
||||
foreach ( $array as $k => $v ) {
|
||||
$option = $key === '' ? array( $k => maybe_unserialize( $this->get_option_without_filtering( $k ) ) ) : $option;
|
||||
if ( is_array( $v ) ) {
|
||||
$this->icl_register_admin_options( $v, $key . '[' . $k . ']', $option[ $k ] );
|
||||
} else {
|
||||
$context = $this->get_context( $key, $k );
|
||||
if ( $v === '' ) {
|
||||
icl_unregister_string( $context, $key . $k );
|
||||
} elseif ( isset( $option[ $k ] ) && ( $key === '' || $opt_keys = self::findKeys( (string) $key ) ) ) {
|
||||
icl_register_string( $context, $key . $k, $option[ $k ], true );
|
||||
$vals = array( $k => 1 );
|
||||
$opt_keys = isset( $opt_keys ) ? array_reverse( $opt_keys ) : [];
|
||||
foreach ( $opt_keys as $opt ) {
|
||||
$vals = array( $opt => $vals );
|
||||
}
|
||||
update_option(
|
||||
'_icl_admin_option_names',
|
||||
array_merge_recursive( (array) get_option( '_icl_admin_option_names' ), $vals ),
|
||||
'no'
|
||||
);
|
||||
$this->option_names = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getModelForRender() {
|
||||
return $this->getModel( $this->getOptions() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $options
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getModel( Collection $options ) {
|
||||
$stringNamesPerContext = $this->getStringNamesPerContext();
|
||||
|
||||
$isRegistered = function ( $context, $name ) use ( $stringNamesPerContext ) {
|
||||
return $stringNamesPerContext->has( $context ) &&
|
||||
$stringNamesPerContext->get( $context )->contains( $name );
|
||||
};
|
||||
|
||||
$getItems = partial( [ $this, 'getItemModel' ], $isRegistered );
|
||||
|
||||
return $options->map( $getItems )
|
||||
->filter()
|
||||
->values()
|
||||
->reduce( [ $this, 'flattenModelItems' ], wpml_collect() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Collection $flattened
|
||||
* @param array $item
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function flattenModelItems( Collection $flattened, array $item ) {
|
||||
if ( empty( $item ) ) {
|
||||
return $flattened;
|
||||
}
|
||||
|
||||
if ( isset( $item['items'] ) ) {
|
||||
return $flattened->merge(
|
||||
$item['items']->reduce( [ $this, 'flattenModelItems' ], wpml_collect() )
|
||||
);
|
||||
}
|
||||
|
||||
return $flattened->push( $item );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $isRegistered - string -> string -> bool
|
||||
* @param mixed $value
|
||||
* @param string $name
|
||||
* @param string $key
|
||||
* @param array $stack
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getItemModel( callable $isRegistered, $value, $name, $key = '', $stack = [] ) {
|
||||
$sub_key = $this->getSubKey( $key, $name );
|
||||
|
||||
$result = [];
|
||||
|
||||
if ( $this->isMultiValue( $value ) ) {
|
||||
$stack[] = $value;
|
||||
|
||||
$getSubItem = function ( $v, $key ) use ( $isRegistered, $sub_key, $stack ) {
|
||||
return $this->getItemModel( $isRegistered, $v, $key, $sub_key, $stack );
|
||||
};
|
||||
$result['items'] = wpml_collect( $value )
|
||||
->reject( $this->isOnStack( $stack ) )
|
||||
->map( $getSubItem );
|
||||
} elseif ( is_string( $value ) || is_numeric( $value ) ) {
|
||||
$context = $this->get_context( $key, $name );
|
||||
$stringName = $this->getDBStringName( $key, $name );
|
||||
|
||||
$result['value'] = $value;
|
||||
$result['fixed'] = $this->is_sub_key_fixed( $sub_key );
|
||||
$result['name'] = $sub_key;
|
||||
$result['registered'] = $isRegistered( $context, $stringName );
|
||||
$result['hasTranslations'] = ! $result['fixed'] && $result['registered']
|
||||
&& icl_st_string_has_translations( $context, $stringName );
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
private function isOnStack( array $stack ) {
|
||||
return function ( $item ) use ( $stack ) {
|
||||
return \wpml_collect( $stack )->first(
|
||||
function ( $currentItem ) use ( $item ) {
|
||||
return $currentItem === $item;
|
||||
}
|
||||
) !== null;
|
||||
};
|
||||
}
|
||||
|
||||
private function is_sub_key_fixed( $sub_key ) {
|
||||
$fixed = false;
|
||||
if ( $keys = self::findKeys( $sub_key ) ) {
|
||||
$fixed = true;
|
||||
$fixed_settings = $this->tm_instance->admin_texts_to_translate;
|
||||
foreach ( $keys as $m ) {
|
||||
if ( $fixed = isset( $fixed_settings[ $m ] ) ) {
|
||||
$fixed_settings = $fixed_settings[ $m ];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $fixed;
|
||||
}
|
||||
|
||||
private function get_context( $option_key, $option_name ) {
|
||||
$keys = self::findKeys( (string) $option_key );
|
||||
|
||||
return self::DOMAIN_NAME_PREFIX . ( $keys ? reset( $keys ) : $option_name );
|
||||
}
|
||||
|
||||
public function getOptions() {
|
||||
return wpml_collect( wp_load_alloptions() )
|
||||
->reject( flip( [ $this, 'is_blacklisted' ] ) )
|
||||
->map( 'maybe_unserialize' );
|
||||
}
|
||||
|
||||
function icl_st_set_admin_options_filters() {
|
||||
$option_names = $this->getOptionNames();
|
||||
|
||||
$isAdmin = is_admin() && ! wpml_is_ajax();
|
||||
|
||||
foreach ( $option_names as $option_key => $option ) {
|
||||
if ( $this->is_blacklisted( $option_key ) ) {
|
||||
unset( $option_names[ $option_key ] );
|
||||
update_option( '_icl_admin_option_names', $option_names, 'no' );
|
||||
} elseif ( $option_key != 'theme' && $option_key != 'plugin' ) { // theme and plugin are an obsolete format before 3.2
|
||||
/**
|
||||
* We don't want to translate admin strings in admin panel because it causes a lot of confusion
|
||||
* when a value is displayed inside the form input.
|
||||
*/
|
||||
if ( ! $isAdmin ) {
|
||||
$this->add_filter_for( $option_key );
|
||||
}
|
||||
add_action( 'update_option_' . $option_key, array( $this, 'on_update_original_value' ), 10, 3 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*/
|
||||
public function force_translate_admin_options( $options ) {
|
||||
wpml_collect( $options )->each( [ $this, 'add_filter_for' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option
|
||||
*/
|
||||
public function add_filter_for( $option ) {
|
||||
add_filter( 'option_' . $option, [ $this, 'icl_st_translate_admin_string' ] );
|
||||
}
|
||||
|
||||
function icl_st_translate_admin_string( $option_value, $key = '', $name = '', $root_level = true ) {
|
||||
if ( $root_level && $this->lock ) {
|
||||
return $option_value;
|
||||
}
|
||||
|
||||
$this->lock = true;
|
||||
|
||||
$lang = $this->st_instance->get_current_string_language( $name );
|
||||
$option_name = substr( current_filter(), 7 );
|
||||
$name = $name === '' ? $option_name : $name;
|
||||
$blog_id = get_current_blog_id();
|
||||
|
||||
if ( isset( $this->cache[ $blog_id ][ $lang ][ $name ] ) ) {
|
||||
$this->lock = false;
|
||||
|
||||
return $this->cache[ $blog_id ][ $lang ][ $name ];
|
||||
}
|
||||
|
||||
$is_serialized = is_serialized( $option_value );
|
||||
$option_value = $is_serialized ? unserialize( $option_value ) : $option_value;
|
||||
|
||||
if ( is_array( $option_value ) || is_object( $option_value ) ) {
|
||||
$option_value = $this->translate_multiple( $option_value, $key, $name );
|
||||
} else {
|
||||
$option_value = $this->translate_single( $option_value, $key, $name, $option_name );
|
||||
}
|
||||
|
||||
$option_value = $is_serialized ? serialize( $option_value ) : $option_value;
|
||||
|
||||
if ( $root_level ) {
|
||||
$this->lock = false;
|
||||
$this->cache[ $blog_id ][ $lang ][ $name ] = $option_value;
|
||||
}
|
||||
|
||||
return $option_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key - string like '[key1][key2]'
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isAdminText( $key, $name ) {
|
||||
|
||||
return null !== Either::of( $this->getSubKey( $key, $name ) )
|
||||
->map( [ self::class, 'getKeysParts' ] )
|
||||
->tryCatch( invoke( 'reduce' )->with( flip( Obj::prop() ), $this->getOptionNames() ) )
|
||||
->getOrElse( null );
|
||||
}
|
||||
|
||||
/**
|
||||
* getKeys :: string [key1][key2][name] => Collection [key1, key2, name]
|
||||
*
|
||||
* @param string $option
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public static function getKeysParts( $option ) {
|
||||
return wpml_collect( self::findKeys( $option ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function findKeys( $string ) {
|
||||
return array_filter( explode( '][', preg_replace( '/^\[(.*)\]$/', '$1', $string ) ), 'strlen' );
|
||||
}
|
||||
|
||||
function clear_cache_for_option( $option_name ) {
|
||||
$blog_id = get_current_blog_id();
|
||||
if ( isset( $this->cache[ $blog_id ] ) ) {
|
||||
foreach ( $this->cache[ $blog_id ] as $lang_code => &$cache_data ) {
|
||||
if ( array_key_exists( $option_name, $cache_data ) ) {
|
||||
unset( $cache_data[ $option_name ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $old_value
|
||||
* @param string|array $value
|
||||
* @param string $option_name
|
||||
* @param string $name
|
||||
* @param string $sub_key
|
||||
*/
|
||||
public function on_update_original_value( $old_value, $value, $option_name, $name = '', $sub_key = '' ) {
|
||||
$name = $name ? $name : $option_name;
|
||||
|
||||
$value = self::object_to_array( $value );
|
||||
$old_value = self::object_to_array( $old_value );
|
||||
|
||||
if ( is_array( $value ) ) {
|
||||
foreach ( array_keys( $value ) as $key ) {
|
||||
$this->on_update_original_value(
|
||||
isset( $old_value[ $key ] ) ? $old_value[ $key ] : '',
|
||||
$value[ $key ],
|
||||
$option_name,
|
||||
$key,
|
||||
$this->getSubKey( $sub_key, $name )
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if ( $this->isAdminText( $sub_key, $name ) ) {
|
||||
icl_st_update_string_actions( self::DOMAIN_NAME_PREFIX . $option_name, $this->getDBStringName( $sub_key, $name ), $old_value, $value );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $sub_key === '' ) {
|
||||
$this->clear_cache_for_option( $option_name );
|
||||
}
|
||||
}
|
||||
|
||||
public function migrate_original_values() {
|
||||
$migrate = function ( $option_name ) {
|
||||
$option_value = maybe_unserialize( $this->get_option_without_filtering( $option_name ) );
|
||||
$this->on_update_original_value( '', $option_value, $option_name );
|
||||
};
|
||||
wpml_collect( $this->getOptionNames() )
|
||||
->keys()
|
||||
->filter()
|
||||
->each( $migrate );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function to lazy load the migration
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
public static function get_migrator() {
|
||||
return function () {
|
||||
wpml_st_load_admin_texts()->migrate_original_values();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $option_value
|
||||
* @param string $key
|
||||
* @param string $name
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
private function translate_multiple( $option_value, $key, $name ) {
|
||||
$subKey = $this->getSubKey( $key, $name );
|
||||
|
||||
foreach ( $option_value as $k => &$value ) {
|
||||
$value = $this->icl_st_translate_admin_string(
|
||||
$value,
|
||||
$subKey,
|
||||
$k,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return $option_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option_value
|
||||
* @param string $key
|
||||
* @param string $name
|
||||
* @param string $option_name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function translate_single( $option_value, $key, $name, $option_name ) {
|
||||
if ( $option_value !== '' && $this->isAdminText( $key, $name ) ) {
|
||||
$option_value = icl_translate( self::DOMAIN_NAME_PREFIX . $option_name, $key . $name, $option_value );
|
||||
}
|
||||
|
||||
return $option_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getOptionNames() {
|
||||
if ( empty( $this->option_names ) ) {
|
||||
$this->option_names = get_option( '_icl_admin_option_names' );
|
||||
if ( ! is_array( $this->option_names ) ) {
|
||||
$this->option_names = [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->option_names;
|
||||
}
|
||||
|
||||
/**
|
||||
* getSubKeys :: string [key1][key2] -> string name => string [key1][key2][name]
|
||||
*
|
||||
* @param string $key - [key1][key2]
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getSubKey( $key, $name ) {
|
||||
return $key . '[' . $name . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* getSubKeys :: string [key1][key2] -> string name => string [key1][key2]name
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getDBStringName( $key, $name ) {
|
||||
return $key . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
private function getStringNamesPerContext() {
|
||||
$strings = make( WPML_ST_DB_Mappers_Strings::class )
|
||||
->get_all_by_context( self::DOMAIN_NAME_PREFIX . '%' );
|
||||
|
||||
return wpml_collect( $strings )
|
||||
->groupBy( 'context' )
|
||||
->map( invoke( 'pluck' )->with( 'name' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isMultiValue( $value ) {
|
||||
return is_array( $value ) ||
|
||||
( is_object( $value ) && '__PHP_Incomplete_Class' !== get_class( $value ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
|
||||
class WPML_ST_MO_Downloader {
|
||||
const LOCALES_XML_FILE = 'http://d2pf4b3z51hfy8.cloudfront.net/wp-locales.xml.gz';
|
||||
|
||||
const CONTEXT = 'WordPress';
|
||||
private $settings;
|
||||
private $xml;
|
||||
private $translation_files = array();
|
||||
/**
|
||||
* @var string[string]
|
||||
*/
|
||||
private $lang_map;
|
||||
/**
|
||||
* @var string[string]
|
||||
*/
|
||||
private $lang_map_rev;
|
||||
|
||||
|
||||
function __construct() {
|
||||
global $wp_version;
|
||||
|
||||
// requires Sitepress
|
||||
if ( ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wpversion = preg_replace( '#-(.+)$#', '', $wp_version );
|
||||
|
||||
$this->settings = get_option( 'icl_adl_settings' );
|
||||
|
||||
if ( empty( $this->settings['wp_version'] ) || version_compare( $wpversion, $this->settings['wp_version'], '>' ) ) {
|
||||
try {
|
||||
$this->updates_check( array( 'trigger' => 'wp-update' ) );
|
||||
} catch ( Exception $e ) {
|
||||
// do nothing - this is automated request for updates
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_transient( 'WPML_ST_MO_Downloader_lang_map' ) === false ) {
|
||||
$this->set_lang_map_from_csv();
|
||||
}
|
||||
$this->lang_map = get_transient( 'WPML_ST_MO_Downloader_lang_map' );
|
||||
$this->lang_map_rev = array_flip( $this->lang_map );
|
||||
|
||||
add_action( 'wp_ajax_icl_adm_updates_check', array( $this, 'show_updates' ) );
|
||||
add_action( 'wp_ajax_icl_adm_save_preferences', array( $this, 'save_preferences' ) );
|
||||
|
||||
}
|
||||
|
||||
function set_lang_map_from_csv() {
|
||||
$fh = fopen( WPML_ST_PATH . '/inc/lang-map.csv', 'r' );
|
||||
while ( list($locale, $code) = fgetcsv( $fh ) ) {
|
||||
$this->lang_map[ $locale ] = $code;
|
||||
}
|
||||
|
||||
if ( isset( $this->lang_map ) && is_array( $this->lang_map ) ) {
|
||||
set_transient( 'WPML_ST_MO_Downloader_lang_map', $this->lang_map );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updates_check( $args = array() ) {
|
||||
global $wp_version, $sitepress;
|
||||
|
||||
$wpversion = preg_replace( '#-(.+)$#', '', $wp_version );
|
||||
$trigger = 'manual';
|
||||
extract( $args, EXTR_OVERWRITE );
|
||||
|
||||
$active_languages = $sitepress->get_active_languages();
|
||||
$default_language = $sitepress->get_default_language();
|
||||
$this->load_xml();
|
||||
$this->get_translation_files();
|
||||
$updates = array();
|
||||
|
||||
foreach ( $active_languages as $language ) {
|
||||
if ( $language != $default_language ) {
|
||||
if ( isset( $this->translation_files[ $language['code'] ] ) ) {
|
||||
foreach ( $this->translation_files[ $language['code'] ] as $project => $info ) {
|
||||
$this->settings['translations'][ $language['code'] ][ $project ]['available'] = $info['signature'];
|
||||
if ( empty( $this->settings['translations'][ $language['code'] ][ $project ]['installed'] ) ||
|
||||
( isset( $info['available'] ) && $this->settings['translations'][ $language['code'] ][ $project ]['installed'] != $info['available'] )
|
||||
) {
|
||||
$updates['languages'][ $language['code'] ][ $project ] = $this->settings['translations'][ $language['code'] ][ $project ]['available'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->settings['wp_version'] = $wpversion;
|
||||
$this->settings['last_time_xml_check'] = time();
|
||||
$this->settings['last_time_xml_check_trigger'] = $trigger;
|
||||
$this->save_settings();
|
||||
|
||||
return $updates;
|
||||
|
||||
}
|
||||
|
||||
function show_updates() {
|
||||
global $sitepress;
|
||||
|
||||
$html = '';
|
||||
|
||||
try {
|
||||
$updates = $this->updates_check();
|
||||
// filter only core( & admin)
|
||||
$updates_core = array();
|
||||
if ( array_key_exists( 'languages', $updates ) && ! empty( $updates['languages'] ) ) {
|
||||
foreach ( $updates['languages'] as $k => $v ) {
|
||||
if ( ! empty( $v['core'] ) ) {
|
||||
$updates_core['languages'][ $k ]['core'] = $v['core'];
|
||||
}
|
||||
if ( ! empty( $v['admin'] ) ) {
|
||||
$updates_core['languages'][ $k ]['admin'] = $v['admin'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$updates = $updates_core;
|
||||
if ( ! empty( $updates ) ) {
|
||||
$html .= '<table>';
|
||||
|
||||
foreach ( $updates['languages'] as $language => $projects ) {
|
||||
$l = $sitepress->get_language_details( $language );
|
||||
|
||||
if ( ! empty( $projects['core'] ) || ! empty( $projects['admin'] ) ) {
|
||||
|
||||
$vkeys = array();
|
||||
foreach ( $projects as $key => $value ) {
|
||||
$vkeys[] = $key . '|' . $value;
|
||||
}
|
||||
$version_key = join( ';', $vkeys );
|
||||
|
||||
$html .= '<tr>';
|
||||
$html .= '<td>' . sprintf(
|
||||
__( 'Updated %s translation is available', 'wpml-string-translation' ),
|
||||
'<strong>' . $l['display_name'] . '</strong>'
|
||||
) . '</td>';
|
||||
$html .= '<td align="right">';
|
||||
$html .= '<a href="' . admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&download_mo=' . $language . '&version=' . $version_key ) . '" class="button-secondary">' . __( 'Review changes and update', 'wpml-string-translation' ) . '</a>';
|
||||
$html .= '</td>';
|
||||
$html .= '<tr>';
|
||||
$html .= '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '</table>';
|
||||
} else {
|
||||
$html .= __( 'No updates found.', 'wpml-string-translation' );
|
||||
}
|
||||
} catch ( Exception $error ) {
|
||||
$html .= '<span style="color:#f00" >' . $error->getMessage() . '</span>';
|
||||
}
|
||||
|
||||
echo json_encode( array( 'html' => $html ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
function save_preferences() {
|
||||
global $sitepress;
|
||||
|
||||
$iclsettings['st']['auto_download_mo'] = @intval( $_POST['auto_download_mo'] );
|
||||
$iclsettings['hide_upgrade_notice'] = implode( '.', array_slice( explode( '.', ICL_SITEPRESS_VERSION ), 0, 3 ) );
|
||||
$sitepress->save_settings( $iclsettings );
|
||||
if ( $iclsettings['st']['auto_download_mo'] ) {
|
||||
try {
|
||||
$this->updates_check( array( 'trigger' => 'setting-changed' ) );
|
||||
} catch ( Exception $e ) {
|
||||
}
|
||||
}
|
||||
wp_send_json_success( array( 'enabled' => $iclsettings['st']['auto_download_mo'] ) );
|
||||
}
|
||||
|
||||
function save_settings() {
|
||||
update_option( 'icl_adl_settings', $this->settings );
|
||||
}
|
||||
|
||||
function get_option( $name ) {
|
||||
return isset( $this->settings[ $name ] ) ? $this->settings[ $name ] : null;
|
||||
}
|
||||
|
||||
function load_xml() {
|
||||
if ( ! class_exists( 'WP_Http' ) ) {
|
||||
include_once ABSPATH . WPINC . '/class-http.php';
|
||||
}
|
||||
$client = new WP_Http();
|
||||
$response = $client->request(
|
||||
self::LOCALES_XML_FILE,
|
||||
array(
|
||||
'timeout' => 15,
|
||||
'decompress' => false,
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) || ! in_array( $response['response']['code'], array( 200, 301, 300 ) ) ) {
|
||||
$load_xml_error_message = '';
|
||||
if ( isset( $response->errors ) ) {
|
||||
$errors = '';
|
||||
foreach ( $response->errors as $error => $error_messages ) {
|
||||
$errors .= $error . '<br/>';
|
||||
foreach ( $error_messages as $error_message ) {
|
||||
$errors .= '- ' . $error_message . '<br/>';
|
||||
}
|
||||
}
|
||||
$load_xml_error_message .= sprintf( __( 'Failed downloading the language information file.', 'wpml-string-translation' ), $errors );
|
||||
$load_xml_error_message .= '<br/>' . sprintf( __( 'Errors: %s', 'wpml-string-translation' ), $errors );
|
||||
} else {
|
||||
$load_xml_error_message .= __( 'Failed downloading the language information file. Please go back and try a little later.', 'wpml-string-translation' );
|
||||
}
|
||||
|
||||
if ( ! is_wp_error( $response ) && isset( $response['response'] ) ) {
|
||||
$load_xml_error_message .= '<br/>Response: ' . $response['response']['code'] . ' (' . $response['response']['message'] . ').';
|
||||
}
|
||||
|
||||
$this->xml = false;
|
||||
|
||||
throw new Exception( $load_xml_error_message );
|
||||
} elseif ( $response['response']['code'] == 200 ) {
|
||||
require_once ICL_PLUGIN_PATH . '/lib/icl_api.php';
|
||||
$this->xml = new SimpleXMLElement( icl_gzdecode( $response['body'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
function get_mo_file_urls( $wplocale ) {
|
||||
if ( ! $this->xml ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
global $wp_version;
|
||||
|
||||
$wpversion = preg_replace( '#-(.+)$#', '', $wp_version );
|
||||
$wpversion = join( '.', array_slice( explode( '.', $wpversion ), 0, 2 ) ) . '.x';
|
||||
|
||||
$exp = explode( '-', $wplocale );
|
||||
$language = $exp[0];
|
||||
$locale = isset( $exp[1] ) ? $wplocale : $language;
|
||||
|
||||
$mo_files = array();
|
||||
|
||||
$projects = $this->xml->xpath( $language . '/' . $locale );
|
||||
if ( ! empty( $projects ) ) {
|
||||
|
||||
$project_names = array();
|
||||
foreach ( $projects[0] as $project_name => $data ) {
|
||||
// subprojects
|
||||
if ( empty( $data->versions ) ) {
|
||||
$subprojects = $this->xml->xpath( $language . '/' . $locale . '/' . $project_name );
|
||||
if ( ! empty( $subprojects ) ) {
|
||||
foreach ( $subprojects[0] as $sub_project_name => $sdata ) {
|
||||
$project_names[] = $project_name . '/' . $sub_project_name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$project_names[] = $project_name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $project_names ) ) {
|
||||
foreach ( $project_names as $project_name ) {
|
||||
// try to get the corresponding version
|
||||
$locv_path = $this->xml->xpath( "{$language}/{$locale}/{$project_name}/versions/version[@number=\"" . $wpversion . '"]' );
|
||||
// try to get the dev recent version
|
||||
if ( empty( $locv_path ) ) {
|
||||
$locv_path = $this->xml->xpath( "{$language}/{$locale}/{$project_name}/versions/version[@number=\"dev\"]" );
|
||||
}
|
||||
if ( ! empty( $locv_path ) ) {
|
||||
$mo_files[ $project_name ]['url'] = (string) $locv_path[0]->url;
|
||||
$mo_files[ $project_name ]['signature'] = (string) $locv_path[0]['signature'];
|
||||
$mo_files[ $project_name ]['translated'] = (string) $locv_path[0]['translated'];
|
||||
$mo_files[ $project_name ]['untranslated'] = (string) $locv_path[0]['untranslated'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mo_files;
|
||||
}
|
||||
|
||||
function get_translation_files() {
|
||||
global $sitepress;
|
||||
|
||||
$active_languages = $sitepress->get_active_languages();
|
||||
|
||||
foreach ( $active_languages as $language ) {
|
||||
$locale = $sitepress->get_locale( $language['code'] );
|
||||
if ( ! isset( $this->lang_map[ $locale ] ) ) {
|
||||
continue;
|
||||
}
|
||||
$wplocale = $this->lang_map[ $locale ];
|
||||
|
||||
$urls = $this->get_mo_file_urls( $wplocale );
|
||||
|
||||
if ( ! empty( $urls ) ) {
|
||||
$this->translation_files[ $language['code'] ] = $urls;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->translation_files;
|
||||
}
|
||||
|
||||
function get_translations( $language, $args = array() ) {
|
||||
global $wpdb;
|
||||
|
||||
$translations = array();
|
||||
$types = array( 'core' );
|
||||
|
||||
extract( $args, EXTR_OVERWRITE );
|
||||
|
||||
if ( ! class_exists( 'WP_Http' ) ) {
|
||||
include_once ABSPATH . WPINC . '/class-http.php';
|
||||
}
|
||||
$client = new WP_Http();
|
||||
|
||||
foreach ( $types as $type ) {
|
||||
|
||||
if ( isset( $this->translation_files[ $language ][ $type ]['url'] ) ) {
|
||||
|
||||
$response = $client->request( $this->translation_files[ $language ][ $type ]['url'], array( 'timeout' => 15 ) );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$err = __( 'Error getting the translation file. Please go back and try again.', 'wordpress-language' );
|
||||
if ( isset( $response->errors['http_request_failed'][0] ) ) {
|
||||
$err .= '<br />' . $response->errors['http_request_failed'][0];
|
||||
}
|
||||
echo '<div class="error"><p>' . $err . '</p></div>';
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
$mo = new MO();
|
||||
$pomo_reader = new POMO_StringReader( $response['body'] );
|
||||
$mo->import_from_reader( $pomo_reader );
|
||||
$data = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT st.value, s.name, s.gettext_context
|
||||
FROM {$wpdb->prefix}icl_string_translations st
|
||||
JOIN {$wpdb->prefix}icl_strings s ON st.string_id = s.id
|
||||
WHERE s.context = %s AND st.language = %s
|
||||
",
|
||||
self::CONTEXT,
|
||||
$language
|
||||
)
|
||||
);
|
||||
$string_existing = array();
|
||||
foreach ( $data as $row ) {
|
||||
$string_existing[ md5( $row->name . $row->gettext_context ) ] = $row->value;
|
||||
}
|
||||
|
||||
foreach ( $mo->entries as $key => $v ) {
|
||||
|
||||
$tpairs = array();
|
||||
$v->singular = str_replace( "\n", '\n', $v->singular );
|
||||
$tpairs[] = array(
|
||||
'string' => $v->singular,
|
||||
'translation' => $v->translations[0],
|
||||
'name' => md5( $v->singular ),
|
||||
'gettext_context' => $v->context,
|
||||
);
|
||||
|
||||
if ( $v->is_plural ) {
|
||||
$v->plural = str_replace( "\n", '\n', $v->plural );
|
||||
$tpairs[] = array(
|
||||
'string' => $v->plural,
|
||||
'translation' => ! empty( $v->translations[1] ) ? $v->translations[1] : $v->translations[0],
|
||||
'name' => md5( $v->plural ),
|
||||
'gettext_context' => $v->context,
|
||||
);
|
||||
}
|
||||
|
||||
foreach ( $tpairs as $pair ) {
|
||||
$key = md5( $pair['name'] . $pair['gettext_context'] );
|
||||
$existing_translation = isset( $string_existing[ $key ] ) ? $string_existing[ $key ] : null;
|
||||
|
||||
if ( empty( $existing_translation ) ) {
|
||||
$translations['new'][] = array(
|
||||
'string' => $pair['string'],
|
||||
'translation' => '',
|
||||
'new' => $pair['translation'],
|
||||
'name' => $pair['name'],
|
||||
'gettext_context' => $pair['gettext_context'],
|
||||
);
|
||||
} else {
|
||||
|
||||
if ( strcmp( $existing_translation, $pair['translation'] ) !== 0 ) {
|
||||
$translations['updated'][] = array(
|
||||
'string' => $pair['string'],
|
||||
'translation' => $existing_translation,
|
||||
'new' => $pair['translation'],
|
||||
'name' => $pair['name'],
|
||||
'gettext_context' => $pair['gettext_context'],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
function save_translations( $data, $language, $version = false ) {
|
||||
|
||||
set_time_limit( 0 );
|
||||
|
||||
if ( false === $version ) {
|
||||
global $wp_version;
|
||||
$version = preg_replace( '#-(.+)$#', '', $wp_version );
|
||||
}
|
||||
|
||||
foreach ( $data as $key => $string ) {
|
||||
if ( $string['gettext_context'] ) {
|
||||
$string_context = array(
|
||||
'domain' => self::CONTEXT,
|
||||
'context' => $string['gettext_context'],
|
||||
);
|
||||
} else {
|
||||
$string_context = self::CONTEXT;
|
||||
}
|
||||
$string_id = icl_register_string( $string_context, $string['name'], $string['string'] );
|
||||
if ( $string_id ) {
|
||||
icl_add_string_translation( $string_id, $language, $string['translation'], ICL_TM_COMPLETE );
|
||||
}
|
||||
}
|
||||
|
||||
$version_projects = explode( ';', $version );
|
||||
foreach ( $version_projects as $project ) {
|
||||
$exp = explode( '|', $project );
|
||||
$this->settings['translations'][ $language ][ $exp[0] ]['time'] = time();
|
||||
$this->settings['translations'][ $language ][ $exp[0] ]['installed'] = $exp[1];
|
||||
}
|
||||
|
||||
$this->save_settings();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
28
wp-content/plugins/wpml-string-translation/inc/constants.php
Normal file
28
wp-content/plugins/wpml-string-translation/inc/constants.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
define( 'WPML_ST_FOLDER', basename( WPML_ST_PATH ) );
|
||||
|
||||
define( 'WPML_ST_URL', plugins_url( '', dirname( __FILE__ ) ) );
|
||||
|
||||
// Old ST status constants, kept for backward compatibility with plugins that use them, like WCML
|
||||
define( 'ICL_STRING_TRANSLATION_PARTIAL', 2 );
|
||||
define( 'ICL_STRING_TRANSLATION_COMPLETE', 10 );
|
||||
define( 'ICL_STRING_TRANSLATION_NEEDS_UPDATE', 3 );
|
||||
define( 'ICL_STRING_TRANSLATION_NOT_TRANSLATED', 0 );
|
||||
define( 'ICL_STRING_TRANSLATION_WAITING_FOR_TRANSLATOR', 1 );
|
||||
|
||||
define( 'ICL_STRING_TRANSLATION_TEMPLATE_DIRECTORY', get_template_directory() );
|
||||
define( 'ICL_STRING_TRANSLATION_STYLESHEET_DIRECTORY', get_stylesheet_directory() );
|
||||
|
||||
define( 'ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_SOURCE', 0 );
|
||||
define( 'ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_PAGE', 1 );
|
||||
define( 'ICL_STRING_TRANSLATION_STRING_TRACKING_THRESHOLD', 5 );
|
||||
|
||||
define( 'ICL_STRING_TRANSLATION_AUTO_REGISTER_THRESHOLD', 500 );
|
||||
|
||||
if ( ! defined( 'ICL_STRING_TRANSLATION_DYNAMIC_CONTEXT' ) ) {
|
||||
define( 'ICL_STRING_TRANSLATION_DYNAMIC_CONTEXT', 'wpml_string' );
|
||||
}
|
||||
|
||||
define( 'WPML_ST_DEFAULT_STRINGS_PER_PAGE', 10 );
|
||||
|
||||
define( 'WPML_ST_WIDGET_STRING_DOMAIN', 'Widgets' );
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
require WPML_ST_PATH . '/inc/functions.php';
|
||||
require WPML_ST_PATH . '/inc/private-actions.php';
|
||||
require WPML_ST_PATH . '/inc/private-filters.php';
|
||||
|
||||
/**
|
||||
* @return WPML_Admin_Texts
|
||||
*/
|
||||
function wpml_st_load_admin_texts() {
|
||||
global $wpml_st_admin_texts;
|
||||
|
||||
if ( ! $wpml_st_admin_texts ) {
|
||||
global $iclTranslationManagement, $WPML_String_Translation;
|
||||
$wpml_st_admin_texts = new WPML_Admin_Texts( $iclTranslationManagement, $WPML_String_Translation );
|
||||
}
|
||||
|
||||
return $wpml_st_admin_texts;
|
||||
}
|
||||
|
||||
1119
wp-content/plugins/wpml-string-translation/inc/functions.php
Normal file
1119
wp-content/plugins/wpml-string-translation/inc/functions.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
|
||||
class WPML_Plugin_String_Scanner extends WPML_String_Scanner implements IWPML_ST_String_Scanner {
|
||||
|
||||
private $current_plugin_file;
|
||||
|
||||
public function scan() {
|
||||
$plugin_file = $_POST['plugin'];
|
||||
$this->current_plugin_file = WPML_PLUGINS_DIR . '/' . $plugin_file;
|
||||
$this->current_type = 'plugin';
|
||||
$this->current_path = dirname( $this->current_plugin_file );
|
||||
$this->text_domain = $this->get_plugin_text_domain();
|
||||
$this->scan_starting( $this->current_type );
|
||||
$text_domain = $this->get_plugin_text_domain();
|
||||
$this->init_text_domain( $text_domain );
|
||||
$this->scan_plugin_files();
|
||||
$this->current_type = 'plugin';
|
||||
$this->set_stats( 'plugin_localization_domains', $plugin_file );
|
||||
$this->scan_response();
|
||||
}
|
||||
|
||||
private function scan_plugin_files( $dir_or_file = false, $recursion = 0 ) {
|
||||
require_once WPML_ST_PATH . '/inc/potx.php';
|
||||
|
||||
foreach ( $_POST['files'] as $file ) {
|
||||
$file = Sanitize::string( $file );
|
||||
if ( $this->file_hashing->hash_changed( $file ) ) {
|
||||
_potx_process_file( $file, 0, array( $this, 'store_results' ), '_potx_save_version', $this->get_default_domain() );
|
||||
$this->add_scanned_file( $file );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_plugin_text_domain() {
|
||||
$text_domain = '';
|
||||
if ( ! function_exists( 'get_plugin_data' ) ) {
|
||||
include_once ABSPATH . '/wp-admin/includes/plugin.php';
|
||||
}
|
||||
if ( function_exists( 'get_plugin_data' ) ) {
|
||||
$plugin_data = get_plugin_data( $this->current_plugin_file );
|
||||
if ( isset( $plugin_data['TextDomain'] ) && $plugin_data['TextDomain'] != '' ) {
|
||||
$text_domain = $plugin_data['TextDomain'];
|
||||
|
||||
return $text_domain;
|
||||
}
|
||||
|
||||
return $text_domain;
|
||||
}
|
||||
|
||||
return $text_domain;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
class WPML_PO_Import {
|
||||
|
||||
private $lines;
|
||||
private $strings;
|
||||
private $error_str;
|
||||
|
||||
public function __construct( $file_name ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$this->strings = array( );
|
||||
$this->error_str = '';
|
||||
$this->lines = file( $file_name );
|
||||
|
||||
$fuzzy = 0;
|
||||
$name = false;
|
||||
$context = '';
|
||||
for ( $k = 0; $k < count( $this->lines ); $k ++ ) {
|
||||
$date_time_flag = false;
|
||||
if ( 0 === strpos( $this->lines[ $k ], '#, fuzzy' ) ) {
|
||||
$fuzzy = 1;
|
||||
$k ++;
|
||||
}
|
||||
if ( 0 === strpos( $this->lines[ $k ], '# wpml-name: ' ) ) {
|
||||
$name = preg_replace( "/^# wpml-name: /i", '', trim( $this->lines[ $k ] ) );
|
||||
$k ++;
|
||||
}
|
||||
|
||||
if ( preg_match( '#msgctxt "(.*)"#im', trim( $this->lines[ $k ] ), $matches ) ) { //we look for the line that poedit needs for unique identification of the string
|
||||
|
||||
$context = $matches[ 1 ];
|
||||
//if ( preg_match( '/wpmldatei18/', $this->lines[ $k ] ) ) { //if it contains the date_time setting we add the flag to escape the control structures in the date time placeholder string
|
||||
// $date_time_flag = true;
|
||||
//}
|
||||
$k ++;
|
||||
}
|
||||
$int = preg_match( '#msgid "(.*)"#im', trim( $this->lines[ $k ] ), $matches );
|
||||
if ( $int ) {
|
||||
list( $string, $k ) = $this->get_string( $matches[1], $k );
|
||||
|
||||
$int = preg_match( '#msgstr "(.*)"#im', trim( $this->lines[ $k + 1 ] ), $matches );
|
||||
if ( $int ) {
|
||||
list( $translation, $k ) = $this->get_string( $matches[ 1 ], $k + 1 );
|
||||
} else {
|
||||
$translation = "";
|
||||
}
|
||||
|
||||
if ( $name === false ) {
|
||||
$name = md5( $string );
|
||||
}
|
||||
|
||||
if ( $string ) {
|
||||
$string_exists = $wpdb->get_var( $wpdb->prepare( "
|
||||
SELECT id FROM {$wpdb->prefix}icl_strings
|
||||
WHERE context=%s AND name=%s AND gettext_context=%s",
|
||||
esc_sql( $_POST[ 'icl_st_i_context_new' ] ? $_POST[ 'icl_st_i_context_new' ] : $_POST[ 'icl_st_i_context' ] ),
|
||||
$name,
|
||||
$context
|
||||
)
|
||||
);
|
||||
|
||||
if ( $date_time_flag ) {
|
||||
$string = str_replace( "\\\\", "\\", $string );
|
||||
$translation = str_replace( "\\\\", "\\", $translation );
|
||||
$name = str_replace( "\\\\", "\\", $name );
|
||||
}
|
||||
|
||||
$this->strings[ ] = array(
|
||||
'string' => $string,
|
||||
'translation' => $translation,
|
||||
'name' => $name,
|
||||
'fuzzy' => $fuzzy,
|
||||
'exists' => $string_exists,
|
||||
'context' => $context
|
||||
);
|
||||
}
|
||||
$k ++;
|
||||
|
||||
$name = false;
|
||||
$context = '';
|
||||
}
|
||||
if ( $k < count( $this->lines ) && ! trim( $this->lines[ $k ] ) ) {
|
||||
$fuzzy = 0;
|
||||
}
|
||||
}
|
||||
if ( empty( $this->strings ) ) {
|
||||
$this->error_str = __( 'No string found', 'wpml-string-translation' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function get_string( $string, $k ) {
|
||||
|
||||
$string = $this->strip_slashes( $string );
|
||||
// check for multiline strings
|
||||
if ( $k + 1 < count( $this->lines ) ) {
|
||||
$int = preg_match( '#^"(.*)"$#', trim( $this->lines[ $k + 1 ] ), $matches );
|
||||
while ( $int ) {
|
||||
$string .= $this->strip_slashes( $matches[ 1 ] );
|
||||
$k++;
|
||||
if ( $k + 1 < count( $this->lines ) ) {
|
||||
$int = preg_match( '#^"(.*)"$#', trim( $this->lines[ $k + 1 ] ), $matches );
|
||||
} else {
|
||||
$int = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array( $string, $k );
|
||||
|
||||
}
|
||||
|
||||
private function strip_slashes( $string ) {
|
||||
$string = str_replace( '\"', '"', $string );
|
||||
$string = str_replace( '\\\\', '\\', $string );
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function has_strings( ) {
|
||||
return ! empty( $this->strings );
|
||||
}
|
||||
|
||||
public function get_strings( ) {
|
||||
return $this->strings;
|
||||
}
|
||||
|
||||
public function get_errors( ) {
|
||||
return $this->error_str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
class WPML_PO_Parser {
|
||||
|
||||
public static function create_po( $strings, $pot_only = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$po = self::get_po_file_header();
|
||||
|
||||
foreach ( $strings as $s ) {
|
||||
$ids[ ] = $s[ 'string_id' ];
|
||||
}
|
||||
if ( ! empty( $ids ) ) {
|
||||
$sql_prepared = $wpdb->prepare( "SELECT string_id, position_in_page
|
||||
FROM {$wpdb->prefix}icl_string_positions
|
||||
WHERE kind=%d AND string_id IN(%s)", ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_SOURCE, implode( ',', $ids ));
|
||||
$res = $wpdb->get_results( $sql_prepared );
|
||||
foreach ( $res as $row ) {
|
||||
$positions[ $row->string_id ] = $row->position_in_page;
|
||||
}
|
||||
}
|
||||
foreach ( $strings as $s ) {
|
||||
$po .= PHP_EOL;
|
||||
if ( ! $pot_only && isset( $s[ 'translations' ] ) && isset( $s[ 'translations' ][ key( $s[ 'translations' ] ) ][ 'value' ] ) ) {
|
||||
$translation = $s[ 'translations' ][ key( $s[ 'translations' ] ) ][ 'value' ];
|
||||
if ( $translation != '' && $s[ 'translations' ][ key( $s[ 'translations' ] ) ][ 'status' ] != ICL_TM_COMPLETE ) {
|
||||
$po .= '#, fuzzy' . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
$translation = '';
|
||||
}
|
||||
if ( isset( $positions[ $s[ 'string_id' ] ] ) ) {
|
||||
$exp = @explode( '::', $positions[ $s[ 'string_id' ] ] );
|
||||
$file = @file( $exp[ 0 ] );
|
||||
} else {
|
||||
unset( $file );
|
||||
unset( $exp );
|
||||
}
|
||||
|
||||
$po_single = '';
|
||||
if ( isset( $file ) && isset( $exp ) ) {
|
||||
$line_number = (int) $exp[ 1 ];
|
||||
$line_number--; // Make it 0 base
|
||||
$line_number -= 2; // Go back 2 lines
|
||||
if ( $line_number < 0 ) {
|
||||
$line_number = 0;
|
||||
}
|
||||
for ( $line = 0; $line < 3; $line++ ) {
|
||||
$po_single .= '#: ' . @trim( $file[ $line_number + $line ] ) . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$po_single .= '# wpml-name: ' . $s[ 'name' ] . PHP_EOL;
|
||||
|
||||
if ( $s[ 'gettext_context' ] ) {
|
||||
$po_single .=
|
||||
'msgctxt "'
|
||||
. $s[ 'gettext_context' ]
|
||||
. '"'
|
||||
. PHP_EOL;
|
||||
}
|
||||
$po_single .= 'msgid ' . self::output_string( $s[ 'value' ] ) . PHP_EOL;
|
||||
$po_single .= 'msgstr ' . self::output_string( $translation ) . PHP_EOL;
|
||||
$po .= $po_single;
|
||||
}
|
||||
|
||||
return $po;
|
||||
}
|
||||
|
||||
public static function get_po_file_header() {
|
||||
$po_title = 'WPML_EXPORT';
|
||||
$translation_language = 'en';
|
||||
|
||||
if ( isset( $_GET['context'] ) ) {
|
||||
$po_title .= '_' . filter_var( $_GET['context'], FILTER_SANITIZE_STRING );
|
||||
}
|
||||
|
||||
if ( isset( $_GET['translation_language'] ) ) {
|
||||
$translation_language = filter_var( $_GET['translation_language'], FILTER_SANITIZE_STRING );
|
||||
}
|
||||
|
||||
$po = "";
|
||||
$po .= '# This file was generated by WPML' . PHP_EOL;
|
||||
$po .= '# WPML is a WordPress plugin that can turn any WordPress or WordPressMU site into a full featured multilingual content management system.' . PHP_EOL;
|
||||
$po .= '# https://wpml.org' . PHP_EOL;
|
||||
$po .= 'msgid ""' . PHP_EOL;
|
||||
$po .= 'msgstr ""' . PHP_EOL;
|
||||
$po .= '"Content-Type: text/plain; charset=utf-8\n"' . PHP_EOL;
|
||||
$po .= '"Content-Transfer-Encoding: 8bit\n"' . PHP_EOL;
|
||||
|
||||
$po .= '"Project-Id-Version:' . $po_title . '\n"' . PHP_EOL;
|
||||
$po .= '"POT-Creation-Date: \n"' . PHP_EOL;
|
||||
$po .= '"PO-Revision-Date: \n"' . PHP_EOL;
|
||||
$po .= '"Last-Translator: \n"' . PHP_EOL;
|
||||
$po .= '"Language-Team: \n"' . PHP_EOL;
|
||||
|
||||
$po .= '"Language:' . $translation_language . '\n"' . PHP_EOL;
|
||||
|
||||
$po .= '"MIME-Version: 1.0\n"' . PHP_EOL;
|
||||
|
||||
return $po;
|
||||
}
|
||||
|
||||
private static function output_string( $str ) {
|
||||
if ( strstr( $str, "\n" ) ) {
|
||||
$str = str_replace( "\r", "", $str );
|
||||
$lines = explode( "\n", $str );
|
||||
$str = '""';
|
||||
foreach ( $lines as $line ) {
|
||||
$str .= PHP_EOL . '"' . self::addslashes( $line ) . '\n"' ;
|
||||
}
|
||||
} else {
|
||||
$str = '"' . self::addslashes( $str ) . '"';
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
private static function addslashes ( $str ) {
|
||||
$str = str_replace( '\\', '\\\\', $str );
|
||||
$str = str_replace( '"', '\"', $str );
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,704 @@
|
||||
<?php
|
||||
|
||||
class WPML_String_Scanner {
|
||||
|
||||
const DEFAULT_DOMAIN = 'default';
|
||||
|
||||
/**
|
||||
* @param string|NULL $type 'plugin' or 'theme'
|
||||
*/
|
||||
protected $current_type;
|
||||
protected $current_path;
|
||||
protected $text_domain;
|
||||
|
||||
private $domains;
|
||||
private $registered_strings;
|
||||
private $lang_codes;
|
||||
private $currently_scanning;
|
||||
private $domains_found;
|
||||
private $default_domain;
|
||||
|
||||
/** @var WP_Filesystem_Base */
|
||||
private $wp_filesystem;
|
||||
|
||||
/** @var WPML_File $wpml_file */
|
||||
private $wpml_file;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $scan_stats;
|
||||
private $scanned_files;
|
||||
|
||||
/**
|
||||
* @var WPML_File_Name_Converter
|
||||
*/
|
||||
private $file_name_converter;
|
||||
|
||||
/**
|
||||
* @var WPML_ST_DB_Mappers_String_Positions
|
||||
*/
|
||||
private $string_positions_mapper;
|
||||
|
||||
/**
|
||||
* @var WPML_ST_DB_Mappers_Strings
|
||||
*/
|
||||
private $strings_mapper;
|
||||
|
||||
/** @var WPML_ST_File_Hashing */
|
||||
protected $file_hashing;
|
||||
|
||||
/**
|
||||
* WPML_String_Scanner constructor.
|
||||
*
|
||||
* @param WP_Filesystem_Base $wp_filesystem
|
||||
* @param WPML_ST_File_Hashing $file_hashing
|
||||
*/
|
||||
public function __construct( WP_Filesystem_Base $wp_filesystem, WPML_ST_File_Hashing $file_hashing ) {
|
||||
global $wpdb;
|
||||
|
||||
$this->domains = array();
|
||||
$this->registered_strings = array();
|
||||
$this->lang_codes = array();
|
||||
$this->domains_found = array();
|
||||
$this->scan_stats = array();
|
||||
$this->scanned_files = array();
|
||||
|
||||
$this->default_domain = 'default';
|
||||
$this->wp_filesystem = $wp_filesystem;
|
||||
$this->file_hashing = $file_hashing;
|
||||
}
|
||||
|
||||
protected function scan_starting( $scanning ) {
|
||||
$this->currently_scanning = $scanning;
|
||||
$this->domains_found[ $this->currently_scanning ] = array();
|
||||
$this->default_domain = 'default';
|
||||
}
|
||||
|
||||
protected function scan_response() {
|
||||
global $__icl_registered_strings, $sitepress;
|
||||
|
||||
$result = array(
|
||||
'scan_successful_message' => esc_html__( 'Scan successful! WPML found %s strings.', 'wpml-string-translation' ),
|
||||
'files_processed_message' => esc_html__( 'The following files were processed:', 'wpml-string-translation' ),
|
||||
'files_processed' => $this->get_scanned_files(),
|
||||
'strings_found' => is_array( $__icl_registered_strings ) ? count( $__icl_registered_strings ) : 0,
|
||||
);
|
||||
|
||||
if ( $result['strings_found'] ) {
|
||||
$result['scan_successful_message'] .= __( ' They were added to the string translation table.', 'wpml-string-translation' );
|
||||
}
|
||||
|
||||
$sitepress->get_wp_api()->wp_send_json_success( $result );
|
||||
}
|
||||
|
||||
final protected function init_text_domain( $text_domain ) {
|
||||
$string_settings = apply_filters( 'wpml_get_setting', false, 'st' );
|
||||
|
||||
$use_header_text_domain = isset( $string_settings['use_header_text_domains_when_missing'] ) && $string_settings['use_header_text_domains_when_missing'];
|
||||
|
||||
$this->default_domain = 'default';
|
||||
|
||||
if ( $use_header_text_domain && $text_domain ) {
|
||||
$this->default_domain = $text_domain;
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_domains_found() {
|
||||
return $this->domains_found[ $this->currently_scanning ];
|
||||
}
|
||||
|
||||
protected function get_default_domain() {
|
||||
return $this->default_domain;
|
||||
}
|
||||
|
||||
protected function maybe_register_string( $value, $gettext_context ) {
|
||||
if ( ! $this->get_string_id( $value, $gettext_context, $gettext_context ) ) {
|
||||
$this->store_results( $value, $gettext_context, $gettext_context, '', 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of files under directory.
|
||||
*
|
||||
* @param string $path Directory to parse.
|
||||
* @param object $filesystem WP_Filesystem object
|
||||
* @return array
|
||||
*/
|
||||
private function extract_files( $path, $filesystem ) {
|
||||
$path = $this->add_dir_separator( $path );
|
||||
$files = array();
|
||||
$list = $filesystem->dirlist( $path );
|
||||
foreach ( $list as $single_file ) {
|
||||
if ( 'f' === $single_file['type'] ) {
|
||||
$files[] = $path . $single_file['name'];
|
||||
} else {
|
||||
$files = array_merge( $files, $this->extract_files( $path . $single_file['name'], $filesystem ) );
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the last character is second argument.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $separator
|
||||
* @return string
|
||||
*/
|
||||
private function add_dir_separator( $path, $separator = DIRECTORY_SEPARATOR ) {
|
||||
if ( strlen( $path ) > 0 ) {
|
||||
if ( substr( $path, -1 ) !== $separator ) {
|
||||
return $path . $separator;
|
||||
} else {
|
||||
return $path;
|
||||
}
|
||||
} else {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
private function fix_existing_string_with_wrong_context( $original_value, $new_string_context, $gettext_context ) {
|
||||
if ( ! isset( $this->current_type ) || ! isset( $this->current_path ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$old_context = $this->get_old_context();
|
||||
|
||||
$new_context_string_id = $this->get_string_id( $original_value, $new_string_context, $gettext_context );
|
||||
|
||||
if ( ! $new_context_string_id ) {
|
||||
$old_context_string_id = $this->get_string_id( $original_value, $old_context, $gettext_context );
|
||||
if ( $old_context_string_id ) {
|
||||
$this->fix_string_context( $old_context_string_id, $new_string_context );
|
||||
unset( $this->registered_strings[ $old_context ] );
|
||||
unset( $this->registered_strings[ $new_string_context ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_old_context() {
|
||||
|
||||
$plugin_or_theme_path = $this->current_path;
|
||||
|
||||
$name = basename( $plugin_or_theme_path );
|
||||
$old_context = $this->current_type . ' ' . $name;
|
||||
|
||||
return $old_context;
|
||||
|
||||
}
|
||||
|
||||
private function get_lang_code( $lang_locale ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! isset( $this->lang_codes[ $lang_locale ] ) ) {
|
||||
$this->lang_codes[ $lang_locale ] = $wpdb->get_var( $wpdb->prepare( "SELECT code FROM {$wpdb->prefix}icl_locale_map WHERE locale=%s", $lang_locale ) );
|
||||
}
|
||||
|
||||
return $this->lang_codes[ $lang_locale ];
|
||||
}
|
||||
|
||||
private function get_string_id( $original, $domain, $gettext_context ) {
|
||||
|
||||
$this->warm_cache( $domain );
|
||||
|
||||
$string_context_name = md5( $gettext_context . md5( $original ) );
|
||||
$string_id = isset( $this->registered_strings[ $domain ] ['context-name'] [ $string_context_name ] ) ? $this->registered_strings[ $domain ] ['context-name'] [ $string_context_name ] : null;
|
||||
|
||||
return $string_id;
|
||||
}
|
||||
|
||||
private function fix_string_context( $string_id, $new_string_context ) {
|
||||
global $wpdb;
|
||||
|
||||
$string = $wpdb->get_row( $wpdb->prepare( "SELECT gettext_context, name FROM {$wpdb->prefix}icl_strings WHERE id=%d", $string_id ) );
|
||||
|
||||
$domain_name_context_md5 = md5( $new_string_context . $string->name . $string->gettext_context );
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_strings',
|
||||
array(
|
||||
'context' => $new_string_context,
|
||||
'domain_name_context_md5' => $domain_name_context_md5,
|
||||
),
|
||||
array( 'id' => $string_id ),
|
||||
array( '%s', '%s' ),
|
||||
'%d'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
protected function set_stats( $key, $item ) {
|
||||
$string_settings = apply_filters( 'wpml_get_setting', false, 'st' );
|
||||
|
||||
foreach ( $this->get_domains_found() as $name => $count ) {
|
||||
$old_count = isset( $string_settings[ $key ][ $item ][ $name ] ) ?
|
||||
$string_settings[ $key ][ $item ][ $name ] :
|
||||
0;
|
||||
|
||||
$string_settings[ $key ][ $item ][ $name ] = $old_count + $count;
|
||||
}
|
||||
|
||||
do_action( 'wpml_set_setting', 'st', $string_settings, true );
|
||||
}
|
||||
|
||||
public function store_results( $string, $domain, $_gettext_context, $file, $line ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$domain = $domain ? $domain : 'WordPress';
|
||||
|
||||
if ( ! isset( $this->domains_found[ $this->currently_scanning ] [ $domain ] ) ) {
|
||||
$this->domains_found[ $this->currently_scanning ] [ $domain ] = 1;
|
||||
} else {
|
||||
$this->domains_found[ $this->currently_scanning ] [ $domain ] += 1;
|
||||
}
|
||||
|
||||
if ( ! in_array( $domain, $this->domains ) ) {
|
||||
$this->domains[] = $domain;
|
||||
|
||||
// clear existing entries (both source and page type)
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->prefix}icl_string_positions WHERE string_id IN
|
||||
(SELECT id FROM {$wpdb->prefix}icl_strings WHERE context = %s)",
|
||||
$domain
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$string = str_replace( '\n', "\n", $string );
|
||||
$string = str_replace( array( '\"', "\\'" ), array( '"', "'" ), $string );
|
||||
// replace extra backslashes added by _potx_process_file
|
||||
$string = str_replace( array( '\\\\' ), array( '\\' ), $string );
|
||||
$string = stripcslashes( $string );
|
||||
|
||||
global $__icl_registered_strings;
|
||||
|
||||
if ( ! isset( $__icl_registered_strings ) ) {
|
||||
$__icl_registered_strings = array();
|
||||
}
|
||||
|
||||
if ( ! isset( $__icl_registered_strings[ $domain . '||' . $string . '||' . $_gettext_context ] ) ) {
|
||||
|
||||
$name = md5( $string );
|
||||
$this->fix_existing_string_with_wrong_context( $string, $domain, $_gettext_context );
|
||||
$this->register_string( $domain, $_gettext_context, $name, $string );
|
||||
|
||||
$__icl_registered_strings[ $domain . '||' . $string . '||' . $_gettext_context ] = true;
|
||||
}
|
||||
|
||||
// store position in source
|
||||
$this->track_string(
|
||||
$string,
|
||||
array(
|
||||
'domain' => $domain,
|
||||
'context' => $_gettext_context,
|
||||
),
|
||||
ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_SOURCE,
|
||||
$file,
|
||||
$line
|
||||
);
|
||||
}
|
||||
|
||||
private function register_string( $domain, $context, $name, $string ) {
|
||||
|
||||
$this->warm_cache( $domain );
|
||||
|
||||
if ( ! isset( $this->registered_strings[ $domain ] ['context-name'] [ md5( $context . $name ) ] ) ) {
|
||||
|
||||
if ( $context ) {
|
||||
$string_context = array(
|
||||
'domain' => $domain,
|
||||
'context' => $context,
|
||||
);
|
||||
} else {
|
||||
$string_context = $domain;
|
||||
}
|
||||
$string_id = icl_register_string( $string_context, $name, $string );
|
||||
|
||||
$this->registered_strings[ $domain ] ['context-name'] [ md5( $context . $name ) ] = $string_id;
|
||||
}
|
||||
}
|
||||
|
||||
private function warm_cache( $domain ) {
|
||||
if ( ! isset( $this->registered_strings[ $domain ] ) ) {
|
||||
|
||||
$this->registered_strings[ $domain ] = array(
|
||||
'context-name' => array(),
|
||||
'value' => array(),
|
||||
);
|
||||
|
||||
$results = $this->get_strings_mapper()->get_all_by_context( $domain );
|
||||
foreach ( $results as $result ) {
|
||||
$this->registered_strings[ $domain ] ['context-name'] [ md5( $result['gettext_context'] . $result['name'] ) ] = $result['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function track_string( $text, $context, $kind = ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_PAGE, $file = null, $line = null ) {
|
||||
list ( $domain, $gettext_context ) = wpml_st_extract_context_parameters( $context );
|
||||
|
||||
// get string id
|
||||
$string_id = $this->get_string_id( $text, $domain, $gettext_context );
|
||||
if ( $string_id ) {
|
||||
$str_pos_mapper = $this->get_string_positions_mapper();
|
||||
$string_records_count = $str_pos_mapper->get_count_of_positions_by_string_and_kind( $string_id, $kind );
|
||||
|
||||
if ( ICL_STRING_TRANSLATION_STRING_TRACKING_THRESHOLD > $string_records_count ) {
|
||||
if ( $kind == ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_PAGE ) {
|
||||
// get page url
|
||||
$https = isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on' ? 's' : '';
|
||||
$position = 'http' . $https . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
} else {
|
||||
$file = $this->get_file_name_converter()->transform_realpath_to_reference( $file );
|
||||
$position = $file . '::' . $line;
|
||||
}
|
||||
|
||||
if ( ! $str_pos_mapper->is_string_tracked( $string_id, $position, $kind ) && ! $this->is_string_preview() ) {
|
||||
$str_pos_mapper->insert( $string_id, $position, $kind );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function add_stat( $text ) {
|
||||
$this->scan_stats[] = $text;
|
||||
}
|
||||
|
||||
protected function get_scan_stats() {
|
||||
return $this->scan_stats;
|
||||
}
|
||||
|
||||
protected function add_scanned_file( $file ) {
|
||||
$this->scanned_files[] = $this->format_path_for_display( $file );
|
||||
}
|
||||
|
||||
protected function get_scanned_files() {
|
||||
return $this->scanned_files;
|
||||
}
|
||||
|
||||
protected function cleanup_wrong_contexts() {
|
||||
global $wpdb;
|
||||
|
||||
$old_context = $this->get_old_context();
|
||||
|
||||
/** @var array $results */
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT id, name, value
|
||||
FROM {$wpdb->prefix}icl_strings
|
||||
WHERE context = %s",
|
||||
$old_context
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $results as $string ) {
|
||||
// See if the string has no translations
|
||||
|
||||
/** @var array $old_translations */
|
||||
$old_translations = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT id, language, status, value
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE string_id = %d",
|
||||
$string->id
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! $old_translations ) {
|
||||
// We don't have any translations so we can delete the string.
|
||||
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_strings', array( 'id' => $string->id ), array( '%d' ) );
|
||||
} else {
|
||||
// check if we have a new string in the right context
|
||||
|
||||
$domains = $this->get_domains_found();
|
||||
|
||||
foreach ( $domains as $domain => $count ) {
|
||||
$new_string_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT id
|
||||
FROM {$wpdb->prefix}icl_strings
|
||||
WHERE context = %s AND name = %s AND value = %s",
|
||||
$domain,
|
||||
$string->name,
|
||||
$string->value
|
||||
)
|
||||
);
|
||||
|
||||
if ( $new_string_id ) {
|
||||
|
||||
// See if it has the same translations
|
||||
|
||||
/** @var array $new_translations */
|
||||
$new_translations = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT id, language, status, value
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE string_id = %d",
|
||||
$new_string_id
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $new_translations as $new_translation ) {
|
||||
foreach ( $old_translations as $index => $old_translation ) {
|
||||
if ( $new_translation->language == $old_translation->language &&
|
||||
$new_translation->status == $old_translation->status &&
|
||||
$new_translation->value == $old_translation->value ) {
|
||||
unset( $old_translations[ $index ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! $old_translations ) {
|
||||
// We don't have any old translations that are not in the new strings so we can delete the string.
|
||||
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_strings', array( 'id' => $string->id ), array( '%d' ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename the context for any strings that are in the old context
|
||||
// This way the update message will no longer show.
|
||||
|
||||
$obsolete_context = str_replace( 'plugin ', '', $old_context );
|
||||
$obsolete_context = str_replace( 'theme ', '', $obsolete_context );
|
||||
$obsolete_context = $obsolete_context . ' (obsolete)';
|
||||
|
||||
$string_update_context = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT id FROM {$wpdb->prefix}icl_strings
|
||||
WHERE context = %s
|
||||
",
|
||||
$old_context
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
if ( $string_update_context ) {
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
UPDATE {$wpdb->prefix}icl_strings
|
||||
SET context = %s
|
||||
WHERE id IN ( " . implode( ',', wp_list_pluck( $string_update_context, 'id' ) ) . ' )
|
||||
',
|
||||
$obsolete_context
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function copy_old_translations( $contexts, $prefix ) {
|
||||
foreach ( $contexts as $context ) {
|
||||
$old_strings = $this->get_strings_by_context( $prefix . ' ' . $context );
|
||||
if ( 0 === count( $old_strings ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$old_translations = $this->get_strings_translations( $old_strings );
|
||||
|
||||
$new_strings = $this->get_strings_by_context( $context );
|
||||
$new_translations = $this->get_strings_translations( $new_strings );
|
||||
|
||||
foreach ( $old_translations as $old_translation ) {
|
||||
// see if we have a new translation.
|
||||
$found = false;
|
||||
foreach ( $new_translations as $new_translation ) {
|
||||
if ( $new_translation->string_id == $old_translation->string_id &&
|
||||
$new_translation->language == $old_translation->language ) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $found ) {
|
||||
// Copy the old translation to the new string.
|
||||
|
||||
// Find the original
|
||||
foreach ( $old_strings as $old_string ) {
|
||||
if ( $old_string->id == $old_translation->string_id ) {
|
||||
// See if we have the same string in the new strings
|
||||
foreach ( $new_strings as $new_string ) {
|
||||
if ( $new_string->value == $old_string->value ) {
|
||||
// Add the old translation to new string.
|
||||
icl_add_string_translation( $new_string->id, $old_translation->language, $old_translation->value, ICL_TM_COMPLETE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_strings_by_context( $context ) {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT id, name, value
|
||||
FROM {$wpdb->prefix}icl_strings
|
||||
WHERE context = %s",
|
||||
$context
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $strings
|
||||
*
|
||||
* @return array<\stdClass>
|
||||
*/
|
||||
private function get_strings_translations( $strings ) {
|
||||
global $wpdb;
|
||||
|
||||
$translations = array();
|
||||
|
||||
if ( count( $strings ) ) {
|
||||
foreach ( array_chunk( $strings, 100 ) as $chunk ) {
|
||||
$ids = array();
|
||||
foreach ( $chunk as $string ) {
|
||||
$ids[] = $string->id;
|
||||
}
|
||||
$ids = implode( ',', $ids );
|
||||
|
||||
$rows = $wpdb->get_results(
|
||||
"
|
||||
SELECT id, string_id, language, status, value
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE string_id IN ({$ids})"
|
||||
);
|
||||
|
||||
$translations = array_merge( $translations, $rows );
|
||||
}
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
protected function remove_notice( $notice_id ) {
|
||||
global $wpml_st_admin_notices;
|
||||
if ( isset( $wpml_st_admin_notices ) ) {
|
||||
/** @var WPML_ST_Themes_And_Plugins_Updates $wpml_st_admin_notices */
|
||||
$wpml_st_admin_notices->remove_notice( $notice_id );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return WPML_ST_DB_Mappers_Strings
|
||||
*/
|
||||
public function get_strings_mapper() {
|
||||
if ( null === $this->strings_mapper ) {
|
||||
global $wpdb;
|
||||
$this->strings_mapper = new WPML_ST_DB_Mappers_Strings( $wpdb );
|
||||
}
|
||||
|
||||
return $this->strings_mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_ST_DB_Mappers_Strings $strings_mapper
|
||||
*/
|
||||
public function set_strings_mapper( WPML_ST_DB_Mappers_Strings $strings_mapper ) {
|
||||
$this->strings_mapper = $strings_mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_ST_DB_Mappers_String_Positions
|
||||
*/
|
||||
public function get_string_positions_mapper() {
|
||||
if ( null === $this->string_positions_mapper ) {
|
||||
global $wpdb;
|
||||
$this->string_positions_mapper = new WPML_ST_DB_Mappers_String_Positions( $wpdb );
|
||||
}
|
||||
|
||||
return $this->string_positions_mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_ST_DB_Mappers_String_Positions $string_positions_mapper
|
||||
*/
|
||||
public function set_string_positions_mapper( WPML_ST_DB_Mappers_String_Positions $string_positions_mapper ) {
|
||||
$this->string_positions_mapper = $string_positions_mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_File_Name_Converter
|
||||
*/
|
||||
public function get_file_name_converter() {
|
||||
if ( null === $this->file_name_converter ) {
|
||||
$this->file_name_converter = new WPML_File_Name_Converter();
|
||||
}
|
||||
|
||||
return $this->file_name_converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_File_Name_Converter $converter
|
||||
*/
|
||||
public function set_file_name_converter( WPML_File_Name_Converter $converter ) {
|
||||
$this->file_name_converter = $converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_File
|
||||
*/
|
||||
protected function get_wpml_file() {
|
||||
if ( ! $this->wpml_file ) {
|
||||
$this->wpml_file = new WPML_File();
|
||||
}
|
||||
|
||||
return $this->wpml_file;
|
||||
}
|
||||
|
||||
private function is_string_preview() {
|
||||
$is_string_preview = false;
|
||||
if ( array_key_exists( 'icl_string_track_value', $_GET ) || array_key_exists( 'icl_string_track_context', $_GET ) ) {
|
||||
$is_string_preview = true;
|
||||
}
|
||||
|
||||
return $is_string_preview;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
protected function scan_php_and_mo_files() {
|
||||
return array_key_exists( 'scan_mo_files', $_POST );
|
||||
}
|
||||
|
||||
protected function scan_only_mo_files() {
|
||||
return array_key_exists( 'scan_only_mo_files', $_POST );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function format_path_for_display( $path ) {
|
||||
$path = stripslashes( $path );
|
||||
$path = $this->get_wpml_file()->get_relative_path( $path );
|
||||
$path = $this->get_wpml_file()->fix_dir_separator( $path );
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
class WPML_Theme_String_Scanner extends WPML_String_Scanner implements IWPML_ST_String_Scanner {
|
||||
|
||||
public function scan() {
|
||||
$this->current_type = 'theme';
|
||||
$this->scan_starting( $this->current_type );
|
||||
$theme_info = wp_get_theme();
|
||||
$text_domain = $theme_info->get( 'TextDomain' );
|
||||
$current_theme_name = array_key_exists( 'theme', $_POST ) ? $_POST['theme'] : '';
|
||||
$this->current_path = $current_theme_name ? get_theme_root() . '/' . $current_theme_name : '';
|
||||
$current_theme = wp_get_theme( $current_theme_name );
|
||||
$this->text_domain = $current_theme->get( 'TextDomain' );
|
||||
$this->init_text_domain( $text_domain );
|
||||
$this->scan_theme_files();
|
||||
$this->set_stats( 'theme_localization_domains', $current_theme_name );
|
||||
|
||||
if ( $theme_info && ! is_wp_error( $theme_info ) ) {
|
||||
$this->remove_notice( $theme_info->get( 'Name' ) );
|
||||
}
|
||||
|
||||
$this->scan_response();
|
||||
}
|
||||
|
||||
private function scan_theme_files() {
|
||||
require_once WPML_ST_PATH . '/inc/potx.php';
|
||||
|
||||
if ( array_key_exists( 'files', $_POST ) ) {
|
||||
|
||||
foreach ( $_POST['files'] as $file ) {
|
||||
$file = filter_var( $file, FILTER_SANITIZE_STRING );
|
||||
if ( $this->file_hashing->hash_changed( $file ) ) {
|
||||
|
||||
$this->add_stat( sprintf( __( 'Scanning file: %s', 'wpml-string-translation' ), $file ) );
|
||||
$this->add_scanned_file( $file );
|
||||
_potx_process_file( $file, 0, array( $this, 'store_results' ), '_potx_save_version', $this->get_default_domain() );
|
||||
|
||||
} else {
|
||||
$this->add_stat( sprintf( __( 'Skipping file: %s', 'wpml-string-translation' ), $file ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
wp-content/plugins/wpml-string-translation/inc/lang-map.csv
Normal file
106
wp-content/plugins/wpml-string-translation/inc/lang-map.csv
Normal file
@@ -0,0 +1,106 @@
|
||||
an,an
|
||||
ar,ar
|
||||
az,az
|
||||
az_TR,az-tr
|
||||
bg_BG,bg
|
||||
bn_BD,bn
|
||||
bs_BA,bs
|
||||
ca,ca
|
||||
ckb,ckb
|
||||
co,co
|
||||
cs_CZ,cs
|
||||
cy,cy
|
||||
da_DK,da
|
||||
de_DE,de
|
||||
de_CH,de
|
||||
dv,dv
|
||||
el,el
|
||||
en_CA,en-ca
|
||||
en_GB,en-gb
|
||||
eo,eo
|
||||
es_CL,es-cl
|
||||
es_ES,es
|
||||
es_PE,es-pe
|
||||
es_VE,es-ve
|
||||
et,et
|
||||
eu,eu
|
||||
fa_AF,fa-af
|
||||
fa_IR,fa
|
||||
fi,fi
|
||||
fo,fo
|
||||
fr_FR,fr
|
||||
fy,fy
|
||||
ga,ga
|
||||
gd,gd
|
||||
gl_ES,gl
|
||||
gu,gu
|
||||
haw_U,haw
|
||||
he_IL,he
|
||||
hi_IN,hi
|
||||
hr,hr
|
||||
hu_HU,hu
|
||||
hy,hy
|
||||
id_ID,id
|
||||
is_IS,is
|
||||
it_IT,it
|
||||
ja,ja
|
||||
jv_ID,jv
|
||||
ka_GE,ka
|
||||
kea,kea
|
||||
kk,kk
|
||||
kn,kn
|
||||
ko_KR,ko
|
||||
ku,ku
|
||||
ky_KY,ky
|
||||
la,la
|
||||
li,li
|
||||
lo,lo
|
||||
lt,lt
|
||||
lv,lv
|
||||
me_ME,me
|
||||
mg_MG,mg
|
||||
mk_MK,mk
|
||||
ml_IN,ml
|
||||
mn,mn
|
||||
mr,mr
|
||||
ms_MY,ms
|
||||
my_MM,mya
|
||||
nb_NO,nb
|
||||
ne_NP,ne
|
||||
nl,nl
|
||||
nl_BE,nl
|
||||
nl_NL,nl
|
||||
nn_NO,nn
|
||||
os,os
|
||||
pa_IN,pa
|
||||
pl_PL,pl
|
||||
pt_BR,pt-br
|
||||
pt_PT,pt
|
||||
ro_RO,ro
|
||||
ru_RU,ru
|
||||
ru_UA,ru-ua
|
||||
sa_IN,sa-in
|
||||
si_LK,si
|
||||
sk_SK,sk
|
||||
sl_SI,sl
|
||||
so_SO,so
|
||||
sq,sq
|
||||
sr_RS,sr
|
||||
srd,srd
|
||||
su_ID,su
|
||||
sv_SE,sv
|
||||
sw,sw
|
||||
ta_IN,ta
|
||||
ta_LK,ta-lk
|
||||
te,te
|
||||
tg,tg
|
||||
th,th
|
||||
tl,tl
|
||||
tr,tr
|
||||
ug_CN,ug
|
||||
uk,uk
|
||||
ur,ur
|
||||
uz_UZ,uz
|
||||
vi,vi
|
||||
zh_CN,zh-cn
|
||||
zh_TW,zh-tw
|
||||
|
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_Admin_Lang_Switcher {
|
||||
|
||||
private $package;
|
||||
private $args;
|
||||
|
||||
public function __construct( $package, $args ) {
|
||||
$this->package = new WPML_Package( $package );
|
||||
$this->args = $args;
|
||||
add_action( 'wp_before_admin_bar_render', array( $this, 'admin_language_switcher' ) );
|
||||
add_action( 'wp_after_admin_bar_render', array( $this, 'add_meta_box' ) );
|
||||
}
|
||||
|
||||
function admin_language_switcher() {
|
||||
global $wp_admin_bar, $wpdb, $sitepress;
|
||||
|
||||
$parent = 'WPML_PACKAGE_LANG';
|
||||
|
||||
$package_language = $this->package->get_package_language();
|
||||
if ( ! $package_language ) {
|
||||
$package_language = $sitepress->get_default_language();
|
||||
}
|
||||
|
||||
$wpml_pt_meta = new WPML_Package_Translation_Metabox( $this->package, $wpdb, $sitepress, $this->args );
|
||||
$package_language_name = $wpml_pt_meta->get_package_language_name();
|
||||
$wp_admin_bar->add_menu(
|
||||
array(
|
||||
'parent' => false,
|
||||
'id' => $parent,
|
||||
'title' => '<img width="18" height="12" src="' . $sitepress->get_flag_url( $package_language ) . '"> ' . $package_language_name,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function add_meta_box() {
|
||||
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$metabox = '<div id="wpml-package-admin-bar-popup" class="wpml-package-popup">';
|
||||
|
||||
$wpml_pt_meta = new WPML_Package_Translation_Metabox( $this->package, $wpdb, $sitepress, $this->args );
|
||||
$metabox .= $wpml_pt_meta->get_metabox();
|
||||
|
||||
$metabox .= '</div>';
|
||||
|
||||
$metabox .= $this->add_js();
|
||||
|
||||
// This is required when a new package is created but it doesn't have any translated content yet.
|
||||
// https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlst-556
|
||||
WPML_Simple_Language_Selector::enqueue_scripts();
|
||||
|
||||
wp_enqueue_style( 'wpml-package-adminbar-popup', WPML_ST_URL . '/res/css/wpml-package-adminbar-popup.css', array(), ICL_SITEPRESS_VERSION );
|
||||
|
||||
echo $metabox;
|
||||
}
|
||||
|
||||
function add_js() {
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
|
||||
<script type="text/javascript">
|
||||
var WPML_Package_Translation = WPML_Package_Translation || {};
|
||||
|
||||
WPML_Package_Translation.AdminLanguageSwitcher = function () {
|
||||
var self = this;
|
||||
|
||||
self.init = function () {
|
||||
self.link = jQuery('#wp-admin-bar-WPML_PACKAGE_LANG').find('.ab-item');
|
||||
self.link.hover(self.show_lang_box, self.hide_lang_box);
|
||||
self.popup = jQuery('#wpml-package-admin-bar-popup');
|
||||
self.popup.css('left', self.link.offset().left);
|
||||
self.popup.hover(self.show_lang_box, self.hide_on_leave);
|
||||
|
||||
jQuery('#icl_package_language').off('wpml-package-language-changed');
|
||||
jQuery('#icl_package_language').on('wpml-package-language-changed', self.package_language_changed);
|
||||
};
|
||||
|
||||
self.show_lang_box = function() {
|
||||
self.popup.css('top', self.link.offset().top + self.link.height() - window.scrollTop);
|
||||
self.popup.show();
|
||||
};
|
||||
|
||||
self.hide_lang_box = function() {
|
||||
self.popup.hide();
|
||||
};
|
||||
|
||||
self.hide_on_leave = function(e) {
|
||||
// Make sure we are fully leaving the popup because this is sometimes
|
||||
// triggered when we open the language select and then move the mouse.
|
||||
var x = e.clientX;
|
||||
var y = e.clientY;
|
||||
var pos = self.popup.offset();
|
||||
if ( x < pos.left || x > pos.left + self.popup.width() || y < pos.top || y > pos.top + self.popup.height()) {
|
||||
self.popup.fadeOut(800);
|
||||
}
|
||||
};
|
||||
|
||||
self.package_language_changed = function( e, lang ) {
|
||||
self.link.html( self.find_flag(lang) + ' ' + lang);
|
||||
self.popup.hide();
|
||||
};
|
||||
|
||||
self.find_flag = function( lang ) {
|
||||
var flag = '';
|
||||
jQuery('.js-simple-lang-selector option').each( function() {
|
||||
if (jQuery(this).text().trim() == lang.trim()) {
|
||||
flag = '<img width="18" height="12" src="' + jQuery(this).data('flag_url') + '">';
|
||||
}
|
||||
|
||||
});
|
||||
return flag;
|
||||
};
|
||||
self.init();
|
||||
};
|
||||
|
||||
jQuery(document).ready(
|
||||
function () {
|
||||
WPML_Package_Translation.admin_language_switcher = new WPML_Package_Translation.AdminLanguageSwitcher();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
define( 'LINE', 0 );
|
||||
define( 'AREA', 1 );
|
||||
define( 'VISUAL', 2 );
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
class WPML_ST_Package_Factory {
|
||||
|
||||
/** @var WPML_WP_Cache_Factory $cache_factory */
|
||||
private $cache_factory;
|
||||
|
||||
public function __construct( WPML_WP_Cache_Factory $cache_factory = null ) {
|
||||
$this->cache_factory = $cache_factory;
|
||||
wp_cache_add_non_persistent_groups( __CLASS__ );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass|\WPML_Package|array|int $package_data
|
||||
*
|
||||
* @return WPML_Package
|
||||
*/
|
||||
public function create( $package_data ) {
|
||||
$cache_item = $this->get_cache_item( $package_data );
|
||||
|
||||
if ( ! $cache_item->exists() ) {
|
||||
$cache_item->set( new WPML_Package( $package_data ) );
|
||||
}
|
||||
|
||||
return $cache_item->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|WPML_Package $package_data
|
||||
*
|
||||
* @return WPML_WP_Cache_Item
|
||||
*/
|
||||
private function get_cache_item( $package_data ) {
|
||||
if ( ! $this->cache_factory ) {
|
||||
$this->cache_factory = new WPML_WP_Cache_Factory();
|
||||
}
|
||||
|
||||
$package_key = md5( json_encode( $package_data ) );
|
||||
|
||||
return $this->cache_factory->create_cache_item( __CLASS__, $package_key );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
class WPML_Package_Exception extends Exception {
|
||||
public $type;
|
||||
|
||||
public function __construct( $type = '', $message = '', $code = 0 ) {
|
||||
parent::__construct( $message, $code );
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,720 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_Helper {
|
||||
const PREFIX_BATCH_STRING = 'batch-string-';
|
||||
|
||||
private $default_language;
|
||||
private $last_registered_string_id;
|
||||
protected $registered_strings;
|
||||
private $package_cleanup;
|
||||
private $package_factory;
|
||||
|
||||
private $cache_group;
|
||||
|
||||
function __construct() {
|
||||
$this->registered_strings = array();
|
||||
$this->cache_group = 'string_package';
|
||||
$this->package_cleanup = new WPML_ST_Package_Cleanup();
|
||||
$this->package_factory = new WPML_ST_Package_Factory();
|
||||
}
|
||||
|
||||
public function set_package_factory( WPML_ST_Package_Factory $factory ) {
|
||||
$this->package_factory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
*/
|
||||
protected function delete_package( $package_id ) {
|
||||
// delete the strings and the translations
|
||||
|
||||
$this->delete_package_strings( $package_id );
|
||||
|
||||
$tm = new WPML_Package_TM( $this->package_factory->create( $package_id ) );
|
||||
$tm->delete_translation_jobs();
|
||||
$tm->delete_translations();
|
||||
|
||||
global $wpdb;
|
||||
$delete_query = "DELETE FROM {$wpdb->prefix}icl_string_packages WHERE id=%d";
|
||||
$delete_prepare = $wpdb->prepare( $delete_query, $package_id );
|
||||
$wpdb->query( $delete_prepare );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_strings_ids_from_package_id( $package_id ) {
|
||||
global $wpdb;
|
||||
$string_ids_query = "SELECT id FROM {$wpdb->prefix}icl_strings WHERE string_package_id=%d";
|
||||
$string_ids_prepare = $wpdb->prepare( $string_ids_query, $package_id );
|
||||
$string_ids = $wpdb->get_col( $string_ids_prepare );
|
||||
|
||||
return $string_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
*/
|
||||
protected function delete_package_strings( $package_id ) {
|
||||
$strings = $this->get_strings_ids_from_package_id( $package_id );
|
||||
|
||||
foreach ( $strings as $string_id ) {
|
||||
do_action( 'wpml_st_delete_all_string_data', $string_id );
|
||||
}
|
||||
}
|
||||
|
||||
protected function loaded() {
|
||||
$this->default_language = icl_get_default_language();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string_value
|
||||
* @param string $string_name
|
||||
* @param array|WPML_Package $package
|
||||
* @param string $string_title
|
||||
* @param string $string_type
|
||||
*/
|
||||
final function register_string_action( $string_value, $string_name, $package, $string_title, $string_type ) {
|
||||
$this->register_string_for_translation( $string_value, $string_name, $package, $string_title, $string_type );
|
||||
|
||||
return $this->last_registered_string_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $default
|
||||
* @param \stdClass|\WPML_Package|array|int $package
|
||||
* @param string $string_name
|
||||
* @param string $string_value
|
||||
*
|
||||
* @return bool|int|mixed
|
||||
*/
|
||||
function string_id_from_package_filter( $default, $package, $string_name, $string_value ) {
|
||||
$string_id = $this->get_string_id_from_package( $package, $string_name, $string_value );
|
||||
if ( ! $string_id ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $string_id;
|
||||
}
|
||||
|
||||
function string_title_from_id_filter( $default, $string_id ) {
|
||||
global $wpdb;
|
||||
$string_title_query = 'SELECT title FROM ' . $wpdb->prefix . 'icl_strings WHERE id=%d';
|
||||
$string_title_sql = $wpdb->prepare( $string_title_query, array( $string_id ) );
|
||||
|
||||
$string_title = $wpdb->get_var( $string_title_sql );
|
||||
|
||||
if ( ! $string_title ) {
|
||||
$string_title = $default;
|
||||
}
|
||||
|
||||
return $string_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string_value
|
||||
* @param string $string_name
|
||||
* @param array|WPML_Package $package
|
||||
* @param string $string_title
|
||||
* @param string $string_type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final public function register_string_for_translation( $string_value, $string_name, $package, $string_title, $string_type ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
$package_id = $package->ID;
|
||||
if ( ! $package_id ) {
|
||||
|
||||
// Need to create a new record.
|
||||
if ( $package->has_kind_and_name() ) {
|
||||
$package_id = self::create_new_package( $package );
|
||||
$package = $this->package_factory->create( $package );
|
||||
}
|
||||
}
|
||||
if ( $package_id ) {
|
||||
$this->maybe_update_package( $package );
|
||||
$tm = new WPML_Package_TM( $package );
|
||||
$tm->validate_translations();
|
||||
|
||||
$this->init_package_registered_strings( $package_id );
|
||||
|
||||
$string_name = $package->sanitize_string_name( $string_name );
|
||||
|
||||
$this->set_package_registered_strings( $package_id, $string_type, $string_title, $string_name, $string_value );
|
||||
$this->last_registered_string_id = $this->register_string_with_wpml( $package, $string_name, $string_title, $string_type, $string_value );
|
||||
$this->package_cleanup->record_register_string( $package, $this->last_registered_string_id );
|
||||
}
|
||||
|
||||
return $string_value;
|
||||
}
|
||||
|
||||
final function get_string_context_from_package( $package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
|
||||
return $package->get_string_context_from_package();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Package $package
|
||||
* @param string $string_name
|
||||
* @param string $string_title
|
||||
* @param string $string_type
|
||||
* @param string $string_value
|
||||
*
|
||||
* @return bool|int|mixed
|
||||
*/
|
||||
final function register_string_with_wpml( $package, $string_name, $string_title, $string_type, $string_value ) {
|
||||
global $wpdb;
|
||||
|
||||
$string_id = $this->get_string_id_from_package( $package, $string_name, $string_value );
|
||||
|
||||
if ( $string_id ) {
|
||||
$package_storage = new WPML_ST_Package_Storage( $package->ID, $wpdb );
|
||||
$did_update = $package_storage->update( $string_title, $string_type, $string_value, $string_id );
|
||||
|
||||
if ( $did_update ) {
|
||||
$this->flush_cache();
|
||||
$package->flush_cache();
|
||||
}
|
||||
}
|
||||
|
||||
return $string_id;
|
||||
}
|
||||
|
||||
final function translate_string( $string_value, $string_name, $package ) {
|
||||
$result = $string_value;
|
||||
|
||||
if ( is_string( $string_value ) ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
|
||||
if ( $package ) {
|
||||
$sanitized_string_name = $package->sanitize_string_name( $string_name );
|
||||
|
||||
$result = $package->translate_string( $string_value, $sanitized_string_name );
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
final function get_translated_strings( $strings, $package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
|
||||
return $package->get_translated_strings( $strings );
|
||||
}
|
||||
|
||||
final function set_translated_strings( $translations, $package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
$package->set_translated_strings( $translations );
|
||||
}
|
||||
|
||||
final function get_translatable_types( $types ) {
|
||||
global $wpdb;
|
||||
|
||||
$package_kinds = $wpdb->get_results( "SELECT kind, kind_slug FROM {$wpdb->prefix}icl_string_packages WHERE id>0" );
|
||||
|
||||
// Add any packages found to the $types array
|
||||
foreach ( $package_kinds as $package_data ) {
|
||||
$package_kind_slug = $package_data->kind_slug;
|
||||
$package_kind = $package_data->kind;
|
||||
$kinds_added = array_keys( $types );
|
||||
if ( ! in_array( $package_kind_slug, $kinds_added ) ) {
|
||||
$translatable_type = new stdClass();
|
||||
$translatable_type->name = $package_kind_slug;
|
||||
$translatable_type->label = $package_kind;
|
||||
$translatable_type->prefix = 'package';
|
||||
$translatable_type->labels = new stdClass();
|
||||
$translatable_type->labels->singular_name = $package_kind;
|
||||
$translatable_type->labels->name = $package_kind;
|
||||
$translatable_type->external_type = 1;
|
||||
$types[ $package_kind_slug ] = $translatable_type;
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Package $item
|
||||
* @param int|WP_Post|WPML_Package $package
|
||||
* @param string $type
|
||||
*
|
||||
* @return bool|WPML_Package
|
||||
*/
|
||||
final public function get_translatable_item( $item, $package, $type = 'package' ) {
|
||||
if ( $type === 'package' || explode( '_', $type )[0] === 'package' ) {
|
||||
$tm = new WPML_Package_TM( $item );
|
||||
|
||||
return $tm->get_translatable_item( $package );
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
final function get_post_title( $title, $package_id ) {
|
||||
$package = $this->package_factory->create( $package_id );
|
||||
if ( $package ) {
|
||||
$title = $package->kind . ' - ' . $package->title;
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
final function get_editor_string_name( $name, $package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
$package_id = $package->ID;
|
||||
$title = $this->get_editor_string_element( $name, $package_id, 'title' );
|
||||
if ( $title && $title != '' ) {
|
||||
$name = $title;
|
||||
} elseif (
|
||||
\WPML\FP\Str::includes( self::PREFIX_BATCH_STRING, $name )
|
||||
&& ( $string = $this->get_st_string_by_batch_name( $name ) )
|
||||
) {
|
||||
$name = $this->empty_if_md5( $string->get_name() )
|
||||
?: ( $string->get_gettext_context() ?: ( $string->get_context() ?: $name ) );
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
private function empty_if_md5( $str ) {
|
||||
return preg_replace( '#^((.+)( - ))?([a-z0-9]{32})$#', '$2', $str );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $batch_string_name
|
||||
*
|
||||
* @return WPML_ST_String|null
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
private function get_st_string_by_batch_name( $batch_string_name ) {
|
||||
$string_id = (int) \WPML\FP\Str::replace( self::PREFIX_BATCH_STRING, '', $batch_string_name );
|
||||
if ( $string_id ) {
|
||||
$string_factory = WPML\Container\make( WPML_ST_String_Factory::class );
|
||||
|
||||
return $string_factory->find_by_id( $string_id );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
final function get_editor_string_style( $style, $field_type, $package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
$package_id = $package->ID;
|
||||
$element_style = $this->get_editor_string_element( $field_type, $package_id, 'type' );
|
||||
if ( $element_style ) {
|
||||
$style = 0;
|
||||
if ( defined( $element_style ) ) {
|
||||
$style = constant( $element_style );
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
final public function get_element_id_from_package_filter( $default, $package_id ) {
|
||||
global $wpdb;
|
||||
$element_id_query = 'SELECT name FROM ' . $wpdb->prefix . 'icl_string_packages WHERE ID=%d';
|
||||
$element_id_prepare = $wpdb->prepare( $element_id_query, $package_id );
|
||||
$element_id = $wpdb->get_var( $element_id_prepare );
|
||||
if ( ! $element_id ) {
|
||||
$element_id = $default;
|
||||
}
|
||||
|
||||
return $element_id;
|
||||
}
|
||||
|
||||
final public function get_package_type( $type, $post_id ) {
|
||||
$package = $this->package_factory->create( $post_id );
|
||||
if ( $package ) {
|
||||
return $this->get_package_context( $package );
|
||||
} else {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
final public function get_package_type_prefix( $type, $post_id ) {
|
||||
if ( $type == 'package' ) {
|
||||
$package = $this->package_factory->create( $post_id );
|
||||
if ( $package ) {
|
||||
$type = $package->get_string_context_from_package();
|
||||
}
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $language_for_element
|
||||
* @param \WPML_Package $current_document
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
final public function get_language_for_element( $language_for_element, $current_document ) {
|
||||
if ( $this->is_a_package( $current_document ) ) {
|
||||
global $sitepress;
|
||||
$language_for_element = $sitepress->get_language_for_element( $current_document->ID, $current_document->get_translation_element_type() );
|
||||
}
|
||||
|
||||
return $language_for_element;
|
||||
}
|
||||
|
||||
final protected function get_package_context( $package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
|
||||
return $package->kind_slug . '-' . $package->name;
|
||||
}
|
||||
|
||||
final function delete_packages_ajax() {
|
||||
if ( ! $this->verify_ajax_call( 'wpml_package_nonce' ) ) {
|
||||
die( 'verification failed' );
|
||||
}
|
||||
$packages_ids = $_POST['packages'];
|
||||
|
||||
$this->delete_packages( $packages_ids );
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
final function delete_package_action( $name, $kind ) {
|
||||
$package_data['name'] = $name;
|
||||
$package_data['kind'] = $kind;
|
||||
|
||||
$package = $this->package_factory->create( $package_data );
|
||||
if ( $package && $package->ID && $this->is_a_package( $package ) ) {
|
||||
$this->delete_package( $package->ID );
|
||||
$this->flush_cache();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param int $post_id */
|
||||
final public function remove_post_packages( $post_id ) {
|
||||
$packages = $this->get_post_string_packages( array(), $post_id );
|
||||
|
||||
foreach ( $packages as $package ) {
|
||||
$this->delete_package( $package->ID );
|
||||
}
|
||||
}
|
||||
|
||||
final protected function delete_packages( $packages_ids ) {
|
||||
$flush_cache = false;
|
||||
|
||||
foreach ( $packages_ids as $package_id ) {
|
||||
$this->delete_package( $package_id );
|
||||
|
||||
$flush_cache = true;
|
||||
}
|
||||
if ( $flush_cache ) {
|
||||
$this->flush_cache();
|
||||
}
|
||||
}
|
||||
|
||||
final function change_package_lang_ajax() {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
if ( ! $this->verify_ajax_call( 'wpml_package_nonce' ) ) {
|
||||
die( 'verification failed' );
|
||||
}
|
||||
|
||||
$package_id = $_POST['package_id'];
|
||||
|
||||
$package = $this->package_factory->create( $package_id );
|
||||
$package->set_strings_language( $_POST['package_lang'] );
|
||||
|
||||
$package_job = new WPML_Package_TM( $package );
|
||||
$package_job->set_language_details( $_POST['package_lang'] );
|
||||
|
||||
$args = filter_var_array( json_decode( base64_decode( $_POST['args'] ) ), FILTER_SANITIZE_STRING );
|
||||
|
||||
$package_metabox = new WPML_Package_Translation_Metabox( $package, $wpdb, $sitepress, $args );
|
||||
$response = array(
|
||||
'metabox' => $package_metabox->get_metabox_status(),
|
||||
'lang' => $package_metabox->get_package_language_name(),
|
||||
);
|
||||
|
||||
wp_send_json( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string_name
|
||||
* @param int $package_id
|
||||
* @param string $column
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_editor_string_element( $string_name, $package_id, $column ) {
|
||||
global $wpdb;
|
||||
|
||||
$element_query = 'SELECT ' . $column . "
|
||||
FROM {$wpdb->prefix}icl_strings
|
||||
WHERE string_package_id=%d AND name=%s";
|
||||
$element_prepared = $wpdb->prepare( $element_query, array( $package_id, $string_name ) );
|
||||
$element = $wpdb->get_var( $element_prepared );
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
private function flush_cache() {
|
||||
// delete the cache key we use
|
||||
wp_cache_delete( 'get_all_packages', $this->cache_group );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Package $package
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
final public static function create_new_package( WPML_Package $package ) {
|
||||
$package_id = $package->create_new_package_record();
|
||||
|
||||
$tm = new WPML_Package_TM( $package );
|
||||
|
||||
$tm->update_package_translations( true );
|
||||
|
||||
return (int) $package_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
*/
|
||||
private function init_package_registered_strings( $package_id ) {
|
||||
if ( ! isset( $this->registered_strings[ $package_id ] ) ) {
|
||||
$this->registered_strings[ $package_id ] = array( 'strings' => array() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
* @param string $string_type
|
||||
* @param string $string_title
|
||||
* @param string $string_name
|
||||
* @param string $string_value
|
||||
*/
|
||||
private function set_package_registered_strings( $package_id, $string_type, $string_title, $string_name, $string_value ) {
|
||||
$this->registered_strings[ $package_id ]['strings'][ $string_name ] = array(
|
||||
'title' => $string_title,
|
||||
'kind' => $string_type,
|
||||
'value' => $string_value,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass|\WPML_Package|array|int $package
|
||||
* @param string $string_name
|
||||
* @param string $string_value
|
||||
*
|
||||
* @return bool|int|mixed
|
||||
*/
|
||||
private function get_string_id_from_package( $package, $string_name, $string_value ) {
|
||||
if ( ! $package instanceof WPML_Package ) {
|
||||
$package = $this->package_factory->create( $package );
|
||||
}
|
||||
|
||||
return $package->get_string_id_from_package( $string_name, $string_value );
|
||||
}
|
||||
|
||||
final function get_external_id_from_package( $package ) {
|
||||
return 'external_' . $package['kind_slug'] . '_' . $package['ID'];
|
||||
}
|
||||
|
||||
final function get_string_context( $package ) {
|
||||
return sanitize_title_with_dashes( $package['kind_slug'] . '-' . $package['name'] );
|
||||
}
|
||||
|
||||
final function get_package_id( $package, $from_cache = true ) {
|
||||
global $wpdb;
|
||||
static $cache = array();
|
||||
|
||||
if ( $this->is_a_package( $package ) ) {
|
||||
$package = object_to_array( $package );
|
||||
}
|
||||
|
||||
$key = $this->get_string_context( $package );
|
||||
if ( ! $from_cache || ! array_key_exists( $key, $cache ) ) {
|
||||
$package_id_query = "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE kind_slug = %s AND name = %s";
|
||||
$package_id_prepare = $wpdb->prepare( $package_id_query, array( $package['kind_slug'], $package['name'] ) );
|
||||
$package_id = $wpdb->get_var( $package_id_prepare );
|
||||
if ( ! $package_id ) {
|
||||
return false;
|
||||
}
|
||||
$cache[ $key ] = $package_id;
|
||||
}
|
||||
|
||||
return $cache[ $key ];
|
||||
}
|
||||
|
||||
final public function get_all_packages() {
|
||||
global $wpdb;
|
||||
$cache_key = 'get_all_packages';
|
||||
$cache_found = false;
|
||||
|
||||
$all_packages = wp_cache_get( $cache_key, $this->cache_group, false, $cache_found );
|
||||
|
||||
if ( ! $cache_found ) {
|
||||
$all_packages = array();
|
||||
$all_packages_data_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages";
|
||||
$all_packages_data = $wpdb->get_results( $all_packages_data_query );
|
||||
foreach ( $all_packages_data as $package_data ) {
|
||||
$package = $this->package_factory->create( $package_data );
|
||||
$all_packages[ $package->ID ] = $package;
|
||||
}
|
||||
if ( $all_packages ) {
|
||||
wp_cache_set( $cache_key, $all_packages, $this->cache_group );
|
||||
}
|
||||
}
|
||||
|
||||
return $all_packages;
|
||||
}
|
||||
|
||||
final protected function is_a_package( $element ) {
|
||||
return is_a( $element, 'WPML_Package' );
|
||||
}
|
||||
|
||||
protected function verify_ajax_call( $ajax_action ) {
|
||||
return isset( $_POST['wpnonce'] ) && wp_verify_nonce( $_POST['wpnonce'], $ajax_action );
|
||||
}
|
||||
|
||||
protected function sanitize_string_name( $string_name ) {
|
||||
$string_name = preg_replace( '/[ \[\]]+/', '-', $string_name );
|
||||
|
||||
return $string_name;
|
||||
}
|
||||
|
||||
public function refresh_packages() {
|
||||
|
||||
// TODO: deprecated.
|
||||
// This is required to support Layouts 1.0
|
||||
do_action( 'WPML_register_string_packages', 'layout', array() );
|
||||
// TODO: END deprecated.
|
||||
|
||||
do_action( 'wpml_register_string_packages' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Package $package
|
||||
*/
|
||||
private function maybe_update_package( $package ) {
|
||||
if ( $package->new_title ) {
|
||||
$package->title = $package->new_title;
|
||||
$package->update_package_record();
|
||||
}
|
||||
}
|
||||
|
||||
public function change_language_of_strings( $strings, $lang ) {
|
||||
global $wpdb;
|
||||
|
||||
$all_ok = true;
|
||||
|
||||
$strings_in = implode( ',', $strings );
|
||||
|
||||
$string_packages_query = "SELECT DISTINCT string_package_id FROM {$wpdb->prefix}icl_strings WHERE id IN ($strings_in)";
|
||||
$package_ids = $wpdb->get_col( $string_packages_query );
|
||||
|
||||
foreach ( $package_ids as $package_id ) {
|
||||
if ( $package_id ) {
|
||||
$package = $this->package_factory->create( $package_id );
|
||||
if ( ! $package->are_all_strings_included( $strings ) ) {
|
||||
$all_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $all_ok ) {
|
||||
$this->set_packages_language( $package_ids, $lang );
|
||||
}
|
||||
|
||||
$response = array();
|
||||
$response['success'] = $all_ok;
|
||||
if ( ! $all_ok ) {
|
||||
$response['error'] = __( 'Some of the strings selected belong to packages. You can only change the language of these strings if all strings in the packages are selected.', 'wpml-string-translation' );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function change_language_of_strings_in_domain( $domain, $langs, $to_lang ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! empty( $langs ) ) {
|
||||
foreach ( $langs as &$lang ) {
|
||||
$lang = "'" . $lang . "'";
|
||||
}
|
||||
$langs = implode( ',', $langs );
|
||||
|
||||
$string_packages_query = "SELECT DISTINCT string_package_id FROM {$wpdb->prefix}icl_strings WHERE context='%s' AND language IN ($langs)";
|
||||
$string_packages_query = $wpdb->prepare( $string_packages_query, $domain );
|
||||
$package_ids = $wpdb->get_col( $string_packages_query );
|
||||
|
||||
$this->set_packages_language( $package_ids, $to_lang );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function set_packages_language( $package_ids, $lang ) {
|
||||
foreach ( $package_ids as $package_id ) {
|
||||
if ( $package_id ) {
|
||||
$package = $this->package_factory->create( $package_id );
|
||||
$package->set_strings_language( $lang );
|
||||
|
||||
$package_job = new WPML_Package_TM( $package );
|
||||
$package_job->set_language_details( $lang );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|array $packages
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return WPML_Package[]
|
||||
*/
|
||||
public function get_post_string_packages( $packages, $post_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$query = $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE post_id = %d", $post_id );
|
||||
$package_ids = $wpdb->get_col( $query );
|
||||
|
||||
$packages = $packages ? $packages : array();
|
||||
|
||||
foreach ( $package_ids as $package_id ) {
|
||||
$packages[ $package_id ] = $this->package_factory->create( $package_id );
|
||||
}
|
||||
|
||||
return $packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $string_id
|
||||
* @param string $language
|
||||
* @param string|null $value
|
||||
* @param int|bool $status
|
||||
* @param int|null $translator_id
|
||||
* @param int|null $translation_service
|
||||
* @param int|null $batch_id
|
||||
*/
|
||||
public function add_string_translation_action( $string_id, $language, $value = null, $status = false, $translator_id = null, $translation_service = null, $batch_id = null ) {
|
||||
icl_add_string_translation( $string_id, $language, $value, $status, $translator_id, $translation_service, $batch_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $package
|
||||
* @param int $package_id
|
||||
*
|
||||
* @return WPML_Package
|
||||
*/
|
||||
public function get_string_package( $package, $package_id ) {
|
||||
return $this->package_factory->create( $package_id );
|
||||
}
|
||||
|
||||
public function start_string_package_registration_action( $package ) {
|
||||
$this->package_cleanup->record_existing_strings( $this->package_factory->create( $package ) );
|
||||
}
|
||||
|
||||
public function delete_unused_package_strings_action( $package ) {
|
||||
$this->package_cleanup->delete_unused_strings( $this->package_factory->create( $package ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
class WPML_Package_Translation_HTML_Packages {
|
||||
var $load_priority = 101;
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'WPML_PT_HTML', array( $this, 'loaded' ), $this->load_priority );
|
||||
}
|
||||
|
||||
public function loaded() {
|
||||
$this->set_admin_hooks();
|
||||
}
|
||||
|
||||
private function set_admin_hooks() {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'wpml_pt_package_table_columns', array( $this, 'render_package_table_columns' ), 10, 1 );
|
||||
add_action( 'wpml_pt_package_table_options', array( $this, 'package_translation_menu_options' ), 10, 1 );
|
||||
add_action( 'wpml_pt_package_table_body', array( $this, 'package_translation_menu_body' ), 10, 1 );
|
||||
add_action( 'wpml_pt_package_status', array( $this, 'render_string_package_status' ), 10, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
public static function package_translation_menu() {
|
||||
$packages = apply_filters( 'wpml_pt_all_packages', array() );
|
||||
$package_kinds = array();
|
||||
|
||||
if ( $packages ) {
|
||||
foreach ( $packages as $package ) {
|
||||
$kind_slugs = array_keys( $package_kinds );
|
||||
if ( ! in_array( $package->kind_slug, $kind_slugs ) ) {
|
||||
$package_kinds[ $package->kind_slug ] = $package->kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$table_title = __( 'Package Management', 'wpml-string-translation' );
|
||||
$package_kind_label = __( 'Display packages for this kind:', 'wpml-string-translation' );
|
||||
$package_kind_options[- 1] = __( 'Display packages for this kind:', 'wpml-string-translation' );
|
||||
foreach ( $package_kinds as $kind_slug => $kind ) {
|
||||
$package_kind_options[ $kind_slug ] = $kind;
|
||||
}
|
||||
?>
|
||||
<h2><?php echo $table_title; ?></h2>
|
||||
|
||||
<p>
|
||||
<label for="package_kind_filter"><?php echo $package_kind_label; ?></label>
|
||||
<select id="package_kind_filter">
|
||||
<?php do_action( 'wpml_pt_package_table_options', $package_kind_options ); ?>
|
||||
</select>
|
||||
</p>
|
||||
|
||||
<table id="icl_package_translations" class="widefat" cellspacing="0">
|
||||
<thead>
|
||||
<?php do_action( 'wpml_pt_package_table_columns', 'thead' ); ?>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<?php do_action( 'wpml_pt_package_table_columns', 'tfoot' ); ?>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<?php do_action( 'wpml_pt_package_table_body', $packages ); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<input id="delete_packages" type="button" class="button-primary" value="<?php echo __( 'Delete Selected Packages', 'wpml-string-translation' ); ?>" disabled="disabled"/>
|
||||
|
||||
<span class="spinner"></span>
|
||||
<span style="display:none" class="js-delete-confirm-message"><?php echo __( "Are you sure you want to delete these packages?\nTheir strings and translations will be deleted too.", 'wpml-string-translation' ); ?></span>
|
||||
|
||||
<?php
|
||||
wp_nonce_field( 'wpml_package_nonce', 'wpml_package_nonce' );
|
||||
}
|
||||
|
||||
public function package_translation_menu_options( $package_kind_options ) {
|
||||
foreach ( $package_kind_options as $option_value => $option_label ) {
|
||||
?>
|
||||
<option value="<?php echo esc_attr( $option_value ); ?>"><?php echo $option_label; ?></option>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<\WPML_Package> $packages
|
||||
*/
|
||||
public function package_translation_menu_body( $packages ) {
|
||||
if ( ! $packages ) {
|
||||
$this->package_translation_menu_no_packages();
|
||||
} else {
|
||||
$this->package_translation_menu_items( $packages );
|
||||
}
|
||||
}
|
||||
|
||||
public function render_package_table_columns( $position ) {
|
||||
?>
|
||||
<tr>
|
||||
<th scope="col" class="manage-column column-cb check-column">
|
||||
<label for="select_all_package_<?php echo $position; ?>" style="display: none;">
|
||||
<?php _e( 'Select All', 'wpml-string-translation' ); ?>
|
||||
</label>
|
||||
<input id="select_all_package_<?php echo $position; ?>" class="js_package_all_cb" type="checkbox"/>
|
||||
</th>
|
||||
<th scope="col"><?php echo __( 'Kind', 'wpml-string-translation' ); ?></th>
|
||||
<th scope="col"><?php echo __( 'Name', 'wpml-string-translation' ); ?></th>
|
||||
<th scope="col"><?php echo __( 'Info', 'wpml-string-translation' ); ?></th>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_string_package_status( $string_count, $translation_in_progress, $default_package_language ) {
|
||||
$package_statuses[] = sprintf( __( 'Contains %s strings', 'wpml-string-translation' ), $string_count );
|
||||
if ( $translation_in_progress ) {
|
||||
$package_statuses[] = '(' . __( 'Translation is in progress', 'wpml-string-translation' ) . ')';
|
||||
}
|
||||
$package_statuses[] = __( 'Default package language', 'wpml-string-translation' ) . ': ' . $default_package_language;
|
||||
|
||||
echo implode( ' - ', $package_statuses );
|
||||
}
|
||||
|
||||
private function package_translation_menu_no_packages() {
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="6" align="center">
|
||||
<strong><?php echo __( 'No packages found', 'wpml-string-translation' ); ?></strong>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<\WPML_Package> $packages
|
||||
*/
|
||||
private function package_translation_menu_items( $packages ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
foreach ( $packages as $package ) {
|
||||
|
||||
$package_language_code = $package->get_package_language();
|
||||
$package_language = $sitepress->get_display_language_name( $package_language_code );
|
||||
|
||||
$tm = new WPML_Package_TM( $package );
|
||||
|
||||
$translation_in_progress = $tm->is_translation_in_progress();
|
||||
$package_id = $package->ID;
|
||||
$string_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}icl_strings WHERE string_package_id=%d", $package_id ) );
|
||||
|
||||
$disabled = disabled( $translation_in_progress, true, false );
|
||||
?>
|
||||
<tr id="row_<?php echo $package_id; ?>" class="js_package js_package_<?php echo esc_attr( $package->kind_slug ); ?>">
|
||||
<td>
|
||||
<input id="package_<?php echo $package_id; ?>" class="js_package_row_cb" type="checkbox" value="<?php echo $package_id; ?>" <?php echo $disabled; ?>/>
|
||||
</td>
|
||||
<td class="js-package-kind">
|
||||
<?php echo $package->kind; ?>
|
||||
</td>
|
||||
<td>
|
||||
<label for="package_<?php echo $package_id; ?>"><?php echo esc_html( $package->title ); ?></label>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<?php
|
||||
do_action( 'wpml_pt_package_status', $string_count, $translation_in_progress, $package_language );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_Translation_Metabox {
|
||||
private $args;
|
||||
private $active_languages;
|
||||
private $container_attributes_html;
|
||||
private $dashboard_link;
|
||||
private $strings_link;
|
||||
private $default_language;
|
||||
private $main_container_attributes;
|
||||
private $show_description;
|
||||
private $show_link;
|
||||
private $show_status;
|
||||
private $show_title;
|
||||
private $status_container_attributes;
|
||||
private $status_container_attributes_html;
|
||||
private $status_container_tag;
|
||||
private $status_element_tag;
|
||||
private $title_tag;
|
||||
|
||||
public $metabox_data;
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
private $translation_statuses;
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var \WPML_Package
|
||||
*/
|
||||
private $package;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $package_language;
|
||||
|
||||
/**
|
||||
* WPML_Package_Translation_Metabox constructor.
|
||||
*
|
||||
* @param stdClass|WPML_Package|array|int $package
|
||||
* @param \wpdb $wpdb
|
||||
* @param \SitePress $sitepress
|
||||
* @param array<string,mixed> $args
|
||||
*/
|
||||
public function __construct( $package, $wpdb, $sitepress, $args = array() ) {
|
||||
|
||||
$this->wpdb = $wpdb;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->package = new WPML_Package( $package );
|
||||
$this->args = $args;
|
||||
|
||||
if ( $this->got_package() ) {
|
||||
$this->dashboard_link = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=dashboard&type=' . $this->package->kind_slug . '&lang=' . $this->package->get_package_language() );
|
||||
$this->strings_link = admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context=' . $this->package->get_string_context_from_package() );
|
||||
}
|
||||
|
||||
$this->parse_arguments( $args );
|
||||
$this->init_metabox_data();
|
||||
}
|
||||
|
||||
private function init_metabox_data() {
|
||||
$this->metabox_data = array();
|
||||
$this->active_languages = $this->sitepress->get_active_languages();
|
||||
$this->default_language = $this->sitepress->get_default_language();
|
||||
$this->package_language = $this->package->get_package_language();
|
||||
$this->package_language = $this->package_language ? $this->package_language : $this->default_language;
|
||||
|
||||
$this->metabox_data['title'] = __( 'WPML Translation', 'wpml-string-translation' );
|
||||
if ( $this->is_package_language_active() ) {
|
||||
$this->metabox_data['translate_title'] = __( 'Send to translation', 'wpml-string-translation' );
|
||||
} else {
|
||||
$this->metabox_data['translate_title'] = __( 'Translate strings', 'wpml-string-translation' );
|
||||
}
|
||||
|
||||
if ( $this->got_package() ) {
|
||||
$this->metabox_data['statuses_title'] = __( 'Translation status:', 'wpml-string-translation' );
|
||||
$this->init_translation_statuses();
|
||||
$this->metabox_data['package_language_title'] = sprintf( __( 'Language of this %1$s is %2$s', 'wpml-string-translation' ), $this->package->kind, $this->get_lang_selector() );
|
||||
} else {
|
||||
$this->metabox_data['package_language_title'] = '';
|
||||
$this->metabox_data['statuses_title'] = __( 'There is nothing to translate.', 'wpml-string-translation' );
|
||||
}
|
||||
}
|
||||
|
||||
private function get_lang_selector() {
|
||||
|
||||
$disable = $this->check_if_language_change_is_ok() ? '' : 'disabled="disabled" ';
|
||||
|
||||
ob_start();
|
||||
|
||||
$languages = $this->active_languages;
|
||||
if ( ! $this->is_package_language_active() ) {
|
||||
$languages = array_merge( array( $this->sitepress->get_language_details( $this->package_language ) ), $languages );
|
||||
} else {
|
||||
$languages = $this->active_languages;
|
||||
}
|
||||
|
||||
$selector = new WPML_Simple_Language_Selector( $this->sitepress );
|
||||
$selector->render(
|
||||
array(
|
||||
'id' => 'icl_package_language',
|
||||
'name' => 'icl_package_language',
|
||||
'show_please_select' => false,
|
||||
'languages' => $languages,
|
||||
'selected' => $this->package_language,
|
||||
'disabled' => ! $this->check_if_language_change_is_ok(),
|
||||
'echo' => true,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<span class="spinner"></span>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function get_package_language_name() {
|
||||
if ( $this->is_package_language_active() ) {
|
||||
return $this->active_languages[ $this->package_language ]['display_name'];
|
||||
} else {
|
||||
$all_languages = $this->sitepress->get_languages();
|
||||
return $all_languages[ $this->package_language ]['display_name'];
|
||||
}
|
||||
}
|
||||
|
||||
private function get_lang_switcher_js() {
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
|
||||
var WPML_Package_Translation = WPML_Package_Translation || {};
|
||||
|
||||
WPML_Package_Translation.MetaBox = function () {
|
||||
var self = this;
|
||||
|
||||
self.init = function () {
|
||||
jQuery('#icl_package_language').off('change');
|
||||
jQuery('#icl_package_language').on('change', self.switch_lang);
|
||||
};
|
||||
|
||||
self.switch_lang = function() {
|
||||
self.disable_controls(true);
|
||||
var data = {
|
||||
action: 'wpml_change_package_lang',
|
||||
wpnonce: jQuery('#wpml_package_nonce').val(),
|
||||
package_id: jQuery('#wpml_package_id').val(),
|
||||
args: jQuery('#wpml_package_args').val(),
|
||||
package_lang: jQuery(this).val()
|
||||
};
|
||||
|
||||
jQuery.ajax(
|
||||
{
|
||||
url: ajaxurl,
|
||||
type: 'post',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
var position = jQuery('#wpml_package_status').prev();
|
||||
jQuery('#wpml_package_status').remove();
|
||||
jQuery(response.metabox).insertAfter(position);
|
||||
|
||||
jQuery('#icl_package_language').trigger('wpml-package-language-changed', [response.lang]);
|
||||
|
||||
self.disable_controls(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.disable_controls = function(state) {
|
||||
var lang_switcher = jQuery('#icl_package_language');
|
||||
if (state) {
|
||||
lang_switcher.next('.spinner').show();
|
||||
lang_switcher.prop('disabled', true);
|
||||
lang_switcher.closest('div').find('a').prop('disabled', true);
|
||||
} else {
|
||||
lang_switcher.next('.spinner').hide();
|
||||
lang_switcher.prop('disabled', false);
|
||||
lang_switcher.closest('div').find('a').prop('disabled', false);
|
||||
}
|
||||
};
|
||||
|
||||
self.init();
|
||||
};
|
||||
|
||||
jQuery(document).ready(
|
||||
function () {
|
||||
WPML_Package_Translation.meta_box = new WPML_Package_Translation.MetaBox();
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
function get_metabox() {
|
||||
$result = '';
|
||||
$result .= '<div ' . $this->container_attributes_html . '>';
|
||||
if ( $this->show_title ) {
|
||||
if ( $this->title_tag ) {
|
||||
$result .= $this->get_tag( $this->title_tag );
|
||||
}
|
||||
$result .= $this->metabox_data['title'];
|
||||
if ( $this->title_tag ) {
|
||||
$result .= $this->get_tag( $this->title_tag, 'closed' );
|
||||
}
|
||||
}
|
||||
if ( $this->show_description ) {
|
||||
$result .= '<div>' . $this->metabox_data['package_language_title'] . '</div>';
|
||||
}
|
||||
if ( $this->show_status ) {
|
||||
$result .= '<p>' . $this->metabox_data['statuses_title'] . '</p>';
|
||||
}
|
||||
|
||||
$result .= $this->get_metabox_status();
|
||||
|
||||
$result .= '</div>';
|
||||
$result .= wp_nonce_field( 'wpml_package_nonce', 'wpml_package_nonce', true, false );
|
||||
$result .= '<input type="hidden" id="wpml_package_id" value="' . $this->package->ID . '" />';
|
||||
$result .= '<input type="hidden" id="wpml_package_args" value="' . base64_encode( wp_json_encode( $this->args ) ) . '" />';
|
||||
|
||||
if ( ! defined( 'DOING_AJAX' ) ) {
|
||||
$result .= $this->get_lang_switcher_js();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get_metabox_status() {
|
||||
$result = '';
|
||||
if ( $this->got_package() ) {
|
||||
$result .= '<div id="wpml_package_status">';
|
||||
if ( $this->show_status && $this->metabox_data['statuses'] ) {
|
||||
if ( $this->status_container_tag ) {
|
||||
$result .= $this->get_tag( $this->status_container_tag . ' ' . $this->status_container_attributes_html );
|
||||
}
|
||||
foreach ( $this->metabox_data['statuses'] as $code => $status ) {
|
||||
$result .= $this->get_tag( $this->status_element_tag );
|
||||
$result .= '<img width="18" height="12" src="' . $this->sitepress->get_flag_url( $code ) . '"> ' . $status['name'] . ' : ' . $status['status'];
|
||||
$result .= $this->get_tag( $this->status_element_tag, 'closed' );
|
||||
}
|
||||
if ( $this->status_container_tag ) {
|
||||
$result .= $this->get_tag( $this->status_container_tag, 'closed' );
|
||||
}
|
||||
}
|
||||
if ( $this->show_link ) {
|
||||
if ( $this->is_package_language_active() ) {
|
||||
$result .= '<p><a style="float:right" class="button-secondary" href="' . $this->dashboard_link . '" target="_blank">' . $this->metabox_data['translate_title'] . '</a></p>';
|
||||
} else {
|
||||
$result .= '<p><a style="float:right" class="button-secondary" href="' . $this->strings_link . '" target="_blank">' . $this->metabox_data['translate_title'] . '</a></p>';
|
||||
}
|
||||
}
|
||||
$result .= '<br /><br /></div>';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function check_if_language_change_is_ok() {
|
||||
|
||||
$ok = true;
|
||||
|
||||
foreach ( $this->translation_statuses as $status ) {
|
||||
if ( isset( $status->status_code ) && $status->status_code != 0 ) {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $ok ) {
|
||||
$translations = $this->package->get_translated_strings( array() );
|
||||
foreach ( $translations as $string ) {
|
||||
foreach ( $string as $lang => $data ) {
|
||||
if ( $data['status'] == ICL_STRING_TRANSLATION_COMPLETE ) {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! $ok ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function attributes_to_string( $attributes ) {
|
||||
$result = '';
|
||||
foreach ( $attributes as $key => $value ) {
|
||||
if ( $result ) {
|
||||
$result .= ' ';
|
||||
}
|
||||
$result .= esc_html( $key ) . '="' . esc_attr( $value ) . '"';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function get_post_translations() {
|
||||
|
||||
$element_type = $this->package->get_package_element_type();
|
||||
$trid = $this->sitepress->get_element_trid( $this->package->ID, $element_type );
|
||||
|
||||
return $this->sitepress->get_element_translations( $trid, $element_type );
|
||||
}
|
||||
|
||||
private function get_tag( $tag, $closed = false ) {
|
||||
$result = '<';
|
||||
if ( $closed ) {
|
||||
$result .= '/';
|
||||
}
|
||||
$result .= $tag . '>';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string|array<string,mixed> > $args
|
||||
*/
|
||||
private function parse_arguments( $args ) {
|
||||
$default_args = array(
|
||||
'show_title' => true,
|
||||
'show_description' => true,
|
||||
'show_status' => true,
|
||||
'show_link' => true,
|
||||
'title_tag' => 'h2',
|
||||
'status_container_tag' => 'ul',
|
||||
'status_element_tag' => 'li',
|
||||
'main_container_attributes' => array(),
|
||||
'status_container_attributes' => array( 'style' => 'padding-left: 10px' ),
|
||||
);
|
||||
|
||||
$args = array_merge( $default_args, $args );
|
||||
|
||||
$this->show_title = $args['show_title'];
|
||||
$this->show_description = $args['show_description'];
|
||||
$this->show_status = $args['show_status'];
|
||||
$this->show_link = $args['show_link'];
|
||||
$this->title_tag = $args['title_tag'];
|
||||
$this->status_container_tag = $args['status_container_tag'];
|
||||
$this->status_element_tag = $args['status_element_tag'];
|
||||
$this->main_container_attributes = $args['main_container_attributes'];
|
||||
$this->status_container_attributes = $args['status_container_attributes'];
|
||||
|
||||
$this->container_attributes_html = $this->attributes_to_string( $this->main_container_attributes );
|
||||
$this->status_container_attributes_html = $this->attributes_to_string( $this->status_container_attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function got_package() {
|
||||
return $this->package && $this->package->ID;
|
||||
}
|
||||
|
||||
private function get_translation_statuses() {
|
||||
$post_translations = $this->get_post_translations();
|
||||
$status = array();
|
||||
foreach ( $post_translations as $language => $translation ) {
|
||||
$res_query = "SELECT status as status_code, needs_update FROM {$this->wpdb->prefix}icl_translation_status WHERE translation_id=%d";
|
||||
$res_args = array( $translation->translation_id );
|
||||
$res_prepare = $this->wpdb->prepare( $res_query, $res_args );
|
||||
/** @var \stdClass $res */
|
||||
$res = $this->wpdb->get_row( $res_prepare );
|
||||
if ( $res ) {
|
||||
$res->status = $res->status_code;
|
||||
switch ( $res->status ) {
|
||||
case ICL_TM_WAITING_FOR_TRANSLATOR:
|
||||
$res->status = __( 'Waiting for translator', 'wpml-string-translation' );
|
||||
break;
|
||||
case ICL_TM_IN_PROGRESS:
|
||||
$res->status = __( 'In progress', 'wpml-string-translation' );
|
||||
break;
|
||||
case ICL_TM_NEEDS_UPDATE:
|
||||
$res->status = '';
|
||||
break;
|
||||
case ICL_TM_COMPLETE:
|
||||
$res->status = __( 'Complete', 'wpml-string-translation' );
|
||||
break;
|
||||
default:
|
||||
$res->status = __( 'Not translated', 'wpml-string-translation' );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $res->needs_update ) {
|
||||
if ( $res->status ) {
|
||||
$res->status .= ' - ';
|
||||
}
|
||||
$res->status .= __( 'Needs update', 'wpml-string-translation' );
|
||||
}
|
||||
$status[ $language ] = $res;
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
private function init_translation_statuses() {
|
||||
$this->metabox_data['statuses'] = array();
|
||||
$this->translation_statuses = $this->get_translation_statuses();
|
||||
foreach ( $this->active_languages as $language_data ) {
|
||||
if ( $language_data['code'] != $this->package_language ) {
|
||||
$display_name = $language_data['display_name'];
|
||||
|
||||
$this->metabox_data['statuses'][ $language_data['code'] ] = array(
|
||||
'name' => $display_name,
|
||||
'status' => $this->get_status_value( $language_data ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_status_value( $language_data ) {
|
||||
if ( isset( $this->translation_statuses[ $language_data['code'] ] ) ) {
|
||||
$status_value = $this->translation_statuses[ $language_data['code'] ]->status;
|
||||
} else {
|
||||
$tm = new WPML_Package_TM( $this->package );
|
||||
if ( $tm->is_in_basket( $language_data['code'] ) ) {
|
||||
$status_value = __( 'In translation basket', 'wpml-string-translation' );
|
||||
} else {
|
||||
$status_value = __( 'Not translated', 'wpml-string-translation' );
|
||||
}
|
||||
}
|
||||
|
||||
return $status_value;
|
||||
}
|
||||
|
||||
private function is_package_language_active() {
|
||||
return in_array( $this->package_language, array_keys( $this->active_languages ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_Translation_Schema {
|
||||
|
||||
const OPTION_NAME = 'wpml-package-translation-db-updates-run';
|
||||
const REQUIRED_VERSION = '0.0.2';
|
||||
|
||||
private static $table_name;
|
||||
|
||||
static function run_update() {
|
||||
$updates_run = get_option( self::OPTION_NAME, array() );
|
||||
|
||||
if ( defined( 'WPML_PT_VERSION_DEV' ) ) {
|
||||
delete_option( 'wpml-package-translation-string-packages-table-updated' );
|
||||
if ( ( $key = array_search( WPML_PT_VERSION_DEV, $updates_run ) ) !== false ) {
|
||||
unset( $updates_run[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! in_array( self::REQUIRED_VERSION, $updates_run ) ) {
|
||||
// We need to make sure we build everything for 0.0.2 because users may
|
||||
// only be updating the string translation plugin and may not do an
|
||||
// activation.
|
||||
self::build_icl_string_packages_table();
|
||||
self::build_icl_string_packages_columns_if_required();
|
||||
self::fix_icl_string_packages_ID_column();
|
||||
self::build_icl_strings_columns_if_required();
|
||||
|
||||
$updates_run[] = self::REQUIRED_VERSION;
|
||||
|
||||
update_option( self::OPTION_NAME, $updates_run );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function current_table_has_column( $column ) {
|
||||
global $wpdb;
|
||||
|
||||
$cols = $wpdb->get_results( 'SHOW COLUMNS FROM `' . self::$table_name . '`' );
|
||||
$found = false;
|
||||
foreach ( $cols as $col ) {
|
||||
if ( $col->Field == $column ) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
private static function add_string_package_id_to_icl_strings() {
|
||||
global $wpdb;
|
||||
$sql = 'ALTER TABLE `' . self::$table_name . '`
|
||||
ADD `string_package_id` BIGINT unsigned NULL AFTER value,
|
||||
ADD INDEX (`string_package_id`)';
|
||||
|
||||
return $wpdb->query( $sql );
|
||||
}
|
||||
|
||||
private static function add_type_to_icl_strings() {
|
||||
global $wpdb;
|
||||
$sql = 'ALTER TABLE `' . self::$table_name . "` ADD `type` VARCHAR(40) NOT NULL DEFAULT 'LINE' AFTER string_package_id";
|
||||
|
||||
return $wpdb->query( $sql );
|
||||
}
|
||||
|
||||
private static function add_title_to_icl_strings() {
|
||||
global $wpdb;
|
||||
$sql = 'ALTER TABLE `' . self::$table_name . '` ADD `title` VARCHAR(160) NULL AFTER type';
|
||||
|
||||
return $wpdb->query( $sql );
|
||||
}
|
||||
|
||||
public static function build_icl_strings_columns_if_required() {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! get_option( 'wpml-package-translation-string-table-updated' ) ) {
|
||||
|
||||
self::$table_name = $wpdb->prefix . 'icl_strings';
|
||||
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '" . self::$table_name . "'" ) == self::$table_name ) {
|
||||
if ( ! self::current_table_has_column( 'string_package_id' ) ) {
|
||||
self::add_string_package_id_to_icl_strings();
|
||||
}
|
||||
|
||||
if ( ! self::current_table_has_column( 'type' ) ) {
|
||||
self::add_type_to_icl_strings();
|
||||
}
|
||||
|
||||
if ( ! self::current_table_has_column( 'title' ) ) {
|
||||
self::add_title_to_icl_strings();
|
||||
}
|
||||
update_option( 'wpml-package-translation-string-table-updated', true, 'no' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function build_icl_string_packages_columns_if_required() {
|
||||
global $wpdb;
|
||||
|
||||
if ( get_option( 'wpml-package-translation-string-packages-table-updated' ) != '0.0.2' ) {
|
||||
|
||||
self::$table_name = $wpdb->prefix . 'icl_string_packages';
|
||||
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '" . self::$table_name . "'" ) == self::$table_name ) {
|
||||
if ( ! self::current_table_has_column( 'kind_slug' ) ) {
|
||||
self::add_kind_slug_to_icl_string_packages();
|
||||
}
|
||||
self::update_kind_slug();
|
||||
|
||||
if ( ! self::current_table_has_column( 'view_link' ) ) {
|
||||
self::add_view_link_to_icl_string_packages();
|
||||
}
|
||||
update_option( 'wpml-package-translation-string-packages-table-updated', '0.0.2', 'no' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function add_kind_slug_to_icl_string_packages() {
|
||||
global $wpdb;
|
||||
$sql = 'ALTER TABLE `' . self::$table_name . "` ADD `kind_slug` varchar(160) DEFAULT '' NOT NULL AFTER `ID`";
|
||||
$result = $wpdb->query( $sql );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function add_view_link_to_icl_string_packages() {
|
||||
global $wpdb;
|
||||
$sql = 'ALTER TABLE `' . self::$table_name . '` ADD `view_link` TEXT NOT NULL AFTER `edit_link`';
|
||||
|
||||
return $wpdb->query( $sql );
|
||||
}
|
||||
|
||||
private static function fix_icl_string_packages_ID_column() {
|
||||
global $wpdb;
|
||||
self::$table_name = $wpdb->prefix . 'icl_string_packages';
|
||||
if ( self::current_table_has_column( 'id' ) ) {
|
||||
$sql = 'ALTER TABLE `' . self::$table_name . '` CHANGE id ID BIGINT UNSIGNED NOT NULL auto_increment;';
|
||||
$wpdb->query( $sql );
|
||||
}
|
||||
}
|
||||
|
||||
private static function build_icl_string_packages_table() {
|
||||
global $wpdb;
|
||||
|
||||
$charset_collate = SitePress_Setup::get_charset_collate();
|
||||
|
||||
self::$table_name = $wpdb->prefix . 'icl_string_packages';
|
||||
$sql = '
|
||||
CREATE TABLE IF NOT EXISTS `' . self::$table_name . '` (
|
||||
`ID` bigint(20) unsigned NOT NULL auto_increment,
|
||||
`kind_slug` varchar(160) NOT NULL,
|
||||
`kind` varchar(160) NOT NULL,
|
||||
`name` varchar(160) NOT NULL,
|
||||
`title` varchar(160) NOT NULL,
|
||||
`edit_link` TEXT NOT NULL,
|
||||
`view_link` TEXT NOT NULL,
|
||||
`post_id` INTEGER DEFAULT NULL,
|
||||
`word_count` VARCHAR(2000) DEFAULT NULL,
|
||||
PRIMARY KEY (`ID`)
|
||||
) ' . $charset_collate . '';
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
private static function update_kind_slug() {
|
||||
global $wpdb;
|
||||
$sql = 'SELECT kind FROM ' . self::$table_name . " WHERE IFNULL(kind_slug,'')='' GROUP BY kind";
|
||||
$kinds = $wpdb->get_col( $sql );
|
||||
$result = ( count( $kinds ) == 0 );
|
||||
foreach ( $kinds as $kind ) {
|
||||
$kind_slug = sanitize_title_with_dashes( $kind );
|
||||
$result = $wpdb->update( self::$table_name, array( 'kind_slug' => $kind_slug ), array( 'kind' => $kind ) );
|
||||
if ( ! $result ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_ST {
|
||||
|
||||
public function get_string_element( $string_id, $column = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$package_query = "SELECT * FROM {$wpdb->prefix}icl_strings WHERE id=%d";
|
||||
$package_prepare = $wpdb->prepare( $package_query, array( $string_id ) );
|
||||
$result = $wpdb->get_row( $package_prepare );
|
||||
|
||||
if ( $result && $column && isset( $result[ $column ] ) ) {
|
||||
$result = $result[ $column ];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function get_string_title( $title, $string_details ) {
|
||||
$string_title = $this->get_string_element( $string_details['string_id'], 'title' );
|
||||
if ( $string_title ) {
|
||||
return $string_title;
|
||||
} else {
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_TM_Jobs {
|
||||
/**
|
||||
* @var WPML_Package
|
||||
*/
|
||||
protected $package;
|
||||
|
||||
protected function __construct( $package ) {
|
||||
$this->package = $package;
|
||||
}
|
||||
|
||||
final public function validate_translations( $create_if_missing = true ) {
|
||||
$trid = $this->get_trid( $create_if_missing );
|
||||
|
||||
return $trid != false;
|
||||
}
|
||||
|
||||
final protected function get_trid( $create_if_missing = true ) {
|
||||
global $sitepress;
|
||||
$package = $this->package;
|
||||
$post_trid = $sitepress->get_element_trid( $package->ID, $package->get_translation_element_type() );
|
||||
if ( ! $post_trid && $create_if_missing ) {
|
||||
$this->set_language_details();
|
||||
$post_trid = $sitepress->get_element_trid( $package->ID, $package->get_translation_element_type() );
|
||||
}
|
||||
|
||||
return $post_trid;
|
||||
}
|
||||
|
||||
final public function set_language_details( $language_code = null ) {
|
||||
global $sitepress;
|
||||
$package = $this->package;
|
||||
$post_id = $package->ID;
|
||||
$post = $this->get_translatable_item( $post_id );
|
||||
$post_id = $post->ID;
|
||||
$element_type = $package->get_translation_element_type();
|
||||
if ( ! $language_code ) {
|
||||
$language_code = icl_get_default_language();
|
||||
}
|
||||
$sitepress->set_element_language_details( $post_id, $element_type, false, $language_code, null, false );
|
||||
}
|
||||
|
||||
final public function get_translatable_item( $package ) {
|
||||
// for TranslationManagement::send_jobs
|
||||
if ( ! is_a( $package, 'WPML_Package' ) ) {
|
||||
$package = new WPML_Package( $package );
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
|
||||
final public function delete_translation_jobs() {
|
||||
global $wpdb;
|
||||
|
||||
$post_translations = $this->get_post_translations();
|
||||
foreach ( $post_translations as $lang => $translation ) {
|
||||
$rid_query = "SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d";
|
||||
$rid_prepare = $wpdb->prepare( $rid_query, array( $translation->translation_id ) );
|
||||
$rid = $wpdb->get_var( $rid_prepare );
|
||||
if ( $rid ) {
|
||||
$job_id_query = "SELECT job_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d";
|
||||
$job_id_prepare = $wpdb->prepare( $job_id_query, array( $rid ) );
|
||||
$job_id = $wpdb->get_var( $job_id_prepare );
|
||||
|
||||
if ( $job_id ) {
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translate_job', array( 'job_id' => $job_id ) );
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'job_id' => $job_id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final public function delete_translations() {
|
||||
global $sitepress;
|
||||
|
||||
$sitepress->delete_element_translation(
|
||||
$this->get_trid(),
|
||||
$this->package->get_translation_element_type()
|
||||
);
|
||||
}
|
||||
|
||||
final public function get_post_translations() {
|
||||
global $sitepress;
|
||||
$package = $this->package;
|
||||
|
||||
$translation_element_type = $package->get_translation_element_type();
|
||||
$trid = $this->get_trid();
|
||||
|
||||
return $sitepress->get_element_translations( $trid, $translation_element_type );
|
||||
}
|
||||
|
||||
final protected function update_translation_job_needs_update( $job_id ) {
|
||||
global $wpdb;
|
||||
$update_data = array( 'translated' => 0 );
|
||||
$update_where = array( 'job_id' => $job_id );
|
||||
$wpdb->update( "{$wpdb->prefix}icl_translate_job", $update_data, $update_where );
|
||||
}
|
||||
|
||||
final function update_translation_job( $rid, $post ) {
|
||||
|
||||
$updated = $this->update_translation_job_fields( $rid, $post );
|
||||
$deleted = $this->delete_translation_job_fields( $rid, $post );
|
||||
|
||||
return ( $updated || $deleted );
|
||||
}
|
||||
|
||||
private function delete_translation_job_fields( $rid, $post ) {
|
||||
$deleted = false;
|
||||
$job_id = $this->get_translation_job_id( $rid );
|
||||
$translation_fields = $this->get_translations_job_fields( $job_id );
|
||||
foreach ( $translation_fields as $field_type => $el ) {
|
||||
// delete fields that are no longer present
|
||||
if ( $el->field_translate && ! isset( $post->string_data[ $field_type ] ) ) {
|
||||
$this->delete_translation_field( $el->tid );
|
||||
if ( ! $deleted ) {
|
||||
$deleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $rid
|
||||
* @param WPML_Package $post
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function update_translation_job_fields( $rid, $post ) {
|
||||
$updated_any = false;
|
||||
|
||||
$job_id = $this->get_translation_job_id( $rid );
|
||||
$translation_fields = $this->get_translations_job_fields( $job_id );
|
||||
|
||||
if ( isset( $post->string_data ) && is_array( $post->string_data ) ) {
|
||||
foreach ( $post->string_data as $field_type => $field_value ) {
|
||||
$updated = $this->insert_update_translation_job_field( $field_value, $translation_fields, $field_type, $job_id );
|
||||
if ( ! $updated_any && $updated ) {
|
||||
$updated_any = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $updated_any;
|
||||
}
|
||||
|
||||
protected function get_translation_job_id( $rid ) {
|
||||
global $wpdb;
|
||||
$job_id_query = "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid";
|
||||
$job_id_prepare = $wpdb->prepare( $job_id_query, $rid );
|
||||
$job_id = $wpdb->get_var( $job_id_prepare );
|
||||
|
||||
return $job_id;
|
||||
}
|
||||
|
||||
private function get_translations_job_fields( $job_id ) {
|
||||
global $wpdb;
|
||||
$translation_fields_query = "SELECT field_type, field_data, tid, field_translate
|
||||
FROM {$wpdb->prefix}icl_translate
|
||||
WHERE job_id=%d";
|
||||
$translation_fields_query = $wpdb->prepare( $translation_fields_query, $job_id );
|
||||
$translation_fields = $wpdb->get_results( $translation_fields_query, OBJECT_K );
|
||||
|
||||
return $translation_fields;
|
||||
}
|
||||
|
||||
private function delete_translation_field( $tid ) {
|
||||
global $wpdb;
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'tid' => $tid ), array( '%d' ) );
|
||||
}
|
||||
|
||||
private function insert_update_translation_job_field( $field_value, $translation_fields, $field_type, $job_id ) {
|
||||
$updated = false;
|
||||
$field_data = base64_encode( $field_value );
|
||||
if ( ! isset( $translation_fields[ $field_type ] ) ) {
|
||||
$this->insert_translation_field( $job_id, $field_type, $field_data );
|
||||
$updated = true;
|
||||
} elseif ( $translation_fields[ $field_type ]->field_data != $field_data ) {
|
||||
$this->update_translation_field( $field_data, $translation_fields, $field_type );
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
private function update_translation_field( $field_data, $translation_fields, $field_type ) {
|
||||
global $wpdb;
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translate',
|
||||
array(
|
||||
'field_data' => $field_data,
|
||||
'field_finished' => 0,
|
||||
),
|
||||
array( 'tid' => $translation_fields[ $field_type ]->tid )
|
||||
);
|
||||
}
|
||||
|
||||
private function insert_translation_field( $job_id, $field_type, $field_data ) {
|
||||
global $wpdb;
|
||||
$data = array(
|
||||
'job_id' => $job_id,
|
||||
'content_id' => 0,
|
||||
'field_type' => $field_type,
|
||||
'field_format' => 'base64',
|
||||
'field_translate' => 1,
|
||||
'field_data' => $field_data,
|
||||
'field_data_translated' => 0,
|
||||
'field_finished' => 0,
|
||||
);
|
||||
|
||||
$wpdb->insert( $wpdb->prefix . 'icl_translate', $data );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_TM extends WPML_Package_TM_Jobs {
|
||||
public function __construct( $package ) {
|
||||
parent::__construct( $package );
|
||||
}
|
||||
|
||||
public function get_translation_statuses() {
|
||||
global $sitepress;
|
||||
$package = $this->package;
|
||||
|
||||
$post_trid = $this->get_trid();
|
||||
$items = array();
|
||||
if ( $post_trid ) {
|
||||
$translation_element_type = $package->get_translation_element_type();
|
||||
$post_translations = $sitepress->get_element_translations( $post_trid, $translation_element_type );
|
||||
foreach ( $post_translations as $lang => $translation ) {
|
||||
$translation->trid = $post_trid;
|
||||
$item[] = $this->set_translation_status( $package, $translation, $lang );
|
||||
}
|
||||
} else {
|
||||
$items[] = $package;
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WPML_Package $package
|
||||
* @param \stdClass $translation
|
||||
* @param string $lang
|
||||
*
|
||||
* @return \WPML_Package
|
||||
*/
|
||||
private function set_translation_status( $package, $translation, $lang ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $package->trid ) {
|
||||
$package->trid = $translation->trid;
|
||||
}
|
||||
|
||||
$res_query = "SELECT status, needs_update, md5 FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d";
|
||||
$res_args = array( $translation->translation_id );
|
||||
$res_prepare = $wpdb->prepare( $res_query, $res_args );
|
||||
$res = $wpdb->get_row( $res_prepare );
|
||||
$_suffix = str_replace( '-', '_', $lang );
|
||||
$status = ICL_TM_NOT_TRANSLATED;
|
||||
if ( $res ) {
|
||||
$status = $res->status;
|
||||
$index = 'needs_update_' . $_suffix;
|
||||
$package->$index = $res->needs_update;
|
||||
}
|
||||
$index = 'status_' . $_suffix;
|
||||
$package->$index = apply_filters( 'wpml_translation_status', $status, $translation->trid, $lang, 'package' );
|
||||
|
||||
return $package;
|
||||
}
|
||||
|
||||
public function is_translation_in_progress() {
|
||||
global $wpdb;
|
||||
|
||||
$post_translations = $this->get_post_translations();
|
||||
|
||||
foreach ( $post_translations as $lang => $translation ) {
|
||||
$res_query = "SELECT status, needs_update, md5
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_id=%d";
|
||||
$res_prepared = $wpdb->prepare( $res_query, array( $translation->translation_id ) );
|
||||
$res = $wpdb->get_row( $res_prepared );
|
||||
if ( $res && $res->status == ICL_TM_IN_PROGRESS ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update translations
|
||||
*
|
||||
* @param bool $is_new_package
|
||||
* @param bool $needs_update - when deleting single field we do not need to change the translation status of the form
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update_package_translations( $is_new_package, $needs_update = true ) {
|
||||
|
||||
global $iclTranslationManagement;
|
||||
|
||||
$updated = false;
|
||||
|
||||
$package = $this->package;
|
||||
$trid = $this->get_trid();
|
||||
|
||||
if ( $is_new_package ) {
|
||||
$this->set_language_details();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$item_md5_translations = $this->get_item_md5_translations( $trid );
|
||||
|
||||
if ( $item_md5_translations ) {
|
||||
$md5 = $iclTranslationManagement->post_md5( $this->package );
|
||||
|
||||
if ( $md5 != $item_md5_translations[0]->md5 ) { // all translations need update
|
||||
|
||||
$translation_package = $iclTranslationManagement->create_translation_package( $this->package );
|
||||
|
||||
foreach ( $item_md5_translations as $translation ) {
|
||||
$translation_id = $translation->translation_id;
|
||||
$previous_state = $this->get_translation_state( $translation );
|
||||
|
||||
$data = array();
|
||||
if ( ! empty( $previous_state ) ) {
|
||||
$data['previous_state'] = serialize( $previous_state );
|
||||
}
|
||||
$data = array(
|
||||
'translation_id' => $translation_id,
|
||||
'translation_package' => serialize( $translation_package ),
|
||||
'md5' => $md5,
|
||||
);
|
||||
|
||||
if ( $needs_update ) {
|
||||
$data['needs_update'] = 1;
|
||||
}
|
||||
|
||||
$update_result = $iclTranslationManagement->update_translation_status( $data );
|
||||
|
||||
$rid = $update_result[0];
|
||||
|
||||
$this->update_translation_job( $rid, $this->package );
|
||||
|
||||
// change job status only when needs update
|
||||
if ( $needs_update ) {
|
||||
$job_id = $this->get_translation_job_id( $rid );
|
||||
if ( $job_id ) {
|
||||
$this->update_translation_job_needs_update( $job_id );
|
||||
$updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
private function get_item_md5_translations( $trid ) {
|
||||
global $wpdb;
|
||||
|
||||
$item_md5_translations_query = "
|
||||
SELECT t.translation_id, s.md5
|
||||
FROM {$wpdb->prefix}icl_translations t
|
||||
NATURAL JOIN {$wpdb->prefix}icl_translation_status s
|
||||
WHERE t.trid=%d
|
||||
AND t.source_language_code IS NOT NULL";
|
||||
$item_md5_translations_prepare = $wpdb->prepare( $item_md5_translations_query, $trid );
|
||||
$item_md5_translations = $wpdb->get_results( $item_md5_translations_prepare );
|
||||
|
||||
return $item_md5_translations;
|
||||
}
|
||||
|
||||
private function get_translation_state( $translation ) {
|
||||
global $wpdb;
|
||||
|
||||
$previous_state_query = "
|
||||
SELECT status, translator_id, needs_update, md5, translation_service, translation_package, timestamp, links_fixed
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_id = %d
|
||||
";
|
||||
$previous_state_prepare = $wpdb->prepare( $previous_state_query, $translation->translation_id );
|
||||
$previous_state = $wpdb->get_row( $previous_state_prepare, ARRAY_A );
|
||||
|
||||
return $previous_state;
|
||||
}
|
||||
|
||||
public function add_package_to_basket( $translation_action, $source_language, $target_language ) {
|
||||
if ( ! $this->validate_basket_package_item( $translation_action, $source_language ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->is_duplicate_or_do_nothing( $translation_action ) ) {
|
||||
$this->duplicate_or_do_nothing( $translation_action, $target_language );
|
||||
} elseif ( $translation_action == 1 ) {
|
||||
$this->send_package_to_basket( $source_language, $target_language );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function duplicate_package( $package_id ) {
|
||||
// TODO: [WPML 3.3] duplication to be done
|
||||
// $this->make_duplicate( $package_id, $language_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $translation_action
|
||||
* @param string $source_language
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validate_basket_package_item( $translation_action, $source_language ) {
|
||||
ICL_AdminNotifier::remove_message( 'the_basket_items_notification' );
|
||||
|
||||
$package = $this->package;
|
||||
$package_id = $package->ID;
|
||||
$basket = TranslationProxy_Basket::get_basket();
|
||||
$package_is_valid = true;
|
||||
$basket_source_language = TranslationProxy_Basket::get_source_language();
|
||||
if ( $basket && $basket_source_language ) {
|
||||
if ( $source_language != $basket_source_language ) {
|
||||
TranslationProxy_Basket::add_message(
|
||||
array(
|
||||
'type' => 'update',
|
||||
'text' => __(
|
||||
'You cannot add packages in this language to the basket since it already contains posts, packages 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-string-translation'
|
||||
),
|
||||
)
|
||||
);
|
||||
TranslationProxy_Basket::update_basket();
|
||||
|
||||
$package_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
$select_one_lang_message = __( 'Please select at least one language to translate into.', 'wpml-string-translation' );
|
||||
|
||||
if ( ! $translation_action ) {
|
||||
TranslationProxy_Basket::add_message(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'text' => $select_one_lang_message,
|
||||
)
|
||||
);
|
||||
|
||||
$package_is_valid = false;
|
||||
} else {
|
||||
TranslationProxy_Basket::remove_message( $select_one_lang_message );
|
||||
}
|
||||
|
||||
if ( ! $package_id ) {
|
||||
TranslationProxy_Basket::add_message(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one document to translate.', 'wpml-string-translation' ),
|
||||
)
|
||||
);
|
||||
|
||||
$package_is_valid = false;
|
||||
|
||||
return $package_is_valid;
|
||||
}
|
||||
|
||||
return $package_is_valid;
|
||||
}
|
||||
|
||||
private function is_duplicate_or_do_nothing( $translation_action ) {
|
||||
return $translation_action == 0 || $translation_action == 2;
|
||||
}
|
||||
|
||||
private function duplicate_or_do_nothing( $translation_action, $target_language ) {
|
||||
$basket = TranslationProxy_Basket::get_basket();
|
||||
|
||||
$package = $this->package;
|
||||
$package_id = $package->ID;
|
||||
|
||||
// iterate posts ids, check if they are in wp_options
|
||||
// if they are set to translate for this particular language
|
||||
// end then remove it
|
||||
// check if we have this post in wp_options
|
||||
// end remove
|
||||
if ( isset( $basket['package'][ $package_id ]['to_langs'][ $target_language ] ) ) {
|
||||
unset( $basket['package'][ $package_id ]['to_langs'][ $target_language ] );
|
||||
TranslationProxy_Basket::update_basket( $basket );
|
||||
}
|
||||
// if user want to duplicate this post, lets do this
|
||||
if ( $translation_action == 2 ) {
|
||||
$this->duplicate_package( $package_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source_language
|
||||
* @param string $target_language
|
||||
*
|
||||
* @throws WPML_Package_Exception
|
||||
*/
|
||||
public function send_package_to_basket( $source_language, $target_language ) {
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
$package = $this->package;
|
||||
$package_id = $package->ID;
|
||||
$basket = TranslationProxy_Basket::get_basket();
|
||||
$language_name = $sitepress->get_display_language_name( $target_language );
|
||||
|
||||
$send_to_basket = true;
|
||||
$package_helper = new WPML_Package_Helper();
|
||||
$post = $package_helper->get_translatable_item( null, $package_id );
|
||||
|
||||
$post_title = esc_html( $post->title );
|
||||
$element_type = $package->get_element_type_prefix() . '_' . $post->kind_slug;
|
||||
$trid = $sitepress->get_element_trid( $package_id, $element_type );
|
||||
$job_id = $iclTranslationManagement->get_translation_job_id( $trid, $target_language );
|
||||
if ( $job_id ) {
|
||||
$job_details = $iclTranslationManagement->get_translation_job( $job_id );
|
||||
$send_to_basket = $this->validate_package_status( $job_details, $post_title, $language_name );
|
||||
}
|
||||
|
||||
if ( $send_to_basket ) {
|
||||
$basket['package'][ $package_id ]['from_lang'] = $source_language;
|
||||
$basket['package'][ $package_id ]['to_langs'][ $target_language ] = 1;
|
||||
// set basket language if not already set
|
||||
if ( ! isset( $basket['source_language'] ) ) {
|
||||
$basket['source_language'] = $source_language;
|
||||
}
|
||||
}
|
||||
TranslationProxy_Basket::update_basket( $basket );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass $job_details
|
||||
* @param string $post_title
|
||||
* @param string $language_name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validate_package_status( $job_details, $post_title, $language_name ) {
|
||||
$send_to_basket = true;
|
||||
$message_args = array();
|
||||
|
||||
if ( ! $job_details->needs_update ) {
|
||||
if ( $job_details->status == ICL_TM_IN_PROGRESS ) {
|
||||
$message_args = array(
|
||||
'type' => 'update',
|
||||
'text' => sprintf(
|
||||
__(
|
||||
'Post "%1$s" will be ignored for %2$s, because translation is already in progress.',
|
||||
'wpml-string-translation'
|
||||
),
|
||||
$post_title,
|
||||
$language_name
|
||||
),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
} elseif ( $job_details->status == ICL_TM_WAITING_FOR_TRANSLATOR ) {
|
||||
$message_args = array(
|
||||
'type' => 'update',
|
||||
'text' => sprintf(
|
||||
__(
|
||||
'Post "%1$s" will be ignored for %2$s, because translation is already waiting for translator.',
|
||||
'wpml-string-translation'
|
||||
),
|
||||
$post_title,
|
||||
$language_name
|
||||
),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
}
|
||||
if ( ! $send_to_basket ) {
|
||||
TranslationProxy_Basket::add_message( $message_args );
|
||||
TranslationProxy_Basket::update_basket();
|
||||
}
|
||||
|
||||
return $send_to_basket;
|
||||
}
|
||||
|
||||
public function is_in_basket( $target_lang ) {
|
||||
if ( class_exists( 'TranslationProxy_Basket' ) ) {
|
||||
$basket = TranslationProxy_Basket::get_basket();
|
||||
return isset( $basket['package'][ $this->package->ID ]['to_langs'][ $target_lang ] );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_Translation_UI {
|
||||
var $load_priority = 101;
|
||||
private $menu_root = '';
|
||||
|
||||
const MENU_SLUG = 'wpml-package-management';
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'wpml_loaded', array( $this, 'loaded' ), $this->load_priority );
|
||||
}
|
||||
|
||||
public function loaded() {
|
||||
|
||||
if ( $this->passed_dependencies() ) {
|
||||
$this->set_admin_hooks();
|
||||
do_action( 'WPML_PT_HTML' );
|
||||
}
|
||||
}
|
||||
|
||||
private function passed_dependencies() {
|
||||
return defined( 'ICL_SITEPRESS_VERSION' )
|
||||
&& defined( 'WPML_ST_VERSION' )
|
||||
&& defined( 'WPML_TM_VERSION' );
|
||||
}
|
||||
|
||||
private function set_admin_hooks() {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'wpml_admin_menu_configure', array( $this, 'menu' ) );
|
||||
add_action( 'wpml_admin_menu_root_configured', array( $this, 'main_menu_configured' ), 10, 2 );
|
||||
|
||||
add_action( 'admin_register_scripts', array( $this, 'admin_register_scripts' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function main_menu_configured( $menu_id, $root_slug ) {
|
||||
if ( 'WPML' === $menu_id ) {
|
||||
$this->menu_root = $root_slug;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $menu_id
|
||||
*/
|
||||
public function menu( $menu_id ) {
|
||||
if ( 'WPML' !== $menu_id || ! defined( 'ICL_PLUGIN_PATH' ) ) {
|
||||
return;
|
||||
}
|
||||
global $sitepress;
|
||||
if ( ! isset( $sitepress ) || ( method_exists( $sitepress, 'get_setting' ) && ! $sitepress->get_setting( 'setup_complete' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $sitepress_settings;
|
||||
|
||||
if ( ! isset( $sitepress_settings['existing_content_language_verified'] ) || ! $sitepress_settings['existing_content_language_verified'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( current_user_can( 'wpml_manage_string_translation' ) ) {
|
||||
$menu = array();
|
||||
$menu['order'] = 1300;
|
||||
$menu['page_title'] = __( 'Packages', 'wpml-string-translation' );
|
||||
$menu['menu_title'] = __( 'Packages', 'wpml-string-translation' );
|
||||
$menu['capability'] = 'wpml_manage_string_translation';
|
||||
$menu['menu_slug'] = self::MENU_SLUG;
|
||||
$menu['function'] = array(
|
||||
'WPML_Package_Translation_HTML_Packages',
|
||||
'package_translation_menu',
|
||||
);
|
||||
|
||||
do_action( 'wpml_admin_menu_register_item', $menu );
|
||||
$this->admin_register_scripts();
|
||||
}
|
||||
}
|
||||
|
||||
function admin_register_scripts() {
|
||||
wp_register_script( 'wpml-package-trans-man-script', WPML_PACKAGE_TRANSLATION_URL . '/resources/js/wpml_package_management.js', array( 'jquery' ) );
|
||||
}
|
||||
|
||||
function admin_enqueue_scripts( $hook ) {
|
||||
if ( get_plugin_page_hookname( self::MENU_SLUG, $this->menu_root ) === $hook ) {
|
||||
wp_enqueue_script( 'wpml-package-trans-man-script' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,806 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package_Translation extends WPML_Package_Helper {
|
||||
var $load_priority = 100;
|
||||
var $package_translation_active;
|
||||
var $admin_lang_switcher = null;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
add_action( 'wpml_loaded', array( $this, 'loaded' ), $this->load_priority, 1 );
|
||||
}
|
||||
|
||||
function loaded( SitePress $sitepress = null ) {
|
||||
parent::loaded();
|
||||
|
||||
if ( null === $sitepress ) {
|
||||
global $sitepress;
|
||||
}
|
||||
|
||||
$is_setup_complete = (bool) $sitepress->get_setting( 'setup_complete', false );
|
||||
|
||||
if ( $is_setup_complete ) {
|
||||
$this->run_db_update();
|
||||
}
|
||||
|
||||
if ( $this->passed_dependencies() && $is_setup_complete ) {
|
||||
$this->add_admin_hooks();
|
||||
$this->add_global_hooks();
|
||||
|
||||
if ( is_admin() ) {
|
||||
|
||||
if ( $this->is_refresh_required() ) {
|
||||
add_action( 'init', array( $this, 'refresh_packages' ), 999, 0 );
|
||||
$this->set_refresh_not_required();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function add_admin_hooks() {
|
||||
if ( is_admin() || $this->is_doing_xmlrpc() || wpml_is_rest_request() ) {
|
||||
add_action( 'wp_ajax_wpml_delete_packages', array( $this, 'delete_packages_ajax' ) );
|
||||
add_action( 'wp_ajax_wpml_change_package_lang', array( $this, 'change_package_lang_ajax' ) );
|
||||
|
||||
/* Core hooks */
|
||||
add_filter( 'wpml_pt_all_packages', array( $this, 'get_all_packages' ) );
|
||||
|
||||
/* Translation hooks for other plugins to use */
|
||||
add_filter( 'wpml_tm_element_type', array( $this, 'get_element_type' ), 10, 2 );
|
||||
add_filter( 'wpml_tm_dashboard_title_locations', array( $this, 'add_title_db_location' ), 10, 2 );
|
||||
|
||||
add_filter( 'wpml_string_title_from_id', array( $this, 'string_title_from_id_filter' ), 10, 2 );
|
||||
// TODO: deprecated, use the 'wpml_register_string' action
|
||||
add_filter( 'WPML_register_string', array( $this, 'register_string_for_translation' ), 10, 5 );
|
||||
|
||||
add_action( 'wpml_add_string_translation', array( $this, 'add_string_translation_action' ), 10, 7 );
|
||||
|
||||
// TODO: These 3 hooks are deprecated. They are needed for Layouts 1.0. Consider removing them after Layouts 1.2 is released
|
||||
add_filter( 'WPML_get_translated_strings', array( $this, 'get_translated_strings' ), 10, 2 );
|
||||
add_action( 'WPML_set_translated_strings', array( $this, 'set_translated_strings' ), 10, 2 );
|
||||
add_action( 'WPML_show_package_language_ui', array( $this, 'show_language_selector' ), 10, 2 );
|
||||
|
||||
add_filter( 'wpml_get_translated_strings', array( $this, 'get_translated_strings' ), 10, 2 );
|
||||
add_action( 'wpml_set_translated_strings', array( $this, 'set_translated_strings' ), 10, 2 );
|
||||
add_action( 'wpml_show_package_language_ui', array( $this, 'show_language_selector' ), 10, 2 );
|
||||
add_action( 'wpml_show_package_language_admin_bar', array( $this, 'show_admin_bar_language_selector' ), 10, 2 );
|
||||
|
||||
/* WPML hooks */
|
||||
add_filter( 'wpml_get_translatable_types', array( $this, 'get_translatable_types' ), 10, 1 );
|
||||
add_filter( 'wpml_get_translatable_item', array( $this, 'get_translatable_item' ), 10, 3 );
|
||||
add_filter( 'wpml_external_item_url', array( $this, 'get_package_edit_url' ), 10, 2 );
|
||||
add_filter( 'wpml_external_item_link', array( $this, 'get_package_edit_link' ), 10, 3 );
|
||||
add_filter( 'wpml_get_external_item_title', array( $this, 'get_package_title' ), 10, 3 );
|
||||
add_filter( 'wpml_element_id_from_package', array( $this, 'get_element_id_from_package_filter' ), 10, 2 );
|
||||
add_filter( 'wpml_get_package_type', array( $this, 'get_package_type' ), 10, 2 );
|
||||
add_filter( 'wpml_get_package_type_prefix', array( $this, 'get_package_type_prefix' ), 10, 2 );
|
||||
add_filter( 'wpml_language_for_element', array( $this, 'get_language_for_element' ), 10, 2 );
|
||||
add_filter( 'wpml_st_get_string_package', array( $this, 'get_string_package' ), 10, 2 );
|
||||
add_action( 'wpml_save_external', [ $this, 'save_package_translations' ], 10, 3 );
|
||||
|
||||
/* Translation queue hooks */
|
||||
add_filter( 'wpml_tm_external_translation_job_title', array( $this, 'get_post_title' ), 10, 2 );
|
||||
add_filter( 'wpml_tm_add_to_basket', array( $this, 'add_to_basket' ), 10, 2 );
|
||||
add_filter( 'wpml_tm_translation_jobs_basket', array( $this, 'update_translation_jobs_basket' ), 10, 3 );
|
||||
add_filter( 'wpml_tm_basket_items_types', array( $this, 'basket_items_types' ), 10, 2 );
|
||||
|
||||
/*
|
||||
TM Hooks */
|
||||
// This is called by \TranslationManagement::send_all_jobs - The hook is dynamically built.
|
||||
add_filter( 'wpml_tm_dashboard_sql', array( $this, 'tm_dashboard_sql_filter' ), 10, 1 );
|
||||
|
||||
/* Translation editor hooks */
|
||||
add_filter( 'wpml_tm_editor_string_name', array( $this, 'get_editor_string_name' ), 10, 2 );
|
||||
add_filter( 'wpml_tm_editor_string_style', array( $this, 'get_editor_string_style' ), 10, 3 );
|
||||
|
||||
/*
|
||||
API Hooks */
|
||||
// @deprecated @since 3.2 Use 'wpml_delete_package'
|
||||
add_action( 'wpml_delete_package_action', array( $this, 'delete_package_action' ), 10, 2 );
|
||||
|
||||
add_action( 'deleted_post', array( $this, 'remove_post_packages' ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_doing_xmlrpc() {
|
||||
return ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST );
|
||||
}
|
||||
|
||||
private function add_global_hooks() {
|
||||
|
||||
// TODO: deprecated, use the 'wpml_translate_string' filter
|
||||
add_filter( 'WPML_translate_string', array( $this, 'translate_string' ), 10, 3 );
|
||||
add_filter( 'wpml_translate_string', array( $this, 'translate_string' ), 10, 3 );
|
||||
|
||||
add_action( 'wpml_register_string', array( $this, 'register_string_action' ), 10, 5 );
|
||||
add_action( 'wpml_start_string_package_registration', array( $this, 'start_string_package_registration_action' ), 10, 1 );
|
||||
add_action( 'wpml_delete_unused_package_strings', array( $this, 'delete_unused_package_strings_action' ), 10, 1 );
|
||||
add_action( 'wpml_delete_package', array( $this, 'delete_package_action' ), 10, 2 );
|
||||
add_filter( 'wpml_st_get_post_string_packages', array( $this, 'get_post_string_packages' ), 10, 2 );
|
||||
|
||||
add_filter( 'wpml_string_id_from_package', array( $this, 'string_id_from_package_filter' ), 10, 4 );
|
||||
|
||||
/* API Hooks */
|
||||
add_filter( 'wpml_is_external', array( $this, 'is_external' ), 10, 2 );
|
||||
}
|
||||
|
||||
private function run_db_update() {
|
||||
if ( is_admin() ) {
|
||||
WPML_Package_Translation_Schema::run_update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function passed_dependencies() {
|
||||
return defined( 'ICL_SITEPRESS_VERSION' )
|
||||
&& defined( 'WPML_ST_VERSION' )
|
||||
&& defined( 'WPML_TM_VERSION' );
|
||||
}
|
||||
|
||||
public function add_title_db_location( $locations ) {
|
||||
global $wpdb;
|
||||
|
||||
$locations[ $wpdb->prefix . 'icl_string_packages' ] = array(
|
||||
'id_column' => 'ID',
|
||||
'title_column' => 'title',
|
||||
'element_type_prefix' => 'package',
|
||||
'date_column' => false,
|
||||
);
|
||||
|
||||
return $locations;
|
||||
}
|
||||
|
||||
function get_package_edit_url( $url, $post_id ) {
|
||||
$package = new WPML_Package( $post_id );
|
||||
if ( ! $package ) {
|
||||
return false;
|
||||
} //not ours
|
||||
if ( isset( $package->edit_link ) ) {
|
||||
$url = $package->edit_link;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function get_package_title( $title, $kind, $id ) {
|
||||
$package = new WPML_Package( $id );
|
||||
if ( ! $package ) {
|
||||
return $title;
|
||||
} //not ours
|
||||
if ( isset( $package->title ) ) {
|
||||
$title = $package->title;
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
function get_package_view_link( $link, $post_id, $hide_if_missing_link = false ) {
|
||||
$package = new WPML_Package( $post_id );
|
||||
if ( ! $package ) {
|
||||
return $link;
|
||||
} //not ours
|
||||
return $this->build_package_link( $package->view_link, $package->title, $hide_if_missing_link );
|
||||
}
|
||||
|
||||
function get_package_edit_link( $link, $post_id, $hide_if_missing_link = false ) {
|
||||
$package = new WPML_Package( $post_id );
|
||||
if ( ! $package ) {
|
||||
return $link;
|
||||
} //not ours
|
||||
return $this->build_package_link( $package->edit_link, esc_html( $package->title ), $hide_if_missing_link );
|
||||
}
|
||||
|
||||
private function build_package_link( $url, $title, $hide_if_missing_link = false ) {
|
||||
$link = '<a href="' . $url . '">' . $title . '</a>';
|
||||
if ( false === $hide_if_missing_link ) {
|
||||
if ( ! $url ) {
|
||||
$link = $title;
|
||||
}
|
||||
} elseif ( ! $url ) {
|
||||
$link = '';
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass|WPML_Package|array|int $package
|
||||
* @param array<string,mixed> $args
|
||||
*/
|
||||
function show_language_selector( $package, $args = array() ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$wpml_pt_meta = new WPML_Package_Translation_Metabox( $package, $wpdb, $sitepress, $args );
|
||||
echo $wpml_pt_meta->get_metabox();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass|WPML_Package|array|int $package
|
||||
* @param array<string,mixed> $args
|
||||
*/
|
||||
function show_admin_bar_language_selector( $package, $args = array() ) {
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-admin-lang-switcher.class.php';
|
||||
$this->admin_lang_switcher = new WPML_Package_Admin_Lang_Switcher( $package, $args );
|
||||
}
|
||||
|
||||
function cleanup_translation_jobs_basket_packages( $translation_jobs_basket ) {
|
||||
if ( empty( $translation_jobs_basket['packages'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $translation_jobs_basket['packages'] as $id => $data ) {
|
||||
if ( ! new WPML_Package( $id ) ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket( $id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function update_translation_jobs_basket( $translation_jobs_cart, $translation_jobs_basket, $item_type ) {
|
||||
if ( $item_type == 'package' ) {
|
||||
if ( ! isset( $translation_jobs_basket[ $item_type ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$packages = $translation_jobs_basket[ $item_type ];
|
||||
if ( empty( $packages ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cleanup_translation_jobs_basket_packages( $translation_jobs_basket );
|
||||
|
||||
global $sitepress;
|
||||
|
||||
$packages_ids = array_keys( $packages );
|
||||
|
||||
foreach ( $packages_ids as $package_id ) {
|
||||
$package = new WPML_Package( $package_id );
|
||||
if ( $package ) {
|
||||
if ( ! isset( $package->ID ) || ! $package->ID ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket( $package_id, 'package' );
|
||||
continue;
|
||||
}
|
||||
|
||||
$package_source_language = $packages[ $package_id ]['from_lang'];
|
||||
$package_target_languages = $packages[ $package_id ]['to_langs'];
|
||||
$language_names = $this->languages_to_csv( $package_target_languages );
|
||||
|
||||
$final_post = array();
|
||||
|
||||
$final_post['post_title'] = $package->title;
|
||||
$final_post['post_notes'] = get_post_meta( $package->ID, '_icl_translator_note', true );
|
||||
$final_post['post_type'] = $package->kind;
|
||||
if ( isset( $package->post_status ) ) {
|
||||
$final_post['post_status'] = $package->post_status;
|
||||
}
|
||||
if ( isset( $package->post_date ) ) {
|
||||
$final_post['post_date'] = $package->post_date;
|
||||
}
|
||||
$final_post['from_lang'] = $package_source_language;
|
||||
$final_post['from_lang_string'] = ucfirst( $sitepress->get_display_language_name( $package_source_language, $sitepress->get_admin_language() ) );
|
||||
$final_post['to_langs'] = $package_target_languages;
|
||||
$final_post['to_langs_string'] = implode( ', ', $language_names );
|
||||
|
||||
$translation_jobs_cart[ $package_id ] = $final_post;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $translation_jobs_cart;
|
||||
}
|
||||
|
||||
public function basket_items_types( $item_types ) {
|
||||
$item_types['package'] = 'custom';
|
||||
|
||||
return $item_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $package_target_languages
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
private function languages_to_csv( $package_target_languages ) {
|
||||
global $sitepress;
|
||||
|
||||
$language_names = array();
|
||||
foreach ( $package_target_languages as $language_code => $value ) {
|
||||
$language_names[] = ucfirst( $sitepress->get_display_language_name( $language_code, $sitepress->get_admin_language() ) );
|
||||
}
|
||||
|
||||
return $language_names;
|
||||
}
|
||||
|
||||
function is_external( $result, $type ) {
|
||||
return $result || is_a( $type, 'WPML_Package' ) || $type == 'package';
|
||||
}
|
||||
|
||||
public function get_element_type( $type, $element ) {
|
||||
if ( $this->is_a_package( $element ) ) {
|
||||
$type = 'package';
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function attributes_to_string( $attributes ) {
|
||||
$result = '';
|
||||
foreach ( $attributes as $key => $value ) {
|
||||
if ( $result ) {
|
||||
$result .= ' ';
|
||||
}
|
||||
$result .= esc_html( $key ) . '="' . esc_attr( $value ) . '"';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $kind_slug
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_package_element_type( $kind_slug ) {
|
||||
if ( is_object( $kind_slug ) ) {
|
||||
$kind_slug = $kind_slug->kind_slug;
|
||||
}
|
||||
if ( is_array( $kind_slug ) ) {
|
||||
$kind_slug = $kind_slug['kind_slug'];
|
||||
}
|
||||
|
||||
return 'package_' . $kind_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $package
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function package_has_kind( $package ) {
|
||||
return isset( $package['kind'] ) && $package['kind'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $package
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function package_has_name( $package ) {
|
||||
return isset( $package['name'] ) && $package['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $package
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function package_has_title( $package ) {
|
||||
return isset( $package['title'] ) && $package['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $package
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function package_has_kind_and_name( $package ) {
|
||||
return $this->package_has_kind( $package ) && $this->package_has_name( $package );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string_name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_string_with_underscores( $string_name ) {
|
||||
return preg_replace( '/[ \[\]]+/', '_', $string_name );
|
||||
}
|
||||
|
||||
function new_external_item( $type, $package_item, $get_string_data = false ) {
|
||||
// create a new external item for the Translation Dashboard or for translation jobs
|
||||
|
||||
$package_id = $package_item['ID'];
|
||||
|
||||
$item = new stdClass();
|
||||
$item->external_type = true;
|
||||
$item->type = $type;
|
||||
$item->ID = $package_id;
|
||||
$item->post_type = $type;
|
||||
$item->post_id = 'external_' . $item->post_type . '_' . $package_item['ID'];
|
||||
$item->post_date = '';
|
||||
$item->post_status = __( 'Active', 'wpml-string-translation' );
|
||||
$item->post_title = $package_item['title'];
|
||||
$item->is_translation = false;
|
||||
|
||||
if ( $get_string_data ) {
|
||||
$item->string_data = $this->_get_package_strings( $package_item );
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
function get_package_from_external_id( $post_id ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$packages = $wpdb->get_col( "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE ID>0" );
|
||||
|
||||
foreach ( $packages as $package_id ) {
|
||||
|
||||
$package = new WPML_Package( $package_id );
|
||||
|
||||
$test = $this->get_external_id_from_package( $package );
|
||||
if ( is_string( $post_id ) && $post_id == $test ) {
|
||||
return $package;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // not a package type
|
||||
}
|
||||
|
||||
function _get_package_strings( $package_item ) {
|
||||
global $wpdb;
|
||||
$strings = array();
|
||||
|
||||
$package_item_id = $package_item['ID'];
|
||||
$results = $wpdb->get_results( $wpdb->prepare( "SELECT name, value FROM {$wpdb->prefix}icl_strings WHERE string_package_id=%d", $package_item_id ) );
|
||||
|
||||
foreach ( $results as $result ) {
|
||||
$string_name = (bool) $package_item_id === true && strpos(
|
||||
$result->name,
|
||||
(string) $package_item_id
|
||||
) === 0
|
||||
? substr( $result->name, strlen( $package_item_id ) + 1 ) : $result->name;
|
||||
$strings[ $string_name ] = $result->value;
|
||||
}
|
||||
|
||||
// Add/update any registered strings
|
||||
if ( isset( $this->registered_strings[ $package_item_id ]['strings'] ) ) {
|
||||
foreach ( $this->registered_strings[ $package_item_id ]['strings'] as $id => $string_data ) {
|
||||
$strings[ $id ] = $string_data['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
function get_link( $item, $package_item, $anchor, $hide_empty ) {
|
||||
if ( $item == '' ) {
|
||||
$package_item = $this->get_package_from_external_id( $package_item );
|
||||
if ( ! $package_item ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$has_link = isset( $package_item->edit_link ) && $package_item->edit_link;
|
||||
if ( false === $anchor ) {
|
||||
if ( $has_link ) {
|
||||
$anchor = '<a href="' . $package_item->edit_link . '">' . $package_item['title'] . '</a>';
|
||||
} elseif ( ! $hide_empty ) {
|
||||
$anchor = $package_item['title'];
|
||||
}
|
||||
} else {
|
||||
if ( $has_link ) {
|
||||
$anchor = '<a href="' . $package_item['edit_link'] . '">' . $anchor . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$item = $anchor;
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update translations
|
||||
*
|
||||
* @param int $package_id
|
||||
* @param bool $is_new - set to true for newly created form (first save without fields)
|
||||
* @param bool $needs_update - when deleting single field we do not need to change the translation status of the form
|
||||
*
|
||||
* @internal param array $item - package information
|
||||
*/
|
||||
function update_package_translations( $package_id, $is_new, $needs_update = true ) {
|
||||
|
||||
global $sitepress, $wpdb, $iclTranslationManagement;
|
||||
|
||||
$item = $this->get_package_details( $package_id );
|
||||
|
||||
$post_id = $this->get_external_id_from_package( new WPML_Package( $package_id ) );
|
||||
$post = $this->get_translatable_item( null, $post_id );
|
||||
if ( ! $post ) {
|
||||
return;
|
||||
}
|
||||
$default_lang = $sitepress->get_default_language();
|
||||
$icl_el_type = $this->get_package_element_type( $item );
|
||||
$trid = $sitepress->get_element_trid( $item['ID'], $icl_el_type );
|
||||
|
||||
if ( $is_new ) {
|
||||
$sitepress->set_element_language_details( $post->ID, $icl_el_type, false, $default_lang, null, false );
|
||||
|
||||
// for new package nothing more to do
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT t.translation_id, s.md5
|
||||
FROM {$wpdb->prefix}icl_translations t
|
||||
NATURAL JOIN {$wpdb->prefix}icl_translation_status s
|
||||
WHERE t.trid=%d
|
||||
AND t.source_language_code IS NOT NULL
|
||||
";
|
||||
$element_translations = $wpdb->get_results( $wpdb->prepare( $sql, $trid ) );
|
||||
|
||||
if ( ! empty( $element_translations ) ) {
|
||||
|
||||
$md5 = $iclTranslationManagement->post_md5( $post );
|
||||
|
||||
if ( $md5 != $element_translations[0]->md5 ) { // all translations need update
|
||||
|
||||
$translation_package = $iclTranslationManagement->create_translation_package( $post );
|
||||
|
||||
foreach ( $element_translations as $trans ) {
|
||||
$_prevstate = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT status, translator_id, needs_update, md5, translation_service, translation_package, timestamp, links_fixed
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_id = %d
|
||||
",
|
||||
$trans->translation_id
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
if ( ! empty( $_prevstate ) ) {
|
||||
$data['_prevstate'] = serialize( $_prevstate );
|
||||
}
|
||||
$data = array(
|
||||
'translation_id' => $trans->translation_id,
|
||||
'translation_package' => serialize( $translation_package ),
|
||||
'md5' => $md5,
|
||||
);
|
||||
|
||||
// update only when something changed (we do not need to change status when deleting a field)
|
||||
if ( $needs_update ) {
|
||||
$data['needs_update'] = 1;
|
||||
}
|
||||
|
||||
$update_result = $iclTranslationManagement->update_translation_status( $data );
|
||||
$rid = $update_result[0];
|
||||
$this->update_icl_translate( $rid, $post );
|
||||
|
||||
// change job status only when needs update
|
||||
if ( $needs_update ) {
|
||||
$job_id = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid", $rid ) );
|
||||
if ( $job_id ) {
|
||||
$wpdb->update( "{$wpdb->prefix}icl_translate_job", array( 'translated' => 0 ), array( 'job_id' => $job_id ), array( '%d' ), array( '%d' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions to update translations when packages are modified in admin
|
||||
*
|
||||
* @param int $rid
|
||||
* @param \stdClass $post
|
||||
*/
|
||||
|
||||
function update_icl_translate( $rid, $post ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$job_id = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid", $rid ) );
|
||||
$elements = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT field_type, field_data, tid, field_translate FROM {$wpdb->prefix}icl_translate
|
||||
WHERE job_id=%d",
|
||||
$job_id
|
||||
),
|
||||
OBJECT_K
|
||||
);
|
||||
|
||||
foreach ( $post->string_data as $field_type => $field_value ) {
|
||||
$field_data = base64_encode( $field_value );
|
||||
if ( ! isset( $elements[ $field_type ] ) ) {
|
||||
// insert new field
|
||||
|
||||
$data = array(
|
||||
'job_id' => $job_id,
|
||||
'content_id' => 0,
|
||||
'field_type' => $field_type,
|
||||
'field_format' => 'base64',
|
||||
'field_translate' => 1,
|
||||
'field_data' => $field_data,
|
||||
'field_data_translated' => 0,
|
||||
'field_finished' => 0,
|
||||
);
|
||||
|
||||
$wpdb->insert( $wpdb->prefix . 'icl_translate', $data );
|
||||
} elseif ( $elements[ $field_type ]->field_data != $field_data ) {
|
||||
// update field value
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translate',
|
||||
array(
|
||||
'field_data' => $field_data,
|
||||
'field_finished' => 0,
|
||||
),
|
||||
array( 'tid' => $elements[ $field_type ]->tid )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $elements as $field_type => $el ) {
|
||||
// delete fields that are no longer present
|
||||
if ( $el->field_translate && ! isset( $post->string_data[ $field_type ] ) ) {
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'tid' => $el->tid ), array( '%d' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_package_details( $package_id ) {
|
||||
global $wpdb;
|
||||
static $cache = array();
|
||||
|
||||
if ( ! isset( $cache[ $package_id ] ) ) {
|
||||
$item = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE ID=%d", $package_id ), ARRAY_A );
|
||||
$cache[ $package_id ] = $item;
|
||||
}
|
||||
|
||||
return $cache[ $package_id ];
|
||||
}
|
||||
|
||||
function get_string_context_title( $context, $string_details ) {
|
||||
global $wpdb;
|
||||
|
||||
static $cache = array();
|
||||
|
||||
if ( ! isset( $cache[ $context ] ) ) {
|
||||
$package_id = $wpdb->get_var( $wpdb->prepare( "SELECT string_package_id FROM {$wpdb->prefix}icl_strings WHERE id=%d", $string_details['string_id'] ) );
|
||||
if ( $package_id ) {
|
||||
$package_details = $this->get_package_details( $package_id );
|
||||
if ( $package_details ) {
|
||||
$cache[ $context ] = $package_details->kind . ' - ' . $package_details->title;
|
||||
} else {
|
||||
$cache[ $context ] = $context;
|
||||
}
|
||||
} else {
|
||||
$cache[ $context ] = $context;
|
||||
}
|
||||
}
|
||||
|
||||
return $cache[ $context ];
|
||||
}
|
||||
|
||||
function get_string_title( $title, $string_details ) {
|
||||
global $wpdb;
|
||||
|
||||
$string_title = $wpdb->get_var( $wpdb->prepare( "SELECT title FROM {$wpdb->prefix}icl_strings WHERE id=%d", $string_details['string_id'] ) );
|
||||
if ( $string_title ) {
|
||||
return $string_title;
|
||||
} else {
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
||||
function _get_post_translations( $package ) {
|
||||
global $sitepress;
|
||||
|
||||
if ( is_object( $package ) ) {
|
||||
$package = get_object_vars( $package );
|
||||
}
|
||||
|
||||
$element_type = $this->get_package_element_type( $package['kind_slug'] );
|
||||
$trid = $sitepress->get_element_trid( $package['ID'], $element_type );
|
||||
|
||||
return $sitepress->get_element_translations( $trid, $element_type );
|
||||
}
|
||||
|
||||
function _is_translation_in_progress( $package ) {
|
||||
global $wpdb;
|
||||
|
||||
$post_translations = self::_get_post_translations( $package );
|
||||
|
||||
foreach ( $post_translations as $lang => $translation ) {
|
||||
$res = $wpdb->get_row( $wpdb->prepare( "SELECT status, needs_update, md5 FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation->translation_id ) );
|
||||
if ( $res && $res->status == ICL_TM_IN_PROGRESS ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _delete_translation_job( $package_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$package = $this->get_package_details( $package_id );
|
||||
|
||||
$post_translations = $this->_get_post_translations( $package );
|
||||
foreach ( $post_translations as $lang => $translation ) {
|
||||
$rid = $wpdb->get_var( $wpdb->prepare( "SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation->translation_id ) );
|
||||
if ( $rid ) {
|
||||
$job_id = $wpdb->get_var( $wpdb->prepare( "SELECT job_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d", $rid ) );
|
||||
|
||||
if ( $job_id ) {
|
||||
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $job_id ) );
|
||||
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}icl_translate WHERE job_id=%d", $job_id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function add_to_basket( $data ) {
|
||||
if ( isset( $data['tr_action'] ) ) {
|
||||
$posts_ids = TranslationProxy_Basket::get_elements_ids( $data, 'package' );
|
||||
|
||||
foreach ( $posts_ids as $id ) {
|
||||
$post_id = $id;
|
||||
$source_language = $data['translate_from'];
|
||||
$target_languages = $data['tr_action'];
|
||||
foreach ( $target_languages as $translate_to => $translation_action ) {
|
||||
$package = new WPML_Package( $post_id );
|
||||
$tm = new WPML_Package_TM( $package );
|
||||
$tm->add_package_to_basket( $translation_action, $source_language, $translate_to );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _no_wpml_warning() {
|
||||
?>
|
||||
<div class="message error">
|
||||
<p>
|
||||
<?php printf( __( 'WPML Package Translation is enabled but not effective. It requires <a href="%s">WPML</a>, String Translation and Translation Management in order to work.', 'wpml-string-translation' ), 'http://wpml.org/' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function tm_dashboard_sql_filter( $sql ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql .= " AND i.element_id NOT IN ( SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE post_id IS NOT NULL AND element_type = 'package_layout' )";
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_refresh_required() {
|
||||
$refresh_required = get_option( 'wpml-package-translation-refresh-required', 'yes' );
|
||||
return 'yes' === $refresh_required || '1' === $refresh_required;
|
||||
}
|
||||
|
||||
private function set_refresh_not_required() {
|
||||
update_option( 'wpml-package-translation-refresh-required', 'no', false );
|
||||
}
|
||||
|
||||
public function save_package_translations( $element_type_prefix, $job, $decoder ) {
|
||||
if ( $element_type_prefix === 'package' ) {
|
||||
$element_type_prefix = $this->get_package_type_prefix( $element_type_prefix, $job->original_doc_id );
|
||||
|
||||
foreach ( $job->elements as $field ) {
|
||||
if ( $field->field_translate ) {
|
||||
$string_id = icl_st_is_registered_string( $element_type_prefix, $field->field_type );
|
||||
if ( ! $string_id ) {
|
||||
icl_register_string( $element_type_prefix, $field->field_type, $decoder( $field->field_data, $field->field_format ) );
|
||||
$string_id = icl_st_is_registered_string( $element_type_prefix, $field->field_type );
|
||||
}
|
||||
if ( $string_id ) {
|
||||
icl_add_string_translation( $string_id, $job->language_code, $decoder( $field->field_data_translated, $field->field_format ), ICL_TM_COMPLETE );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,537 @@
|
||||
<?php
|
||||
|
||||
class WPML_Package {
|
||||
|
||||
const CACHE_GROUP = 'WPML_Package';
|
||||
|
||||
public $ID;
|
||||
public $view_link;
|
||||
public $edit_link;
|
||||
public $is_translation;
|
||||
public $string_data;
|
||||
public $title;
|
||||
public $new_title;
|
||||
public $kind_slug;
|
||||
public $kind;
|
||||
public $trid;
|
||||
public $name;
|
||||
public $translation_element_type;
|
||||
public $post_id;
|
||||
|
||||
private $element_type_prefix;
|
||||
|
||||
/**
|
||||
* @param stdClass|WPML_Package|array|int $data_item
|
||||
*/
|
||||
function __construct( $data_item ) {
|
||||
$this->element_type_prefix = 'package';
|
||||
$this->view_link = '';
|
||||
$this->edit_link = '';
|
||||
$this->post_id = null;
|
||||
if ( $data_item ) {
|
||||
if ( is_object( $data_item ) ) {
|
||||
$data_item = get_object_vars( $data_item );
|
||||
}
|
||||
if ( is_numeric( $data_item ) ) {
|
||||
$data_item = $this->init_from_id( $data_item, ARRAY_A );
|
||||
}
|
||||
if ( isset( $data_item['title'] ) ) {
|
||||
$this->new_title = $data_item['title'];
|
||||
}
|
||||
if ( $data_item && is_array( $data_item ) ) {
|
||||
$this->init_from_array( $data_item );
|
||||
}
|
||||
$this->new_title = $this->new_title != $this->title ? $this->new_title : null;
|
||||
}
|
||||
}
|
||||
|
||||
private function init_from_id( $id, $output = OBJECT ) {
|
||||
global $wpdb;
|
||||
|
||||
$packages_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE id=%s";
|
||||
$packages_prepared = $wpdb->prepare( $packages_query, $id );
|
||||
$package = $wpdb->get_row( $packages_prepared, $output );
|
||||
|
||||
return $package;
|
||||
}
|
||||
|
||||
public function __get( $property ) {
|
||||
if ( $property == 'id' ) {
|
||||
_deprecated_argument( 'id', '0.0.2', "Property 'id' is deprecated. Please use 'ID'." );
|
||||
|
||||
return $this->ID;
|
||||
}
|
||||
if ( $property == 'post_id' ) {
|
||||
return $this->ID;
|
||||
}
|
||||
if ( $property == 'post_title' ) {
|
||||
return $this->title;
|
||||
}
|
||||
if ( $property == 'post_type' ) {
|
||||
return $this->kind_slug;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __set( $property, $value ) {
|
||||
if ( $property == 'id' ) {
|
||||
_deprecated_argument( 'id', '0.0.2', "Property 'id' is deprecated. Please use 'ID'." );
|
||||
$this->ID = $value;
|
||||
} else {
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset( $property ) {
|
||||
if ( $property == 'id' ) {
|
||||
return isset( $this->ID );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __unset( $property ) {
|
||||
if ( $property == 'id' ) {
|
||||
unset( $this->$property );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_translation_element_type() {
|
||||
return $this->translation_element_type;
|
||||
}
|
||||
|
||||
public function get_package_post_id() {
|
||||
return $this->get_element_type_prefix() . '_' . $this->kind_slug . '_' . $this->ID;
|
||||
}
|
||||
|
||||
public function get_element_type_prefix() {
|
||||
return $this->element_type_prefix;
|
||||
}
|
||||
|
||||
public function set_package_post_data() {
|
||||
$this->translation_element_type = $this->element_type_prefix . '_' . $this->kind_slug;
|
||||
$this->update_strings_data();
|
||||
}
|
||||
|
||||
public function update_strings_data() {
|
||||
$strings = [];
|
||||
$package_id = $this->ID;
|
||||
if ( $package_id ) {
|
||||
$results = $this->get_package_strings();
|
||||
foreach ( $results as $result ) {
|
||||
$string_name = $this->get_package_string_name_from_st_name( $result );
|
||||
$strings[ $string_name ] = $result->value;
|
||||
}
|
||||
|
||||
$this->string_data = $strings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $refresh
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_package_strings( $refresh = false ) {
|
||||
global $wpdb;
|
||||
$package_id = $this->ID;
|
||||
$results = false;
|
||||
if ( $package_id ) {
|
||||
|
||||
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
|
||||
$cache_key = 'strings:' . $package_id;
|
||||
$found = false;
|
||||
|
||||
$results = $cache->get( $cache_key, $found );
|
||||
if ( ! $found || $refresh ) {
|
||||
$results_query = "
|
||||
SELECT id, name, value, wrap_tag, type, title
|
||||
FROM {$wpdb->prefix}icl_strings
|
||||
WHERE string_package_id=%d
|
||||
ORDER BY location, id ASC";
|
||||
$results_prepare = $wpdb->prepare( $results_query, $package_id );
|
||||
$results = $wpdb->get_results( $results_prepare );
|
||||
|
||||
$cache->set( $cache_key, $results );
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function set_strings_language( $language_code ) {
|
||||
global $wpdb;
|
||||
$package_id = $this->ID;
|
||||
if ( $package_id ) {
|
||||
$update_query = "UPDATE {$wpdb->prefix}icl_strings SET language=%s WHERE string_package_id=%d";
|
||||
$update_prepare = $wpdb->prepare( $update_query, $language_code, $package_id );
|
||||
$wpdb->query( $update_prepare );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass $result
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_package_string_name_from_st_name( $result ) {
|
||||
|
||||
// package string name is the same as the string name.
|
||||
return $result->name;
|
||||
}
|
||||
|
||||
private function sanitize_attributes() {
|
||||
if ( isset( $this->name ) ) {
|
||||
$this->name = $this->sanitize_string_name( $this->name );
|
||||
}
|
||||
if ( ( ! isset( $this->title ) || $this->title === '' ) && isset( $this->name ) ) {
|
||||
$this->title = $this->name;
|
||||
}
|
||||
if ( ! isset( $this->edit_link ) ) {
|
||||
$this->edit_link = '';
|
||||
}
|
||||
|
||||
$this->sanitize_kind();
|
||||
}
|
||||
|
||||
public function create_new_package_record() {
|
||||
$this->sanitize_attributes();
|
||||
|
||||
$package_id = $this->package_exists();
|
||||
if ( ! $package_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$data = array(
|
||||
'kind_slug' => $this->kind_slug,
|
||||
'kind' => $this->kind,
|
||||
'name' => $this->name,
|
||||
'title' => $this->title,
|
||||
'edit_link' => $this->edit_link,
|
||||
'view_link' => $this->view_link,
|
||||
'post_id' => $this->post_id,
|
||||
);
|
||||
$wpdb->insert( $wpdb->prefix . 'icl_string_packages', $data );
|
||||
$package_id = $wpdb->insert_id;
|
||||
|
||||
$this->ID = $package_id;
|
||||
}
|
||||
|
||||
return $package_id;
|
||||
}
|
||||
|
||||
public function update_package_record() {
|
||||
$result = false;
|
||||
|
||||
if ( $this->ID ) {
|
||||
global $wpdb;
|
||||
|
||||
$update_data = array(
|
||||
'kind_slug' => $this->kind_slug,
|
||||
'kind' => $this->kind,
|
||||
'name' => $this->name,
|
||||
'title' => $this->title,
|
||||
'edit_link' => $this->edit_link,
|
||||
'view_link' => $this->view_link,
|
||||
);
|
||||
$update_where = array(
|
||||
'ID' => $this->ID,
|
||||
);
|
||||
$result = $wpdb->update( $wpdb->prefix . 'icl_string_packages', $update_data, $update_where );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get_package_id() {
|
||||
return $this->ID;
|
||||
}
|
||||
|
||||
public function sanitize_string_name( $string_name ) {
|
||||
$string_name = preg_replace( '/[ \[\]]+/', '-', $string_name );
|
||||
|
||||
return $string_name;
|
||||
}
|
||||
|
||||
function translate_string( $string_value, $sanitized_string_name ) {
|
||||
$package_id = $this->get_package_id();
|
||||
|
||||
if ( $package_id ) {
|
||||
$sanitized_string_name = $this->sanitize_string_name( $sanitized_string_name );
|
||||
|
||||
$string_context = $this->get_string_context_from_package();
|
||||
|
||||
$string_name = $sanitized_string_name;
|
||||
|
||||
return icl_translate( $string_context, $string_name, $string_value );
|
||||
} else {
|
||||
return $string_value;
|
||||
}
|
||||
}
|
||||
|
||||
function get_string_context_from_package() {
|
||||
return $this->kind_slug . '-' . $this->name;
|
||||
}
|
||||
|
||||
public function get_string_id_from_package( $string_name, $string_value ) {
|
||||
$package_id = $this->get_package_id();
|
||||
$string_context = $this->get_string_context_from_package();
|
||||
|
||||
$string_data = array(
|
||||
'context' => $string_context,
|
||||
'name' => $string_name,
|
||||
);
|
||||
|
||||
/**
|
||||
* @param int|null $default
|
||||
* @param array $string_data {
|
||||
*
|
||||
* @type string $context
|
||||
* @type string $name Optional
|
||||
* }
|
||||
*/
|
||||
$string_id = apply_filters( 'wpml_string_id', null, $string_data );
|
||||
|
||||
if ( ! $string_id ) {
|
||||
$string_id = icl_register_string( $string_context, $string_name, $string_value, null, $this->get_package_language() );
|
||||
}
|
||||
|
||||
return $string_id;
|
||||
}
|
||||
|
||||
function get_translated_strings( $strings ) {
|
||||
$package_id = $this->get_package_id();
|
||||
|
||||
if ( $package_id ) {
|
||||
$results = $this->get_package_strings();
|
||||
|
||||
foreach ( $results as $result ) {
|
||||
$translations = icl_get_string_translations_by_id( $result->id );
|
||||
if ( ! empty( $translations ) ) {
|
||||
$string_name = $this->get_package_string_name_from_st_name( $result );
|
||||
$strings[ $string_name ] = $translations;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
function set_translated_strings( $translations ) {
|
||||
global $wpdb;
|
||||
|
||||
$this->sanitize_attributes();
|
||||
$package_id = $this->get_package_id();
|
||||
|
||||
if ( $package_id ) {
|
||||
foreach ( $translations as $string_name => $languages ) {
|
||||
$string_id_query = "SELECT id FROM {$wpdb->prefix}icl_strings WHERE name='%s'";
|
||||
$string_id_prepare = $wpdb->prepare( $string_id_query, $string_name );
|
||||
$string_id = $wpdb->get_var( $string_id_prepare );
|
||||
foreach ( $languages as $language_code => $language_data ) {
|
||||
icl_add_string_translation( $string_id, $language_code, $language_data['value'], $language_data['status'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function init_from_array( $args ) {
|
||||
foreach ( $args as $key => $value ) {
|
||||
if ( 'id' == $key ) {
|
||||
$key = 'ID';
|
||||
}
|
||||
$this->$key = $value;
|
||||
}
|
||||
|
||||
$this->sanitize_attributes();
|
||||
|
||||
if ( $this->package_id_exists() || $this->package_name_and_kind_exists() ) {
|
||||
$this->set_package_from_db();
|
||||
}
|
||||
$this->set_package_post_data();
|
||||
}
|
||||
|
||||
public function has_kind_and_name() {
|
||||
return ( isset( $this->kind ) && isset( $this->name ) && $this->kind && $this->name );
|
||||
}
|
||||
|
||||
private function set_package_from_db() {
|
||||
$package = false;
|
||||
if ( $this->package_id_exists() ) {
|
||||
$package = $this->get_package_from_id();
|
||||
} elseif ( $this->package_name_and_kind_exists() ) {
|
||||
$package = $this->get_package_from_name_and_kind();
|
||||
}
|
||||
if ( $package ) {
|
||||
$this->object_to_package( $package );
|
||||
}
|
||||
$this->sanitize_kind();
|
||||
}
|
||||
|
||||
private function get_package_from_id() {
|
||||
$result = false;
|
||||
if ( $this->has_id() ) {
|
||||
global $wpdb;
|
||||
|
||||
$package_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE ID=%d";
|
||||
$package_prepared = $wpdb->prepare( $package_query, array( $this->ID ) );
|
||||
|
||||
$result = $wpdb->get_row( $package_prepared );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function get_package_from_name_and_kind() {
|
||||
global $wpdb;
|
||||
|
||||
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
|
||||
$cache_key = 'name-kind:' . $this->kind_slug . $this->name;
|
||||
$found = false;
|
||||
|
||||
$result = $cache->get( $cache_key, $found );
|
||||
if ( ! $found ) {
|
||||
|
||||
$package_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE kind_slug=%s AND name=%s";
|
||||
$package_prepared = $wpdb->prepare( $package_query, array( $this->kind_slug, $this->name ) );
|
||||
|
||||
$result = $wpdb->get_row( $package_prepared );
|
||||
|
||||
if ( $result ) {
|
||||
$cache->set( $cache_key, $result );
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function package_name_and_kind_exists() {
|
||||
$result = false;
|
||||
if ( $this->has_kind_and_name() ) {
|
||||
$result = (bool) $this->get_package_from_name_and_kind();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function package_id_exists() {
|
||||
$result = false;
|
||||
if ( $this->has_id() ) {
|
||||
global $wpdb;
|
||||
|
||||
$package_query = "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE ID=%d";
|
||||
$package_prepared = $wpdb->prepare( $package_query, array( $this->ID ) );
|
||||
|
||||
$result = $wpdb->get_var( $package_prepared );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|mixed
|
||||
*/
|
||||
protected function package_exists() {
|
||||
$existing_package = false;
|
||||
if ( $this->has_id() ) {
|
||||
$existing_package = $this->package_id_exists();
|
||||
} elseif ( $this->has_kind_and_name() ) {
|
||||
$existing_package = $this->package_name_and_kind_exists();
|
||||
}
|
||||
|
||||
return $existing_package;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function has_id() {
|
||||
return isset( $this->ID ) && $this->ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass $package
|
||||
*/
|
||||
private function object_to_package( $package ) {
|
||||
$this->ID = $package->ID;
|
||||
$this->kind_slug = $package->kind_slug;
|
||||
$this->kind = $package->kind;
|
||||
$this->name = $package->name;
|
||||
$this->title = $package->title;
|
||||
$this->edit_link = $package->edit_link;
|
||||
$this->view_link = $package->view_link;
|
||||
}
|
||||
|
||||
private function get_kind_from_slug() {
|
||||
global $wpdb;
|
||||
if ( $this->kind_slug ) {
|
||||
$kinds_query = "SELECT kind FROM {$wpdb->prefix}icl_string_packages WHERE kind_slug=%s GROUP BY kind";
|
||||
$kinds_prepared = $wpdb->prepare( $kinds_query, $this->kind_slug );
|
||||
$kinds = $wpdb->get_col( $kinds_prepared );
|
||||
if ( count( $kinds ) > 1 ) {
|
||||
throw new WPML_Package_Exception( 'error', 'Package contains multiple kinds' );
|
||||
}
|
||||
if ( $kinds ) {
|
||||
return $kinds[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function sanitize_kind() {
|
||||
if ( isset( $this->kind ) && ( ! isset( $this->kind_slug ) || trim( $this->kind_slug ) === '' ) ) {
|
||||
$this->kind_slug = sanitize_title_with_dashes( $this->kind );
|
||||
}
|
||||
if ( $this->kind == $this->kind_slug ) {
|
||||
$this->kind = $this->get_kind_from_slug();
|
||||
}
|
||||
}
|
||||
|
||||
public function get_package_element_type() {
|
||||
return 'package_' . $this->kind_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_package_language() {
|
||||
global $sitepress;
|
||||
|
||||
if ( $this->post_id ) {
|
||||
$details = null;
|
||||
$post = get_post( $this->post_id );
|
||||
|
||||
if ( $post ) {
|
||||
$details = $sitepress->get_element_language_details( $this->post_id, 'post_' . $post->post_type );
|
||||
}
|
||||
} else {
|
||||
$element_type = $this->get_package_element_type();
|
||||
$details = $sitepress->get_element_language_details( $this->ID, $element_type );
|
||||
}
|
||||
|
||||
if ( $details ) {
|
||||
return $details->language_code;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function are_all_strings_included( $strings ) {
|
||||
// check to see if all the strings in this package are present in $strings
|
||||
$package_strings = $this->get_package_strings();
|
||||
if ( is_array( $package_strings ) ) {
|
||||
foreach ( $package_strings as $string ) {
|
||||
if ( ! in_array( $string->id, $strings ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function flush_cache() {
|
||||
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
|
||||
$cache->flush_group_cache();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*globals jQuery, ajaxurl*/
|
||||
/*jshint browser:true, devel:true*/
|
||||
|
||||
var WPML_Package_Translation = WPML_Package_Translation || {};
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
WPML_Package_Translation.ManagementPage = function () {
|
||||
var self = this;
|
||||
|
||||
self.init = function () {
|
||||
jQuery('.js_package_all_cb').on('change', self.check_uncheck_all);
|
||||
jQuery('.js_package_row_cb').on('change', self.enable_disable_delete);
|
||||
jQuery('#delete_packages').on('click', self.delete_selected_packages);
|
||||
jQuery('#package_kind_filter').on('change', self.filter_by_kind);
|
||||
};
|
||||
|
||||
self.check_uncheck_all = function () {
|
||||
var package_all_cb = jQuery('.js_package_all_cb').first();
|
||||
|
||||
var checked = package_all_cb.prop('checked');
|
||||
jQuery('.js_package_row_cb').each(
|
||||
function () {
|
||||
if (!jQuery(this).is(':disabled')) {
|
||||
jQuery(this).prop('checked', checked);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
self.enable_disable_delete();
|
||||
};
|
||||
|
||||
self.enable_disable_delete = function () {
|
||||
var enable = jQuery('.js_package_row_cb:checked:visible').length !== 0;
|
||||
|
||||
jQuery('#delete_packages').prop('disabled', !enable);
|
||||
};
|
||||
|
||||
self.delete_selected_packages = function () {
|
||||
|
||||
if (confirm(jQuery('.js-delete-confirm-message').html())) {
|
||||
jQuery('#delete_packages').prop('disabled', true);
|
||||
jQuery('.spinner').css( 'float', 'none' ).addClass( 'is-active' );
|
||||
|
||||
var selected = jQuery('.js_package_row_cb:checked:visible');
|
||||
|
||||
var packages = [];
|
||||
|
||||
selected.each(
|
||||
function () {
|
||||
packages.push(jQuery(this).val());
|
||||
}
|
||||
);
|
||||
|
||||
var data = {
|
||||
action: 'wpml_delete_packages',
|
||||
wpnonce: jQuery('#wpml_package_nonce').attr('value'),
|
||||
packages: packages
|
||||
};
|
||||
|
||||
jQuery.ajax(
|
||||
{
|
||||
url: ajaxurl,
|
||||
type: 'post',
|
||||
data: data,
|
||||
success: function () {
|
||||
selected.each(
|
||||
function () {
|
||||
var package_row = jQuery(this).closest('.js_package');
|
||||
package_row.fadeOut(
|
||||
1000, function () {
|
||||
jQuery(this).remove();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
jQuery('.spinner').removeClass( 'is-active' );
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
self.all_selected = function () {
|
||||
var kind_slug = jQuery('#package_kind_filter').val();
|
||||
return kind_slug === '-1';
|
||||
};
|
||||
|
||||
self.filter_by_kind = function () {
|
||||
var kind_slug = jQuery('#package_kind_filter').val();
|
||||
var icl_package_translations = jQuery('#icl_package_translations');
|
||||
var icl_package_translations_body = icl_package_translations.find('tbody');
|
||||
if (self.all_selected()) {
|
||||
icl_package_translations_body.find('tr').show();
|
||||
} else {
|
||||
icl_package_translations_body.find('tr').hide();
|
||||
icl_package_translations_body.find('tr.js_package.js_package_' + kind_slug).show();
|
||||
}
|
||||
self.enable_disable_delete();
|
||||
};
|
||||
|
||||
self.init();
|
||||
};
|
||||
|
||||
jQuery(
|
||||
function () {
|
||||
WPML_Package_Translation.management_page = new WPML_Package_Translation.ManagementPage();
|
||||
}
|
||||
);
|
||||
|
||||
}());
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/*
|
||||
WPML Package Translation
|
||||
This is now part of String Translation.
|
||||
*/
|
||||
|
||||
if ( defined( 'WPML_PACKAGE_TRANSLATION' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
define( 'WPML_PACKAGE_TRANSLATION', '0.0.2' );
|
||||
define( 'WPML_PACKAGE_TRANSLATION_PATH', dirname( __FILE__ ) );
|
||||
define( 'WPML_PACKAGE_TRANSLATION_URL', WPML_ST_URL . '/inc/' . basename( WPML_PACKAGE_TRANSLATION_PATH ) );
|
||||
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-constants.php';
|
||||
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-exception.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-helper.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-ui.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-html-packages.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-metabox.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-st.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-tm-jobs.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-tm.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package.class.php';
|
||||
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation.class.php';
|
||||
|
||||
$WPML_package_translation = new WPML_Package_Translation();
|
||||
$WPML_Package_Translation_UI = new WPML_Package_Translation_UI();
|
||||
$WPML_Package_Translation_HTML_Packages = new WPML_Package_Translation_HTML_Packages();
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
function wpml_st_pos_scan_store_results( $string, $domain, $context, $file, $line ) {
|
||||
global $__wpml_st_po_file_content;
|
||||
static $strings = array();
|
||||
|
||||
$key = md5( $domain . $context . $string );
|
||||
//avoid duplicates
|
||||
if ( isset( $strings[ $key ] ) ) {
|
||||
return false;
|
||||
}
|
||||
$strings[ $key ] = true;
|
||||
|
||||
$file = @file( $file );
|
||||
if ( ! empty( $file ) ) {
|
||||
$__wpml_st_po_file_content .= PHP_EOL;
|
||||
$__wpml_st_po_file_content .= '# ' . @trim( $file[ $line - 2 ] ) . PHP_EOL;
|
||||
$__wpml_st_po_file_content .= '# ' . @trim( $file[ $line - 1 ] ) . PHP_EOL;
|
||||
$__wpml_st_po_file_content .= '# ' . @trim( $file[ $line ] ) . PHP_EOL;
|
||||
}
|
||||
|
||||
//$__wpml_st_po_file_content .= 'msgid "'.str_replace('"', '\"', $string).'"' . PHP_EOL;
|
||||
$__wpml_st_po_file_content .= PHP_EOL;
|
||||
if ( $context ) {
|
||||
$__wpml_st_po_file_content .= 'msgctxt "' . addslashes( $context ) . '"' . PHP_EOL;
|
||||
}
|
||||
$__wpml_st_po_file_content .= 'msgid "' . $string . '"' . PHP_EOL;
|
||||
$__wpml_st_po_file_content .= 'msgstr ""' . PHP_EOL;
|
||||
}
|
||||
714
wp-content/plugins/wpml-string-translation/inc/potx.php
Normal file
714
wp-content/plugins/wpml-string-translation/inc/potx.php
Normal file
@@ -0,0 +1,714 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
*/
|
||||
|
||||
// $Id: potx.inc,v 1.1.2.17.2.7.2.19.4.1 2009/07/19 12:54:42 goba Exp $
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Extraction API used by the web and command line interface.
|
||||
*
|
||||
* This include file implements the default string and file version
|
||||
* storage as well as formatting of POT files for web download or
|
||||
* file system level creation. The strings, versions and file contents
|
||||
* are handled with global variables to reduce the possible memory overhead
|
||||
* and API clutter of passing them around. Custom string and version saving
|
||||
* functions can be implemented to use the functionality provided here as an
|
||||
* API for Drupal code to translatable string conversion.
|
||||
*
|
||||
* The potx-cli.php script can be used with this include file as
|
||||
* a command line interface to string extraction. The potx.module
|
||||
* can be used as a web interface for manual extraction.
|
||||
*
|
||||
* For a module using potx as an extraction API, but providing more
|
||||
* sophisticated functionality on top of it, look into the
|
||||
* 'Localization server' module: http://drupal.org/project/l10n_server
|
||||
*/
|
||||
|
||||
/**
|
||||
* Silence status reports.
|
||||
*/
|
||||
define('POTX_STATUS_SILENT', 0);
|
||||
|
||||
/**
|
||||
* Drupal message based status reports.
|
||||
*/
|
||||
define('POTX_STATUS_MESSAGE', 1);
|
||||
|
||||
/**
|
||||
* Command line status reporting.
|
||||
*
|
||||
* Status goes to standard output, errors to standard error.
|
||||
*/
|
||||
define('POTX_STATUS_CLI', 2);
|
||||
|
||||
/**
|
||||
* Structured array status logging.
|
||||
*
|
||||
* Useful for coder review status reporting.
|
||||
*/
|
||||
define('POTX_STATUS_STRUCTURED', 3);
|
||||
|
||||
/**
|
||||
* Core parsing mode:
|
||||
* - .info files folded into general.pot
|
||||
* - separate files generated for modules
|
||||
*/
|
||||
define('POTX_BUILD_CORE', 0);
|
||||
|
||||
/**
|
||||
* Multiple files mode:
|
||||
* - .info files folded into their module pot files
|
||||
* - separate files generated for modules
|
||||
*/
|
||||
define('POTX_BUILD_MULTIPLE', 1);
|
||||
|
||||
/**
|
||||
* Single file mode:
|
||||
* - all files folded into one pot file
|
||||
*/
|
||||
define('POTX_BUILD_SINGLE', 2);
|
||||
|
||||
/**
|
||||
* Save string to both installer and runtime collection.
|
||||
*/
|
||||
define('POTX_STRING_BOTH', 0);
|
||||
|
||||
/**
|
||||
* Save string to installer collection only.
|
||||
*/
|
||||
define('POTX_STRING_INSTALLER', 1);
|
||||
|
||||
/**
|
||||
* Save string to runtime collection only.
|
||||
*/
|
||||
define('POTX_STRING_RUNTIME', 2);
|
||||
|
||||
/**
|
||||
* Parse source files in Drupal 5.x format.
|
||||
*/
|
||||
define('POTX_API_5', 5);
|
||||
|
||||
/**
|
||||
* Parse source files in Drupal 6.x format.
|
||||
*
|
||||
* Changes since 5.x documented at http://drupal.org/node/114774
|
||||
*/
|
||||
define('POTX_API_6', 6);
|
||||
|
||||
/**
|
||||
* Parse source files in Drupal 7.x format.
|
||||
*
|
||||
* Changes since 6.x documented at http://drupal.org/node/224333
|
||||
*/
|
||||
define('POTX_API_7', 7);
|
||||
|
||||
/**
|
||||
* When no context is used. Makes it easy to look these up.
|
||||
*/
|
||||
define('POTX_CONTEXT_NONE', NULL);
|
||||
|
||||
/**
|
||||
* When there was a context identification error.
|
||||
*/
|
||||
define('POTX_CONTEXT_ERROR', FALSE);
|
||||
|
||||
/**
|
||||
* Process a file and put extracted information to the given parameters.
|
||||
*
|
||||
* @param string $file_path Complete path to file to process.
|
||||
* @param int $strip_prefix An integer denoting the number of chars to strip from filepath for output.
|
||||
* @param callable|string $save_callback Callback function to use to save the collected strings.
|
||||
* @param callable|string $version_callback Callback function to use to save collected version numbers.
|
||||
* @param string $default_domain Default domain to be used if one can't be found.
|
||||
*/
|
||||
function _potx_process_file($file_path,
|
||||
$strip_prefix = 0,
|
||||
$save_callback = '_potx_save_string',
|
||||
$version_callback = '_potx_save_version',
|
||||
$default_domain = '') {
|
||||
|
||||
global $_potx_tokens, $_potx_lookup;
|
||||
|
||||
// Always grab the CVS version number from the code
|
||||
if ( !wpml_st_file_path_is_valid( $file_path ) ) {
|
||||
return;
|
||||
}
|
||||
$code = file_get_contents($file_path);
|
||||
$file_name = $strip_prefix > 0 ? substr($file_path, $strip_prefix) : $file_path;
|
||||
_potx_find_version_number($code, $file_name, $version_callback);
|
||||
|
||||
// Extract raw PHP language tokens.
|
||||
$raw_tokens = token_get_all($code);
|
||||
unset($code);
|
||||
|
||||
// Remove whitespace and possible HTML (the later in templates for example),
|
||||
// count line numbers so we can include them in the output.
|
||||
$_potx_tokens = array();
|
||||
$_potx_lookup = array();
|
||||
$token_number = 0;
|
||||
$line_number = 1;
|
||||
// Fill array for finding token offsets quickly.
|
||||
$src_tokens = array(
|
||||
'__', 'esc_attr__', 'esc_html__', '_e', 'esc_attr_e', 'esc_html_e',
|
||||
'_x', 'esc_attr_x', 'esc_html_x', '_ex',
|
||||
'_n', '_nx'
|
||||
);
|
||||
foreach ($raw_tokens as $token) {
|
||||
if ((!is_array($token)) || (($token[0] != T_WHITESPACE) && ($token[0] != T_INLINE_HTML))) {
|
||||
if (is_array($token)) {
|
||||
$token[] = $line_number;
|
||||
|
||||
if ($token[0] == T_STRING || ($token[0] == T_VARIABLE && in_array($token[1], $src_tokens))) {
|
||||
if (!isset($_potx_lookup[$token[1]])) {
|
||||
$_potx_lookup[$token[1]] = array();
|
||||
}
|
||||
$_potx_lookup[$token[1]][] = $token_number;
|
||||
}
|
||||
}
|
||||
$_potx_tokens[] = $token;
|
||||
$token_number++;
|
||||
}
|
||||
// Collect line numbers.
|
||||
if (is_array($token)) {
|
||||
$line_number += count(explode("\n", $token[1])) - 1;
|
||||
}
|
||||
else {
|
||||
$line_number += count(explode("\n", $token)) - 1;
|
||||
}
|
||||
}
|
||||
unset($raw_tokens);
|
||||
|
||||
if(!empty($src_tokens))
|
||||
foreach($src_tokens as $tk){
|
||||
_potx_find_t_calls_with_context($file_name, $save_callback, $tk, $default_domain);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape quotes in a strings depending on the surrounding
|
||||
* quote type used.
|
||||
*
|
||||
* @param string $str The strings to escape
|
||||
*/
|
||||
function _potx_format_quoted_string($str) {
|
||||
$quo = substr($str, 0, 1);
|
||||
$str = substr($str, 1, -1);
|
||||
if ($quo == '"') {
|
||||
$str = stripcslashes($str);
|
||||
}
|
||||
else {
|
||||
$str = strtr($str, array("\\'" => "'", "\\\\" => "\\"));
|
||||
}
|
||||
return addcslashes($str, "\0..\37\\\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_potx_unquote_context_or_domain( $string ) {
|
||||
$quote_type = mb_substr( $string, 0, 1 );
|
||||
return trim( $string, $quote_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a marker error with an extract of where the error was found.
|
||||
*
|
||||
* @param string $file Name of file
|
||||
* @param int $line Line number of error
|
||||
* @param string $marker Function name with which the error was identified
|
||||
* @param int $ti Index on the token array
|
||||
* @param string $error Helpful error message for users.
|
||||
* @param string $docs_url Documentation reference.
|
||||
*/
|
||||
function _potx_marker_error($file, $line, $marker, $ti, $error, $docs_url = NULL) {
|
||||
global $_potx_tokens;
|
||||
|
||||
$tokens = '';
|
||||
$ti += 2;
|
||||
$tc = count($_potx_tokens);
|
||||
$par = 1;
|
||||
while ((($tc - $ti) > 0) && $par) {
|
||||
if (is_array($_potx_tokens[$ti])) {
|
||||
$tokens .= $_potx_tokens[$ti][1];
|
||||
}
|
||||
else {
|
||||
$tokens .= $_potx_tokens[$ti];
|
||||
if ($_potx_tokens[$ti] == "(") {
|
||||
$par++;
|
||||
}
|
||||
else if ($_potx_tokens[$ti] == ")") {
|
||||
$par--;
|
||||
}
|
||||
}
|
||||
$ti++;
|
||||
}
|
||||
potx_status('error', $error, $file, $line, $marker .'('. $tokens, $docs_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Status notification function.
|
||||
*
|
||||
* @param string $op Operation to perform or type of message text.
|
||||
* - set: sets the reporting mode to $value
|
||||
* use one of the POTX_STATUS_* constants as $value
|
||||
* - get: returns the list of error messages recorded
|
||||
* if $value is true, it also clears the internal message cache
|
||||
* - error: sends an error message in $value with optional $file and $line
|
||||
* - status: sends a status message in $value
|
||||
* @param string $value Value depending on $op.
|
||||
* @param string $file Name of file the error message is related to.
|
||||
* @param int $line Number of line the error message is related to.
|
||||
* @param string $excerpt Excerpt of the code in question, if available.
|
||||
* @param string $docs_url URL to the guidelines to follow to fix the problem.
|
||||
*/
|
||||
function potx_status($op, $value = NULL, $file = NULL, $line = NULL, $excerpt = NULL, $docs_url = NULL) {
|
||||
static $mode = POTX_STATUS_CLI;
|
||||
static $messages = array();
|
||||
|
||||
switch ($op) {
|
||||
case 'set':
|
||||
// Setting the reporting mode.
|
||||
$mode = $value;
|
||||
return;
|
||||
|
||||
case 'get':
|
||||
// Getting the errors. Optionally deleting the messages.
|
||||
$errors = $messages;
|
||||
if (!empty($value)) {
|
||||
$messages = array();
|
||||
}
|
||||
return $errors;
|
||||
|
||||
case 'error':
|
||||
case 'status':
|
||||
|
||||
// Location information is required in 3 of the four possible reporting
|
||||
// modes as part of the error message. The structured mode needs the
|
||||
// file, line and excerpt info separately, not in the text.
|
||||
$location_info = '';
|
||||
if (($mode != POTX_STATUS_STRUCTURED) && isset($file)) {
|
||||
if (isset($line)) {
|
||||
if (isset($excerpt)) {
|
||||
$location_info = potx_t('At %excerpt in %file on line %line.', array('%excerpt' => $excerpt, '%file' => $file, '%line' => $line));
|
||||
}
|
||||
else {
|
||||
$location_info = potx_t('In %file on line %line.', array('%file' => $file, '%line' => $line));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isset($excerpt)) {
|
||||
$location_info = potx_t('At %excerpt in %file.', array('%excerpt' => $excerpt, '%file' => $file));
|
||||
}
|
||||
else {
|
||||
$location_info = potx_t('In %file.', array('%file' => $file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation helpers are provided as readable text in most modes.
|
||||
$read_more = '';
|
||||
if (($mode != POTX_STATUS_STRUCTURED) && isset($docs_url)) {
|
||||
$read_more = ($mode == POTX_STATUS_CLI) ? potx_t('Read more at @url', array('@url' => $docs_url)) : potx_t('Read more at <a href="@url">@url</a>', array('@url' => $docs_url));
|
||||
}
|
||||
|
||||
// Error message or progress text to display.
|
||||
switch ($mode) {
|
||||
case POTX_STATUS_CLI:
|
||||
if(defined('STDERR') && defined('STDOUT')){
|
||||
fwrite($op == 'error' ? STDERR : STDOUT, join("\n", array($value, $location_info, $read_more)) ."\n\n");
|
||||
}
|
||||
break;
|
||||
case POTX_STATUS_SILENT:
|
||||
if ($op == 'error') {
|
||||
$messages[] = join(' ', array($value, $location_info, $read_more));
|
||||
}
|
||||
break;
|
||||
case POTX_STATUS_STRUCTURED:
|
||||
if ($op == 'error') {
|
||||
$messages[] = array($value, $file, $line, $excerpt, $docs_url);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect all occurances of t()-like calls.
|
||||
*
|
||||
* These sequences are searched for:
|
||||
* T_STRING("$function_name") + "(" + T_CONSTANT_ENCAPSED_STRING + ")"
|
||||
* T_STRING("$function_name") + "(" + T_CONSTANT_ENCAPSED_STRING + ","
|
||||
*
|
||||
* @param string $file Name of file parsed.
|
||||
* @param callable $save_callback Callback function used to save strings.
|
||||
* @param string $function_name The name of the function to look for (could be 't', '$t', 'st'
|
||||
* or any other t-like function).
|
||||
* @param int $string_mode String mode to use: POTX_STRING_INSTALLER, POTX_STRING_RUNTIME or
|
||||
* POTX_STRING_BOTH.
|
||||
*/
|
||||
function _potx_find_t_calls($file, $save_callback, $function_name = 't', $string_mode = POTX_STRING_RUNTIME) {
|
||||
global $_potx_tokens, $_potx_lookup;
|
||||
|
||||
// Lookup tokens by function name.
|
||||
if (isset($_potx_lookup[$function_name])) {
|
||||
foreach ($_potx_lookup[$function_name] as $ti) {
|
||||
list($ctok, $par, $mid, $rig) = array($_potx_tokens[$ti], $_potx_tokens[$ti+1], $_potx_tokens[$ti+2], $_potx_tokens[$ti+3]);
|
||||
list($type, $string, $line) = $ctok;
|
||||
if ($par == "(") {
|
||||
if (in_array($rig, array(")", ","))
|
||||
&& (is_array($mid) && ($mid[0] == T_CONSTANT_ENCAPSED_STRING))) {
|
||||
// This function is only used for context-less call types.
|
||||
$save_callback(_potx_format_quoted_string($mid[1]), POTX_CONTEXT_NONE, $file, $line, $string_mode);
|
||||
}
|
||||
else {
|
||||
// $function_name() found, but inside is something which is not a string literal.
|
||||
_potx_marker_error($file, $line, $function_name, $ti, potx_t('The first parameter to @function() should be a literal string. There should be no variables, concatenation, constants or other non-literal strings there.', array('@function' => $function_name)), 'http://drupal.org/node/322732');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect all occurances of t()-like calls from Drupal 7 (with context).
|
||||
*
|
||||
* These sequences are searched for:
|
||||
* T_STRING("$function_name") + "(" + T_CONSTANT_ENCAPSED_STRING + ")"
|
||||
* T_STRING("$function_name") + "(" + T_CONSTANT_ENCAPSED_STRING + ","
|
||||
* and then an optional value for the replacements and an optional array
|
||||
* for the options with an optional context key.
|
||||
*
|
||||
* @param string $file Name of file parsed.
|
||||
* @param callable $save_callback Callback function used to save strings.
|
||||
* @param string $function_name
|
||||
* @param string $default_domain
|
||||
* @param int $string_mode String mode to use: POTX_STRING_INSTALLER, POTX_STRING_RUNTIME or
|
||||
* POTX_STRING_BOTH.
|
||||
*
|
||||
* @internal param $function_name The name of the function to look for (could be 't', '$t', 'st'* The name of the function to look for (could be 't', '$t', 'st'
|
||||
* or any other t-like function). Drupal 7 only supports context on t().
|
||||
*/
|
||||
function _potx_find_t_calls_with_context(
|
||||
$file,
|
||||
$save_callback,
|
||||
$function_name = '_e',
|
||||
$default_domain = '',
|
||||
$string_mode = POTX_STRING_RUNTIME
|
||||
) {
|
||||
global $_potx_tokens, $_potx_lookup;
|
||||
|
||||
$filter_by_domain = isset( $_GET['domain'] ) ? filter_var( $_GET['domain'], FILTER_SANITIZE_STRING ) : null;
|
||||
|
||||
// Lookup tokens by function name.
|
||||
if ( isset( $_potx_lookup[ $function_name ] ) ) {
|
||||
foreach ( $_potx_lookup[ $function_name ] as $ti ) {
|
||||
list( $ctok, $par, $mid, $rig ) = array(
|
||||
$_potx_tokens[ $ti ],
|
||||
$_potx_tokens[ $ti + 1 ],
|
||||
$_potx_tokens[ $ti + 2 ],
|
||||
$_potx_tokens[ $ti + 3 ]
|
||||
);
|
||||
list( $type, $string, $line ) = $ctok;
|
||||
if ( $par == "(" ) {
|
||||
if ( in_array( $rig, array( ")", "," ) )
|
||||
&& ( is_array( $mid ) && ( $mid[ 0 ] == T_CONSTANT_ENCAPSED_STRING ) )
|
||||
) {
|
||||
$context = false;
|
||||
// By default, there is no context.
|
||||
$domain = POTX_CONTEXT_NONE;
|
||||
if ( $rig == ',' ) {
|
||||
if ( in_array( $function_name, array( '_x', '_ex', 'esc_attr_x', 'esc_html_x' ), true ) ) {
|
||||
$domain_offset = 6;
|
||||
$context_offset = 4;
|
||||
} elseif ( $function_name == '_n' ) {
|
||||
$domain_offset = _potx_find_end_of_function( $ti, '(', ')' ) - 1 - $ti;
|
||||
$context_offset = false;
|
||||
$text_plural = $_potx_tokens[ $ti + 4 ][ 1 ];
|
||||
} elseif ( $function_name == '_nx' ) {
|
||||
$domain_offset = _potx_find_end_of_function( $ti, '(', ')' ) - 1 - $ti;
|
||||
$context_offset = $domain_offset - 2;
|
||||
$text_plural = $_potx_tokens[ $ti + 4 ][ 1 ];
|
||||
} else {
|
||||
$domain_offset = 4;
|
||||
$context_offset = false;
|
||||
}
|
||||
|
||||
if ( ! isset( $_potx_tokens[ $ti + $domain_offset ][ 1 ] )
|
||||
|| ! preg_match( '#^(\'|")(.+)#', $_potx_tokens[ $ti + $domain_offset ][ 1 ] )
|
||||
) {
|
||||
if ( $default_domain ) {
|
||||
$domain = $default_domain;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$domain = wpml_potx_unquote_context_or_domain( $_potx_tokens[ $ti + $domain_offset ][ 1 ] );
|
||||
}
|
||||
|
||||
// exception for gettext calls with contexts
|
||||
if ( false !== $context_offset && isset( $_potx_tokens[ $ti + $context_offset ] ) ) {
|
||||
if ( ! preg_match( '#^(\'|")(.+)#', @$_potx_tokens[ $ti + $context_offset ][ 1 ] ) ) {
|
||||
$constant_val = @constant( $_potx_tokens[ $ti + $context_offset ][ 1 ] );
|
||||
if ( ! is_null( $constant_val ) ) {
|
||||
$context = $constant_val;
|
||||
} else {
|
||||
if ( function_exists( @$_potx_tokens[ $ti + $context_offset ][ 1 ] ) ) {
|
||||
$context = @$_potx_tokens[ $ti + $context_offset ][ 1 ]();
|
||||
if ( empty( $context ) ) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$context = wpml_potx_unquote_context_or_domain( $_potx_tokens[ $ti + $context_offset ][ 1 ] );
|
||||
}
|
||||
|
||||
} else {
|
||||
$context = false;
|
||||
}
|
||||
}
|
||||
if (
|
||||
$domain !== POTX_CONTEXT_ERROR &&
|
||||
( ! $filter_by_domain || $filter_by_domain === $domain ) &&
|
||||
is_callable( $save_callback, false, $callback_name )
|
||||
) {
|
||||
// Only save if there was no error in context parsing.
|
||||
call_user_func( $save_callback,
|
||||
_potx_format_quoted_string( $mid[ 1 ] ),
|
||||
$domain,
|
||||
@strval( $context ),
|
||||
$file,
|
||||
$line,
|
||||
$string_mode );
|
||||
if ( isset( $text_plural ) ) {
|
||||
call_user_func( $save_callback,
|
||||
_potx_format_quoted_string( $text_plural ),
|
||||
$domain,
|
||||
$context,
|
||||
$file,
|
||||
$line,
|
||||
$string_mode );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// $function_name() found, but inside is something which is not a string literal.
|
||||
_potx_marker_error( $file,
|
||||
$line,
|
||||
$function_name,
|
||||
$ti,
|
||||
potx_t( 'The first parameter to @function() should be a literal string. There should be no variables, concatenation, constants or other non-literal strings there.',
|
||||
array( '@function' => $function_name ) ),
|
||||
'http://drupal.org/node/322732' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to look up the token closing the current function.
|
||||
*
|
||||
* @param string $here The token at the function name
|
||||
*/
|
||||
function _potx_find_end_of_function($here, $open = '{', $close = '}') {
|
||||
global $_potx_tokens;
|
||||
|
||||
// Seek to open brace.
|
||||
while (is_array($_potx_tokens[$here]) || $_potx_tokens[$here] != $open) {
|
||||
$here++;
|
||||
}
|
||||
$nesting = 1;
|
||||
while ($nesting > 0) {
|
||||
$here++;
|
||||
if (!is_array($_potx_tokens[$here])) {
|
||||
if ($_potx_tokens[$here] == $close) {
|
||||
$nesting--;
|
||||
}
|
||||
if ($_potx_tokens[$here] == $open) {
|
||||
$nesting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $here;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to move past potx_t() and format_plural() arguments in search of context.
|
||||
*
|
||||
* @param string $here The token before the start of the arguments
|
||||
*/
|
||||
function _potx_skip_args($here) {
|
||||
global $_potx_tokens;
|
||||
|
||||
$nesting = 0;
|
||||
// Go through to either the end of the function call or to a comma
|
||||
// after the current position on the same nesting level.
|
||||
while (!(($_potx_tokens[$here] == ',' && $nesting == 0) ||
|
||||
($_potx_tokens[$here] == ')' && $nesting == -1))) {
|
||||
$here++;
|
||||
if (!is_array($_potx_tokens[$here])) {
|
||||
if ($_potx_tokens[$here] == ')') {
|
||||
$nesting--;
|
||||
}
|
||||
if ($_potx_tokens[$here] == '(') {
|
||||
$nesting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we run out of nesting, it means we reached the end of the function call,
|
||||
// so we skipped the arguments but did not find meat for looking at the
|
||||
// specified context.
|
||||
return ($nesting == 0 ? $here : FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to find the value for 'context' on t() and format_plural().
|
||||
*
|
||||
* @param int $tf Start position of the original function.
|
||||
* @param int $ti Start position where we should search from.
|
||||
* @param string $file Full path name of file parsed.
|
||||
* @param string $function_name The name of the function to look for. Either 'format_plural' or 't'
|
||||
* given that Drupal 7 only supports context on these.
|
||||
*/
|
||||
function _potx_find_context($tf, $ti, $file, $function_name) {
|
||||
global $_potx_tokens;
|
||||
|
||||
// Start from after the comma and skip the possible arguments for the function
|
||||
// so we can look for the context.
|
||||
if (($ti = _potx_skip_args($ti)) && ($_potx_tokens[$ti] == ',')) {
|
||||
// Now we actually might have some definition for a context. The $options
|
||||
// argument is coming up, which might have a key for context.
|
||||
echo "TI:" . $ti."\n";
|
||||
list($com, $arr, $par) = array($_potx_tokens[$ti], $_potx_tokens[$ti+1], $_potx_tokens[$ti+2]);
|
||||
if ($com == ',' && $arr[1] == 'array' && $par == '(') {
|
||||
$nesting = 0;
|
||||
$ti += 3;
|
||||
// Go through to either the end of the array or to the key definition of
|
||||
// context on the same nesting level.
|
||||
while (!((is_array($_potx_tokens[$ti]) && (in_array($_potx_tokens[$ti][1], array('"context"', "'context'"))) && ($_potx_tokens[$ti][0] == T_CONSTANT_ENCAPSED_STRING) && ($nesting == 0)) ||
|
||||
($_potx_tokens[$ti] == ')' && $nesting == -1))) {
|
||||
$ti++;
|
||||
if (!is_array($_potx_tokens[$ti])) {
|
||||
if ($_potx_tokens[$ti] == ')') {
|
||||
$nesting--;
|
||||
}
|
||||
if ($_potx_tokens[$ti] == '(') {
|
||||
$nesting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($nesting == 0) {
|
||||
// Found the 'context' key on the top level of the $options array.
|
||||
list($arw, $str) = array($_potx_tokens[$ti+1], $_potx_tokens[$ti+2]);
|
||||
if (is_array($arw) && $arw[1] == '=>' && is_array($str) && $str[0] == T_CONSTANT_ENCAPSED_STRING) {
|
||||
return _potx_format_quoted_string($str[1]);
|
||||
}
|
||||
else {
|
||||
list($type, $string, $line) = $_potx_tokens[$ti];
|
||||
// @todo: fix error reference.
|
||||
_potx_marker_error($file, $line, $function_name, $tf, potx_t('The context element in the options array argument to @function() should be a literal string. There should be no variables, concatenation, constants or other non-literal strings there.', array('@function' => $function_name)), 'http://drupal.org/node/322732');
|
||||
// Return with error.
|
||||
return POTX_CONTEXT_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Did not found 'context' key in $options array.
|
||||
return POTX_CONTEXT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After skipping args, we did not find a comma to look for $options.
|
||||
return POTX_CONTEXT_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exact CVS version number from the file, so we can
|
||||
* push that into the generated output.
|
||||
*
|
||||
* @param string $code Complete source code of the file parsed.
|
||||
* @param string $file Name of the file parsed.
|
||||
* @param callable $version_callback Callback used to save the version information.
|
||||
*/
|
||||
function _potx_find_version_number($code, $file, $version_callback) {
|
||||
// Prevent CVS from replacing this pattern with actual info.
|
||||
if (preg_match('!\\$I'.'d: ([^\\$]+) Exp \\$!', $code, $version_info)) {
|
||||
$version_callback($version_info[1], $file);
|
||||
}
|
||||
else {
|
||||
// Unknown version information.
|
||||
$version_callback($file .': n/a', $file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default $version_callback used by the potx system. Saves values
|
||||
* to a global array to reduce memory consumption problems when
|
||||
* passing around big chunks of values.
|
||||
*
|
||||
* @param string $value The version number value of $file. If NULL, the collected
|
||||
* values are returned.
|
||||
* @param string $file Name of file where the version information was found.
|
||||
*/
|
||||
function _potx_save_version($value = NULL, $file = NULL) {
|
||||
global $_potx_versions;
|
||||
|
||||
if (isset($value)) {
|
||||
$_potx_versions[$file] = $value;
|
||||
}
|
||||
else {
|
||||
return $_potx_versions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default $save_callback used by the potx system. Saves values
|
||||
* to global arrays to reduce memory consumption problems when
|
||||
* passing around big chunks of values.
|
||||
*
|
||||
* @param string $value The string value. If NULL, the array of collected values
|
||||
* are returned for the given $string_mode.
|
||||
* @param string $context From Drupal 7, separate contexts are supported. POTX_CONTEXT_NONE is
|
||||
* the default, if the code does not specify a context otherwise.
|
||||
* @param string $file Name of file where the string was found.
|
||||
* @param int $line Line number where the string was found.
|
||||
* @param int $string_mode String mode: POTX_STRING_INSTALLER, POTX_STRING_RUNTIME
|
||||
* or POTX_STRING_BOTH.
|
||||
*/
|
||||
function _potx_save_string($value = NULL, $context = NULL, $file = NULL, $line = 0, $string_mode = POTX_STRING_RUNTIME) {
|
||||
global $_potx_strings, $_potx_install;
|
||||
|
||||
if (isset($value)) {
|
||||
switch ($string_mode) {
|
||||
case POTX_STRING_BOTH:
|
||||
// Mark installer strings as duplicates of runtime strings if
|
||||
// the string was both recorded in the runtime and in the installer.
|
||||
$_potx_install[$value][$context][$file][] = $line .' (dup)';
|
||||
// Break intentionally missing.
|
||||
case POTX_STRING_RUNTIME:
|
||||
// Mark runtime strings as duplicates of installer strings if
|
||||
// the string was both recorded in the runtime and in the installer.
|
||||
$_potx_strings[$value][$context][$file][] = $line . ($string_mode == POTX_STRING_BOTH ? ' (dup)' : '');
|
||||
break;
|
||||
case POTX_STRING_INSTALLER:
|
||||
$_potx_install[$value][$context][$file][] = $line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ($string_mode == POTX_STRING_RUNTIME ? $_potx_strings : $_potx_install);
|
||||
}
|
||||
}
|
||||
|
||||
function potx_t( $string, $args = array() ) {
|
||||
|
||||
return strtr ( $string, $args );
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
function wpml_st_parse_config( $file_or_object ) {
|
||||
global $wpdb;
|
||||
|
||||
require_once WPML_ST_PATH . '/inc/admin-texts/wpml-admin-text-import.class.php';
|
||||
$config = new WPML_Admin_Text_Configuration( $file_or_object );
|
||||
$config_array = $config->get_config_array();
|
||||
|
||||
if ( ! empty( $config_array ) ) {
|
||||
$config_handler = $file_or_object;
|
||||
|
||||
if ( isset( $file_or_object->type, $file_or_object->admin_text_context ) ) {
|
||||
$config_handler = $file_or_object->type . $file_or_object->admin_text_context;
|
||||
}
|
||||
|
||||
$st_records = new WPML_ST_Records( $wpdb );
|
||||
$import = new WPML_Admin_Text_Import( $st_records, new WPML_WP_API() );
|
||||
$config_handler_hash = md5( serialize( $config_handler ) );
|
||||
$import->parse_config( $config_array, $config_handler_hash );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_action( 'wpml_parse_config_file', 'wpml_st_parse_config', 10, 1 );
|
||||
add_action( 'wpml_parse_custom_config', 'wpml_st_parse_config', 10, 1 );
|
||||
|
||||
/**
|
||||
* Action run on the wp_loaded hook that registers widget titles,
|
||||
* tagline and bloginfo as well as the current theme's strings when
|
||||
* String translation is first activated
|
||||
*/
|
||||
function wpml_st_initialize_basic_strings() {
|
||||
/** @var WPML_String_Translation $WPML_String_Translation */
|
||||
global $sitepress, $pagenow, $WPML_String_Translation;
|
||||
|
||||
$load_action = new WPML_ST_WP_Loaded_Action(
|
||||
$sitepress,
|
||||
$WPML_String_Translation,
|
||||
$pagenow,
|
||||
isset( $_GET['page'] ) ? $_GET['page'] : ''
|
||||
);
|
||||
if ( $sitepress->is_setup_complete() ) {
|
||||
$load_action->run();
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'wp_loaded', 'wpml_st_initialize_basic_strings' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $old
|
||||
* @param string $new
|
||||
*/
|
||||
function icl_st_update_blogname_actions( $old, $new ) {
|
||||
icl_st_update_string_actions(
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_DOMAIN,
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_NAME_BLOGNAME,
|
||||
$old,
|
||||
$new,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $old
|
||||
* @param string $new
|
||||
*/
|
||||
function icl_st_update_blogdescription_actions( $old, $new ) {
|
||||
icl_st_update_string_actions(
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_DOMAIN,
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_NAME_BLOGDESCRIPTION,
|
||||
$old,
|
||||
$new,
|
||||
true
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use function WPML\Container\make;
|
||||
|
||||
/**
|
||||
* @param array $source_languages
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
function filter_tm_source_langs( $source_languages ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
static $tm_filter;
|
||||
if ( ! $tm_filter ) {
|
||||
$tm_filter = new WPML_TM_Filters( $wpdb, $sitepress );
|
||||
}
|
||||
|
||||
return $tm_filter->filter_tm_source_langs( $source_languages );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bool $assigned_correctly
|
||||
* @param string $string_translation_id in the format used by
|
||||
* TM functionality as
|
||||
* "string|{$string_translation_id}"
|
||||
* @param int $translator_id
|
||||
* @param int|string $service
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function wpml_st_filter_job_assignment( $assigned_correctly, $string_translation_id, $translator_id, $service ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$tm_filter = new WPML_TM_Filters( $wpdb, $sitepress );
|
||||
|
||||
return $tm_filter->job_assigned_to_filter( $assigned_correctly, $string_translation_id, $translator_id, $service );
|
||||
}
|
||||
|
||||
add_filter( 'wpml_tm_allowed_source_languages', 'filter_tm_source_langs', 10, 1 );
|
||||
add_filter( 'wpml_job_assigned_to_after_assignment', 'wpml_st_filter_job_assignment', 10, 4 );
|
||||
|
||||
/**
|
||||
* @deprecated since WPML ST 3.0.0
|
||||
*
|
||||
* @param string $val
|
||||
*
|
||||
* @return string
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
function wpml_st_blog_title_filter( $val ) {
|
||||
/** @var WPML_ST_Blog_Name_And_Description_Hooks $filter */
|
||||
$filter = make( WPML_ST_Blog_Name_And_Description_Hooks::class );
|
||||
return $filter->option_blogname_filter( $val );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since WPML ST 3.0.0
|
||||
*
|
||||
* @param string $val
|
||||
*
|
||||
* @return string
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
function wpml_st_blog_description_filter( $val ) {
|
||||
/** @var WPML_ST_Blog_Name_And_Description_Hooks $filter */
|
||||
$filter = make( WPML_ST_Blog_Name_And_Description_Hooks::class );
|
||||
return $filter->option_blogdescription_filter( $val );
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
class WPML_Localization {
|
||||
/**
|
||||
* @var \wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
|
||||
/**
|
||||
* WPML_Localization constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
public function get_theme_localization_stats( $theme_localization_domains = array() ) {
|
||||
if ( empty( $theme_localization_domains ) || ! is_array( $theme_localization_domains ) ) {
|
||||
$theme_localization_domains = icl_get_sub_setting( 'st', 'theme_localization_domains' );
|
||||
}
|
||||
return $this->get_domain_stats( $theme_localization_domains, 'theme' );
|
||||
}
|
||||
|
||||
public function get_domain_stats( $localization_domains, $default, $no_wordpress = false, $count_in_progress_as_completed = false ) {
|
||||
$results = array();
|
||||
if ( $localization_domains ) {
|
||||
$domains = array();
|
||||
|
||||
foreach ( (array) $localization_domains as $domain ) {
|
||||
if ( ! ( $no_wordpress && 'WordPress' === $domain ) ) {
|
||||
$domains[] = $domain ? $domain : $default;
|
||||
}
|
||||
}
|
||||
if ( ! empty( $domains ) ) {
|
||||
$sql = "SELECT context, status, COUNT(id) AS c
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
WHERE context IN ('" . join( "','", $domains ) . "')
|
||||
GROUP BY context, status";
|
||||
$results = $this->wpdb->get_results( $sql );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->results_to_array( $results, $count_in_progress_as_completed );
|
||||
}
|
||||
|
||||
public function get_localization_stats( $component_type ) {
|
||||
$localization_data = $this->get_localization_data( $component_type );
|
||||
|
||||
$results = array();
|
||||
$all_domains = array();
|
||||
|
||||
foreach ( $localization_data as $component => $localization_domains ) {
|
||||
$all_domains = array_merge( $all_domains, array_keys( $localization_domains ) );
|
||||
}
|
||||
|
||||
$all_results = $this->get_domain_stats( $all_domains, $component_type, true );
|
||||
foreach ( $localization_data as $component => $localization_domains ) {
|
||||
$domains = array_keys( $localization_domains );
|
||||
foreach ( $domains as $domain ) {
|
||||
if ( array_key_exists( $domain, $all_results ) ) {
|
||||
$results[ $component ][ $domain ] = $all_results[ $domain ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function get_localization_data( $component_type ) {
|
||||
$localization_data = apply_filters( 'wpml_sub_setting', array(), 'st', 'plugin' === $component_type ? 'plugin_localization_domains' : 'theme_localization_domains' );
|
||||
if ( ! is_array( current( $localization_data ) ) ) {
|
||||
if ( 'plugin' === $component_type ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$localization_data = array();
|
||||
foreach ( wp_get_themes() as $theme_folder => $theme ) {
|
||||
if ( $theme->get( 'TextDomain' ) ) {
|
||||
$localization_data[ $theme_folder ] = array( $theme->get( 'TextDomain' ) => 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $localization_data;
|
||||
}
|
||||
|
||||
public function get_wrong_plugin_localization_stats() {
|
||||
$results = $this->wpdb->get_results(
|
||||
"
|
||||
SELECT context, status, COUNT(id) AS c
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
WHERE context LIKE ('plugin %')
|
||||
GROUP BY context, status
|
||||
"
|
||||
);
|
||||
|
||||
return $this->results_to_array( $results );
|
||||
}
|
||||
|
||||
public function get_wrong_theme_localization_stats() {
|
||||
$results = $this->wpdb->get_results(
|
||||
"
|
||||
SELECT context, status, COUNT(id) AS c
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
WHERE context LIKE ('theme %')
|
||||
GROUP BY context, status
|
||||
"
|
||||
);
|
||||
|
||||
$results = $this->results_to_array( $results );
|
||||
|
||||
$theme_path = TEMPLATEPATH;
|
||||
$old_theme_context = 'theme ' . basename( $theme_path );
|
||||
|
||||
unset( $results[ $old_theme_context ] );
|
||||
|
||||
return $results;
|
||||
|
||||
}
|
||||
|
||||
public function does_theme_require_rescan() {
|
||||
|
||||
$theme_path = TEMPLATEPATH;
|
||||
$old_theme_context = 'theme ' . basename( $theme_path );
|
||||
|
||||
$result = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
SELECT COUNT(id) AS c
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
WHERE context = %s",
|
||||
$old_theme_context
|
||||
)
|
||||
);
|
||||
|
||||
return $result ? true : false;
|
||||
}
|
||||
|
||||
public function get_most_popular_domain( $plugin ) {
|
||||
$plugin_localization_domains = icl_get_sub_setting( 'st', 'plugin_localization_domains' );
|
||||
|
||||
$most_popular = '';
|
||||
$most_count = 0;
|
||||
|
||||
foreach ( $plugin_localization_domains[ $plugin ] as $name => $count ) {
|
||||
if ( $name == 'WordPress' || $name == 'default' ) {
|
||||
continue;
|
||||
}
|
||||
if ( $count > $most_count ) {
|
||||
$most_popular = $name;
|
||||
$most_count = $count;
|
||||
}
|
||||
}
|
||||
|
||||
return $most_popular;
|
||||
}
|
||||
private function results_to_array( $results, $count_in_progress_as_completed = false ) {
|
||||
$stats = array();
|
||||
|
||||
foreach ( $results as $r ) {
|
||||
if ( ! isset( $stats[ $r->context ]['complete'] ) ) {
|
||||
$stats[ $r->context ]['complete'] = 0;
|
||||
}
|
||||
if ( ! isset( $stats[ $r->context ]['incomplete'] ) ) {
|
||||
$stats[ $r->context ]['incomplete'] = 0;
|
||||
}
|
||||
if (
|
||||
$r->status == ICL_TM_COMPLETE ||
|
||||
( $count_in_progress_as_completed && $r->status == ICL_TM_IN_PROGRESS )
|
||||
) {
|
||||
$stats[ $r->context ]['complete'] += $r->c;
|
||||
} else {
|
||||
$stats[ $r->context ]['incomplete'] += $r->c;
|
||||
}
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
class WPML_ST_String_Update {
|
||||
private $wpdb;
|
||||
|
||||
/**
|
||||
* WPML_ST_String_Update constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an original string without changing its id or its translations
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string $name
|
||||
* @param string $old_value
|
||||
* @param string $new_value
|
||||
* @param bool|false $force_complete , @see \WPML_ST_String_Update::handle_status_change
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function update_string( $domain, $name, $old_value, $new_value, $force_complete = false ) {
|
||||
if ( $new_value != $old_value ) {
|
||||
$string = $this->get_initial_string( $name, $domain, $old_value, $new_value );
|
||||
$this->wpdb->update(
|
||||
$this->wpdb->prefix . 'icl_strings',
|
||||
array( 'value' => $new_value ),
|
||||
array( 'id' => $string->id )
|
||||
);
|
||||
$is_widget = $domain === WPML_ST_WIDGET_STRING_DOMAIN;
|
||||
if ( $is_widget && $new_value ) {
|
||||
$this->update_widget_name( $string->name, $old_value, $new_value );
|
||||
}
|
||||
$this->handle_status_change( $string, $force_complete || $is_widget );
|
||||
|
||||
/**
|
||||
* This action is fired when a string original value is modified.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string $name
|
||||
* @param string $old_value
|
||||
* @param string $new_value
|
||||
* @param bool|false $force_complete
|
||||
* @param stdClass $string
|
||||
*/
|
||||
do_action( 'wpml_st_update_string', $domain, $name, $old_value, $new_value, $force_complete, $string );
|
||||
}
|
||||
|
||||
return isset( $string ) && isset( $string->id ) ? $string->id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
function sanitize_string( $string ) {
|
||||
return html_entity_decode( $string, ENT_QUOTES );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles string status changes resulting from the string update
|
||||
*
|
||||
* @param object $string
|
||||
* @param bool $force_complete if true, all translations will be marked as complete even though a string's original value has been updated,
|
||||
* currently this applies to blogname and tagline strings
|
||||
*/
|
||||
private function handle_status_change( $string, $force_complete ) {
|
||||
if ( $string->status == ICL_TM_COMPLETE || $string->status == ICL_STRING_TRANSLATION_PARTIAL ) {
|
||||
$new_status = $force_complete ? ICL_TM_COMPLETE : ICL_TM_NEEDS_UPDATE;
|
||||
foreach (
|
||||
array(
|
||||
'icl_string_translations' => 'string_id',
|
||||
'icl_strings' => 'id',
|
||||
) as $table_name => $id_col
|
||||
) {
|
||||
$this->wpdb->update(
|
||||
$this->wpdb->prefix . $table_name,
|
||||
array( 'status' => $new_status ),
|
||||
array( $id_col => $string->id )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $context
|
||||
* @param string $old_value
|
||||
* @param string $new_value
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
private function get_initial_string( $name, $context, $old_value, $new_value ) {
|
||||
$string = $this->read_string_from_db( $name, $context );
|
||||
if ( ! $string ) {
|
||||
if ( $context !== WPML_ST_WIDGET_STRING_DOMAIN ) {
|
||||
icl_register_string( $context, $name, $new_value );
|
||||
} else {
|
||||
list( $res, $name ) = $this->update_widget_name( $name, $old_value, $new_value );
|
||||
if ( ! $res ) {
|
||||
icl_register_string( $context, $name, $new_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
$string = $this->read_string_from_db( $name, $context );
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a strings id,value,status and name directly from the database without any caching.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $context
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
private function read_string_from_db( $name, $context ) {
|
||||
|
||||
return $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
" SELECT id, value, status, name
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
WHERE context = %s
|
||||
AND name = %s
|
||||
LIMIT 1",
|
||||
$context,
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a widgets string name if it's value got changed, since widget string's name and value are coupled.
|
||||
* Changes in value necessitate changes in the name. @see \icl_sw_filters_widget_title and \icl_sw_filters_widget_body
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $old_value
|
||||
* @param string $new_value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function update_widget_name( $name, $old_value, $new_value ) {
|
||||
$res = 0;
|
||||
if ( 0 === strpos( $name, 'widget title - ' ) ) {
|
||||
$name = 'widget title - ' . md5( $new_value );
|
||||
$old_name = 'widget title - ' . md5( $old_value );
|
||||
|
||||
if ( $this->read_string_from_db( $name, WPML_ST_WIDGET_STRING_DOMAIN ) ) {
|
||||
$old_string = $this->read_string_from_db( $old_name, WPML_ST_WIDGET_STRING_DOMAIN );
|
||||
if ( $old_string ) {
|
||||
$this->delete_old_widget_title_string_if_new_already_exists( $old_string );
|
||||
}
|
||||
} else {
|
||||
$res = $this->write_widget_update_to_db( WPML_ST_WIDGET_STRING_DOMAIN, $old_name, $name );
|
||||
}
|
||||
} elseif ( 0 === strpos( $name, 'widget body - ' ) ) {
|
||||
$name = 'widget body - ' . md5( $new_value );
|
||||
$res = $this->write_widget_update_to_db(
|
||||
WPML_ST_WIDGET_STRING_DOMAIN,
|
||||
'widget body - ' . md5( $old_value ),
|
||||
$name
|
||||
);
|
||||
}
|
||||
|
||||
return array( $res, $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes updates to a widget strings name to the icl_strings table.
|
||||
*
|
||||
* @param string $context
|
||||
* @param string $old_name
|
||||
* @param string $new_name
|
||||
*
|
||||
* @return false|int false on error, 1 on successful update and 0 if no update took place
|
||||
*/
|
||||
private function write_widget_update_to_db( $context, $old_name, $new_name ) {
|
||||
|
||||
return $this->wpdb->update(
|
||||
$this->wpdb->prefix . 'icl_strings',
|
||||
array(
|
||||
'name' => $new_name,
|
||||
'domain_name_context_md5' => md5( WPML_ST_WIDGET_STRING_DOMAIN . $new_name ),
|
||||
),
|
||||
array(
|
||||
'context' => $context,
|
||||
'name' => $old_name,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function delete_old_widget_title_string_if_new_already_exists( $string ) {
|
||||
$this->wpdb->delete( $this->wpdb->prefix . 'icl_string_translations', array( 'string_id' => $string->id ) );
|
||||
$this->wpdb->delete( $this->wpdb->prefix . 'icl_strings', array( 'id' => $string->id ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,947 @@
|
||||
<?php
|
||||
/**
|
||||
* WPML_String_Translation class file.
|
||||
*
|
||||
* @package WPML\ST
|
||||
*/
|
||||
|
||||
use WPML\ST\Gettext\AutoRegisterSettings;
|
||||
use WPML\ST\StringsFilter\Translator;
|
||||
use function WPML\Container\make;
|
||||
|
||||
/**
|
||||
* Class WPML_String_Translation
|
||||
*/
|
||||
class WPML_String_Translation {
|
||||
|
||||
const CACHE_GROUP = 'wpml-string-translation';
|
||||
|
||||
private $load_priority = 400;
|
||||
|
||||
private $messages = array();
|
||||
|
||||
private $string_filters = array();
|
||||
|
||||
private $active_languages;
|
||||
|
||||
private $current_string_language_cache = array();
|
||||
|
||||
/** @var WPML_ST_String_Factory $string_factory */
|
||||
private $string_factory;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $admin_language;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_admin_action_from_referer;
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
protected $sitepress;
|
||||
|
||||
/**
|
||||
* @var WPML_WP_Cache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_ST_String_Factory $string_factory
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, WPML_ST_String_Factory $string_factory ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->string_factory = $string_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up basic actions hooked by ST
|
||||
*/
|
||||
public function set_basic_hooks() {
|
||||
if ( $this->sitepress->get_wp_api()->constant( 'WPML_TM_VERSION' ) ) {
|
||||
add_action( 'wpml_tm_loaded', array( $this, 'load' ) );
|
||||
} else {
|
||||
add_action(
|
||||
'wpml_loaded',
|
||||
array( $this, 'load' ),
|
||||
$this->load_priority
|
||||
);
|
||||
}
|
||||
add_action(
|
||||
'plugins_loaded',
|
||||
array( $this, 'check_db_for_gettext_context' ),
|
||||
1000
|
||||
);
|
||||
add_action(
|
||||
'wpml_language_has_switched',
|
||||
array( $this, 'wpml_language_has_switched' )
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the internal cache for all language codes.
|
||||
*
|
||||
* @used-by WPML_String_Translation::get_string_filter to not load string filters
|
||||
* for languages that do not
|
||||
* exist.
|
||||
* @used-by WPML_String_Translation::get_admin_string_filter See above.
|
||||
*/
|
||||
function init_active_languages() {
|
||||
$this->active_languages = array_keys( $this->sitepress->get_languages() );
|
||||
}
|
||||
|
||||
function load() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
if ( ! $sitepress || ! $sitepress->get_setting( 'setup_complete' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->plugin_localization();
|
||||
|
||||
$factory = new WPML_ST_Upgrade_Command_Factory( $wpdb, $sitepress );
|
||||
$upgrade = new WPML_ST_Upgrade( $sitepress, $factory );
|
||||
$upgrade->run();
|
||||
|
||||
$this->init_active_languages();
|
||||
|
||||
$wpml_string_shortcode = new WPML\ST\Shortcode( $wpdb );
|
||||
$wpml_string_shortcode->init_hooks();
|
||||
|
||||
wpml_st_load_admin_texts();
|
||||
|
||||
add_action( 'init', array( $this, 'init' ) );
|
||||
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load(
|
||||
array(
|
||||
'WPML_Slug_Translation_Factory',
|
||||
)
|
||||
);
|
||||
|
||||
add_filter( 'pre_update_option_blogname', array( $this, 'pre_update_option_blogname' ), 5, 2 );
|
||||
add_filter( 'pre_update_option_blogdescription', array( $this, 'pre_update_option_blogdescription' ), 5, 2 );
|
||||
|
||||
// Handle Admin Notices
|
||||
|
||||
add_action( 'icl_ajx_custom_call', array( $this, 'ajax_calls' ), 10, 2 );
|
||||
|
||||
/**
|
||||
* @deprecated 3.3 - Each string has its own language now.
|
||||
*/
|
||||
add_filter( 'WPML_ST_strings_language', array( $this, 'get_strings_language' ) );
|
||||
add_filter( 'wpml_st_strings_language', array( $this, 'get_strings_language' ) );
|
||||
|
||||
add_action( 'wpml_st_delete_all_string_data', array( $this, 'delete_all_string_data' ), 10, 1 );
|
||||
|
||||
add_filter( 'wpml_st_string_status', array( $this, 'get_string_status_filter' ), 10, 2 );
|
||||
add_filter( 'wpml_string_id', array( $this, 'get_string_id_filter' ), 10, 2 );
|
||||
add_filter( 'wpml_get_string_language', array( $this, 'get_string_language_filter' ), 10, 3 );
|
||||
|
||||
do_action( 'wpml_st_loaded' );
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
if ( is_admin() ) {
|
||||
wp_enqueue_style( 'thickbox' );
|
||||
wp_enqueue_script( 'jquery' );
|
||||
wp_enqueue_script( 'thickbox' );
|
||||
|
||||
$reset = new WPML_ST_Reset( $wpdb );
|
||||
add_action( 'wpml_reset_plugins_after', array( $reset, 'reset' ) );
|
||||
}
|
||||
|
||||
add_action( 'wpml_admin_menu_configure', array( $this, 'menu' ) );
|
||||
|
||||
add_filter( 'plugin_action_links', array( $this, 'plugin_action_links' ), 10, 2 );
|
||||
|
||||
$current_page = array_key_exists( 'page', $_GET ) ? $_GET['page'] : '';
|
||||
if ( $current_page && is_admin() ) {
|
||||
|
||||
$allowed_pages_for_resources = array( WPML_ST_FOLDER . '/menu/string-translation.php' );
|
||||
if ( in_array( $current_page, $allowed_pages_for_resources, true ) && current_user_can( 'manage_options' ) && empty( $_POST ) ) {
|
||||
wp_enqueue_script( 'wpml-st-change-lang', WPML_ST_URL . '/res/js/change_string_lang.js', array( 'jquery', 'jquery-ui-dialog', 'wpml-st-scripts' ), WPML_ST_VERSION );
|
||||
}
|
||||
|
||||
$allowed_pages_for_resources[] = ICL_PLUGIN_FOLDER . '/menu/theme-localization.php';
|
||||
if ( in_array( $current_page, $allowed_pages_for_resources, true ) ) {
|
||||
wp_enqueue_script( 'wp-color-picker' );
|
||||
wp_enqueue_style( 'wp-color-picker' );
|
||||
wp_enqueue_script( 'wpml-st-settings', WPML_ST_URL . '/res/js/settings.js', array( 'jquery' ), WPML_ST_VERSION );
|
||||
wp_enqueue_script( 'wpml-st-scripts', WPML_ST_URL . '/res/js/scripts.js', array( 'jquery', 'jquery-ui-dialog' ), WPML_ST_VERSION );
|
||||
wp_enqueue_script( OTGS_Assets_Handles::POPOVER_TOOLTIP );
|
||||
wp_enqueue_style( OTGS_Assets_Handles::POPOVER_TOOLTIP );
|
||||
wp_enqueue_script( 'wpml-auto-register-strings', WPML_ST_URL . '/res/js/auto-register-strings.js', array( 'jquery', 'jquery-ui-dialog', 'wpml-st-scripts' ), WPML_ST_VERSION );
|
||||
wp_enqueue_script( 'wpml-st-change-domian-lang', WPML_ST_URL . '/res/js/change_string_domain_lang.js', array( 'jquery', 'jquery-ui-dialog' ), WPML_ST_VERSION );
|
||||
wp_enqueue_script( 'wpml-st-translation_basket', WPML_ST_URL . '/res/js/wpml_string_translation_basket.js', array( 'jquery' ), WPML_ST_VERSION );
|
||||
wp_enqueue_script( 'wpml-plugin-list-table-filter', WPML_ST_URL . '/res/js/wpml-plugin-list-table-filter.js', array( 'jquery' ), WPML_ST_VERSION );
|
||||
wp_enqueue_style( 'wpml-st-styles', WPML_ST_URL . '/res/css/style.css', array(), WPML_ST_VERSION );
|
||||
wp_enqueue_style( 'wpml-dialog', ICL_PLUGIN_URL . '/res/css/dialog.css', array( 'otgs-dialogs' ), ICL_SITEPRESS_VERSION );
|
||||
wp_enqueue_style( 'wp-jquery-ui-dialog' );
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'wpml_custom_localization_type', array( $this, 'localization_type_ui' ) );
|
||||
add_action( 'wp_ajax_st_theme_localization_rescan', array( $this, 'scan_theme_for_strings' ) );
|
||||
add_action( 'wp_ajax_st_plugin_localization_rescan', array( $this, 'scan_plugins_for_strings' ) );
|
||||
add_action( 'wp_ajax_icl_st_pop_download', array( $this, 'plugin_po_file_download' ) );
|
||||
add_action( 'wp_ajax_wpml_change_string_lang', array( $this, 'change_string_lang_ajax_callback' ) );
|
||||
add_action( 'wp_ajax_wpml_change_string_lang_of_domain', array( $this, 'change_string_lang_of_domain_ajax_callback' ) );
|
||||
|
||||
// auto-registration settings: saving excluded contexts
|
||||
/** @var AutoRegisterSettings $auto_register_settings */
|
||||
$auto_register_settings = WPML\Container\make( AutoRegisterSettings::class );
|
||||
add_action( 'wp_ajax_wpml_st_exclude_contexts', array( $auto_register_settings, 'saveExcludedContexts' ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function plugin_localization() {
|
||||
load_plugin_textdomain( 'wpml-string-translation', false, WPML_ST_FOLDER . '/locale' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @param string $name
|
||||
* @param string|false $original_value
|
||||
* @param boolean|null $has_translation
|
||||
* @param null|string $target_lang
|
||||
*
|
||||
* @return string|bool
|
||||
* @since 2.2.3
|
||||
*
|
||||
*/
|
||||
function translate_string( $context, $name, $original_value = false, &$has_translation = null, $target_lang = null ) {
|
||||
|
||||
return icl_translate( $context, $name, $original_value, false, $has_translation, $target_lang );
|
||||
}
|
||||
|
||||
function add_message( $text, $type = 'updated' ) {
|
||||
$this->messages[] = array(
|
||||
'type' => $type,
|
||||
'text' => $text,
|
||||
);
|
||||
}
|
||||
|
||||
function show_messages() {
|
||||
if ( ! empty( $this->messages ) ) {
|
||||
foreach ( $this->messages as $m ) {
|
||||
printf( '<div class="%s fade"><p>%s</p></div>', $m['type'], $m['text'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ajax_calls( $call, $data ) {
|
||||
require_once WPML_ST_PATH . '/inc/admin-texts/wpml-admin-text-configuration.php';
|
||||
|
||||
switch ( $call ) {
|
||||
|
||||
case 'icl_st_delete_strings':
|
||||
$arr = explode( ',', $data['value'] );
|
||||
wpml_unregister_string_multi( $arr );
|
||||
echo '1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $menu_id
|
||||
*/
|
||||
function menu( $menu_id ) {
|
||||
if ( 'WPML' !== $menu_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->sitepress || ! $this->sitepress->get_wp_api()->constant( 'ICL_PLUGIN_PATH' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$setup_complete = apply_filters( 'wpml_get_setting', false, 'setup_complete' );
|
||||
if ( ! $setup_complete ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$existing_content_language_verified = apply_filters(
|
||||
'wpml_get_setting',
|
||||
false,
|
||||
'existing_content_language_verified'
|
||||
);
|
||||
|
||||
if ( ! $existing_content_language_verified ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( current_user_can( 'wpml_manage_string_translation' ) || current_user_can( 'manage_translations' ) ) {
|
||||
$menu = array();
|
||||
$menu['order'] = 800;
|
||||
$menu['page_title'] = __( 'String Translation', 'wpml-string-translation' );
|
||||
$menu['menu_title'] = __( 'String Translation', 'wpml-string-translation' );
|
||||
$menu['capability'] = current_user_can( 'wpml_manage_string_translation' ) ? 'wpml_manage_string_translation' : 'manage_translations';
|
||||
$menu['menu_slug'] = WPML_ST_FOLDER . '/menu/string-translation.php';
|
||||
|
||||
do_action( 'wpml_admin_menu_register_item', $menu );
|
||||
}
|
||||
}
|
||||
|
||||
function plugin_action_links( $links, $file ) {
|
||||
$this_plugin = basename( WPML_ST_PATH ) . '/plugin.php';
|
||||
if ( $file == $this_plugin ) {
|
||||
$links[] = '<a href="admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php">' .
|
||||
__( 'Configure', 'wpml-string-translation' ) . '</a>';
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
public function localization_type_ui() {
|
||||
$plugin_localization_factory = new WPML_ST_Plugin_Localization_UI_Factory();
|
||||
$plugin_localization = $plugin_localization_factory->create();
|
||||
|
||||
$theme_localization_factory = new WPML_ST_Theme_Localization_UI_Factory();
|
||||
$theme_localization = $theme_localization_factory->create();
|
||||
|
||||
$localization = new WPML_Theme_Plugin_Localization_UI();
|
||||
|
||||
echo $localization->render( $theme_localization );
|
||||
echo $localization->render( $plugin_localization );
|
||||
}
|
||||
|
||||
function scan_theme_for_strings() {
|
||||
require_once WPML_ST_PATH . '/inc/gettext/wpml-theme-string-scanner.class.php';
|
||||
|
||||
$file_hashing = new WPML_ST_File_Hashing();
|
||||
$scan_for_strings = new WPML_Theme_String_Scanner( wpml_get_filesystem_direct(), $file_hashing );
|
||||
$scan_for_strings->scan();
|
||||
}
|
||||
|
||||
function scan_plugins_for_strings() {
|
||||
require_once WPML_ST_PATH . '/inc/gettext/wpml-plugin-string-scanner.class.php';
|
||||
$file_hashing = new WPML_ST_File_Hashing();
|
||||
$scan_for_strings = new WPML_Plugin_String_Scanner( wpml_get_filesystem_direct(), $file_hashing );
|
||||
$scan_for_strings->scan();
|
||||
}
|
||||
|
||||
function plugin_po_file_download( $file = false, $recursion = 0 ) {
|
||||
global $__wpml_st_po_file_content;
|
||||
|
||||
if ( empty( $file ) && ! empty( $_GET['file'] ) ) {
|
||||
$file = WPML_PLUGINS_DIR . '/' . filter_var( $_GET['file'], FILTER_SANITIZE_STRING );
|
||||
}
|
||||
if ( empty( $file ) && ! wpml_st_file_path_is_valid( $file ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_null( $__wpml_st_po_file_content ) ) {
|
||||
$__wpml_st_po_file_content = '';
|
||||
}
|
||||
|
||||
require_once WPML_ST_PATH . '/inc/potx.php';
|
||||
require_once WPML_ST_PATH . '/inc/potx-callback.php';
|
||||
|
||||
if ( is_file( $file ) && WPML_PLUGINS_DIR == dirname( $file ) ) {
|
||||
|
||||
_potx_process_file( $file, 0, 'wpml_st_pos_scan_store_results', '_potx_save_version', '' );
|
||||
} else {
|
||||
|
||||
if ( ! $recursion ) {
|
||||
$file = dirname( $file );
|
||||
}
|
||||
|
||||
if ( is_dir( $file ) ) {
|
||||
$dh = opendir( $file );
|
||||
while ( $dh && false !== ( $f = readdir( $dh ) ) ) {
|
||||
if ( 0 === strpos( $f, '.' ) ) {
|
||||
continue;
|
||||
}
|
||||
$this->plugin_po_file_download( $file . '/' . $f, $recursion + 1 );
|
||||
}
|
||||
} elseif ( preg_match( '#(\.php|\.inc)$#i', $file ) ) {
|
||||
_potx_process_file( $file, 0, 'wpml_st_pos_scan_store_results', '_potx_save_version', '' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $recursion ) {
|
||||
$po = WPML_PO_Parser::get_po_file_header();
|
||||
$po .= $__wpml_st_po_file_content;
|
||||
|
||||
$filename = isset( $_GET['domain'] ) ?
|
||||
filter_var( $_GET['domain'], FILTER_SANITIZE_STRING ) :
|
||||
basename( $file );
|
||||
|
||||
header( 'Content-Type: application/force-download' );
|
||||
header( 'Content-Type: application/octet-stream' );
|
||||
header( 'Content-Type: application/download' );
|
||||
header( 'Content-Transfer-Encoding: binary' );
|
||||
header( 'Content-Disposition: attachment; filename="' . $filename . '.po"' );
|
||||
header( 'Content-Length: ' . strlen( $po ) );
|
||||
echo $po;
|
||||
exit( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string value of a string
|
||||
* @param string $lang_code language code of the string
|
||||
*
|
||||
* @return int number of words in the string
|
||||
*/
|
||||
public function estimate_word_count( $string, $lang_code ) {
|
||||
$string = strip_tags( $string );
|
||||
|
||||
return in_array(
|
||||
$lang_code,
|
||||
array(
|
||||
'ja',
|
||||
'ko',
|
||||
'zh-hans',
|
||||
'zh-hant',
|
||||
'mn',
|
||||
'ne',
|
||||
'hi',
|
||||
'pa',
|
||||
'ta',
|
||||
'th',
|
||||
)
|
||||
) ? strlen( $string ) / 6
|
||||
: count( explode( ' ', $string ) );
|
||||
}
|
||||
|
||||
function cancel_remote_translation( $rid ) {
|
||||
/** @var wpdb $wpdb */
|
||||
global $wpdb;
|
||||
|
||||
$translation_ids = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
" SELECT string_translation_id
|
||||
FROM {$wpdb->prefix}icl_string_status
|
||||
WHERE rid = %d",
|
||||
$rid
|
||||
)
|
||||
);
|
||||
$cancel_count = 0;
|
||||
foreach ( $translation_ids as $translation_id ) {
|
||||
$res = (bool) $this->cancel_local_translation( $translation_id );
|
||||
$cancel_count = $res ? $cancel_count + 1 : $cancel_count;
|
||||
}
|
||||
|
||||
return $cancel_count;
|
||||
}
|
||||
|
||||
function cancel_local_translation( $id, $return_original_id = false ) {
|
||||
global $wpdb;
|
||||
$string_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
" SELECT string_id
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE id=%d AND status IN (%d, %d)",
|
||||
$id,
|
||||
ICL_TM_IN_PROGRESS,
|
||||
ICL_TM_WAITING_FOR_TRANSLATOR
|
||||
)
|
||||
);
|
||||
if ( $string_id ) {
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'status' => ICL_TM_NOT_TRANSLATED,
|
||||
'translation_service' => null,
|
||||
'translator_id' => null,
|
||||
'batch_id' => null,
|
||||
),
|
||||
array( 'id' => $id )
|
||||
);
|
||||
icl_update_string_status( $string_id );
|
||||
$res = $return_original_id ? $string_id : $id;
|
||||
} else {
|
||||
$res = false;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param string $old_value
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
function pre_update_option_blogname( $value, $old_value ) {
|
||||
return $this->pre_update_option_settings(
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_NAME_BLOGNAME,
|
||||
$value,
|
||||
$old_value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param string $old_value
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
function pre_update_option_blogdescription( $value, $old_value ) {
|
||||
return $this->pre_update_option_settings(
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_NAME_BLOGDESCRIPTION,
|
||||
$value,
|
||||
$old_value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option name of the option
|
||||
* @param string|array $value new value of the option
|
||||
* @param string|array $old_value currently saved value for the option
|
||||
*
|
||||
* @return string|array the value actually to be written into the wp_options table
|
||||
*/
|
||||
function pre_update_option_settings( $option, $value, $old_value ) {
|
||||
$wp_api = $this->sitepress->get_wp_api();
|
||||
if ( $wp_api->is_multisite()
|
||||
&& $wp_api->ms_is_switched()
|
||||
&& ! $this->sitepress->get_setting( 'setup_complete' )
|
||||
) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$option = new WPML_ST_Admin_Blog_Option(
|
||||
$this->sitepress,
|
||||
$this,
|
||||
$option
|
||||
);
|
||||
|
||||
return $option->pre_update_filter( $old_value, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new admin option translation object
|
||||
*
|
||||
* @param string $option_name
|
||||
* @param string $language_code
|
||||
*
|
||||
* @return WPML_ST_Admin_Option_Translation
|
||||
*/
|
||||
public function get_admin_option( $option_name, $language_code = '' ) {
|
||||
|
||||
return new WPML_ST_Admin_Option_Translation(
|
||||
$this->sitepress,
|
||||
$this,
|
||||
$option_name,
|
||||
$language_code
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_ST_String_Factory
|
||||
*/
|
||||
public function string_factory() {
|
||||
|
||||
return $this->string_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang_code
|
||||
*/
|
||||
public function clear_string_filter( $lang_code ) {
|
||||
unset( $this->string_filters[ $lang_code ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
*
|
||||
* @return WPML_Displayed_String_Filter
|
||||
*/
|
||||
public function get_string_filter( $lang ) {
|
||||
|
||||
if ( true === (bool) $this->active_languages && in_array( $lang, $this->active_languages, true ) ) {
|
||||
return $this->get_admin_string_filter( $lang );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
*
|
||||
* @return mixed|\WPML_Register_String_Filter|null
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
public function get_admin_string_filter( $lang ) {
|
||||
global $sitepress_settings, $wpdb, $sitepress;
|
||||
|
||||
if ( isset( $sitepress_settings['st']['db_ok_for_gettext_context'] ) ) {
|
||||
if ( ! ( isset( $this->string_filters[ $lang ] )
|
||||
&& 'WPML_Register_String_Filter' == get_class( $this->string_filters[ $lang ] ) )
|
||||
) {
|
||||
$this->string_filters[ $lang ] = isset( $this->string_filters[ $lang ] ) ? $this->string_filters[ $lang ] : false;
|
||||
|
||||
/** @var AutoRegisterSettings $auto_register_settings */
|
||||
$auto_register_settings = WPML\Container\make( AutoRegisterSettings::class );
|
||||
|
||||
$this->string_filters[ $lang ] = new WPML_Register_String_Filter(
|
||||
$wpdb,
|
||||
$sitepress,
|
||||
$this->string_factory,
|
||||
make( Translator::class, [ ':language' => $lang ] ),
|
||||
$auto_register_settings->getExcludedDomains()
|
||||
);
|
||||
}
|
||||
|
||||
return $this->string_filters[ $lang ];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.3 - Each string has its own language now.
|
||||
*/
|
||||
public function get_strings_language( $language = '' ) {
|
||||
$string_settings = $this->get_strings_settings();
|
||||
|
||||
$string_language = $language ? $language : 'en';
|
||||
if ( isset( $string_settings['strings_language'] ) ) {
|
||||
$string_language = $string_settings['strings_language'];
|
||||
}
|
||||
|
||||
return $string_language;
|
||||
}
|
||||
|
||||
public function delete_all_string_data( $string_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$icl_string_positions_query = "DELETE FROM {$wpdb->prefix}icl_string_positions WHERE string_id=%d";
|
||||
$icl_string_status_query = "DELETE FROM {$wpdb->prefix}icl_string_status WHERE string_translation_id IN (SELECT id FROM {$wpdb->prefix}icl_string_translations WHERE string_id=%d)";
|
||||
$icl_string_translations_query = "DELETE FROM {$wpdb->prefix}icl_string_translations WHERE string_id=%d";
|
||||
$icl_strings_query = "DELETE FROM {$wpdb->prefix}icl_strings WHERE id=%d";
|
||||
|
||||
$icl_string_positions_prepare = $wpdb->prepare( $icl_string_positions_query, $string_id );
|
||||
$icl_string_status_prepare = $wpdb->prepare( $icl_string_status_query, $string_id );
|
||||
$icl_string_translations_prepare = $wpdb->prepare( $icl_string_translations_query, $string_id );
|
||||
$icl_strings_prepare = $wpdb->prepare( $icl_strings_query, $string_id );
|
||||
|
||||
$wpdb->query( $icl_string_positions_prepare );
|
||||
$wpdb->query( $icl_string_status_prepare );
|
||||
$wpdb->query( $icl_string_translations_prepare );
|
||||
$wpdb->query( $icl_strings_prepare );
|
||||
|
||||
}
|
||||
|
||||
public function get_strings_settings() {
|
||||
global $sitepress;
|
||||
|
||||
if ( version_compare( ICL_SITEPRESS_VERSION, '3.2', '<' ) ) {
|
||||
global $sitepress_settings;
|
||||
|
||||
$string_settings = isset( $sitepress_settings['st'] ) ? $sitepress_settings['st'] : array();
|
||||
} else {
|
||||
$string_settings = $sitepress ? $sitepress->get_string_translation_settings() : array();
|
||||
}
|
||||
|
||||
$string_settings['strings_language'] = 'en';
|
||||
if ( ! isset( $string_settings['icl_st_auto_reg'] ) ) {
|
||||
$string_settings['icl_st_auto_reg'] = 'disable';
|
||||
}
|
||||
$string_settings['strings_per_page'] = ICL_STRING_TRANSLATION_AUTO_REGISTER_THRESHOLD;
|
||||
|
||||
return $string_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $empty Not used, but needed for the hooked filter
|
||||
* @param int $string_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_string_status_filter( $empty = null, $string_id = 0 ) {
|
||||
return $this->get_string_status( $string_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $default Set the default value to return in case no string or more than one string is found
|
||||
* @param array $string_data {
|
||||
*
|
||||
* @type string $context
|
||||
* @type string $name Optional
|
||||
* }
|
||||
* @return int|null If there is more than one string_id, it will return the value set in $default.
|
||||
*/
|
||||
public function get_string_id_filter( $default = null, $string_data = array() ) {
|
||||
$result = $default;
|
||||
|
||||
$string_id = $this->get_string_id( $string_data );
|
||||
|
||||
return $string_id ? $string_id : $result;
|
||||
}
|
||||
|
||||
private function get_string_status( $string_id ) {
|
||||
global $wpdb;
|
||||
$status = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT MIN(status)
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE
|
||||
string_id=%d
|
||||
",
|
||||
$string_id
|
||||
)
|
||||
);
|
||||
|
||||
return $status !== null ? (int) $status : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $string_data {
|
||||
*
|
||||
* @type string $context
|
||||
* @type string $name Optional
|
||||
* }
|
||||
* @return int|null
|
||||
*/
|
||||
private function get_string_id( $string_data ) {
|
||||
$context = isset( $string_data['context'] ) ? $string_data['context'] : null;
|
||||
$name = isset( $string_data['name'] ) ? $string_data['name'] : null;
|
||||
|
||||
$result = null;
|
||||
if ( $name && $context ) {
|
||||
global $wpdb;
|
||||
$string_id_query = "SELECT id FROM {$wpdb->prefix}icl_strings WHERE context=%s";
|
||||
$string_id_args = array( $context );
|
||||
if ( $name ) {
|
||||
$string_id_query .= ' AND name=%s';
|
||||
$string_id_args[] = $name;
|
||||
}
|
||||
$string_id_prepare = $wpdb->prepare( $string_id_query, $string_id_args );
|
||||
$string_id = $wpdb->get_var( $string_id_prepare );
|
||||
|
||||
$result = (int) $string_id;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $empty Not used, but needed for the hooked filter
|
||||
* @param string $domain
|
||||
* @param string $name
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_string_language_filter( $empty = null, $domain = '', $name = '' ) {
|
||||
global $wpdb;
|
||||
|
||||
$key = md5( $domain . '_' . $name );
|
||||
list( $string_lang, $found ) = $this->get_cache()->get_with_found( $key );
|
||||
|
||||
if ( ! $found ) {
|
||||
$string_query = "SELECT language FROM {$wpdb->prefix}icl_strings WHERE context=%s AND name=%s";
|
||||
$string_prepare = $wpdb->prepare( $string_query, $domain, $name );
|
||||
$string_lang = $wpdb->get_var( $string_prepare );
|
||||
|
||||
$this->get_cache()->set( $key, $string_lang, 600 );
|
||||
}
|
||||
|
||||
return $string_lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_WP_Cache $cache
|
||||
*/
|
||||
public function set_cache( WPML_WP_Cache $cache ) {
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_WP_Cache
|
||||
*/
|
||||
public function get_cache() {
|
||||
if ( null === $this->cache ) {
|
||||
$this->cache = new WPML_WP_Cache( self::CACHE_GROUP );
|
||||
}
|
||||
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
function check_db_for_gettext_context() {
|
||||
$string_settings = apply_filters( 'wpml_get_setting', [], 'st' );
|
||||
if ( ! isset( $string_settings['db_ok_for_gettext_context'] ) ) {
|
||||
|
||||
if ( function_exists( 'icl_table_column_exists' ) && icl_table_column_exists( 'icl_strings', 'domain_name_context_md5' ) ) {
|
||||
$string_settings['db_ok_for_gettext_context'] = true;
|
||||
do_action( 'wpml_set_setting', 'st', $string_settings, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function initialize_wp_and_widget_strings() {
|
||||
$this->check_db_for_gettext_context();
|
||||
|
||||
icl_register_string(
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_DOMAIN,
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_NAME_BLOGNAME,
|
||||
get_option( 'blogname' )
|
||||
);
|
||||
|
||||
icl_register_string(
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_DOMAIN,
|
||||
WPML_ST_Blog_Name_And_Description_Hooks::STRING_NAME_BLOGDESCRIPTION,
|
||||
get_option( 'blogdescription' )
|
||||
);
|
||||
|
||||
wpml_st_init_register_widget_titles();
|
||||
|
||||
// create a list of active widgets
|
||||
$active_text_widgets = array();
|
||||
$widgets = (array) get_option( 'sidebars_widgets' );
|
||||
foreach ( $widgets as $k => $w ) {
|
||||
if ( 'wp_inactive_widgets' != $k && $k != 'array_version' ) {
|
||||
if ( is_array( $widgets[ $k ] ) ) {
|
||||
foreach ( $widgets[ $k ] as $v ) {
|
||||
if ( preg_match( '#text-([0-9]+)#i', $v, $matches ) ) {
|
||||
$active_text_widgets[] = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$widget_text = get_option( 'widget_text' );
|
||||
if ( is_array( $widget_text ) ) {
|
||||
foreach ( $widget_text as $k => $w ) {
|
||||
if ( ! empty( $w ) && isset( $w['title'], $w['text'] ) && in_array( $k, $active_text_widgets ) && $w['text'] ) {
|
||||
icl_register_string( WPML_ST_WIDGET_STRING_DOMAIN, 'widget body - ' . md5( $w['text'] ), $w['text'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language the current string is to be translated into.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_current_string_language( $name ) {
|
||||
if ( isset( $this->current_string_language_cache[ $name ] ) ) {
|
||||
return $this->current_string_language_cache[ $name ];
|
||||
}
|
||||
|
||||
$key = 'current_language';
|
||||
$found = false;
|
||||
$current_language = WPML_Non_Persistent_Cache::get( $key, 'WPML_String_Translation', $found );
|
||||
if ( ! $found ) {
|
||||
$wp_api = $this->sitepress->get_wp_api();
|
||||
$current_language = $wp_api->constant( 'DOING_AJAX' )
|
||||
&& $this->is_admin_action_from_referer()
|
||||
? $this->sitepress->user_lang_by_authcookie()
|
||||
: $this->sitepress->get_current_language();
|
||||
WPML_Non_Persistent_Cache::set( $key, $current_language, 'WPML_String_Translation' );
|
||||
}
|
||||
|
||||
if ( $this->should_use_admin_language()
|
||||
&& ! WPML_ST_Blog_Name_And_Description_Hooks::is_string( $name ) ) {
|
||||
$admin_display_lang = $this->get_admin_language();
|
||||
$current_language = $admin_display_lang ? $admin_display_lang : $current_language;
|
||||
}
|
||||
|
||||
$ret = apply_filters(
|
||||
'icl_current_string_language',
|
||||
$current_language,
|
||||
$name
|
||||
);
|
||||
$this->current_string_language_cache[ $name ] = $ret === 'all'
|
||||
? $this->sitepress->get_default_language() : $ret;
|
||||
|
||||
return $this->current_string_language_cache[ $name ];
|
||||
}
|
||||
|
||||
public function should_use_admin_language() {
|
||||
$key = 'should_use_admin_language';
|
||||
$found = false;
|
||||
$should_use_admin_language = WPML_Non_Persistent_Cache::get( $key, 'WPML_String_Translation', $found );
|
||||
if ( ! $found ) {
|
||||
$wp_api = $this->sitepress->get_wp_api();
|
||||
$should_use_admin_language = $wp_api->constant( 'WP_ADMIN' ) && ( $this->is_admin_action_from_referer() || ! $wp_api->constant( 'DOING_AJAX' ) );
|
||||
WPML_Non_Persistent_Cache::set( $key, $should_use_admin_language, 'WPML_String_Translation' );
|
||||
}
|
||||
|
||||
return $should_use_admin_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_admin_language() {
|
||||
if ( $this->sitepress->is_wpml_switch_language_triggered() ) {
|
||||
return $this->sitepress->get_admin_language();
|
||||
}
|
||||
|
||||
if ( ! $this->admin_language ) {
|
||||
$this->admin_language = $this->sitepress->get_admin_language();
|
||||
}
|
||||
|
||||
return $this->admin_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_admin_action_from_referer() {
|
||||
if ( $this->is_admin_action_from_referer === null ) {
|
||||
$this->is_admin_action_from_referer = $this->sitepress->check_if_admin_action_from_referer();
|
||||
}
|
||||
|
||||
return $this->is_admin_action_from_referer;
|
||||
}
|
||||
|
||||
public function wpml_language_has_switched() {
|
||||
// clear the current language cache
|
||||
$this->current_string_language_cache = array();
|
||||
}
|
||||
|
||||
public function change_string_lang_ajax_callback() {
|
||||
if ( ! $this->verify_ajax_call( 'wpml_change_string_language_nonce' ) ) {
|
||||
die( 'verification failed' );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$change_string_language_dialog = new WPML_Change_String_Language_Select( $wpdb, $this->sitepress );
|
||||
|
||||
$string_ids = array_map( 'intval', $_POST['strings'] );
|
||||
$lang = filter_var( isset( $_POST['language'] ) ? $_POST['language'] : '', FILTER_SANITIZE_SPECIAL_CHARS );
|
||||
$response = $change_string_language_dialog->change_language_of_strings( $string_ids, $lang );
|
||||
|
||||
wp_send_json( $response );
|
||||
}
|
||||
|
||||
public function change_string_lang_of_domain_ajax_callback() {
|
||||
if ( ! $this->verify_ajax_call( 'wpml_change_string_domain_language_nonce' ) ) {
|
||||
die( 'verification failed' );
|
||||
}
|
||||
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$change_string_language_domain_dialog = new WPML_Change_String_Domain_Language_Dialog( $wpdb, $sitepress, $this->string_factory );
|
||||
$response = $change_string_language_domain_dialog->change_language_of_strings(
|
||||
$_POST['domain'],
|
||||
isset( $_POST['langs'] ) ? $_POST['langs'] : array(),
|
||||
$_POST['language'],
|
||||
$_POST['use_default'] == 'true'
|
||||
);
|
||||
|
||||
wp_send_json( $response );
|
||||
}
|
||||
|
||||
private function verify_ajax_call( $ajax_action ) {
|
||||
return isset( $_POST['wpnonce'] ) && wp_verify_nonce( $_POST['wpnonce'], $ajax_action );
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user