first commit
This commit is contained in:
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user