Файловый менеджер - Редактировать - /var/www/xthruster/html/wp-content/uploads/flags/translations-file-scan.tar
Назад
wpml-st-translations-file-dictionary.php 0000644 00000004220 14721552044 0014461 0 ustar 00 <?php use WPML\ST\TranslationFile\EntryQueries; class WPML_ST_Translations_File_Dictionary { /** @var WPML_ST_Translations_File_Dictionary_Storage */ private $storage; /** * @param WPML_ST_Translations_File_Dictionary_Storage $storage */ public function __construct( WPML_ST_Translations_File_Dictionary_Storage $storage ) { $this->storage = $storage; } /** * @param string $file_path * * @return WPML_ST_Translations_File_Entry|null */ public function find_file_info_by_path( $file_path ) { $result = $this->storage->find( $file_path ); if ( $result ) { return current( $result ); } return null; } /** * @param WPML_ST_Translations_File_Entry $file */ public function save( WPML_ST_Translations_File_Entry $file ) { $this->storage->save( $file ); } /** * @return WPML_ST_Translations_File_Entry[] */ public function get_not_imported_files() { return $this->storage->find( null, [ WPML_ST_Translations_File_Entry::NOT_IMPORTED, WPML_ST_Translations_File_Entry::PARTLY_IMPORTED, ] ); } public function clear_skipped() { $skipped = wpml_collect( $this->storage->find( null, [ WPML_ST_Translations_File_Entry::SKIPPED ] ) ); $skipped->each( function ( WPML_ST_Translations_File_Entry $entry ) { $entry->set_status( WPML_ST_Translations_File_Entry::NOT_IMPORTED ); $this->storage->save( $entry ); } ); } /** * @return WPML_ST_Translations_File_Entry[] */ public function get_imported_files() { return $this->storage->find( null, WPML_ST_Translations_File_Entry::IMPORTED ); } /** * @param null|string $extension * @param null|string $locale * * @return array */ public function get_domains( $extension = null, $locale = null ) { $files = wpml_collect( $this->storage->find() ); if ( $extension ) { $files = $files->filter( EntryQueries::isExtension( $extension ) ); } if ( $locale ) { $files = $files->filter( function ( WPML_ST_Translations_File_Entry $file ) use ( $locale ) { return $file->get_file_locale() === $locale; } ); } return $files->map( EntryQueries::getDomain() ) ->unique() ->values() ->toArray(); } } wpml-st-translations-file-unicode-characters-filter.php 0000644 00000002525 14721552044 0017350 0 ustar 00 <?php class WPML_ST_Translations_File_Unicode_Characters_Filter { /** @var string */ private $pattern; public function __construct() { $parts = array( '([0-9|#][\x{20E3}])', '[\x{00ae}|\x{00a9}|\x{203C}|\x{2047}|\x{2048}|\x{2049}|\x{3030}|\x{303D}|\x{2139}|\x{2122}|\x{3297}|\x{3299}][\x{FE00}-\x{FEFF}]?', '[\x{2190}-\x{21FF}][\x{FE00}-\x{FEFF}]?', '[\x{2300}-\x{23FF}][\x{FE00}-\x{FEFF}]?', '[\x{2460}-\x{24FF}][\x{FE00}-\x{FEFF}]?', '[\x{25A0}-\x{25FF}][\x{FE00}-\x{FEFF}]?', '[\x{2600}-\x{27BF}][\x{FE00}-\x{FEFF}]?', '[\x{2900}-\x{297F}][\x{FE00}-\x{FEFF}]?', '[\x{2B00}-\x{2BF0}][\x{FE00}-\x{FEFF}]?', '[\x{1F000}-\x{1F6FF}][\x{FE00}-\x{FEFF}]?', ); $this->pattern = '/' . implode( '|', $parts ) . '/u'; } /** * @param WPML_ST_Translations_File_Translation[] $translations * * @return WPML_ST_Translations_File_Translation[] */ public function filter( array $translations ) { return array_filter( $translations, array( $this, 'is_valid' ) ); } /** * @param \WPML_ST_Translations_File_Translation $translation * * @return bool */ public function is_valid( WPML_ST_Translations_File_Translation $translation ) { if ( preg_match( $this->pattern, $translation->get_original() ) || preg_match( $this->pattern, $translation->get_translation() ) ) { return false; } return true; } } wpml-st-translations-file-string-status-update.php 0000644 00000002575 14721552044 0016436 0 ustar 00 <?php class WPML_ST_Translations_File_String_Status_Update { /** @var int */ private $number_of_secondary_languages; /** @var wpdb */ private $wpdb; /** * @param int $number_of_secondary_languages * @param wpdb $wpdb */ public function __construct( $number_of_secondary_languages, wpdb $wpdb ) { $this->number_of_secondary_languages = $number_of_secondary_languages; $this->wpdb = $wpdb; } public function add_hooks() { add_action( 'wpml_st_translations_file_post_import', array( $this, 'update_string_statuses' ), 10, 1 ); } public function update_string_statuses( WPML_ST_Translations_File_Entry $file ) { if ( ! in_array( $file->get_status(), array( WPML_ST_Translations_File_Entry::IMPORTED, WPML_ST_Translations_File_Entry::FINISHED ), true ) ) { return; } $sql = " UPDATE {$this->wpdb->prefix}icl_strings s SET s.status = CASE ( SELECT COUNT(t.id) FROM {$this->wpdb->prefix}icl_string_translations t WHERE t.string_id = s.id AND (t.status = %d OR t.mo_string IS NOT NULL) ) WHEN %d THEN %d WHEN 0 THEN %d ELSE %d END WHERE s.context = %s "; $sql = $this->wpdb->prepare( $sql, ICL_TM_COMPLETE, $this->number_of_secondary_languages, ICL_TM_COMPLETE, ICL_TM_NOT_TRANSLATED, ICL_TM_IN_PROGRESS, $file->get_domain() ); $this->wpdb->query( $sql ); } } dictionary/class-st-translations-file-dictionary-storage.php 0000644 00000000477 14721552044 0020430 0 ustar 00 <?php interface WPML_ST_Translations_File_Dictionary_Storage { public function save( WPML_ST_Translations_File_Entry $file ); /** * @param null|string $path * @param null|string|array $status * * @return WPML_ST_Translations_File_Entry[] */ public function find( $path = null, $status = null ); } dictionary/class-st-translations-file-dicionary-storage-table.php 0000644 00000010205 14721552044 0021317 0 ustar 00 <?php class WPML_ST_Translations_File_Dictionary_Storage_Table implements WPML_ST_Translations_File_Dictionary_Storage { /** @var wpdb */ private $wpdb; /** @var null|array */ private $data; /** @var WPML_ST_Translations_File_Entry[] */ private $new_data = array(); /** @var WPML_ST_Translations_File_Entry[] */ private $updated_data = array(); /** * @param wpdb $wpdb */ public function __construct( wpdb $wpdb ) { $this->wpdb = $wpdb; } public function add_hooks() { add_action( 'shutdown', array( $this, 'persist' ), 11, 0 ); } public function save( WPML_ST_Translations_File_Entry $file ) { $this->load_data(); $is_new = ! isset( $this->data[ $file->get_path() ] ); $this->data[ $file->get_path() ] = $file; if ( $is_new ) { $this->new_data[] = $file; } else { $this->updated_data[] = $file; } } /** * We have to postpone saving of real data because target table may not be created yet by migration process */ public function persist() { foreach ( $this->new_data as $file ) { $sql = "INSERT IGNORE INTO {$this->wpdb->prefix}icl_mo_files_domains ( file_path, file_path_md5, domain, status, num_of_strings, last_modified, component_type, component_id ) VALUES ( %s, %s, %s, %s, %d, %d, %s, %s )"; $this->wpdb->query( $this->wpdb->prepare( $sql, array( $file->get_path(), $file->get_path_hash(), $file->get_domain(), $file->get_status(), $file->get_imported_strings_count(), $file->get_last_modified(), $file->get_component_type(), $file->get_component_id(), ) ) ); } foreach ( $this->updated_data as $file ) { $this->wpdb->update( $this->wpdb->prefix . 'icl_mo_files_domains', $this->file_to_array( $file ), array( 'file_path_md5' => $file->get_path_hash(), ), array( '%s', '%s', '%d', '%d' ) ); } } /** * @param WPML_ST_Translations_File_Entry $file * @param array $data * * @return array */ private function file_to_array( WPML_ST_Translations_File_Entry $file, array $data = array() ) { $data['domain'] = $file->get_domain(); $data['status'] = $file->get_status(); $data['num_of_strings'] = $file->get_imported_strings_count(); $data['last_modified'] = $file->get_last_modified(); return $data; } public function find( $path = null, $status = null ) { $this->load_data(); if ( null !== $path ) { return isset( $this->data[ $path ] ) ? array( $this->data[ $path ] ) : array(); } if ( null === $status ) { return array_values( $this->data ); } if ( ! is_array( $status ) ) { $status = array( $status ); } $result = array(); foreach ( $this->data as $file ) { if ( in_array( $file->get_status(), $status, true ) ) { $result[] = $file; } } return $result; } /** * Checks if the given $path is on the wp_icl_mo_files_domains table. * It's only there when ST has handled the file. * * @param string $path * @param string $domain * * @return bool */ public function is_path_handled( $path, $domain ) { $file = new WPML_ST_Translations_File_Entry( $path, $domain ); // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared $id = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT id FROM {$this->wpdb->prefix}icl_mo_files_domains WHERE file_path_md5 = %s LIMIT 1", $file->get_path_hash() ) ); // phpcs:enable WordPress.WP.PreparedSQL.NotPrepared return null !== $id; } private function load_data() { if ( null === $this->data ) { $this->data = array(); $sql = "SELECT * FROM {$this->wpdb->prefix}icl_mo_files_domains"; $rowset = $this->wpdb->get_results( $sql ); foreach ( $rowset as $row ) { $file = new WPML_ST_Translations_File_Entry( $row->file_path, $row->domain, $row->status ); $file->set_imported_strings_count( $row->num_of_strings ); $file->set_last_modified( $row->last_modified ); $file->set_component_type( $row->component_type ); $file->set_component_id( $row->component_id ); $this->data[ $file->get_path() ] = $file; } } } public function reset() { $this->data = null; } } wpml-st-translations-file-scan-factory.php 0000644 00000013110 14721552044 0014703 0 ustar 00 <?php use function WPML\Container\make; class WPML_ST_Translations_File_Scan_Factory { private $dictionary; private $queue; private $storage; private $wpml_file; private $find_aggregate; public function check_core_dependencies() { global $wpdb; $string_index_check = new WPML_ST_Upgrade_String_Index( $wpdb ); $scan_ui_block = new WPML_ST_Translations_File_Scan_UI_Block( wpml_get_admin_notices() ); if ( ! $string_index_check->is_uc_domain_name_context_index_unique() ) { $scan_ui_block->block_ui(); return false; } $scan_ui_block->unblock_ui(); if ( ! function_exists( 'is_plugin_active' ) || ! function_exists( 'get_plugins' ) ) { $file = ABSPATH . 'wp-admin/includes/plugin.php'; if ( file_exists( $file ) ) { require_once $file; } else { return false; } } $wpml_file = $this->get_wpml_file(); return method_exists( $wpml_file, 'get_relative_path' ); } /** * @return array */ public function create_hooks() { $st_upgrade = WPML\Container\make( 'WPML_ST_Upgrade' ); if ( ! $st_upgrade->has_command_been_executed( 'WPML_ST_Upgrade_MO_Scanning' ) ) { return []; } $load = [ // Listener of 'wpml_st_translations_file_post_import' hook. 'stats-update' => $this->get_stats_update(), 'string-status-update' => $this->get_string_status_update(), ]; if ( current_user_can( 'manage_options' ) && ( ! is_admin() || $this->isThemeAndLocalizationPage() ) ) { // Only register / update .mo files when the user is an admin. // NOTE: it's tending to only load this on the Themen and Plugins // localization page, but some .mo files are only loaded on the // frontend (plugins which separating frontend and backend strings). $load['mo-file-registration'] = $this->store_translation_files_info_on_db(); } return $load; } private function isThemeAndLocalizationPage() { global $sitepress; return $sitepress ->get_wp_api() ->is_core_page( 'theme-localization.php' ); } /** * @return WPML_ST_Translations_File_Queue */ public function create_queue() { if ( ! $this->queue ) { global $wpdb; $charset_filter_factory = new WPML_ST_Translations_File_Scan_Db_Charset_Filter_Factory( $wpdb ); $this->queue = new WPML_ST_Translations_File_Queue( $this->create_dictionary(), new WPML_ST_Translations_File_Scan( $charset_filter_factory ), $this->create_storage(), new WPML_Language_Records( $wpdb ), $this->get_scan_limit(), new WPML_Transient() ); } return $this->queue; } /** * @return WPML_ST_Translations_File_Scan_Storage */ private function create_storage() { if ( ! $this->storage ) { global $wpdb; $this->storage = new WPML_ST_Translations_File_Scan_Storage( $wpdb, new WPML_ST_Bulk_Strings_Insert( $wpdb ) ); } return $this->storage; } /** * @return WPML_ST_Translations_File_Dictionary */ private function create_dictionary() { if ( ! $this->dictionary ) { global $sitepress; /** @var WPML_ST_Translations_File_Dictionary_Storage_Table $table_storage */ $table_storage = make( WPML_ST_Translations_File_Dictionary_Storage_Table::class ); $st_upgrade = new WPML_ST_Upgrade( $sitepress ); if ( $st_upgrade->has_command_been_executed( 'WPML_ST_Upgrade_MO_Scanning' ) ) { $table_storage->add_hooks(); } $this->dictionary = new WPML_ST_Translations_File_Dictionary( $table_storage ); } return $this->dictionary; } /** * @return int */ private function get_scan_limit() { $limit = WPML_ST_Translations_File_Queue::DEFAULT_LIMIT; if ( defined( 'WPML_ST_MO_SCANNING_LIMIT' ) ) { $limit = WPML_ST_MO_SCANNING_LIMIT; } return $limit; } private function get_sitepress() { global $sitepress; return $sitepress; } private function get_wpml_wp_api() { $sitepress = $this->get_sitepress(); if ( ! $sitepress ) { return new WPML_WP_API(); } return $sitepress->get_wp_api(); } private function get_wpml_file() { if ( ! $this->wpml_file ) { $this->wpml_file = new WPML_File( $this->get_wpml_wp_api(), new WP_Filesystem_Direct( null ) ); } return $this->wpml_file; } /** * @return WPML_ST_Translations_File_Registration */ private function store_translation_files_info_on_db() { return new WPML_ST_Translations_File_Registration( $this->create_dictionary(), $this->get_wpml_file(), $this->get_aggregate_find_component(), $this->get_sitepress()->get_active_languages() ); } /** * @return WPML_ST_Translations_File_Component_Stats_Update_Hooks */ private function get_stats_update() { global $wpdb; return new WPML_ST_Translations_File_Component_Stats_Update_Hooks( new WPML_ST_Strings_Stats( $wpdb, $this->get_sitepress() ) ); } /** * @return WPML_ST_Translations_File_Component_Details */ private function get_aggregate_find_component() { if ( null === $this->find_aggregate ) { $debug_backtrace = new WPML_Debug_BackTrace(); $this->find_aggregate = new WPML_ST_Translations_File_Component_Details( new WPML_ST_Translations_File_Components_Find_Plugin( $debug_backtrace ), new WPML_ST_Translations_File_Components_Find_Theme( $debug_backtrace, $this->get_wpml_file() ), $this->get_wpml_file() ); } return $this->find_aggregate; } /** * @return WPML_ST_Translations_File_String_Status_Update */ private function get_string_status_update() { global $wpdb; $num_of_secondary_languages = count( $this->get_sitepress()->get_active_languages() ) - 1; $status_update = new WPML_ST_Translations_File_String_Status_Update( $num_of_secondary_languages, $wpdb ); $status_update->add_hooks(); return $status_update; } } wpml-st-translations-file-entry.php 0000644 00000011103 14721552044 0013453 0 ustar 00 <?php class WPML_ST_Translations_File_Entry { const NOT_IMPORTED = 'not_imported'; const IMPORTED = 'imported'; const PARTLY_IMPORTED = 'partly_imported'; const FINISHED = 'finished'; const SKIPPED = 'skipped'; const PATTERN_SEARCH_LANG_MO = '#[-]?([a-z]+[_A-Z]*)\.mo$#i'; const PATTERN_SEARCH_LANG_JSON = '#([a-z]+[_A-Z]*)-[-a-z0-9]+\.json$#i'; /** @var string */ private $path; /** @var string */ private $domain; /** @var int */ private $status; /** @var int */ private $imported_strings_count = 0; /** @var int */ private $last_modified; /** @var string */ private $component_type; /** @var string */ private $component_id; /** * @param string $path * @param string $domain * @param string $status */ public function __construct( $path, $domain, $status = self::NOT_IMPORTED ) { if ( ! is_string( $path ) ) { throw new InvalidArgumentException( 'MO File path must be string type' ); } if ( ! is_string( $domain ) ) { throw new InvalidArgumentException( 'MO File domain must be string type' ); } $this->path = $this->convert_to_relative_path( $path ); $this->domain = $domain; $this->validate_status( $status ); $this->status = $status; } /** * We can't rely on ABSPATH in out tests * * @param string $path * * @return string */ private function convert_to_relative_path( $path ) { $parts = explode( DIRECTORY_SEPARATOR, $this->fix_dir_separator( WP_CONTENT_DIR ) ); return str_replace( WP_CONTENT_DIR, end( $parts ), $path ); } /** * @return string */ public function get_path() { return $this->path; } public function get_full_path() { $wp_content_dir = $this->fix_dir_separator( WP_CONTENT_DIR ); $parts = explode( DIRECTORY_SEPARATOR, $wp_content_dir ); return str_replace( end( $parts ), $wp_content_dir, $this->path ); } /** * @return string */ public function get_path_hash() { return md5( $this->path ); } /** * @return string */ public function get_domain() { return $this->domain; } /** * @return int */ public function get_status() { return $this->status; } /** * @param string $status */ public function set_status( $status ) { $this->validate_status( $status ); $this->status = $status; } /** * @return int */ public function get_imported_strings_count() { return $this->imported_strings_count; } /** * @param int $imported_strings_count */ public function set_imported_strings_count( $imported_strings_count ) { $this->imported_strings_count = (int) $imported_strings_count; } /** * @return int */ public function get_last_modified() { return $this->last_modified; } /** * @param int $last_modified */ public function set_last_modified( $last_modified ) { $this->last_modified = (int) $last_modified; } public function __get( $name ) { if ( in_array( $name, array( 'path', 'domain', 'status', 'imported_strings_count', 'last_modified' ), true ) ) { return $this->$name; } if ( $name === 'path_md5' ) { return $this->get_path_hash(); } return null; } /** * It extracts locale from mo file path, examples * '/wp-content/languages/admin-pl_PL.mo' => 'pl' * '/wp-content/plugins/sitepress/sitepress-hr.mo' => 'hr' * * @return null|string * @throws RuntimeException */ public function get_file_locale() { return \WPML\Container\make( WPML_ST_Translations_File_Locale::class )->get( $this->get_path(), $this->get_domain() ); } /** * @return string */ public function get_component_type() { return $this->component_type; } /** * @param string $component_type */ public function set_component_type( $component_type ) { $this->component_type = $component_type; } /** * @return string */ public function get_component_id() { return $this->component_id; } /** * @param string $component_id */ public function set_component_id( $component_id ) { $this->component_id = $component_id; } /** * @param string $status */ private function validate_status( $status ) { $allowed_statuses = array( self::NOT_IMPORTED, self::IMPORTED, self::PARTLY_IMPORTED, self::FINISHED, self::SKIPPED, ); if ( ! in_array( $status, $allowed_statuses, true ) ) { throw new InvalidArgumentException( 'Status of MO file is invalid' ); } } /** * @param string $path * * @return string */ private function fix_dir_separator( $path ) { return ( '\\' === DIRECTORY_SEPARATOR ) ? str_replace( '/', '\\', $path ) : str_replace( '\\', '/', $path ); } public function get_extension() { return pathinfo( $this->path, PATHINFO_EXTENSION ); } } wpml-st-translations-file-scan-storage.php 0000644 00000004720 14721552044 0014707 0 ustar 00 <?php class WPML_ST_Translations_File_Scan_Storage { /** @var wpdb */ private $wpdb; /** @var WPML_ST_Bulk_Strings_Insert */ private $bulk_insert; /** * @param wpdb $wpdb * @param WPML_ST_Bulk_Strings_Insert $bulk_insert */ public function __construct( wpdb $wpdb, WPML_ST_Bulk_Strings_Insert $bulk_insert ) { $this->wpdb = $wpdb; $this->bulk_insert = $bulk_insert; } public function save( array $translations, $domain, $lang ) { $this->bulk_insert->insert_strings( $this->build_string_collection( $translations, $domain ) ); $string_translations = $this->build_string_translation_collection( $translations, $lang, $this->get_string_maps( $domain ) ); $this->bulk_insert->insert_string_translations( $string_translations ); } /** * @param WPML_ST_Translations_File_Translation[] $translations * @param string $domain * * @return WPML_ST_Models_String[] */ private function build_string_collection( array $translations, $domain ) { $result = array(); foreach ( $translations as $translation ) { $result[] = new WPML_ST_Models_String( 'en', $domain, $translation->get_context(), $translation->get_original(), ICL_TM_NOT_TRANSLATED ); } return $result; } /** * @param string $domain * * @return array */ private function get_string_maps( $domain ) { $sql = " SELECT id, value, gettext_context FROM {$this->wpdb->prefix}icl_strings WHERE context = %s "; $rowset = $this->wpdb->get_results( $this->wpdb->prepare( $sql, $domain ) ); $result = array(); foreach ( $rowset as $row ) { $result[ $row->value ][ $row->gettext_context ] = $row->id; } return $result; } /** * @param WPML_ST_Translations_File_Translation[] $translations * @param string $lang * @param array $value_id_map * * @return WPML_ST_Models_String_Translation[] */ private function build_string_translation_collection( array $translations, $lang, $value_id_map ) { $result = array(); foreach ( $translations as $translation ) { if ( ! isset( $value_id_map[ $translation->get_original() ] ) ) { continue; } $result[] = new WPML_ST_Models_String_Translation( $value_id_map[ $translation->get_original() ][ $translation->get_context() ], $lang, ICL_TM_NOT_TRANSLATED, null, $translation->get_translation() ); } return $result; } } charset-validation/wpml-st-translations-file-scan-charset-validation.php 0000644 00000000177 14721552044 0022607 0 ustar 00 <?php interface WPML_ST_Translations_File_Scan_Charset_Validation { /** * @return bool */ public function is_valid(); } charset-validation/wpml-st-translations-file-scan-db-table-list.php 0000644 00000000571 14721552044 0021447 0 ustar 00 <?php class WPML_ST_Translations_File_Scan_Db_Table_List { /** @var wpdb */ private $wpdb; /** * @param wpdb $wpdb */ public function __construct( wpdb $wpdb ) { $this->wpdb = $wpdb; } /** * @return array */ public function get_tables() { return array( $this->wpdb->prefix . 'icl_strings', $this->wpdb->prefix . 'icl_string_translations', ); } } charset-validation/wpml-st-translations-file-scan-db-charset-validation-factory.php 0000644 00000000752 14721552044 0024636 0 ustar 00 <?php class WPML_ST_Translations_File_Scan_Db_Charset_Filter_Factory { /** @var wpdb $wpdb */ private $wpdb; public function __construct( wpdb $wpdb ) { $this->wpdb = $wpdb; } public function create() { $charset_validator = new WPML_ST_Translations_File_Scan_Db_Charset_Validation( $this->wpdb, new WPML_ST_Translations_File_Scan_Db_Table_List( $this->wpdb ) ); return $charset_validator->is_valid() ? null : new WPML_ST_Translations_File_Unicode_Characters_Filter(); } } charset-validation/wpml-st-translations-file-scan-db-charset-validation.php 0000644 00000002452 14721552044 0023170 0 ustar 00 <?php class WPML_ST_Translations_File_Scan_Db_Charset_Validation implements WPML_ST_Translations_File_Scan_Charset_Validation { /** @var wpdb */ private $wpdb; /** @var WPML_ST_Translations_File_Scan_Db_Table_List */ private $table_list; /** * @param wpdb $wpdb * @param WPML_ST_Translations_File_Scan_Db_Table_List $table_list */ public function __construct( wpdb $wpdb, WPML_ST_Translations_File_Scan_Db_Table_List $table_list ) { $this->wpdb = $wpdb; $this->table_list = $table_list; } /** * @return bool */ public function is_valid() { if ( ! $this->wpdb->has_cap( 'utf8mb4' ) ) { return false; } $chunks = array(); foreach ( $this->table_list->get_tables() as $table ) { $chunks[] = $this->get_unique_collation_list_from_table( $table ); } $collations = call_user_func_array( 'array_merge', $chunks ); $collations = array_unique( $collations ); return count( $collations ) < 2; } /** * @param string $table * * @return array */ private function get_unique_collation_list_from_table( $table ) { /** @var array $columns */ $columns = $this->wpdb->get_results( "SHOW FULL COLUMNS FROM `{$table}` WHERE Collation LIKE 'utf8mb4%'" ); return array_unique( wp_list_pluck( $columns, 'Collation' ) ); } } components/wpml-st-translations-file-components-find-plugin.php 0000644 00000004203 14721552044 0021101 0 ustar 00 <?php class WPML_ST_Translations_File_Components_Find_Plugin implements WPML_ST_Translations_File_Components_Find { /** @var WPML_Debug_BackTrace */ private $debug_backtrace; /** @var string */ private $plugin_dir; /** @var array */ private $plugin_ids; /** * @param WPML_Debug_BackTrace $debug_backtrace */ public function __construct( WPML_Debug_BackTrace $debug_backtrace ) { $this->debug_backtrace = $debug_backtrace; $this->plugin_dir = realpath( WPML_PLUGINS_DIR ); } public function find_id( $file ) { $directory = $this->find_plugin_directory( $file ); if ( ! $directory ) { return null; } return $this->get_plugin_id_by_directory( $directory ); } private function find_plugin_directory( $file ) { if ( false !== strpos( $file, $this->plugin_dir ) ) { return $this->extract_plugin_directory( $file ); } return $this->find_plugin_directory_in_backtrace(); } private function find_plugin_directory_in_backtrace() { $file = $this->find_file_in_backtrace(); if ( ! $file ) { return null; } return $this->extract_plugin_directory( $file ); } private function find_file_in_backtrace() { $stack = $this->debug_backtrace->get_backtrace(); foreach ( $stack as $call ) { if ( isset( $call['function'] ) && 'load_plugin_textdomain' === $call['function'] ) { return $call['file']; } } return null; } /** * @param string $file_path * * @return string */ private function extract_plugin_directory( $file_path ) { $dir = ltrim( str_replace( $this->plugin_dir, '', $file_path ), DIRECTORY_SEPARATOR ); $dir = explode( DIRECTORY_SEPARATOR, $dir ); return trim( $dir[0], DIRECTORY_SEPARATOR ); } /** * @param string $directory * * @return string|null */ private function get_plugin_id_by_directory( $directory ) { foreach ( $this->get_plugin_ids() as $plugin_id ) { if ( 0 === strpos( $plugin_id, $directory . '/' ) ) { return $plugin_id; } } return null; } /** * @return string[] */ private function get_plugin_ids() { if ( null === $this->plugin_ids ) { $this->plugin_ids = array_keys( get_plugins() ); } return $this->plugin_ids; } } components/wpml-st-translations-file-components-find-theme.php 0000644 00000003340 14721552044 0020706 0 ustar 00 <?php class WPML_ST_Translations_File_Components_Find_Theme implements WPML_ST_Translations_File_Components_Find { /** @var WPML_Debug_BackTrace */ private $debug_backtrace; /** @var WPML_File $file */ private $file; /** @var string */ private $theme_dir; /** * @param WPML_Debug_BackTrace $debug_backtrace * @param WPML_File $file */ public function __construct( WPML_Debug_BackTrace $debug_backtrace, WPML_File $file ) { $this->debug_backtrace = $debug_backtrace; $this->file = $file; $this->theme_dir = $this->file->fix_dir_separator( get_theme_root() ); } public function find_id( $file ) { return $this->find_theme_directory( $file ); } private function find_theme_directory( $file ) { if ( false !== strpos( $file, $this->theme_dir ) ) { return $this->extract_theme_directory( $file ); } return $this->find_theme_directory_in_backtrace(); } private function find_theme_directory_in_backtrace() { $file = $this->find_file_in_backtrace(); if ( ! $file ) { return null; } return $this->extract_theme_directory( $file ); } private function find_file_in_backtrace() { $stack = $this->debug_backtrace->get_backtrace(); foreach ( $stack as $call ) { if ( isset( $call['function'] ) && 'load_theme_textdomain' === $call['function'] ) { return $call['file']; } } return null; } /** * @param string $file_path * * @return string */ private function extract_theme_directory( $file_path ) { $file_path = $this->file->fix_dir_separator( $file_path ); $dir = ltrim( str_replace( $this->theme_dir, '', $file_path ), DIRECTORY_SEPARATOR ); $dir = explode( DIRECTORY_SEPARATOR, $dir ); return trim( $dir[0], DIRECTORY_SEPARATOR ); } } components/wpml-st-translations-file-component-details.php 0000644 00000006404 14721552044 0020134 0 ustar 00 <?php class WPML_ST_Translations_File_Component_Details { /** @var WPML_ST_Translations_File_Components_Find[] */ private $finders; /** @var WPML_File $file */ private $file; /** @var string */ private $plugin_dir; /** @var string */ private $theme_dir; /** @var string */ private $languages_plugin_dir; /** @var string */ private $languages_theme_dir; /** @var array */ private $cache = array(); /** * @param WPML_ST_Translations_File_Components_Find_Plugin $plugin_id_finder * @param WPML_ST_Translations_File_Components_Find_Theme $theme_id_finder * @param WPML_File $wpml_file */ public function __construct( WPML_ST_Translations_File_Components_Find_Plugin $plugin_id_finder, WPML_ST_Translations_File_Components_Find_Theme $theme_id_finder, WPML_File $wpml_file ) { $this->finders['plugin'] = $plugin_id_finder; $this->finders['theme'] = $theme_id_finder; $this->file = $wpml_file; $this->theme_dir = $this->file->fix_dir_separator( get_theme_root() ); $this->plugin_dir = $this->file->fix_dir_separator( (string) realpath( WPML_PLUGINS_DIR ) ); $wp_content_dir = realpath( WP_CONTENT_DIR ); $this->languages_plugin_dir = $this->file->fix_dir_separator( $wp_content_dir . '/languages/plugins' ); $this->languages_theme_dir = $this->file->fix_dir_separator( $wp_content_dir . '/languages/themes' ); } /** * @param string $file_full_path * * @return array */ public function find_details( $file_full_path ) { $file_full_path = $this->file->fix_dir_separator( $file_full_path ); if ( ! isset( $this->cache[ $file_full_path ] ) ) { $type = $this->find_type( $file_full_path ); if ( 'other' === $type ) { $this->cache[ $file_full_path ] = array( $type, null ); } else { $this->cache[ $file_full_path ] = array( $type, $this->find_id( $type, $file_full_path ) ); } } return $this->cache[ $file_full_path ]; } /** * @param string $component_type * @param string $file_full_path * * @return null|string */ public function find_id( $component_type, $file_full_path ) { if ( ! isset( $this->finders[ $component_type ] ) ) { return null; } return $this->finders[ $component_type ]->find_id( $file_full_path ); } /** * @param string $file_full_path * * @return string */ public function find_type( $file_full_path ) { if ( $this->theme_dir && ( $this->string_contains( $file_full_path, $this->theme_dir ) || $this->string_contains( $file_full_path, $this->languages_theme_dir ) ) ) { return 'theme'; } if ( $this->string_contains( $file_full_path, $this->plugin_dir ) || $this->string_contains( $file_full_path, $this->languages_plugin_dir ) ) { return 'plugin'; } return 'other'; } /** * @param string $file_full_path * * @return bool */ public function is_component_active( $file_full_path ) { list( $type, $id ) = $this->find_details( $file_full_path ); if ( 'other' === $type ) { return true; } if ( ! $id ) { return false; } if ( 'plugin' === $type ) { return is_plugin_active( $id ); } else { return get_stylesheet_directory() === get_theme_root() . '/' . $id; } } private function string_contains( $haystack, $needle ) { return false !== strpos( $haystack, $needle ); } } components/wpml-st-translations-file-components-find.php 0000644 00000000240 14721552044 0017602 0 ustar 00 <?php interface WPML_ST_Translations_File_Components_Find { /** * @param string $file * * @return string|null */ public function find_id( $file ); } wpml-st-translations-file-queue.php 0000644 00000012255 14721552044 0013447 0 ustar 00 <?php use WPML\ST\TranslationFile\EntryQueries; use WPML\ST\TranslationFile\QueueFilter; class WPML_ST_Translations_File_Queue { const DEFAULT_LIMIT = 20000; const TIME_LIMIT = 10; // seconds const LOCK_FIELD = '_wpml_st_file_scan_in_progress'; /** @var WPML_ST_Translations_File_Dictionary */ private $file_dictionary; /** @var WPML_ST_Translations_File_Scan */ private $file_scan; /** @var WPML_ST_Translations_File_Scan_Storage */ private $file_scan_storage; /** @var WPML_Language_Records */ private $language_records; /** @var int */ private $limit; /** @var WPML_Transient */ private $transient; /** * @param WPML_ST_Translations_File_Dictionary $file_dictionary * @param WPML_ST_Translations_File_Scan $file_scan * @param WPML_ST_Translations_File_Scan_Storage $file_scan_storage * @param WPML_Language_Records $language_records * @param int $limit * @param WPML_Transient $transient */ public function __construct( WPML_ST_Translations_File_Dictionary $file_dictionary, WPML_ST_Translations_File_Scan $file_scan, WPML_ST_Translations_File_Scan_Storage $file_scan_storage, WPML_Language_Records $language_records, $limit, WPML_Transient $transient ) { $this->file_dictionary = $file_dictionary; $this->file_scan = $file_scan; $this->file_scan_storage = $file_scan_storage; $this->language_records = $language_records; $this->limit = $limit; $this->transient = $transient; } /** * @param QueueFilter|null $queueFilter */ public function import( QueueFilter $queueFilter = null ) { $this->file_dictionary->clear_skipped(); $files = $this->file_dictionary->get_not_imported_files(); if ( count( $files ) ) { $this->lock(); $start_time = time(); $imported = 0; foreach ( $files as $file ) { if ( $imported >= $this->limit || time() - $start_time > self::TIME_LIMIT ) { break; } if ( ! $queueFilter || $queueFilter->isSelected( $file ) ) { $translations = $this->file_scan->load_translations( $file->get_full_path() ); try { $number_of_translations = count( $translations ); if ( ! $number_of_translations ) { throw new RuntimeException( 'File is empty' ); } $translations = $this->constrain_translations_number( $translations, $file->get_imported_strings_count(), $this->limit - $imported ); $imported += $imported_in_file = count( $translations ); $this->file_scan_storage->save( $translations, $file->get_domain(), $this->map_language_code( $file->get_file_locale() ) ); $file->set_imported_strings_count( $file->get_imported_strings_count() + $imported_in_file ); if ( $file->get_imported_strings_count() >= $number_of_translations ) { $file->set_status( WPML_ST_Translations_File_Entry::IMPORTED ); } else { $file->set_status( WPML_ST_Translations_File_Entry::PARTLY_IMPORTED ); } } catch ( WPML_ST_Bulk_Strings_Insert_Exception $e ) { $file->set_status( WPML_ST_Translations_File_Entry::PARTLY_IMPORTED ); break; } catch ( Exception $e ) { $file->set_status( WPML_ST_Translations_File_Entry::IMPORTED ); } } else { $file->set_status( WPML_ST_Translations_File_Entry::SKIPPED ); } $this->file_dictionary->save( $file ); do_action( 'wpml_st_translations_file_post_import', $file ); } $this->unlock(); } } /** * @param string $locale * * @return string */ private function map_language_code( $locale ) { $language_code = $this->language_records->get_language_code( $locale ); if ( $language_code ) { return $language_code; } return $locale; } /** * @return bool */ public function is_completed() { return 0 === count( $this->file_dictionary->get_not_imported_files() ) && 0 < count( $this->file_dictionary->get_imported_files() ); } /** * @return string[] */ public function get_processed() { return wp_list_pluck( $this->file_dictionary->get_imported_files(), 'path' ); } /** * @return bool */ public function is_processing() { return 0 !== count( $this->file_dictionary->get_not_imported_files() ); } /** * @return int */ public function get_pending() { return count( $this->file_dictionary->get_not_imported_files() ); } public function mark_as_finished() { foreach ( $this->file_dictionary->get_imported_files() as $file ) { $file->set_status( WPML_ST_Translations_File_Entry::FINISHED ); $this->file_dictionary->save( $file ); } } /** * @param array $translations * @param int $offset * @param int $limit * * @return array */ private function constrain_translations_number( array $translations, $offset, $limit ) { if ( $limit > count( $translations ) ) { return $translations; } return array_slice( $translations, $offset, $limit ); } public function is_locked() { return (bool) $this->transient->get( self::LOCK_FIELD ); } private function lock() { $this->transient->set( self::LOCK_FIELD, 1, MINUTE_IN_SECONDS * 5 ); } private function unlock() { $this->transient->delete( self::LOCK_FIELD ); } } EntryQueries.php 0000644 00000003235 14721552044 0007723 0 ustar 00 <?php namespace WPML\ST\TranslationFile; class EntryQueries { /** * @param string $type * * @return \Closure */ public static function isType( $type ) { return function ( \WPML_ST_Translations_File_Entry $entry ) use ( $type ) { return $entry->get_component_type() === $type; }; } /** * @param string $extension * * @return \Closure */ public static function isExtension( $extension ) { return function ( \WPML_ST_Translations_File_Entry $file ) use ( $extension ) { return $file->get_extension() === $extension; }; } /** * @return \Closure */ public static function getResourceName() { return function ( \WPML_ST_Translations_File_Entry $entry ) { $function = 'get' . ucfirst( $entry->get_component_type() ) . 'Name'; return self::$function( $entry ); }; } /** * @return \Closure */ public static function getDomain() { return function( \WPML_ST_Translations_File_Entry $file ) { return $file->get_domain(); }; } /** * @param \WPML_ST_Translations_File_Entry $entry * * @return string */ private static function getPluginName( \WPML_ST_Translations_File_Entry $entry ) { $data = get_plugin_data( WPML_PLUGINS_DIR . '/' . $entry->get_component_id(), false, false ); return $data['Name']; } /** * @param \WPML_ST_Translations_File_Entry $entry * * @return string */ private static function getThemeName( \WPML_ST_Translations_File_Entry $entry ) { return $entry->get_component_id(); } /** * @param \WPML_ST_Translations_File_Entry $entry * * @return mixed|string|void */ private static function getOtherName( \WPML_ST_Translations_File_Entry $entry ) { return 'WordPress'; } } QueueFilter.php 0000644 00000001752 14721552044 0007520 0 ustar 00 <?php namespace WPML\ST\TranslationFile; use WPML_ST_Translations_File_Entry; class QueueFilter { /** @var array */ private $plugins; /** @var array */ private $themes; /** @var array */ private $other; /** * @param array $plugins * @param array $themes * @param array $other */ public function __construct( array $plugins, array $themes, array $other ) { $this->plugins = $plugins; $this->themes = $themes; $this->other = $other; } /** * @param WPML_ST_Translations_File_Entry $file * * @return bool */ public function isSelected( WPML_ST_Translations_File_Entry $file ) { $getResourceName = EntryQueries::getResourceName(); $resourceName = $getResourceName( $file ); switch ( $file->get_component_type() ) { case 'plugin': return in_array( $resourceName, $this->plugins ); case 'theme': return in_array( $resourceName, $this->themes ); case 'other': return in_array( $resourceName, $this->other ); } return false; } } UI/InstalledComponents.php 0000644 00000002124 14721552044 0011562 0 ustar 00 <?php /** * @author OnTheGo Systems */ namespace WPML\ST\MO\Scan\UI; use WPML\Collect\Support\Collection; use WPML_ST_Translations_File_Entry; class InstalledComponents { /** * @param Collection $components Collection of WPML_ST_Translations_File_Entry objects. * * @return Collection */ public static function filter( Collection $components ) { return $components ->reject( self::isPluginMissing() ) ->reject( self::isThemeMissing() ); } /** * WPML_ST_Translations_File_Entry -> bool * * @return \Closure */ public static function isPluginMissing() { return function( WPML_ST_Translations_File_Entry $entry ) { return 'plugin' === $entry->get_component_type() && ! is_readable( WPML_PLUGINS_DIR . '/' . $entry->get_component_id() ); }; } /** * WPML_ST_Translations_File_Entry -> bool * * @return \Closure */ public static function isThemeMissing() { return function( WPML_ST_Translations_File_Entry $entry ) { return 'theme' === $entry->get_component_type() && ! wp_get_theme( $entry->get_component_id() )->exists(); }; } } UI/Factory.php 0000644 00000007041 14721552044 0007207 0 ustar 00 <?php namespace WPML\ST\MO\Scan\UI; use WPML\Collect\Support\Collection; use WPML\ST\MO\Generate\DomainsAndLanguagesRepository; use WPML\ST\MO\Generate\Process\ProcessFactory; use WPML_ST_Translations_File_Dictionary_Storage_Table; use WPML_ST_Translations_File_Dictionary; use WPML\WP\OptionManager; use function WPML\Container\make; use function WPML\FP\partial; class Factory implements \IWPML_Backend_Action_Loader, \IWPML_Deferred_Action_Loader { const WPML_VERSION_INTRODUCING_ST_MO_FLOW = '4.3.0'; const OPTION_GROUP = 'ST-MO'; const IGNORE_WPML_VERSION = 'ignore-wpml-version'; /** * @return callable|null * @throws \WPML\Auryn\InjectionException */ public function create() { if ( current_user_can( 'manage_options' ) && function_exists( 'wpml_is_rest_enabled' ) && wpml_is_rest_enabled() ) { global $sitepress; $wp_api = $sitepress->get_wp_api(); $pre_gen_dissmissed = self::isDismissed(); $st_page = $wp_api->is_core_page( 'theme-localization.php' ) || $wp_api->is_string_translation_page(); if ( ( $st_page || ( ! $st_page && ! $pre_gen_dissmissed ) ) && ( DomainsAndLanguagesRepository::hasTranslationFilesTable() || is_network_admin() ) ) { $files_to_import = $st_page ? $this->getFilesToImport() : wpml_collect( [] ); $domains_to_pre_generate_count = self::getDomainsToPreGenerateCount(); if ( $files_to_import->count() || $domains_to_pre_generate_count || isset( $_GET['search'] ) ) { return partial( [ UI::class, 'add_hooks' ], Model::provider( $files_to_import, $domains_to_pre_generate_count, $st_page, is_network_admin() ), $st_page ); } } } return null; } public function get_load_action() { return 'init'; } /** * @return bool * @throws \WPML\Auryn\InjectionException */ public static function isDismissed() { return make( OptionManager::class )->get( self::OPTION_GROUP, 'pregen-dismissed', false ); } /** * @return Collection * @throws \WPML\Auryn\InjectionException */ private function getFilesToImport() { /** @var WPML_ST_Translations_File_Dictionary $file_dictionary */ $file_dictionary = make( WPML_ST_Translations_File_Dictionary::class, [ 'storage' => WPML_ST_Translations_File_Dictionary_Storage_Table::class ] ); $file_dictionary->clear_skipped(); return InstalledComponents::filter( wpml_collect( $file_dictionary->get_not_imported_files() ) ); } /** * @return bool */ private static function isPreGenerationRequired() { return self::shouldIgnoreWpmlVersion() || self::wpmlStartVersionBeforeMOFlow(); } /** * @return bool */ private static function wpmlStartVersionBeforeMOFlow() { return version_compare( get_option( \WPML_Installation::WPML_START_VERSION_KEY, '0.0.0' ), self::WPML_VERSION_INTRODUCING_ST_MO_FLOW, '<' ); } /** * @return int * @throws \WPML\Auryn\InjectionException */ public static function getDomainsToPreGenerateCount() { return self::isPreGenerationRequired() ? make( ProcessFactory::class )->create()->getPagesCount() : 0; } /** * @return bool */ public static function shouldIgnoreWpmlVersion() { return make( OptionManager::class )->get( self::OPTION_GROUP, self::IGNORE_WPML_VERSION, false ); } public static function ignoreWpmlVersion() { make( OptionManager::class )->set( self::OPTION_GROUP, self::IGNORE_WPML_VERSION, true ); } public static function clearIgnoreWpmlVersion() { make( OptionManager::class )->set( self::OPTION_GROUP, self::IGNORE_WPML_VERSION, false ); } } UI/Model.php 0000644 00000003411 14721552044 0006635 0 ustar 00 <?php namespace WPML\ST\MO\Scan\UI; use WPML\Collect\Support\Collection; use WPML\ST\MO\Generate\MultiSite\Condition; use WPML\ST\TranslationFile\EntryQueries; class Model { /** * @param Collection $files_to_scan * @param int $domains_to_pre_generate_count * @param bool $is_st_page * @param bool $is_network_admin * * @return \Closure */ public static function provider( Collection $files_to_scan, $domains_to_pre_generate_count, $is_st_page, $is_network_admin ) { return function () use ( $files_to_scan, $domains_to_pre_generate_count, $is_st_page ) { return [ 'files_to_scan' => [ 'count' => $files_to_scan->count(), 'plugins' => self::filterFilesByType( $files_to_scan, 'plugin' ), 'themes' => self::filterFilesByType( $files_to_scan, 'theme' ), 'other' => self::filterFilesByType( $files_to_scan, 'other' ), ], 'domains_to_pre_generate_count' => $domains_to_pre_generate_count, 'file_path' => WP_LANG_DIR . '/wpml', 'is_st_page' => $is_st_page, 'admin_texts_url' => 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&trop=1', 'is_search' => isset( $_GET['search'] ), 'run_ror_all_sites' => ( new Condition() )->shouldRunWithAllSites(), ]; }; } /** * @param Collection $files_to_scan * @param string $type * * @return array */ private static function filterFilesByType( Collection $files_to_scan, $type ) { return $files_to_scan->filter( EntryQueries::isType( $type ) ) ->map( EntryQueries::getResourceName() ) ->unique() ->values() ->toArray(); } } UI/UI.php 0000644 00000001324 14721552044 0006113 0 ustar 00 <?php namespace WPML\ST\MO\Scan\UI; use \WPML\ST\WP\App\Resources; use WPML\LIB\WP\Hooks as WPHooks; class UI { public static function add_hooks( callable $getModel, $isSTPage ) { WPHooks::onAction( 'admin_enqueue_scripts' ) ->then( $getModel ) ->then( [ self::class, 'localize' ] ) ->then( Resources::enqueueApp( 'mo-scan' ) ); if ( ! $isSTPage ) { WPHooks::onAction( [ 'admin_notices', 'network_admin_notices' ] ) ->then( [ self::class, 'add_admin_notice' ] ); } } public static function add_admin_notice() { ?> <div id="wpml-mo-scan-st-page"></div> <?php } public static function localize( $model ) { return [ 'name' => 'wpml_mo_scan_ui_files', 'data' => $model, ]; } } wpml-st-translations-file-translation.php 0000644 00000001343 14721552044 0014655 0 ustar 00 <?php class WPML_ST_Translations_File_Translation { /** @var string */ private $original; /** @var string */ private $translation; /** @var string */ private $context; /** * @param string $original * @param string $translation * @param string $context */ public function __construct( $original, $translation, $context = '' ) { $this->original = $original; $this->translation = $translation; $this->context = $context; } /** * @return string */ public function get_original() { return $this->original; } /** * @return string */ public function get_translation() { return $this->translation; } /** * @return string */ public function get_context() { return $this->context; } } wpml-st-translations-file-component-stats-update-hooks.php 0000644 00000001317 14721552044 0020057 0 ustar 00 <?php class WPML_ST_Translations_File_Component_Stats_Update_Hooks { /** @var WPML_ST_Strings_Stats */ private $string_stats; /** * @param WPML_ST_Strings_Stats $string_stats */ public function __construct( WPML_ST_Strings_Stats $string_stats ) { $this->string_stats = $string_stats; } public function add_hooks() { add_action( 'wpml_st_translations_file_post_import', array( $this, 'update_stats' ), 10, 1 ); } /** * @param WPML_ST_Translations_File_Entry $file */ public function update_stats( WPML_ST_Translations_File_Entry $file ) { if ( $file->get_component_id() ) { $this->string_stats->update( $file->get_component_id(), $file->get_component_type(), $file->get_domain() ); } } } translations-file/wpml-st-translations-file-locale.php 0000644 00000007370 14721552044 0017222 0 ustar 00 <?php class WPML_ST_Translations_File_Locale { const PATTERN_SEARCH_LANG_JSON = '#DOMAIN_PLACEHOLDER(LOCALES_PLACEHOLDER)-[-_a-z0-9]+\.json$#i'; /** @var \SitePress */ private $sitepress; /** @var \WPML_Locale */ private $locale; /** * @param SitePress $sitepress * @param WPML_Locale $locale */ public function __construct( SitePress $sitepress, WPML_Locale $locale ) { $this->sitepress = $sitepress; $this->locale = $locale; } /** * It extracts language code from mo file path, examples * '/wp-content/languages/admin-pl_PL.mo' => 'pl' * '/wp-content/plugins/sitepress/sitepress-hr.mo' => 'hr' * '/wp-content/languages/fr_FR-4gh5e6d3g5s33d6gg51zas2.json' => 'fr_FR' * '/wp-content/plugins/my-plugin/languages/-my-plugin-fr_FR-my-handler.json' => 'fr_FR' * * @param string $filepath * @param string $domain * * @return string */ public function get( $filepath, $domain ) { switch ( $this->get_extension( $filepath ) ) { case 'mo': return $this->get_from_mo_file( $filepath ); case 'json': return $this->get_from_json_file( $filepath, $domain ); default: return ''; } } /** * @param string $filepath * * @return string|null */ private function get_extension( $filepath ) { return wpml_collect( pathinfo( $filepath ) )->get( 'extension', null ); } /** * @param string $filepath * * @return string */ private function get_from_mo_file( $filepath ) { return $this->get_locales() ->first( function ( $locale ) use ( $filepath ) { return strpos( $filepath, $locale . '.mo' ); }, '' ); } /** * @param string $filepath * @param string $domain * * @return string */ private function get_from_json_file( $filepath, $domain ) { $original_domain = $this->get_original_domain_for_json( $filepath, $domain ); $domain_replace = 'default' === $original_domain ? '' : $original_domain . '-'; $locales = $this->get_locales()->implode( '|' ); $searches['native-file'] = '#' . $domain_replace . '(' . $locales . ')-[-_a-z0-9]+\.json$#i'; $searches['wpml-file'] = '#' . $domain . '-(' . $locales . ').json#i'; foreach ( $searches as $search ) { if ( preg_match( $search, $filepath, $matches ) && isset( $matches[1] ) ) { return $matches[1]; } } return ''; } /** * We need the original domain name to refine the regex pattern. * Unfortunately, the domain is concatenated with the script handler * in the import queue table. That's why we need to retrieve the original * domain from the registration domain and the filepath. * * @param string $filepath * @param string $domain * * @return string */ private function get_original_domain_for_json( $filepath, $domain ) { $filename = basename( $filepath ); /** * Case of WP JED files: * - filename: de_DE-73f9977556584a369800e775b48f3dbe.json * - domain: default-some-script * => original_domain: default */ if ( 0 === strpos( $domain, 'default' ) && 0 !== strpos( $filename, 'default' ) ) { return 'default'; } /** * Case of 3rd part JED files: * - filename: plugin-domain-de_DE-script-handler.json * - domain: plugin-domain-script-handler * => original_domain: plugin-domain */ $filename_parts = explode( '-', $filename ); $domain_parts = explode( '-', $domain ); $original_domain_parts = array(); foreach ( $domain_parts as $i => $part ) { if ( $filename_parts[ $i ] !== $part ) { break; } $original_domain_parts[] = $part; } return implode( '-', $original_domain_parts ); } /** * @return \WPML\Collect\Support\Collection */ private function get_locales() { return \wpml_collect( $this->sitepress->get_active_languages() ) ->keys() ->map( [ $this->locale, 'get_locale' ] ); } } translations-file/wpml-st-translations-file-mo.php 0000644 00000002125 14721552044 0016367 0 ustar 00 <?php class WPML_ST_Translations_File_MO implements IWPML_ST_Translations_File { /** @var string $filepath */ private $filepath; /** * @param string $filepath */ public function __construct( $filepath ) { $this->filepath = $filepath; } /** * @return WPML_ST_Translations_File_Translation[] */ public function get_translations() { $translations = array(); $mo = new MO(); $pomo_reader = new POMO_CachedFileReader( $this->filepath ); // @see wpmldev-1856 /** @phpstan-ignore-next-line */ $mo->import_from_reader( $pomo_reader ); foreach ( $mo->entries as $str => $v ) { $str = str_replace( "\n", '\n', $v->singular ); $translations[] = new WPML_ST_Translations_File_Translation( $str, $v->translations[0], $v->context ); if ( $v->is_plural ) { $str = str_replace( "\n", '\n', $v->plural ); $translation = ! empty( $v->translations[1] ) ? $v->translations[1] : $v->translations[0]; $translations[] = new WPML_ST_Translations_File_Translation( $str, $translation, $v->context ); } } return $translations; } } translations-file/iwpml-st-translations-file.php 0000644 00000000224 14721552044 0016125 0 ustar 00 <?php interface IWPML_ST_Translations_File { /** * @return WPML_ST_Translations_File_Translation[] */ public function get_translations(); } translations-file/wpml-st-translations-file-jed.php 0000644 00000004230 14721552044 0016515 0 ustar 00 <?php class WPML_ST_Translations_File_JED implements IWPML_ST_Translations_File { const EMPTY_PROPERTY_NAME = '_empty_'; const DECODED_EOT_CHAR = '"\u0004"'; const PLURAL_SUFFIX_PATTERN = ' [plural %d]'; /** @var string $filepath */ private $filepath; /** @var string $decoded_eot_char */ private $decoded_eot_char; public function __construct( $filepath ) { $this->filepath = $filepath; $this->decoded_eot_char = json_decode( self::DECODED_EOT_CHAR ); } /** * @return WPML_ST_Translations_File_Translation[] */ public function get_translations() { $translations = array(); $data = json_decode( (string) file_get_contents( $this->filepath ) ); if ( isset( $data->locale_data->messages ) ) { $entries = (array) $data->locale_data->messages; unset( $entries[ self::EMPTY_PROPERTY_NAME ] ); foreach ( $entries as $str => $str_data ) { $str_data = (array) $str_data; if ( ! isset( $str_data[0] ) ) { continue; } list( $str, $context ) = $this->get_string_and_context( $str ); $count_translations = count( $str_data ); $translations[] = new WPML_ST_Translations_File_Translation( $str, $str_data[0], $context ); if ( $count_translations > 1 ) { /** * The strings coming after the first element are the plural translations. * As we don't have the information about the original plural in the JED file, * we will add a suffix to the original singular string. */ for ( $i = 1; $i < $count_translations; $i++ ) { $plural_str = $str . sprintf( self::PLURAL_SUFFIX_PATTERN, $i ); $translations[] = new WPML_ST_Translations_File_Translation( $plural_str, $str_data[ $i ], $context ); } } } } return $translations; } /** * The context is the first part of the string separated with the EOT char (\u0004) * * @param string $string * * @return array */ private function get_string_and_context( $string ) { $context = ''; $parts = explode( $this->decoded_eot_char, $string ); if ( $parts && count( $parts ) > 1 ) { $context = $parts[0]; $string = $parts[1]; } return array( $string, $context ); } } wpml-st-translations-file-registration.php 0000644 00000013127 14721552044 0015034 0 ustar 00 <?php use WPML\Element\API\Languages; use WPML\FP\Fns; class WPML_ST_Translations_File_Registration { const PATH_PATTERN_SEARCH_MO = '#(-)?([a-z]+)([_A-Z]*)\.mo$#i'; const PATH_PATTERN_REPLACE_MO = '${1}%s.mo'; const PATH_PATTERN_SEARCH_JSON = '#(DOMAIN_PLACEHOLDER)([a-z]+)([_A-Z]*)(-[-_a-z0-9]+)\.json$#i'; const PATH_PATTERN_REPLACE_JSON = '${1}%s${4}.json'; /** @var WPML_ST_Translations_File_Dictionary */ private $file_dictionary; /** @var WPML_File */ private $wpml_file; /** @var WPML_ST_Translations_File_Component_Details */ private $components_find; /** @var array */ private $active_languages; /** @var array */ private $cache = array(); /** @var callable - string->string */ private $getWPLocale; /** * @param WPML_ST_Translations_File_Dictionary $file_dictionary * @param WPML_File $wpml_file * @param WPML_ST_Translations_File_Component_Details $components_find * @param array $active_languages */ public function __construct( WPML_ST_Translations_File_Dictionary $file_dictionary, WPML_File $wpml_file, WPML_ST_Translations_File_Component_Details $components_find, array $active_languages ) { $this->file_dictionary = $file_dictionary; $this->wpml_file = $wpml_file; $this->components_find = $components_find; $this->active_languages = $active_languages; $this->getWPLocale = Fns::memorize( Languages::getWPLocale() ); } public function add_hooks() { add_filter( 'override_load_textdomain', array( $this, 'cached_save_mo_file_info' ), 11, 3 ); add_filter( 'pre_load_script_translations', array( $this, 'add_json_translations_to_import_queue' ), 10, 4 ); } /** * @param bool $override * @param string $domain * @param string $mo_file_path * * @return bool */ public function cached_save_mo_file_info( $override, $domain, $mo_file_path ) { if ( ! isset( $this->cache[ $mo_file_path ] ) ) { $this->cache[ $mo_file_path ] = $this->save_file_info( $domain, $domain, $mo_file_path ); } return $override; } /** * @param string|false $translations translations in the JED format * @param string|false $file * @param string $handle * @param string $original_domain * * @return string|false */ public function add_json_translations_to_import_queue( $translations, $file, $handle, $original_domain ) { if ( $file && ! isset( $this->cache[ $file ] ) ) { $registration_domain = WPML_ST_JED_Domain::get( $original_domain, $handle ); $this->cache[ $file ] = $this->save_file_info( $original_domain, $registration_domain, $file ); } return $translations; } /** * @param string $original_domain * @param string $registration_domain which can be composed with the script-handle for JED files * @param string $file_path * * @return true */ private function save_file_info( $original_domain, $registration_domain, $file_path ) { try { $file_path_pattern = $this->get_file_path_pattern( $file_path, $original_domain ); foreach ( $this->active_languages as $lang_data ) { $file_path_in_lang = sprintf( (string) $file_path_pattern, $lang_data['default_locale'] ); $this->register_single_file( $registration_domain, $file_path_in_lang ); } } catch ( Exception $e ) { } return true; } /** * @param string $file_path * @param string $original_domain * * @return string|null * @throws InvalidArgumentException */ private function get_file_path_pattern( $file_path, $original_domain ) { $pathinfo = pathinfo( $file_path ); $file_type = isset( $pathinfo['extension'] ) ? $pathinfo['extension'] : null; switch ( $file_type ) { case 'mo': return preg_replace( self::PATH_PATTERN_SEARCH_MO, self::PATH_PATTERN_REPLACE_MO, $file_path ); case 'json': $domain_replace = 'default' === $original_domain ? '' : $original_domain . '-'; $search_pattern = str_replace( 'DOMAIN_PLACEHOLDER', $domain_replace, self::PATH_PATTERN_SEARCH_JSON ); return preg_replace( $search_pattern, self::PATH_PATTERN_REPLACE_JSON, $file_path ); } throw new RuntimeException( 'The "' . $file_type . '" file type is not supported for registration' ); } /** * @param string $registration_domain * @param string $file_path */ private function register_single_file( $registration_domain, $file_path ) { if ( ! $this->wpml_file->file_exists( $file_path ) || $this->isGeneratedFile( $file_path ) ) { return; } $relative_path = $this->wpml_file->get_relative_path( $file_path ); $last_modified = $this->wpml_file->get_file_modified_timestamp( $file_path ); $file = $this->file_dictionary->find_file_info_by_path( $relative_path ); if ( ! $file ) { if ( ! $this->components_find->is_component_active( $file_path ) ) { return; } $file = new WPML_ST_Translations_File_Entry( $relative_path, $registration_domain ); $file->set_last_modified( $last_modified ); list( $component_type, $component_id ) = $this->components_find->find_details( $file_path ); $file->set_component_type( $component_type ); $file->set_component_id( $component_id ); $this->file_dictionary->save( $file ); } elseif ( $file->get_last_modified() !== $last_modified ) { $file->set_status( WPML_ST_Translations_File_Entry::NOT_IMPORTED ); $file->set_last_modified( $last_modified ); $file->set_imported_strings_count( 0 ); $this->file_dictionary->save( $file ); } } private function isGeneratedFile( $path ) { return strpos( $this->wpml_file->fix_dir_separator( $path ), $this->wpml_file->fix_dir_separator( WPML\ST\TranslationFile\Manager::getSubdir() ) ) === 0; } } wpml-st-translations-file-scan-ui-block.php 0000644 00000007231 14721552044 0014750 0 ustar 00 <?php class WPML_ST_Translations_File_Scan_UI_Block { const NOTICES_GROUP = 'wpml-st-mo-scan'; const NOTICES_MO_SCANNING_BLOCKED = 'mo-scanning-blocked'; /** @var WPML_Notices */ private $notices; /** @var string */ private $link = 'https://wpml.org/faq/how-to-deal-with-error-messages-about-a-broken-table-that-needs-fixing/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmlst'; /** * @param WPML_Notices $notices */ public function __construct( WPML_Notices $notices ) { $this->notices = $notices; } public function block_ui() { $this->disable_option(); $this->remove_default_notice(); $this->display_notice(); } public function unblock_ui() { if ( is_admin() ) { $this->notices->remove_notice( self::NOTICES_GROUP, self::NOTICES_MO_SCANNING_BLOCKED ); } } private function disable_option() { add_filter( 'wpml_localization_options_ui_model', array( $this, 'disable_option_handler' ) ); } public function disable_option_handler( $model ) { if ( ! isset( $model['top_options'][0] ) ) { return $model; } $model['top_options'][0]['disabled'] = true; $model['top_options'][0]['message'] = $this->get_short_notice_message(); return $model; } private function get_short_notice_message() { $message = _x( 'WPML cannot replace .mo files because of technical problems in the String Translation table.', 'MO Import blocked short 1/3', 'wpml-string-translation' ); $message .= ' ' . _x( 'WPML support team knows how to fix it.', 'MO Import blocked short 2/3', 'wpml-string-translation' ); $message .= ' ' . sprintf( _x( 'Please add a message in the relevant <a href="%s" target="_blank" >support thread</a> and we\'ll fix it for you.', 'MO Import blocked short 3/3', 'wpml-string-translation' ), $this->link ); return '<span class="icl_error_text" >' . $message . '</span>'; } private function display_notice() { $message = _x( 'There is a problem with the String Translation table in your site.', 'MO Import blocked 1/4', 'wpml-string-translation' ); $message .= ' ' . _x( 'This problem is not causing a problem running the site right now, but can become a critical issue in the future.', 'MO Import blocked 2/4', 'wpml-string-translation' ); $message .= ' ' . _x( 'WPML support team knows how to fix it.', 'MO Import blocked 3/4', 'wpml-string-translation' ); $message .= ' ' . sprintf( _x( 'Please add a message in the relevant <a href="%s" target="_blank">support thread</a> and we\'ll fix it for you.', 'MO Import blocked 4/4', 'wpml-string-translation' ), $this->link ); $notice = $this->notices->create_notice( self::NOTICES_MO_SCANNING_BLOCKED, $message, self::NOTICES_GROUP ); $notice->set_css_class_types( 'error' ); $notice->set_dismissible( false ); $restricted_pages = array( 'sitepress-multilingual-cms/menu/languages.php', 'sitepress-multilingual-cms/menu/menu-sync/menus-sync.php', 'sitepress-multilingual-cms/menu/support.php', 'sitepress-multilingual-cms/menu/taxonomy-translation.php', 'sitepress-multilingual-cms/menu/theme-localization.php', 'wpml-media', 'wpml-package-management', 'wpml-string-translation/menu/string-translation.php', 'wpml-sticky-links', 'wpml-translation-management/menu/translations-queue.php', 'wpml-translation-management/menu/main.php', ); $notice->set_restrict_to_pages( $restricted_pages ); $this->notices->add_notice( $notice ); } private function remove_default_notice() { $this->notices->remove_notice( WPML_ST_Themes_And_Plugins_Settings::NOTICES_GROUP, WPML_ST_Themes_And_Plugins_Updates::WPML_ST_FASTER_SETTINGS_NOTICE_ID ); } } wpml-st-translations-file-scan.php 0000644 00000002404 14721552044 0013242 0 ustar 00 <?php class WPML_ST_Translations_File_Scan { /** * @var WPML_ST_Translations_File_Scan_Db_Charset_Filter_Factory */ private $charset_filter_factory; /** * @param WPML_ST_Translations_File_Scan_Db_Charset_Filter_Factory $charset_filter_factory */ public function __construct( WPML_ST_Translations_File_Scan_Db_Charset_Filter_Factory $charset_filter_factory ) { $this->charset_filter_factory = $charset_filter_factory; } /** * @param string $file * * @return WPML_ST_Translations_File_Translation[] */ public function load_translations( $file ) { if ( ! file_exists( $file ) ) { return array(); } $translations = array(); $file_type = pathinfo( $file, PATHINFO_EXTENSION ); switch ( $file_type ) { case 'mo': $translations_file = new WPML_ST_Translations_File_MO( $file ); $translations = $translations_file->get_translations(); break; case 'json': $translations_file = new WPML_ST_Translations_File_JED( $file ); $translations = $translations_file->get_translations(); break; } $unicode_characters_filter = $this->charset_filter_factory->create(); if ( $unicode_characters_filter ) { $translations = $unicode_characters_filter->filter( $translations ); } return $translations; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.3-4ubuntu2.24 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка