WordPress 如何在多语言环境下加载不同文本域文件

WordPress 多语言环境下文本域文件加载:一场代码与逻辑的对话

大家好!今天我们来聊聊 WordPress 多语言环境下的文本域文件加载,这对于开发多语言主题和插件至关重要。我会尽量用通俗易懂的方式,结合代码示例,带大家深入理解其中的原理和实践。

1. 什么是文本域 (Text Domain)?

在 WordPress 的多语言体系中,文本域扮演着至关重要的角色。它本质上是一个字符串,用于标识你的主题或插件中所有需要翻译的文本。你可以把它想象成一个命名空间,避免不同主题或插件之间的翻译文本冲突。

例如,你的主题名为 "MyAwesomeTheme",那么你就可以将 "myawesometheme" 作为你的文本域。所有需要翻译的文本都应该通过 __(), _e(), _x(), _n() 等函数,并指定这个文本域。

2. 为什么需要加载不同的文本域文件?

简单来说,我们需要为每种语言提供一个包含翻译后的文本的文件。这个文件将原始文本(在你的代码中)映射到对应的翻译文本。WordPress 通过文本域来识别应该加载哪个翻译文件。

例如,假设你的主题支持英语 (en_US) 和法语 (fr_FR)。你需要两个翻译文件:myawesometheme-en_US.momyawesometheme-fr_FR.mo。前者包含英语的翻译,后者包含法语的翻译。当 WordPress 站点设置为法语时,它会加载 myawesometheme-fr_FR.mo 文件,将主题中的英文文本替换成法文。

3. 如何加载文本域文件?load_theme_textdomain()load_plugin_textdomain()

WordPress 提供了两个核心函数来加载文本域文件:

  • load_theme_textdomain( string $textdomain, string|false $template_directory = false, string|false $mofile = false ): bool:用于加载主题的文本域文件。
  • load_plugin_textdomain( string $textdomain, string|false $deprecated = false, string $plugin_rel_path = false ): bool:用于加载插件的文本域文件。

让我们分别看看它们的参数:

  • $textdomain: (必须) 文本域的名称,例如 "myawesometheme"。
  • $template_directory: (主题函数的可选参数) 主题的模板目录,默认为 false,表示使用当前主题的目录。通常使用 get_template_directory()get_stylesheet_directory() 获取。
  • $mofile: (主题函数的可选参数) MO 文件的完整路径。如果省略,WordPress 将尝试在标准位置查找 MO 文件。
  • $deprecated: (插件函数的可选参数) 已弃用,不建议使用。
  • $plugin_rel_path: (插件函数的可选参数) 插件目录中包含 MO 文件的相对路径。如果 MO 文件位于插件根目录下,则可以设置为 false 或省略。

4. 主题中加载文本域文件的步骤

通常,在主题的 functions.php 文件中,我们会使用 after_setup_theme 动作来加载文本域文件。

<?php
function myawesometheme_setup() {
    load_theme_textdomain( 'myawesometheme', get_template_directory() . '/languages' );

    // 其他主题设置...
}
add_action( 'after_setup_theme', 'myawesometheme_setup' );
?>

这段代码做了以下几件事:

  1. 定义了一个名为 myawesometheme_setup 的函数。
  2. 使用 load_theme_textdomain() 函数加载文本域文件。
    • 文本域设置为 myawesometheme
    • MO 文件所在的目录设置为 get_template_directory() . '/languages'。这意味着 WordPress 将在主题根目录下的 languages 文件夹中查找 MO 文件,例如 languages/myawesometheme-fr_FR.mo
  3. 使用 add_action() 函数将 myawesometheme_setup 函数绑定到 after_setup_theme 动作。这确保了在主题初始化完成后,文本域文件会被加载。

5. 插件中加载文本域文件的步骤

在插件的主文件中,通常会在插件激活时加载文本域文件。

<?php
/**
 * Plugin Name: My Awesome Plugin
 * Description: A simple plugin.
 * Version: 1.0.0
 * Author: Your Name
 */

function myawesomeplugin_load_textdomain() {
    load_plugin_textdomain( 'myawesomeplugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
add_action( 'plugins_loaded', 'myawesomeplugin_load_textdomain' );
?>

这段代码与主题的代码类似,但有一些关键的区别:

  1. load_plugin_textdomain() 函数用于加载插件的文本域文件。
  2. plugin_basename( __FILE__ ) 返回插件主文件的基本名称,例如 my-awesome-plugin/my-awesome-plugin.php
  3. dirname( plugin_basename( __FILE__ ) ) 返回插件的目录名,例如 my-awesome-plugin
  4. MO 文件所在的目录设置为 dirname( plugin_basename( __FILE__ ) ) . '/languages'。这意味着 WordPress 将在插件目录下的 languages 文件夹中查找 MO 文件,例如 my-awesome-plugin/languages/myawesomeplugin-fr_FR.mo
  5. 使用 add_action() 函数将 myawesomeplugin_load_textdomain 函数绑定到 plugins_loaded 动作。这确保了在所有插件加载完成后,文本域文件会被加载。

6. 翻译函数的使用:__(), _e(), _x(), _n()

这些函数用于在你的代码中标记需要翻译的文本。

  • __( string $text, string $domain = 'default' ): string: 返回翻译后的文本。
  • _e( string $text, string $domain = 'default' ): void: 输出翻译后的文本。
  • _x( string $text, string $context, string $domain = 'default' ): string: 返回翻译后的文本,并提供上下文信息。上下文信息可以帮助翻译人员区分具有相同文本但含义不同的字符串。
  • _n( string $single, string $plural, int $number, string $domain = 'default' ): string: 返回单数或复数形式的翻译后的文本,具体取决于 $number 的值。

以下是一些示例:

<?php
// 使用 __() 函数
$translated_text = __( 'Hello, world!', 'myawesometheme' );
echo $translated_text;

// 使用 _e() 函数
_e( 'Welcome to my website!', 'myawesomeplugin' );

// 使用 _x() 函数
$translated_text = _x( 'Post', 'noun', 'myawesometheme' ); // 例如,'文章'
echo $translated_text;

$translated_text = _x( 'Post', 'verb', 'myawesometheme' ); // 例如,'发布'
echo $translated_text;

// 使用 _n() 函数
$comment_count = 5;
$translated_text = _n( '%s comment', '%s comments', $comment_count, 'myawesomeplugin' );
printf( $translated_text, number_format_i18n( $comment_count ) ); // 输出 "5 comments"
?>

7. MO 和 PO 文件:翻译的幕后英雄

  • PO (Portable Object) 文件: 是一种文本文件,包含原始文本和对应的翻译文本。它是人类可读的,通常由翻译人员使用专门的软件(例如 Poedit)进行编辑。
  • MO (Machine Object) 文件: 是 PO 文件的编译版本,是机器可读的。WordPress 使用 MO 文件来快速查找和替换翻译后的文本。

翻译流程通常是这样的:

  1. 开发人员在代码中使用翻译函数标记需要翻译的文本。
  2. 使用工具(例如 WP-CLI 或 Poedit)从代码中提取所有需要翻译的文本,并生成一个 POT (Portable Object Template) 文件。POT 文件本质上是一个空的 PO 文件,只包含原始文本。
  3. 将 POT 文件复制并重命名为对应语言的 PO 文件,例如 myawesometheme-fr_FR.po
  4. 翻译人员使用 Poedit 等软件打开 PO 文件,并填写翻译后的文本。
  5. 使用 Poedit 将 PO 文件编译成 MO 文件,例如 myawesometheme-fr_FR.mo
  6. 将 MO 文件上传到主题或插件的 languages 目录中。

8. 使用 WP-CLI 生成 POT 文件

WP-CLI (WordPress Command Line Interface) 是一个强大的命令行工具,可以用来管理 WordPress 站点。它提供了一个方便的命令来生成 POT 文件。

wp i18n make-pot . languages/myawesometheme.pot --slug=myawesometheme

这个命令做了以下几件事:

  • wp i18n make-pot .: 调用 WP-CLI 的 i18n make-pot 命令,该命令用于生成 POT 文件。 . 表示当前目录,即在当前目录下搜索需要翻译的文本。
  • languages/myawesometheme.pot: 指定 POT 文件的输出路径和文件名。
  • --slug=myawesometheme: 指定文本域的名称。

9. 代码示例:一个完整的例子

让我们把所有东西放在一起,创建一个简单的插件,演示如何加载文本域文件并使用翻译函数。

<?php
/**
 * Plugin Name: My Multilingual Plugin
 * Description: A simple plugin demonstrating multilingual support.
 * Version: 1.0.0
 * Author: Your Name
 */

// 加载文本域文件
function mymultilingualplugin_load_textdomain() {
    load_plugin_textdomain( 'mymultilingualplugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
add_action( 'plugins_loaded', 'mymultilingualplugin_load_textdomain' );

// 创建一个简单的管理页面
function mymultilingualplugin_admin_menu() {
    add_menu_page(
        __( 'My Plugin Settings', 'mymultilingualplugin' ), // 页面标题
        __( 'My Plugin', 'mymultilingualplugin' ), // 菜单标题
        'manage_options',
        'my-multilingual-plugin',
        'mymultilingualplugin_settings_page'
    );
}
add_action( 'admin_menu', 'mymultilingualplugin_admin_menu' );

// 创建设置页面
function mymultilingualplugin_settings_page() {
    ?>
    <div class="wrap">
        <h1><?php _e( 'My Plugin Settings', 'mymultilingualplugin' ); ?></h1>
        <p><?php _e( 'Welcome to the settings page for my multilingual plugin!', 'mymultilingualplugin' ); ?></p>
        <p><?php _e( 'This is a simple example demonstrating how to use text domains and translation functions in WordPress.', 'mymultilingualplugin' ); ?></p>
    </div>
    <?php
}
?>

这个插件做了以下几件事:

  1. 加载文本域文件,与之前的例子相同。
  2. 创建一个简单的管理页面,并在菜单中添加一个条目。
    • 使用 __() 函数翻译页面标题和菜单标题。
  3. 创建一个设置页面,并在页面上显示一些文本。
    • 使用 _e() 函数输出翻译后的文本。

为了使这个插件真正支持多语言,你需要:

  1. 创建一个 languages 文件夹在插件的根目录下。
  2. 使用 WP-CLI 或 Poedit 从插件代码中提取所有需要翻译的文本,并生成一个 POT 文件,例如 languages/mymultilingualplugin.pot
  3. 将 POT 文件复制并重命名为对应语言的 PO 文件,例如 languages/mymultilingualplugin-fr_FR.po
  4. 翻译人员使用 Poedit 等软件打开 PO 文件,并填写翻译后的文本。
  5. 使用 Poedit 将 PO 文件编译成 MO 文件,例如 languages/mymultilingualplugin-fr_FR.mo
  6. 将 MO 文件上传到插件的 languages 目录中。
  7. 将 WordPress 站点的语言设置为法语。

现在,当你访问插件的设置页面时,你会看到页面上的文本已经被翻译成法语。

10.表格总结:关键函数和文件

函数/文件 描述
load_theme_textdomain() 用于加载主题的文本域文件。
load_plugin_textdomain() 用于加载插件的文本域文件。
__() 返回翻译后的文本。
_e() 输出翻译后的文本。
_x() 返回翻译后的文本,并提供上下文信息。
_n() 返回单数或复数形式的翻译后的文本,具体取决于数量。
PO 文件 包含原始文本和对应的翻译文本,人类可读。
MO 文件 PO 文件的编译版本,机器可读。
POT 文件 模板文件,包含需要翻译的原始文本,用于创建 PO 文件。

11. 常见的陷阱和调试技巧

  • 文本域名称错误: 确保在 load_theme_textdomain()load_plugin_textdomain() 函数中使用的文本域名与在翻译函数(__(), _e() 等)中使用的文本域名一致。
  • MO 文件路径错误: 确保 MO 文件位于正确的位置,并且 load_theme_textdomain()load_plugin_textdomain() 函数指向该位置。
  • 缓存问题: WordPress 可能会缓存翻译后的文本。尝试清除 WordPress 的缓存或禁用缓存插件。
  • 语言环境设置错误: 确保 WordPress 站点的语言环境设置正确。可以在 wp-config.php 文件中设置 WPLANG 常量,或者在 WordPress 后台的 "设置" -> "常规" 页面中设置站点语言。
  • 编码问题: 确保 PO 和 MO 文件使用 UTF-8 编码。
  • PO 文件未编译: 确保 PO 文件已经编译成 MO 文件。

12. 总结:让你的代码说多种语言

多语言支持对于 WordPress 主题和插件来说至关重要,它可以帮助你吸引更广泛的用户。 通过正确使用文本域、翻译函数和 MO 文件,你可以轻松地将你的代码翻译成多种语言。 记住,细致的测试和调试是确保多语言支持正常工作的关键。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注