
wordPress 插件翻译失效通常并非文件路径或 .mo 文件错误所致,而是因翻译加载时机早于文本输出——load_plugin_textdomain() 必须在调用 __() 等翻译函数前完成初始化。
wordpress 插件翻译失效通常并非文件路径或 `.mo` 文件错误所致,而是因翻译加载时机早于文本输出——load_plugin_textdomain() 必须在调用 __() 等翻译函数前完成初始化。
在开发 wordpress 自定义插件时,即使已正确生成 .pot 和对应语言的 .mo 文件(如 translated_plugin-es_ES.mo),且 load_plugin_textdomain() 返回 true,翻译仍可能不生效。根本原因往往不是配置错误,而是执行顺序问题:WordPress 的翻译系统必须在调用 __(‘Text’, ‘text-domain’) 之前完成文本域(text domain)的加载。
? 核心问题:构造函数中过早调用翻译函数
观察原始代码:
public function __construct() { add_action('init', [$this, 'translate_it']); echo __('Test Text', 'translated_plugin'); // ❌ 错误:此时 text domain 尚未加载! }
此处 echo __(‘Test Text’, …) 直接写在 __construct() 中,而 add_action(‘init’, …) 仅是“注册”回调,并不会立即执行。实际执行顺序如下:
- WordPress 加载插件 → 实例化 Application 对象
- __construct() 执行 → 立即输出未翻译的 ‘Test Text’
- 后续 WordPress 运行到 do_action(‘init’) 阶段
- 此时才执行 translate_it() → 调用 load_plugin_textdomain() 加载翻译
因此,首次输出必然为原始英文(或默认语言),因为翻译系统尚未就绪。
✅ 正确做法:确保翻译加载完成后再使用翻译函数
所有需要翻译的字符串输出(包括前端渲染、管理界面、ajax 响应等),都必须安排在 load_plugin_textdomain() 成功执行之后。推荐方案如下:
✅ 方案一:将翻译输出移至 init 回调中(适用于调试/简单场景)
public function __construct() { add_action('init', [$this, 'translate_it']); } public function translate_it() { $loaded = load_plugin_textdomain( 'translated_plugin', false, dirname(dirname(plugin_basename(__FILE__))) . '/languages/' ); if ($loaded) { error_log('✅ Text domain "translated_plugin" loaded successfully.'); } else { error_log('❌ Failed to load text domain.'); } // ✅ 安全:此时翻译已就绪 echo '<p>' . __('Hello from Translated Plugin!', 'translated_plugin') . '</p>'; }
? 提示:生产环境请避免在 init 中直接 echo HTML;应改用 add_shortcode()、add_action(‘wp_enqueue_scripts’) 或模板钩子等标准方式输出内容。
✅ 方案二(推荐):分离加载与使用逻辑,提升可维护性
public function __construct() { // 仅注册加载动作 add_action('init', [$this, 'load_textdomain']); // 在翻译就绪后注册其他依赖翻译的功能 add_action('plugins_loaded', [$this, 'setup_translated_features']); } public function load_textdomain() { load_plugin_textdomain( 'translated_plugin', false, dirname(dirname(plugin_basename(__FILE__))) . '/languages/' ); } public function setup_translated_features() { // ✅ 此时可安全使用所有翻译函数 add_action('admin_notices', [$this, 'show_admin_notice']); add_shortcode('translated_greeting', [$this, 'render_greeting']); } public function show_admin_notice() { echo '<div class="notice notice-info"><p>' . __('This admin notice is properly translated.', 'translated_plugin') . '</p></div>'; } public function render_greeting() { return '<p>' . __('Welcome to our plugin!', 'translated_plugin') . '</p>'; }
⚠️ 其他关键注意事项
- Text Domain 必须严格一致:插件头部注释、load_plugin_textdomain() 第一个参数、所有 __() / _e() 函数第二个参数三者必须完全相同(包括下划线、大小写),例如全部为 translated_plugin。
- Domain Path 路径需准确:确保 languages/ 文件夹位于插件根目录下,且 .mo 文件命名规范为
– .mo(如 translated_plugin-zh_CN.mo)。 - 避免在 plugins_loaded 之前调用翻译函数:init 是常用安全时机,但若需更早支持(如多语言 URL 处理),可考虑 plugins_loaded(注意:此时 get_locale() 已可用,但主题尚未加载)。
- 验证加载结果:始终检查 load_plugin_textdomain() 返回值,并配合 error_log() 或开发者工具确认是否成功。
- 缓存影响:启用对象缓存或 OPcache 时,修改 .mo 文件后需清空缓存;浏览器端也建议硬刷新(Ctrl+Shift+R)。
? 快速验证步骤
- 在 translate_it() 中添加日志:
error_log('Locale: ' . get_locale()); error_log('MO file path: ' . WP_PLUGIN_DIR . '/translated_plugin/languages/translated_plugin-' . get_locale() . '.mo'); - 检查 PHP 错误日志确认路径是否存在;
- 使用 Loco Translate 插件直接编辑并保存翻译,自动刷新 .mo;
- 切换站点语言(设置 → 通用 → 网站语言),并确保用户个人语言设置未覆盖全局设置。
遵循以上时机控制与结构规范,99% 的插件翻译失效问题即可解决——这不是 WordPress 的 bug,而是对钩子生命周期理解的关键实践。