文章目录
-
- 在当今互联网全球化时代,网站访问者来自世界各地,使用不同的语言。根据统计,超过75%的互联网用户更倾向于使用母语浏览网站内容,而超过50%的用户表示,如果网站没有他们熟悉的语言版本,他们会立即离开。对于WordPress网站所有者来说,提供多语言支持不再是奢侈选项,而是提升用户体验、扩大受众范围、增加转化率的必要手段。 传统的多语言解决方案如WPML、Polylang等插件虽然功能强大,但往往价格昂贵、系统臃肿,且不一定完全符合每个网站的特定需求。通过WordPress代码二次开发,我们可以创建轻量级、高度定制化的多语言翻译工具,同时整合其他实用的小工具功能,打造一个既高效又符合网站特色的多语言解决方案。 本文将手把手指导您如何通过WordPress代码二次开发,为网站添加多语言翻译功能,并在此过程中实现一些常用的互联网小工具,让您的网站在国际化的同时,功能也更加丰富完善。
-
- 在开始编码之前,我们需要确定多语言实现的基本策略。主要有以下几种方案: 子目录结构:如example.com/en/、example.com/es/ 子域名结构:如en.example.com、es.example.com 不同顶级域名:如example.com、example.es 参数结构:如example.com?lang=en 对于大多数中小型网站,子目录结构是最简单且SEO友好的选择。我们将采用这种方案,通过WordPress的重写规则来实现。
- 我们的多语言翻译工具需要具备以下核心功能: 语言切换器(前端显示) 内容翻译管理后台 自动检测用户浏览器语言 SEO优化(hreflang标签等) 翻译字符串管理 语言特定的URL重写 同时,我们将整合以下常用小工具: 社交分享按钮 阅读进度指示器 回到顶部按钮 夜间模式切换
- 我们将创建一个自定义插件来实现所有功能,这样即使更换主题,功能也能保持完整。插件结构如下: multilingual-tools/ ├── multilingual-tools.php # 主插件文件 ├── includes/ │ ├── class-language-switcher.php # 语言切换器 │ ├── class-translation-manager.php # 翻译管理器 │ ├── class-url-rewriter.php # URL重写器 │ └── class-utilities.php # 实用小工具 ├── admin/ │ ├── css/ │ ├── js/ │ └── admin-pages.php # 管理页面 ├── public/ │ ├── css/ │ ├── js/ │ └── frontend-display.php # 前端显示 └── languages/ # 语言文件
-
- 首先,在wp-content/plugins/目录下创建multilingual-tools文件夹,然后创建主插件文件: <?php /** * Plugin Name: 多语言翻译工具 * Plugin URI: https://yourwebsite.com/ * Description: 为WordPress网站添加多语言支持和实用小工具 * Version: 1.0.0 * Author: 您的名称 * License: GPL v2 or later * Text Domain: multilingual-tools * Domain Path: /languages */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('MLT_VERSION', '1.0.0'); define('MLT_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('MLT_PLUGIN_URL', plugin_dir_url(__FILE__)); // 自动加载类文件 spl_autoload_register(function ($class_name) { $prefix = 'MLT_'; $base_dir = MLT_PLUGIN_DIR . 'includes/'; $len = strlen($prefix); if (strncmp($prefix, $class_name, $len) !== 0) { return; } $relative_class = substr($class_name, $len); $file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php'; if (file_exists($file)) { require $file; } }); // 初始化插件 function mlt_init() { // 检查必要条件 if (!function_exists('register_rest_route')) { add_action('admin_notices', function() { echo '<div class="notice notice-error"><p>多语言工具需要WordPress 4.7或更高版本。</p></div>'; }); return; } // 加载文本域 load_plugin_textdomain('multilingual-tools', false, dirname(plugin_basename(__FILE__)) . '/languages'); // 初始化各个组件 if (is_admin()) { new MLT_Admin_Pages(); } else { new MLT_Frontend_Display(); } new MLT_Language_Switcher(); new MLT_Translation_Manager(); new MLT_URL_Rewriter(); new MLT_Utilities(); } add_action('plugins_loaded', 'mlt_init'); // 激活/停用钩子 register_activation_hook(__FILE__, 'mlt_activate'); register_deactivation_hook(__FILE__, 'mlt_deactivate'); function mlt_activate() { // 创建必要的数据库表 global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_name = $wpdb->prefix . 'mlt_translations'; $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, original_text text NOT NULL, translated_text text NOT NULL, language_code varchar(10) NOT NULL, context varchar(100) DEFAULT '', type varchar(50) DEFAULT 'string', post_id bigint(20) DEFAULT 0, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY language_code (language_code), KEY type_post_id (type, post_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); // 添加默认选项 add_option('mlt_settings', array( 'enabled_languages' => array('en', 'zh'), 'default_language' => 'en', 'auto_detect' => true, 'show_flags' => true, 'hreflang' => true, 'utilities' => array( 'social_share' => true, 'reading_progress' => true, 'back_to_top' => true, 'dark_mode' => false ) )); // 刷新重写规则 flush_rewrite_rules(); } function mlt_deactivate() { // 清理临时数据 flush_rewrite_rules(); }
- 在includes目录下创建class-language-switcher.php: <?php class MLT_Language_Switcher { private $settings; private $current_language; private $available_languages; public function __construct() { $this->settings = get_option('mlt_settings', array()); $this->available_languages = $this->settings['enabled_languages'] ?? array('en'); $this->current_language = $this->get_current_language(); $this->init_hooks(); } private function init_hooks() { // 添加语言切换器到菜单 add_filter('wp_nav_menu_items', array($this, 'add_language_switcher_to_menu'), 10, 2); // 短代码支持 add_shortcode('language_switcher', array($this, 'language_switcher_shortcode')); // 小工具支持 add_action('widgets_init', array($this, 'register_widget')); // AJAX语言切换 add_action('wp_ajax_mlt_switch_language', array($this, 'ajax_switch_language')); add_action('wp_ajax_nopriv_mlt_switch_language', array($this, 'ajax_switch_language')); } public function get_current_language() { // 从URL参数获取 if (isset($_GET['lang']) && in_array($_GET['lang'], $this->available_languages)) { setcookie('mlt_language', $_GET['lang'], time() + YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN); return $_GET['lang']; } // 从Cookie获取 if (isset($_COOKIE['mlt_language']) && in_array($_COOKIE['mlt_language'], $this->available_languages)) { return $_COOKIE['mlt_language']; } // 自动检测浏览器语言 if ($this->settings['auto_detect'] ?? true) { $browser_lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); if (in_array($browser_lang, $this->available_languages)) { return $browser_lang; } } // 返回默认语言 return $this->settings['default_language'] ?? 'en'; } public function add_language_switcher_to_menu($items, $args) { if ($args->theme_location == 'primary' || apply_filters('mlt_show_in_menu', false)) { $switcher = $this->render_switcher(); $items .= '<li class="menu-item menu-item-language-switcher">' . $switcher . '</li>'; } return $items; } public function language_switcher_shortcode($atts) { $atts = shortcode_atts(array( 'type' => 'dropdown', 'show_flags' => true, 'show_names' => true ), $atts, 'language_switcher'); return $this->render_switcher($atts['type'], $atts['show_flags'], $atts['show_names']); } private function render_switcher($type = 'dropdown', $show_flags = true, $show_names = true) { $languages = $this->get_language_data(); $current_lang = $this->current_language; ob_start(); if ($type === 'dropdown') { ?> <div class="mlt-language-switcher mlt-dropdown"> <button class="mlt-switcher-toggle"> <?php if ($show_flags): ?> <span class="mlt-flag mlt-flag-<?php echo esc_attr($current_lang); ?>"></span> <?php endif; ?> <?php if ($show_names): ?> <span class="mlt-language-name"><?php echo esc_html($languages[$current_lang]['name']); ?></span> <?php endif; ?> <span class="mlt-arrow">▼</span> </button> <ul class="mlt-dropdown-menu"> <?php foreach ($languages as $code => $language): ?> <?php if ($code !== $current_lang): ?> <li> <a href="<?php echo esc_url($this->get_language_url($code)); ?>" class="mlt-language-link" data-lang="<?php echo esc_attr($code); ?>"> <?php if ($show_flags): ?> <span class="mlt-flag mlt-flag-<?php echo esc_attr($code); ?>"></span> <?php endif; ?> <?php if ($show_names): ?> <span class="mlt-language-name"><?php echo esc_html($language['name']); ?></span> <?php endif; ?> </a> </li> <?php endif; ?> <?php endforeach; ?> </ul> </div> <?php } else { ?> <div class="mlt-language-switcher mlt-list"> <?php foreach ($languages as $code => $language): ?> <a href="<?php echo esc_url($this->get_language_url($code)); ?>" class="mlt-language-link <?php echo $code === $current_lang ? 'mlt-current' : ''; ?>" data-lang="<?php echo esc_attr($code); ?>"> <?php if ($show_flags): ?> <span class="mlt-flag mlt-flag-<?php echo esc_attr($code); ?>"></span> <?php endif; ?> <?php if ($show_names): ?> <span class="mlt-language-name"><?php echo esc_html($language['name']); ?></span> <?php endif; ?> </a> <?php endforeach; ?> </div> <?php } return ob_get_clean(); } private function get_language_data() { $languages = array( 'en' => array('name' => 'English', 'native_name' => 'English', 'flag' => 'us'), 'zh' => array('name' => '中文', 'native_name' => '简体中文', 'flag' => 'cn'), 'es' => array('name' => 'Español', 'native_name' => 'Español', 'flag' => 'es'), 'fr' => array('name' => 'Français', 'native_name' => 'Français', 'flag' => 'fr'), 'de' => array('name' => 'Deutsch', 'native_name' => 'Deutsch', 'flag' => 'de'), 'ja' => array('name' => '日本語', 'native_name' => '日本語', 'flag' => 'jp'), 'ko' => array('name' => '한국어', 'native_name' => '한국어', 'flag' => 'kr'), 'ru' => array('name' => 'Русский', 'native_name' => 'Русский', 'flag' => 'ru') ); // 只返回启用的语言 $enabled_languages = $this->available_languages; return array_intersect_key($languages, array_flip($enabled_languages)); } private function get_language_url($language_code) { global $wp; $current_url = home_url($wp->request); // 如果是默认语言,移除语言参数 if ($language_code === ($this->settings['default_language'] ?? 'en')) { return remove_query_arg('lang', $current_url); } // 添加语言参数 return add_query_arg('lang', $language_code, $current_url); } public function ajax_switch_language() { if (!isset($_POST['language']) || !in_array($_POST['language'], $this->available_languages)) { wp_die('Invalid language'); } $language = sanitize_text_field($_POST['language']); setcookie('mlt_language', $language, time() + YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN); wp_send_json_success(array( 'redirect' => $this->get_language_url($language) )); } public function register_widget() { register_widget('MLT_Language_Switcher_Widget'); } } // 语言切换器小工具 class MLT_Language_Switcher_Widget extends WP_Widget { public function __construct() { parent::__construct( 'mlt_language_switcher', __('Language Switcher', 'multilingual-tools'), array('description' => __('Display a language switcher', 'multilingual-tools')) ); } public function widget($args, $instance) { echo $args['before_widget']; if (!empty($instance['title'])) { echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title']; } $switcher = new MLT_Language_Switcher(); echo $switcher->language_switcher_shortcode(array( 'type' => $instance['type'] ?? 'list', 'show_flags' => !empty($instance['show_flags']), 'show_names' => !empty($instance['show_names']) )); echo $args['after_widget']; } public function form($instance) { $title = $instance['title'] ?? __('Languages', 'multilingual-tools'); $type = $instance['type'] ?? 'list'; $show_flags = isset($instance['show_flags']) ? (bool) $instance['show_flags'] : true; $show_names = isset($instance['show_names']) ? (bool) $instance['show_names'] : true; ?> <p> <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>"> </p> <p> <label for="<?php echo $this->get_field_id('type'); ?>"><?php _e('Display type:'); ?></label> <select class="widefat" id="<?php echo $this->get_field_id('type'); ?>" name="<?php echo $this->get_field_name('type'); ?>">
- 在includes目录下创建class-translation-manager.php: <?php class MLT_Translation_Manager { private $table_name; private $current_language; public function __construct() { global $wpdb; $this->table_name = $wpdb->prefix . 'mlt_translations'; $this->current_language = $this->get_current_language(); $this->init_hooks(); } private function init_hooks() { // 翻译字符串 add_filter('gettext', array($this, 'translate_text'), 10, 3); add_filter('ngettext', array($this, 'translate_plural'), 10, 5); // 翻译文章内容 add_filter('the_content', array($this, 'translate_content'), 10); add_filter('the_title', array($this, 'translate_title'), 10, 2); add_filter('the_excerpt', array($this, 'translate_excerpt'), 10); // REST API端点 add_action('rest_api_init', array($this, 'register_rest_routes')); // 自动翻译(使用外部API) add_action('save_post', array($this, 'auto_translate_post'), 10, 3); // 翻译管理界面 if (is_admin()) { add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts')); } } public function get_current_language() { $settings = get_option('mlt_settings', array()); $default_lang = $settings['default_language'] ?? 'en'; if (isset($_GET['lang']) && $this->is_language_enabled($_GET['lang'])) { return sanitize_text_field($_GET['lang']); } if (isset($_COOKIE['mlt_language']) && $this->is_language_enabled($_COOKIE['mlt_language'])) { return sanitize_text_field($_COOKIE['mlt_language']); } return $default_lang; } private function is_language_enabled($lang_code) { $settings = get_option('mlt_settings', array()); $enabled_languages = $settings['enabled_languages'] ?? array('en'); return in_array($lang_code, $enabled_languages); } public function translate_text($translated, $text, $domain) { // 如果是默认语言,直接返回 if ($this->current_language === ($this->get_default_language())) { return $translated; } // 检查是否有缓存 $cache_key = 'mlt_translation_' . md5($text . $domain . $this->current_language); $cached = wp_cache_get($cache_key, 'multilingual-tools'); if ($cached !== false) { return $cached; } // 从数据库获取翻译 global $wpdb; $translation = $wpdb->get_var($wpdb->prepare( "SELECT translated_text FROM {$this->table_name} WHERE original_text = %s AND language_code = %s AND context = %s AND type = 'string' LIMIT 1", $text, $this->current_language, $domain )); if ($translation) { wp_cache_set($cache_key, $translation, 'multilingual-tools', HOUR_IN_SECONDS); return $translation; } // 如果没有找到翻译,可以尝试自动翻译 if (apply_filters('mlt_auto_translate_strings', false)) { $auto_translation = $this->auto_translate_string($text, $this->current_language); if ($auto_translation) { $this->save_translation($text, $auto_translation, $this->current_language, $domain, 'string'); wp_cache_set($cache_key, $auto_translation, 'multilingual-tools', HOUR_IN_SECONDS); return $auto_translation; } } return $translated; } public function translate_plural($translated, $single, $plural, $number, $domain) { if ($this->current_language === ($this->get_default_language())) { return $translated; } $text = ($number == 1) ? $single : $plural; return $this->translate_text($text, $text, $domain); } public function translate_content($content) { global $post; if (!$post || $this->current_language === ($this->get_default_language())) { return $content; } // 获取文章翻译 $translated_content = $this->get_post_translation($post->ID, 'post_content', $this->current_language); if ($translated_content) { return $translated_content; } // 自动翻译内容 if (apply_filters('mlt_auto_translate_content', true)) { $auto_translation = $this->auto_translate_text($content, $this->current_language); if ($auto_translation) { $this->save_post_translation($post->ID, 'post_content', $auto_translation, $this->current_language); return $auto_translation; } } return $content; } public function translate_title($title, $post_id = null) { if (!$post_id || $this->current_language === ($this->get_default_language())) { return $title; } $translated_title = $this->get_post_translation($post_id, 'post_title', $this->current_language); if ($translated_title) { return $translated_title; } if (apply_filters('mlt_auto_translate_titles', true)) { $auto_translation = $this->auto_translate_text($title, $this->current_language); if ($auto_translation) { $this->save_post_translation($post_id, 'post_title', $auto_translation, $this->current_language); return $auto_translation; } } return $title; } public function translate_excerpt($excerpt) { global $post; if (!$post || $this->current_language === ($this->get_default_language())) { return $excerpt; } $translated_excerpt = $this->get_post_translation($post->ID, 'post_excerpt', $this->current_language); if ($translated_excerpt) { return $translated_excerpt; } if (apply_filters('mlt_auto_translate_excerpts', true)) { $auto_translation = $this->auto_translate_text($excerpt, $this->current_language); if ($auto_translation) { $this->save_post_translation($post->ID, 'post_excerpt', $auto_translation, $this->current_language); return $auto_translation; } } return $excerpt; } private function get_post_translation($post_id, $field, $language) { global $wpdb; $translation = $wpdb->get_var($wpdb->prepare( "SELECT translated_text FROM {$this->table_name} WHERE post_id = %d AND language_code = %s AND type = %s LIMIT 1", $post_id, $language, $field )); return $translation; } private function save_post_translation($post_id, $field, $translation, $language) { global $wpdb; // 检查是否已存在 $existing = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$this->table_name} WHERE post_id = %d AND language_code = %s AND type = %s LIMIT 1", $post_id, $language, $field )); if ($existing) { // 更新现有记录 $wpdb->update( $this->table_name, array( 'translated_text' => $translation, 'updated_at' => current_time('mysql') ), array( 'post_id' => $post_id, 'language_code' => $language, 'type' => $field ) ); } else { // 插入新记录 $wpdb->insert( $this->table_name, array( 'original_text' => '', 'translated_text' => $translation, 'language_code' => $language, 'type' => $field, 'post_id' => $post_id, 'created_at' => current_time('mysql'), 'updated_at' => current_time('mysql') ) ); } // 清除缓存 wp_cache_delete('mlt_post_translation_' . $post_id . '_' . $field . '_' . $language, 'multilingual-tools'); } private function save_translation($original, $translated, $language, $context = '', $type = 'string') { global $wpdb; $existing = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$this->table_name} WHERE original_text = %s AND language_code = %s AND context = %s AND type = %s LIMIT 1", $original, $language, $context, $type )); if ($existing) { $wpdb->update( $this->table_name, array( 'translated_text' => $translated, 'updated_at' => current_time('mysql') ), array('id' => $existing) ); } else { $wpdb->insert( $this->table_name, array( 'original_text' => $original, 'translated_text' => $translated, 'language_code' => $language, 'context' => $context, 'type' => $type, 'created_at' => current_time('mysql'), 'updated_at' => current_time('mysql') ) ); } } private function auto_translate_string($text, $target_lang) { // 使用免费的翻译API,如Google Translate(需要API密钥) // 这里使用模拟数据,实际使用时需要替换为真实的API调用 $api_key = get_option('mlt_translation_api_key', ''); if (empty($api_key) || strlen($text) > 5000) { return false; } // 模拟翻译 - 实际应调用API $translations = array( 'en' => array( 'hello' => 'hello', 'welcome' => 'welcome' ), 'zh' => array( 'hello' => '你好', 'welcome' => '欢迎' ), 'es' => array( 'hello' => 'hola', 'welcome' => 'bienvenido' ) ); $text_lower = strtolower(trim($text)); if (isset($translations[$target_lang][$text_lower])) { return $translations[$target_lang][$text_lower]; } // 实际API调用示例(使用Google Translate) /* $url = "https://translation.googleapis.com/language/translate/v2"; $response = wp_remote_post($url, array( 'body' => array( 'q' => $text, 'target' => $target_lang, 'key' => $api_key ) )); if (!is_wp_error($response)) { $body = json_decode(wp_remote_retrieve_body($response), true); if (isset($body['data']['translations'][0]['translatedText'])) { return $body['data']['translations'][0]['translatedText']; } } */ return false; } private function auto_translate_text($text, $target_lang) { // 对于长文本,可以分段翻译 $max_length = 5000; if (strlen($text) <= $max_length) { return $this->auto_translate_string($text, $target_lang); } // 分段处理 $paragraphs = explode("n", $text); $translated_paragraphs = array(); foreach ($paragraphs as $paragraph) { if (strlen($paragraph) > $max_length) { // 如果段落仍然太长,进一步分割 $sentences = preg_split('/(?<=[.?!])s+/', $paragraph); $translated_sentences = array(); foreach ($sentences as $sentence) { $translated = $this->auto_translate_string($sentence, $target_lang); $translated_sentences[] = $translated ?: $sentence; } $translated_paragraphs[] = implode(' ', $translated_sentences); } else { $translated = $this->auto_translate_string($paragraph, $target_lang); $translated_paragraphs[] = $translated ?: $paragraph; } } return implode("n", $translated_paragraphs); } public function auto_translate_post($post_id, $post, $update) { // 只在发布时自动翻译 if ($post->post_status !== 'publish' || wp_is_post_revision($post_id)) { return; } // 检查是否已经翻译过 $already_translated = get_post_meta($post_id, '_mlt_auto_translated', true); if ($already_translated) { return; } $settings = get_option('mlt_settings', array()); $enabled_languages = $settings['enabled_languages'] ?? array('en'); $default_language = $settings['default_language'] ?? 'en'; foreach ($enabled_languages as $lang) { if ($lang === $default_language) { continue; } // 翻译标题 $translated_title = $this->auto_translate_text($post->post_title, $lang); if ($translated_title) { $this->save_post_translation($post_id, 'post_title', $translated_title, $lang); } // 翻译内容 $translated_content = $this->auto_translate_text($post->post_content, $lang); if ($translated_content) { $this->save_post_translation($post_id, 'post_content', $translated_content, $lang); } // 翻译摘要 if (!empty($post->post_excerpt)) { $translated_excerpt = $this->auto_translate_text($post->post_excerpt, $lang); if ($translated_excerpt) { $this->save_post_translation($post_id, 'post_excerpt', $translated_excerpt, $lang); } } } update_post_meta($post_id, '_mlt_auto_translated', true); } public function register_rest_routes() { register_rest_route('mlt/v1', '/translations', array( 'methods' => 'GET', 'callback' => array($this, 'get_translations_api'), 'permission_callback' => function() { return current_user_can('manage_options'); } )); register_rest_route('mlt/v1', '/translations', array( 'methods' => 'POST', 'callback' => array($this, 'save_translation_api'), 'permission_callback' => function() { return current_user_can('manage_options'); } )); register_rest_route('mlt/v1', '/translate', array( 'methods' => 'POST', 'callback' => array($this, 'translate_text_api'), 'permission_callback' => function() { return current_user_can('edit_posts'); } )); } public function add_admin_menu() { add_menu_page( __('Translations', 'multilingual-tools'), __('Translations', 'multilingual-tools'), 'manage_options', 'mlt-translations', array($this, 'render_translations_page'), 'dashicons-translation', 30 ); add_submenu_page( 'mlt-translations', __('String Translations', 'multilingual-tools'), __('Strings', 'multilingual-tools'), 'manage_options', 'mlt-string-translations', array($this, 'render_string_translations_page') ); add_submenu_page( 'mlt-translations', __('Content Translations', 'multilingual-tools'), __('Content', 'multilingual-tools'), 'manage_options', 'mlt-content-translations', array($this, 'render_content_translations_page') ); } public function enqueue_admin_scripts($hook) { if (strpos($hook, 'mlt-') === false) { return; } wp_enqueue_style( 'mlt-admin-style', MLT_PLUGIN_URL . 'admin/css/admin.css', array(), MLT_VERSION ); wp_enqueue_script( 'mlt-admin-script', MLT_PLUGIN_URL . 'admin/js/admin.js', array('jquery', 'wp-api'), MLT_VERSION, true ); wp_localize_script('mlt-admin-script', 'mlt_admin', array( 'ajax_url' => admin_url('admin-ajax.php'),
在当今互联网全球化时代,网站访问者来自世界各地,使用不同的语言。根据统计,超过75%的互联网用户更倾向于使用母语浏览网站内容,而超过50%的用户表示,如果网站没有他们熟悉的语言版本,他们会立即离开。对于WordPress网站所有者来说,提供多语言支持不再是奢侈选项,而是提升用户体验、扩大受众范围、增加转化率的必要手段。
传统的多语言解决方案如WPML、Polylang等插件虽然功能强大,但往往价格昂贵、系统臃肿,且不一定完全符合每个网站的特定需求。通过WordPress代码二次开发,我们可以创建轻量级、高度定制化的多语言翻译工具,同时整合其他实用的小工具功能,打造一个既高效又符合网站特色的多语言解决方案。
本文将手把手指导您如何通过WordPress代码二次开发,为网站添加多语言翻译功能,并在此过程中实现一些常用的互联网小工具,让您的网站在国际化的同时,功能也更加丰富完善。
在开始编码之前,我们需要确定多语言实现的基本策略。主要有以下几种方案:
- 子目录结构:如example.com/en/、example.com/es/
- 子域名结构:如en.example.com、es.example.com
- 不同顶级域名:如example.com、example.es
- 参数结构:如example.com?lang=en
对于大多数中小型网站,子目录结构是最简单且SEO友好的选择。我们将采用这种方案,通过WordPress的重写规则来实现。
我们的多语言翻译工具需要具备以下核心功能:
- 语言切换器(前端显示)
- 内容翻译管理后台
- 自动检测用户浏览器语言
- SEO优化(hreflang标签等)
- 翻译字符串管理
- 语言特定的URL重写
同时,我们将整合以下常用小工具:
- 社交分享按钮
- 阅读进度指示器
- 回到顶部按钮
- 夜间模式切换
我们将创建一个自定义插件来实现所有功能,这样即使更换主题,功能也能保持完整。插件结构如下:
multilingual-tools/
├── multilingual-tools.php # 主插件文件
├── includes/
│ ├── class-language-switcher.php # 语言切换器
│ ├── class-translation-manager.php # 翻译管理器
│ ├── class-url-rewriter.php # URL重写器
│ └── class-utilities.php # 实用小工具
├── admin/
│ ├── css/
│ ├── js/
│ └── admin-pages.php # 管理页面
├── public/
│ ├── css/
│ ├── js/
│ └── frontend-display.php # 前端显示
└── languages/ # 语言文件
首先,在wp-content/plugins/目录下创建multilingual-tools文件夹,然后创建主插件文件:
<?php
/**
* Plugin Name: 多语言翻译工具
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress网站添加多语言支持和实用小工具
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: multilingual-tools
* Domain Path: /languages
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('MLT_VERSION', '1.0.0');
define('MLT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('MLT_PLUGIN_URL', plugin_dir_url(__FILE__));
// 自动加载类文件
spl_autoload_register(function ($class_name) {
$prefix = 'MLT_';
$base_dir = MLT_PLUGIN_DIR . 'includes/';
$len = strlen($prefix);
if (strncmp($prefix, $class_name, $len) !== 0) {
return;
}
$relative_class = substr($class_name, $len);
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
if (file_exists($file)) {
require $file;
}
});
// 初始化插件
function mlt_init() {
// 检查必要条件
if (!function_exists('register_rest_route')) {
add_action('admin_notices', function() {
echo '<div class="notice notice-error"><p>多语言工具需要WordPress 4.7或更高版本。</p></div>';
});
return;
}
// 加载文本域
load_plugin_textdomain('multilingual-tools', false, dirname(plugin_basename(__FILE__)) . '/languages');
// 初始化各个组件
if (is_admin()) {
new MLT_Admin_Pages();
} else {
new MLT_Frontend_Display();
}
new MLT_Language_Switcher();
new MLT_Translation_Manager();
new MLT_URL_Rewriter();
new MLT_Utilities();
}
add_action('plugins_loaded', 'mlt_init');
// 激活/停用钩子
register_activation_hook(__FILE__, 'mlt_activate');
register_deactivation_hook(__FILE__, 'mlt_deactivate');
function mlt_activate() {
// 创建必要的数据库表
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'mlt_translations';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
original_text text NOT NULL,
translated_text text NOT NULL,
language_code varchar(10) NOT NULL,
context varchar(100) DEFAULT '',
type varchar(50) DEFAULT 'string',
post_id bigint(20) DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY language_code (language_code),
KEY type_post_id (type, post_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 添加默认选项
add_option('mlt_settings', array(
'enabled_languages' => array('en', 'zh'),
'default_language' => 'en',
'auto_detect' => true,
'show_flags' => true,
'hreflang' => true,
'utilities' => array(
'social_share' => true,
'reading_progress' => true,
'back_to_top' => true,
'dark_mode' => false
)
));
// 刷新重写规则
flush_rewrite_rules();
}
function mlt_deactivate() {
// 清理临时数据
flush_rewrite_rules();
}
在includes目录下创建class-language-switcher.php:
<?php
class MLT_Language_Switcher {
private $settings;
private $current_language;
private $available_languages;
public function __construct() {
$this->settings = get_option('mlt_settings', array());
$this->available_languages = $this->settings['enabled_languages'] ?? array('en');
$this->current_language = $this->get_current_language();
$this->init_hooks();
}
private function init_hooks() {
// 添加语言切换器到菜单
add_filter('wp_nav_menu_items', array($this, 'add_language_switcher_to_menu'), 10, 2);
// 短代码支持
add_shortcode('language_switcher', array($this, 'language_switcher_shortcode'));
// 小工具支持
add_action('widgets_init', array($this, 'register_widget'));
// AJAX语言切换
add_action('wp_ajax_mlt_switch_language', array($this, 'ajax_switch_language'));
add_action('wp_ajax_nopriv_mlt_switch_language', array($this, 'ajax_switch_language'));
}
public function get_current_language() {
// 从URL参数获取
if (isset($_GET['lang']) && in_array($_GET['lang'], $this->available_languages)) {
setcookie('mlt_language', $_GET['lang'], time() + YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN);
return $_GET['lang'];
}
// 从Cookie获取
if (isset($_COOKIE['mlt_language']) && in_array($_COOKIE['mlt_language'], $this->available_languages)) {
return $_COOKIE['mlt_language'];
}
// 自动检测浏览器语言
if ($this->settings['auto_detect'] ?? true) {
$browser_lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
if (in_array($browser_lang, $this->available_languages)) {
return $browser_lang;
}
}
// 返回默认语言
return $this->settings['default_language'] ?? 'en';
}
public function add_language_switcher_to_menu($items, $args) {
if ($args->theme_location == 'primary' || apply_filters('mlt_show_in_menu', false)) {
$switcher = $this->render_switcher();
$items .= '<li class="menu-item menu-item-language-switcher">' . $switcher . '</li>';
}
return $items;
}
public function language_switcher_shortcode($atts) {
$atts = shortcode_atts(array(
'type' => 'dropdown',
'show_flags' => true,
'show_names' => true
), $atts, 'language_switcher');
return $this->render_switcher($atts['type'], $atts['show_flags'], $atts['show_names']);
}
private function render_switcher($type = 'dropdown', $show_flags = true, $show_names = true) {
$languages = $this->get_language_data();
$current_lang = $this->current_language;
ob_start();
if ($type === 'dropdown') {
?>
<div class="mlt-language-switcher mlt-dropdown">
<button class="mlt-switcher-toggle">
<?php if ($show_flags): ?>
<span class="mlt-flag mlt-flag-<?php echo esc_attr($current_lang); ?>"></span>
<?php endif; ?>
<?php if ($show_names): ?>
<span class="mlt-language-name"><?php echo esc_html($languages[$current_lang]['name']); ?></span>
<?php endif; ?>
<span class="mlt-arrow">▼</span>
</button>
<ul class="mlt-dropdown-menu">
<?php foreach ($languages as $code => $language): ?>
<?php if ($code !== $current_lang): ?>
<li>
<a href="<?php echo esc_url($this->get_language_url($code)); ?>"
class="mlt-language-link"
data-lang="<?php echo esc_attr($code); ?>">
<?php if ($show_flags): ?>
<span class="mlt-flag mlt-flag-<?php echo esc_attr($code); ?>"></span>
<?php endif; ?>
<?php if ($show_names): ?>
<span class="mlt-language-name"><?php echo esc_html($language['name']); ?></span>
<?php endif; ?>
</a>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
</div>
<?php
} else {
?>
<div class="mlt-language-switcher mlt-list">
<?php foreach ($languages as $code => $language): ?>
<a href="<?php echo esc_url($this->get_language_url($code)); ?>"
class="mlt-language-link <?php echo $code === $current_lang ? 'mlt-current' : ''; ?>"
data-lang="<?php echo esc_attr($code); ?>">
<?php if ($show_flags): ?>
<span class="mlt-flag mlt-flag-<?php echo esc_attr($code); ?>"></span>
<?php endif; ?>
<?php if ($show_names): ?>
<span class="mlt-language-name"><?php echo esc_html($language['name']); ?></span>
<?php endif; ?>
</a>
<?php endforeach; ?>
</div>
<?php
}
return ob_get_clean();
}
private function get_language_data() {
$languages = array(
'en' => array('name' => 'English', 'native_name' => 'English', 'flag' => 'us'),
'zh' => array('name' => '中文', 'native_name' => '简体中文', 'flag' => 'cn'),
'es' => array('name' => 'Español', 'native_name' => 'Español', 'flag' => 'es'),
'fr' => array('name' => 'Français', 'native_name' => 'Français', 'flag' => 'fr'),
'de' => array('name' => 'Deutsch', 'native_name' => 'Deutsch', 'flag' => 'de'),
'ja' => array('name' => '日本語', 'native_name' => '日本語', 'flag' => 'jp'),
'ko' => array('name' => '한국어', 'native_name' => '한국어', 'flag' => 'kr'),
'ru' => array('name' => 'Русский', 'native_name' => 'Русский', 'flag' => 'ru')
);
// 只返回启用的语言
$enabled_languages = $this->available_languages;
return array_intersect_key($languages, array_flip($enabled_languages));
}
private function get_language_url($language_code) {
global $wp;
$current_url = home_url($wp->request);
// 如果是默认语言,移除语言参数
if ($language_code === ($this->settings['default_language'] ?? 'en')) {
return remove_query_arg('lang', $current_url);
}
// 添加语言参数
return add_query_arg('lang', $language_code, $current_url);
}
public function ajax_switch_language() {
if (!isset($_POST['language']) || !in_array($_POST['language'], $this->available_languages)) {
wp_die('Invalid language');
}
$language = sanitize_text_field($_POST['language']);
setcookie('mlt_language', $language, time() + YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN);
wp_send_json_success(array(
'redirect' => $this->get_language_url($language)
));
}
public function register_widget() {
register_widget('MLT_Language_Switcher_Widget');
}
}
// 语言切换器小工具
class MLT_Language_Switcher_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'mlt_language_switcher',
__('Language Switcher', 'multilingual-tools'),
array('description' => __('Display a language switcher', 'multilingual-tools'))
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
$switcher = new MLT_Language_Switcher();
echo $switcher->language_switcher_shortcode(array(
'type' => $instance['type'] ?? 'list',
'show_flags' => !empty($instance['show_flags']),
'show_names' => !empty($instance['show_names'])
));
echo $args['after_widget'];
}
public function form($instance) {
$title = $instance['title'] ?? __('Languages', 'multilingual-tools');
$type = $instance['type'] ?? 'list';
$show_flags = isset($instance['show_flags']) ? (bool) $instance['show_flags'] : true;
$show_names = isset($instance['show_names']) ? (bool) $instance['show_names'] : true;
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
name="<?php echo $this->get_field_name('title'); ?>" type="text"
value="<?php echo esc_attr($title); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id('type'); ?>"><?php _e('Display type:'); ?></label>
<select class="widefat" id="<?php echo $this->get_field_id('type'); ?>"
name="<?php echo $this->get_field_name('type'); ?>">
在includes目录下创建class-translation-manager.php:
<?php
class MLT_Translation_Manager {
private $table_name;
private $current_language;
public function __construct() {
global $wpdb;
$this->table_name = $wpdb->prefix . 'mlt_translations';
$this->current_language = $this->get_current_language();
$this->init_hooks();
}
private function init_hooks() {
// 翻译字符串
add_filter('gettext', array($this, 'translate_text'), 10, 3);
add_filter('ngettext', array($this, 'translate_plural'), 10, 5);
// 翻译文章内容
add_filter('the_content', array($this, 'translate_content'), 10);
add_filter('the_title', array($this, 'translate_title'), 10, 2);
add_filter('the_excerpt', array($this, 'translate_excerpt'), 10);
// REST API端点
add_action('rest_api_init', array($this, 'register_rest_routes'));
// 自动翻译(使用外部API)
add_action('save_post', array($this, 'auto_translate_post'), 10, 3);
// 翻译管理界面
if (is_admin()) {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
}
public function get_current_language() {
$settings = get_option('mlt_settings', array());
$default_lang = $settings['default_language'] ?? 'en';
if (isset($_GET['lang']) && $this->is_language_enabled($_GET['lang'])) {
return sanitize_text_field($_GET['lang']);
}
if (isset($_COOKIE['mlt_language']) && $this->is_language_enabled($_COOKIE['mlt_language'])) {
return sanitize_text_field($_COOKIE['mlt_language']);
}
return $default_lang;
}
private function is_language_enabled($lang_code) {
$settings = get_option('mlt_settings', array());
$enabled_languages = $settings['enabled_languages'] ?? array('en');
return in_array($lang_code, $enabled_languages);
}
public function translate_text($translated, $text, $domain) {
// 如果是默认语言,直接返回
if ($this->current_language === ($this->get_default_language())) {
return $translated;
}
// 检查是否有缓存
$cache_key = 'mlt_translation_' . md5($text . $domain . $this->current_language);
$cached = wp_cache_get($cache_key, 'multilingual-tools');
if ($cached !== false) {
return $cached;
}
// 从数据库获取翻译
global $wpdb;
$translation = $wpdb->get_var($wpdb->prepare(
"SELECT translated_text FROM {$this->table_name}
WHERE original_text = %s
AND language_code = %s
AND context = %s
AND type = 'string'
LIMIT 1",
$text,
$this->current_language,
$domain
));
if ($translation) {
wp_cache_set($cache_key, $translation, 'multilingual-tools', HOUR_IN_SECONDS);
return $translation;
}
// 如果没有找到翻译,可以尝试自动翻译
if (apply_filters('mlt_auto_translate_strings', false)) {
$auto_translation = $this->auto_translate_string($text, $this->current_language);
if ($auto_translation) {
$this->save_translation($text, $auto_translation, $this->current_language, $domain, 'string');
wp_cache_set($cache_key, $auto_translation, 'multilingual-tools', HOUR_IN_SECONDS);
return $auto_translation;
}
}
return $translated;
}
public function translate_plural($translated, $single, $plural, $number, $domain) {
if ($this->current_language === ($this->get_default_language())) {
return $translated;
}
$text = ($number == 1) ? $single : $plural;
return $this->translate_text($text, $text, $domain);
}
public function translate_content($content) {
global $post;
if (!$post || $this->current_language === ($this->get_default_language())) {
return $content;
}
// 获取文章翻译
$translated_content = $this->get_post_translation($post->ID, 'post_content', $this->current_language);
if ($translated_content) {
return $translated_content;
}
// 自动翻译内容
if (apply_filters('mlt_auto_translate_content', true)) {
$auto_translation = $this->auto_translate_text($content, $this->current_language);
if ($auto_translation) {
$this->save_post_translation($post->ID, 'post_content', $auto_translation, $this->current_language);
return $auto_translation;
}
}
return $content;
}
public function translate_title($title, $post_id = null) {
if (!$post_id || $this->current_language === ($this->get_default_language())) {
return $title;
}
$translated_title = $this->get_post_translation($post_id, 'post_title', $this->current_language);
if ($translated_title) {
return $translated_title;
}
if (apply_filters('mlt_auto_translate_titles', true)) {
$auto_translation = $this->auto_translate_text($title, $this->current_language);
if ($auto_translation) {
$this->save_post_translation($post_id, 'post_title', $auto_translation, $this->current_language);
return $auto_translation;
}
}
return $title;
}
public function translate_excerpt($excerpt) {
global $post;
if (!$post || $this->current_language === ($this->get_default_language())) {
return $excerpt;
}
$translated_excerpt = $this->get_post_translation($post->ID, 'post_excerpt', $this->current_language);
if ($translated_excerpt) {
return $translated_excerpt;
}
if (apply_filters('mlt_auto_translate_excerpts', true)) {
$auto_translation = $this->auto_translate_text($excerpt, $this->current_language);
if ($auto_translation) {
$this->save_post_translation($post->ID, 'post_excerpt', $auto_translation, $this->current_language);
return $auto_translation;
}
}
return $excerpt;
}
private function get_post_translation($post_id, $field, $language) {
global $wpdb;
$translation = $wpdb->get_var($wpdb->prepare(
"SELECT translated_text FROM {$this->table_name}
WHERE post_id = %d
AND language_code = %s
AND type = %s
LIMIT 1",
$post_id,
$language,
$field
));
return $translation;
}
private function save_post_translation($post_id, $field, $translation, $language) {
global $wpdb;
// 检查是否已存在
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$this->table_name}
WHERE post_id = %d
AND language_code = %s
AND type = %s
LIMIT 1",
$post_id,
$language,
$field
));
if ($existing) {
// 更新现有记录
$wpdb->update(
$this->table_name,
array(
'translated_text' => $translation,
'updated_at' => current_time('mysql')
),
array(
'post_id' => $post_id,
'language_code' => $language,
'type' => $field
)
);
} else {
// 插入新记录
$wpdb->insert(
$this->table_name,
array(
'original_text' => '',
'translated_text' => $translation,
'language_code' => $language,
'type' => $field,
'post_id' => $post_id,
'created_at' => current_time('mysql'),
'updated_at' => current_time('mysql')
)
);
}
// 清除缓存
wp_cache_delete('mlt_post_translation_' . $post_id . '_' . $field . '_' . $language, 'multilingual-tools');
}
private function save_translation($original, $translated, $language, $context = '', $type = 'string') {
global $wpdb;
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$this->table_name}
WHERE original_text = %s
AND language_code = %s
AND context = %s
AND type = %s
LIMIT 1",
$original,
$language,
$context,
$type
));
if ($existing) {
$wpdb->update(
$this->table_name,
array(
'translated_text' => $translated,
'updated_at' => current_time('mysql')
),
array('id' => $existing)
);
} else {
$wpdb->insert(
$this->table_name,
array(
'original_text' => $original,
'translated_text' => $translated,
'language_code' => $language,
'context' => $context,
'type' => $type,
'created_at' => current_time('mysql'),
'updated_at' => current_time('mysql')
)
);
}
}
private function auto_translate_string($text, $target_lang) {
// 使用免费的翻译API,如Google Translate(需要API密钥)
// 这里使用模拟数据,实际使用时需要替换为真实的API调用
$api_key = get_option('mlt_translation_api_key', '');
if (empty($api_key) || strlen($text) > 5000) {
return false;
}
// 模拟翻译 - 实际应调用API
$translations = array(
'en' => array(
'hello' => 'hello',
'welcome' => 'welcome'
),
'zh' => array(
'hello' => '你好',
'welcome' => '欢迎'
),
'es' => array(
'hello' => 'hola',
'welcome' => 'bienvenido'
)
);
$text_lower = strtolower(trim($text));
if (isset($translations[$target_lang][$text_lower])) {
return $translations[$target_lang][$text_lower];
}
// 实际API调用示例(使用Google Translate)
/*
$url = "https://translation.googleapis.com/language/translate/v2";
$response = wp_remote_post($url, array(
'body' => array(
'q' => $text,
'target' => $target_lang,
'key' => $api_key
)
));
if (!is_wp_error($response)) {
$body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($body['data']['translations'][0]['translatedText'])) {
return $body['data']['translations'][0]['translatedText'];
}
}
*/
return false;
}
private function auto_translate_text($text, $target_lang) {
// 对于长文本,可以分段翻译
$max_length = 5000;
if (strlen($text) <= $max_length) {
return $this->auto_translate_string($text, $target_lang);
}
// 分段处理
$paragraphs = explode("n", $text);
$translated_paragraphs = array();
foreach ($paragraphs as $paragraph) {
if (strlen($paragraph) > $max_length) {
// 如果段落仍然太长,进一步分割
$sentences = preg_split('/(?<=[.?!])s+/', $paragraph);
$translated_sentences = array();
foreach ($sentences as $sentence) {
$translated = $this->auto_translate_string($sentence, $target_lang);
$translated_sentences[] = $translated ?: $sentence;
}
$translated_paragraphs[] = implode(' ', $translated_sentences);
} else {
$translated = $this->auto_translate_string($paragraph, $target_lang);
$translated_paragraphs[] = $translated ?: $paragraph;
}
}
return implode("n", $translated_paragraphs);
}
public function auto_translate_post($post_id, $post, $update) {
// 只在发布时自动翻译
if ($post->post_status !== 'publish' || wp_is_post_revision($post_id)) {
return;
}
// 检查是否已经翻译过
$already_translated = get_post_meta($post_id, '_mlt_auto_translated', true);
if ($already_translated) {
return;
}
$settings = get_option('mlt_settings', array());
$enabled_languages = $settings['enabled_languages'] ?? array('en');
$default_language = $settings['default_language'] ?? 'en';
foreach ($enabled_languages as $lang) {
if ($lang === $default_language) {
continue;
}
// 翻译标题
$translated_title = $this->auto_translate_text($post->post_title, $lang);
if ($translated_title) {
$this->save_post_translation($post_id, 'post_title', $translated_title, $lang);
}
// 翻译内容
$translated_content = $this->auto_translate_text($post->post_content, $lang);
if ($translated_content) {
$this->save_post_translation($post_id, 'post_content', $translated_content, $lang);
}
// 翻译摘要
if (!empty($post->post_excerpt)) {
$translated_excerpt = $this->auto_translate_text($post->post_excerpt, $lang);
if ($translated_excerpt) {
$this->save_post_translation($post_id, 'post_excerpt', $translated_excerpt, $lang);
}
}
}
update_post_meta($post_id, '_mlt_auto_translated', true);
}
public function register_rest_routes() {
register_rest_route('mlt/v1', '/translations', array(
'methods' => 'GET',
'callback' => array($this, 'get_translations_api'),
'permission_callback' => function() {
return current_user_can('manage_options');
}
));
register_rest_route('mlt/v1', '/translations', array(
'methods' => 'POST',
'callback' => array($this, 'save_translation_api'),
'permission_callback' => function() {
return current_user_can('manage_options');
}
));
register_rest_route('mlt/v1', '/translate', array(
'methods' => 'POST',
'callback' => array($this, 'translate_text_api'),
'permission_callback' => function() {
return current_user_can('edit_posts');
}
));
}
public function add_admin_menu() {
add_menu_page(
__('Translations', 'multilingual-tools'),
__('Translations', 'multilingual-tools'),
'manage_options',
'mlt-translations',
array($this, 'render_translations_page'),
'dashicons-translation',
30
);
add_submenu_page(
'mlt-translations',
__('String Translations', 'multilingual-tools'),
__('Strings', 'multilingual-tools'),
'manage_options',
'mlt-string-translations',
array($this, 'render_string_translations_page')
);
add_submenu_page(
'mlt-translations',
__('Content Translations', 'multilingual-tools'),
__('Content', 'multilingual-tools'),
'manage_options',
'mlt-content-translations',
array($this, 'render_content_translations_page')
);
}
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'mlt-') === false) {
return;
}
wp_enqueue_style(
'mlt-admin-style',
MLT_PLUGIN_URL . 'admin/css/admin.css',
array(),
MLT_VERSION
);
wp_enqueue_script(
'mlt-admin-script',
MLT_PLUGIN_URL . 'admin/js/admin.js',
array('jquery', 'wp-api'),
MLT_VERSION,
true
);
wp_localize_script('mlt-admin-script', 'mlt_admin', array(
'ajax_url' => admin_url('admin-ajax.php'),