define_constants(); $this->load_dependencies(); $this->init_hooks(); } /** * System path definition maps. */ private function define_constants() { if (! defined('AF_TRANSLATE_FILE')) { define('AF_TRANSLATE_FILE', __FILE__); } if (! defined('AF_TRANSLATE_BASE')) { define('AF_TRANSLATE_BASE', plugin_basename(AF_TRANSLATE_FILE)); } if (! defined('AF_TRANSLATE_DIR')) { define('AF_TRANSLATE_DIR', dirname(AF_TRANSLATE_FILE)); } if (! defined('AF_TRANSLATE_PATH')) { define('AF_TRANSLATE_PATH', plugin_dir_path(__FILE__)); } if (! defined('AF_TRANSLATE_URL')) { define('AF_TRANSLATE_URL', plugin_dir_url(__FILE__)); } // Add an optional indicator lookup helper if (! defined('AF_TRANSLATE_IS_PRO')) { define('AF_TRANSLATE_IS_PRO', class_exists('AF_Translate_Pro') || defined('AF_TRANSLATE_PRO_FILE')); } } /** * High-performance memory-optimized asset loading schema. */ private function load_dependencies() { // Shared global multi-dimensional localization data configurations require_once AF_TRANSLATE_PATH . 'includes/class-i18n-data.php'; require_once AF_TRANSLATE_PATH . 'includes/class-af-translate.php'; // Critical Performance Safeguard: Execute heavy analysis suites only on back-end requests if (is_admin()) { require_once AF_TRANSLATE_PATH . 'includes/class-bundle-analyzer.php'; require_once AF_TRANSLATE_PATH . 'includes/class-translate-scanner.php'; require_once AF_TRANSLATE_PATH . 'includes/class-project-config.php'; require_once AF_TRANSLATE_PATH . 'includes/class-project-ajax.php'; require_once AF_TRANSLATE_PATH . 'includes/class-editor-view.php'; require_once AF_TRANSLATE_PATH . 'includes/class-file-pot-generator.php'; require_once AF_TRANSLATE_PATH . 'includes/class-file-compiler.php'; require_once AF_TRANSLATE_PATH . 'includes/class-file-stream.php'; require_once AF_TRANSLATE_PATH . 'includes/class-file-ajax.php'; require_once AF_TRANSLATE_PATH . 'includes/class-editor-path-validator.php'; require_once AF_TRANSLATE_PATH . 'includes/class-editor-po-processor.php'; require_once AF_TRANSLATE_PATH . 'includes/class-editor-ajax-handler.php'; require_once AF_TRANSLATE_PATH . 'includes/class-translate-ai-engine.php'; require_once AF_TRANSLATE_PATH . 'includes/class-translate-ai-ajax.php'; //require_once AF_TRANSLATE_PATH . 'includes/class-translate-ai-bridge.php'; } } /** * Standard runtime execution initialization hooks. */ private function init_hooks() { add_action('plugins_loaded', array($this, 'boot_core_engine')); /** * CRITICAL GLOBAL HOOK: Intercepts and redirects MO file loading metrics. * Must run globally (outside of is_admin) so frontend visitors see custom strings. */ add_filter('load_textdomain_mofile', array($this, 'af_translate_load_from_uploads'), 1, 2); add_filter('plugin_row_meta', [$this, 'plugin_row_meta'], 10, 2); add_filter('plugin_action_links_' . AF_TRANSLATE_BASE, [$this, 'plugin_action_links']); } public function plugin_action_links($links) { $settings_link = sprintf('%2$s', admin_url('admin.php?page=af-translate'), esc_html__('Get Started', 'af-translate')); array_unshift($links, $settings_link); $links['af-translate-ai-connecter'] = sprintf('%2$s', admin_url('admin.php?page=af-translate-ai-connecter'), esc_html__('AI Settings', 'af-translate')); return $links; } public function plugin_row_meta($plugin_meta, $plugin_file) { if (AF_TRANSLATE_BASE === $plugin_file) { $row_meta = [ 'af-translate-plugins' => sprintf('%2$s', admin_url('admin.php?page=af-translate-plugins'), esc_html__('Translate Plugins', 'af-translate')), 'af-translate-themes' => sprintf('%2$s', admin_url('admin.php?page=af-translate-themes'), esc_html__('Translate Themes', 'af-translate')), ]; $plugin_meta = array_merge($plugin_meta, $row_meta); } return $plugin_meta; } public function af_translate_load_from_uploads($mofile, $domain) { // error_log("WATCHDOG: WordPress is attempting to load translations for domain: [$domain] | File: [$mofile]"); // if ($domain === 'shopical-pro') { // error_log("AF Translate FOUND IT: Domain [$domain] requested file: [$mofile]"); // } // return $mofile; // 1. Skip core translation if ('default' === $domain) { return $mofile; } $filename = basename($mofile); // 2. Robust Regex: matches either "domain-locale.mo" or "locale.mo" // This safely extracts the locale even if the domain prefix is missing. $pattern = '/^(?:' . preg_quote($domain, '/') . '-)?(.+)\.mo$/'; if (!preg_match($pattern, $filename, $matches)) { return $mofile; // Exit if filename format is unexpected } $locale = $matches[1]; $upload_dir = wp_upload_dir(); $base_path = $upload_dir['basedir'] . '/af-translate/'; // 3. Construct the exact filename we are looking for // This ensures we always look for "domain-locale.mo" $target_filename = $domain . '-' . $locale . '.mo'; $directories = [ $base_path . 'themes/', $base_path . 'plugins/', $base_path . 'core/' ]; foreach ($directories as $dir) { // ADD THIS LOG: // error_log("AF Translate DEBUG: Searching for [$target_filename] in [$dir]"); $found = $this->find_file_case_insensitive($dir, $target_filename); if ($found) { // DEBUG: See if we are actually swapping the file // error_log("AF Translate SUCCESS: Swapping $mofile with $found"); return $found; } } return $mofile; } /** * Case-insensitive file search helper */ private function find_file_case_insensitive($directory, $filename) { if (!is_dir($directory)) return false; // Scan directory and compare names using case-insensitive comparison $files = scandir($directory); foreach ($files as $file) { if (strcasecmp($file, $filename) === 0) { return $directory . $file; } } return false; } /** * Instantiates the foundational translation controller framework safely. */ public function boot_core_engine() { // 1. Boot the core foundational translation framework if (class_exists('AF_Translate_Core')) { new AF_Translate_Core(); } // 2. Ignite the streaming download hooks for admin-post.php if (class_exists('AF_Translate_File_Streaming')) { AF_Translate_File_Streaming::init_hooks(); } // 3. Editor Workbench AJAX Actions if (class_exists('AF_Translate_Editor_AJAX_Handler')) { add_action('wp_ajax_af_translate_save_pot', array('AF_Translate_Editor_AJAX_Handler', 'handle_save')); } // 4. Extended Utilities AJAX Actions if (class_exists('AF_Translate_Ajax_Extended')) { add_action('wp_ajax_af_translate_init_locale', array('AF_Translate_Ajax_Extended', 'ajax_init_po_handler')); add_action('wp_ajax_af_translate_import_po', array('AF_Translate_Ajax_Extended', 'ajax_import_po_handler')); } /** * POLYMORPHIC ROUTER: Intercepts the shared action hook collision * and safely directs traffic to the correct engine component. */ add_action('wp_ajax_af_translate_sync_po', array($this, 'route_sync_po_requests')); /** * Freemius. */ if (!class_exists('AF_Translate_Pro')) { require_once(AF_TRANSLATE_DIR . '/freemius.php'); } } /** * Polymorphic AJAX Router to handle shared action hook collisions safely. * Evaluates parameters to differentiate between the editor screen and portability screen. */ public function route_sync_po_requests() { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Operational routing controller check; verification is safely deferred to downstream workbench sync execution context handlers. if (isset($_POST['po_file_target']) && class_exists('AF_Translate_Editor_AJAX_Handler')) { AF_Translate_Editor_AJAX_Handler::handle_sync(); exit; } // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Operational routing controller check; verification is safely deferred to downstream module dashboard sync handlers. if (isset($_POST['component']) && class_exists('AF_Translate_Ajax_Extended')) { AF_Translate_Ajax_Extended::ajax_sync_po_handler(); exit; } wp_send_json_error(esc_html__('Invalid transaction routing parameter signature.', 'af-translate')); } } /** * Accessor function shortcut to instantiate the architectural controller context. * * @return AF_Translate */ function af_translate_engine() { return AF_Translate::instance(); } // Ignite operational plugin setup af_translate_engine();