base -> language code $fallback_locales = array($locale); // If locale has underscores, extract base locale (e.g., nl_NL_formal -> nl_NL) if (strpos($locale, '_') !== false) { $parts = explode('_', $locale); if (count($parts) >= 2) { $base_locale = $parts[0] . '_' . $parts[1]; if (!in_array($base_locale, $fallback_locales, true)) { $fallback_locales[] = $base_locale; } } // Also try language code only (e.g., nl_NL -> nl) if (count($parts) >= 1) { $lang_only = $parts[0]; if (!in_array($lang_only, $fallback_locales, true)) { $fallback_locales[] = $lang_only; } } } // Try each locale in fallback chain foreach ($fallback_locales as $try_locale) { $mofile = $lang_dir . 'ai-translate-' . $try_locale . '.mo'; if (file_exists($mofile)) { // Unload existing textdomain first if reloading if ($force_user_locale && is_textdomain_loaded('ai-translate')) { unload_textdomain('ai-translate'); } load_textdomain('ai-translate', $mofile); if (is_textdomain_loaded('ai-translate')) { return; } } } // Final fallback to standard load_plugin_textdomain. Plugin ships its own .mo files in // /languages/, so we cannot rely solely on WordPress 4.6+ automatic translation loading // (which only picks up /wp-content/languages/plugins/ai-translate-*.mo files). // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- needed for bundled translations load_plugin_textdomain( 'ai-translate', false, dirname(plugin_basename(__FILE__)) . '/languages/' ); } // Load textdomain for frontend with site locale add_action('plugins_loaded', function() { ai_translate_load_textdomain(); // Load with site locale for frontend }, 1); // For admin pages, load textdomain with user locale (this overrides the frontend load) add_action('admin_init', function() { if (is_user_logged_in()) { $user_locale = get_user_locale(); $site_locale = get_locale(); // Always load user locale for admin, even if same as site locale ai_translate_load_textdomain(true); // Force load with user locale } }, 1); // High priority to override any other loads // Include core/admin and runtime classes. define('AI_TRANSLATE_PLUGIN_FILE', __FILE__); require_once __DIR__ . '/includes/class-ai-translate-core.php'; require_once __DIR__ . '/includes/helpers.php'; require_once __DIR__ . '/includes/request-path.php'; require_once __DIR__ . '/includes/routing-query.php'; require_once __DIR__ . '/includes/reasoning-helpers.php'; require_once __DIR__ . '/includes/api-keys.php'; require_once __DIR__ . '/includes/language-redirect.php'; require_once __DIR__ . '/includes/admin-page.php'; require_once __DIR__ . '/includes/class-ai-lang.php'; require_once __DIR__ . '/includes/class-ai-cache.php'; require_once __DIR__ . '/includes/class-ai-cache-meta.php'; require_once __DIR__ . '/includes/class-ai-dom.php'; require_once __DIR__ . '/includes/class-ai-segment-store.php'; require_once __DIR__ . '/includes/class-ai-batch.php'; require_once __DIR__ . '/includes/class-ai-seo.php'; require_once __DIR__ . '/includes/class-ai-url.php'; require_once __DIR__ . '/includes/class-ai-ob.php'; require_once __DIR__ . '/includes/class-ai-slugs.php'; require_once __DIR__ . '/includes/class-ai-prewarm.php'; require_once __DIR__ . '/includes/class-ai-rest-strings.php'; require_once __DIR__ . '/includes/class-ai-settings-sanitizer.php'; \AITranslate\AI_Prewarm::init(); require_once __DIR__ . '/includes/class-ai-404-recovery.php'; require_once __DIR__ . '/includes/class-ai-sitemap.php'; // Initialize sitemap integration \AITranslate\AI_Sitemap::init(); require_once __DIR__ . '/includes/attr-transients.php'; require_once __DIR__ . '/includes/rewrite-rules.php'; /** * Add a 5-star rating link to the plugin row on the Plugins screen. * * This renders a golden 5-star link that points to the plugin's WordPress.org page, * similar to popular plugins. Only affects the AI Translate row. * * @param string[] $links Existing meta links for the row. * @param string $file Plugin basename for the current row. * @return string[] */ add_filter('plugin_row_meta', function (array $links, $file) { if ($file !== plugin_basename(__FILE__)) { return $links; } $url = 'https://wordpress.org/plugins/ai-translate/'; $label = __('Rate on WordPress.org', 'ai-translate'); $stars = '★★★★★'; $links[] = sprintf( '%3$s', esc_url($url), esc_attr($label), esc_html($stars) ); return $links; }, 10, 2); /** * Plugin activation: flush rewrite rules and create database tables. */ register_activation_hook(__FILE__, function () { // Ensure rules are registered before flushing ai_translate_register_rewrite_rules(); // Automatically set permalinks to 'post-name' if they're currently 'plain' // since the plugin requires rewrite rules to function $permalink_structure = get_option('permalink_structure'); if ($permalink_structure === '' || $permalink_structure === null) { // Set to 'post-name' structure which is /%postname%/ update_option('permalink_structure', '/%postname%/'); } flush_rewrite_rules(); // Create cache metadata table \AITranslate\AI_Cache_Meta::create_table(); // Create the segment store and schedule its daily cleanup \AITranslate\AI_Segment_Store::create_table(); \AITranslate\AI_Segment_Store::schedule_purge(); }); register_deactivation_hook(__FILE__, function () { \AITranslate\AI_Segment_Store::unschedule_purge(); }); // Daily removal of segments older than the cache duration; also schedules itself for existing installs. add_action(\AITranslate\AI_Segment_Store::purge_hook(), ['\\AITranslate\\AI_Segment_Store', 'run_purge']); add_action('init', ['\\AITranslate\\AI_Segment_Store', 'schedule_purge']); // Background measurement of thinking models (queued after a successful API validation). add_action(\AITranslate\AI_Translate_Core::PROBE_HOOK, ['\\AITranslate\\AI_Translate_Core', 'run_scheduled_probe'], 10, 2); require_once __DIR__ . '/includes/request-filters.php'; require_once __DIR__ . '/includes/frontend-output.php'; require_once __DIR__ . '/includes/catalog-strings.php'; /** * REST endpoint for dynamic UI attribute translation. */ add_action('rest_api_init', ['\\AITranslate\\AI_REST_Strings', 'register']); require_once __DIR__ . '/includes/request-routing.php'; require_once __DIR__ . '/includes/permalinks.php'; require_once __DIR__ . '/includes/cache-invalidation.php'; /** * One-time warmup: generate translated slugs for existing top-level pages so * language-prefixed URLs immediately resolve (prevents blank pages before first visit). * Mirrors robustness in the original implementation by pre-seeding the slug map. */ // Runs in WP-Cron, a batch at a time (see AI_Slugs::run_warmup); init only queues it. add_action(\AITranslate\AI_Slugs::WARMUP_HOOK, ['\\AITranslate\\AI_Slugs', 'run_warmup'], 10, 1); add_action('init', ['\\AITranslate\\AI_Slugs', 'schedule_warmup'], 99); require_once __DIR__ . '/includes/fallback-routing.php'; /** * Add Settings quick link on the Plugins page. */ add_filter('plugin_action_links_' . plugin_basename(__FILE__), function ($links) { $url = admin_url('admin.php?page=ai-translate'); $settings_link = '' . esc_html__('Instellingen', 'ai-translate') . ''; array_unshift($links, $settings_link); return $links; }); require_once __DIR__ . '/includes/query-filters.php'; require_once __DIR__ . '/includes/language-switcher.php'; require_once __DIR__ . '/includes/nav-menus.php';