WordPress 插件国际化:深入理解 load_plugin_textdomain
大家好!今天我们来深入探讨 WordPress 插件国际化的核心函数:load_plugin_textdomain
。国际化(i18n)和本地化(l10n)是使你的插件能够被全球用户使用的关键步骤。load_plugin_textdomain
正是连接你的插件与不同语言翻译文件的桥梁。
1. 国际化和本地化的概念回顾
在深入 load_plugin_textdomain
之前,我们先简要回顾一下国际化和本地化的概念:
-
国际化 (i18n): 设计和开发软件,使其能够在无需修改代码的情况下适应不同的语言和区域设置。这包括准备代码以使用翻译文件,处理不同的日期、时间和货币格式等。
-
本地化 (l10n): 将国际化的软件适配到特定的语言和区域。这通常涉及翻译用户界面文本,调整日期和时间格式,以及适应当地的文化习俗。
2. load_plugin_textdomain
函数详解
load_plugin_textdomain
函数用于加载插件的翻译文件,从而使插件可以显示本地化的文本。它的基本语法如下:
<?php
load_plugin_textdomain(
string $domain,
bool $deprecated, // 已弃用,始终传递 false
string $plugin_rel_path = false
);
?>
-
$domain
(string): 插件的唯一文本域 (text domain)。这是最重要的参数,用于区分不同插件或主题的翻译字符串。强烈建议使用与插件 slug (插件目录名) 相同的文本域。 -
$deprecated
(bool): 已弃用的参数,始终传递false
。 -
$plugin_rel_path
(string, optional): 翻译文件相对于插件主文件的路径。如果省略,WordPress 会在wp-content/languages/plugins/
目录下查找翻译文件。建议将翻译文件放在插件目录下的languages
文件夹中,并在此处指定相对路径。
3. 使用 load_plugin_textdomain
的步骤
使用 load_plugin_textdomain
的典型步骤如下:
-
确定文本域 (text domain): 为你的插件选择一个唯一的文本域。通常,建议使用与插件目录名相同的名称。例如,如果你的插件目录是
my-awesome-plugin
,那么文本域也应该是my-awesome-plugin
。 -
准备翻译字符串: 在你的插件代码中使用国际化函数 (
__()
,_e()
,_x()
,_n()
,_ex()
) 来包装需要翻译的文本。 -
创建 POT 文件: 使用工具(如 Poedit 或 WP-CLI)从你的插件代码中提取所有翻译字符串,并创建一个
.pot
(Portable Object Template) 文件。这个文件作为翻译的基础模板。 -
创建 MO/PO 文件: 将
.pot
文件分发给翻译人员。翻译人员使用 Poedit 或其他翻译工具创建特定语言的.po
(Portable Object) 文件,然后将其编译成.mo
(Machine Object) 文件。.mo
文件是 WordPress 实际使用的二进制翻译文件。 -
放置 MO/PO 文件: 将
.mo
和.po
文件放置在正确的目录下。通常,建议将它们放在插件目录下的languages
文件夹中。文件名应遵循textdomain-locale.mo
的格式,例如my-awesome-plugin-zh_CN.mo
。 -
调用
load_plugin_textdomain
: 在你的插件的主文件中,使用load_plugin_textdomain
函数加载翻译文件。
4. 代码示例
以下是一个完整的代码示例,演示了如何使用 load_plugin_textdomain
:
my-awesome-plugin.php (插件主文件):
<?php
/**
* Plugin Name: My Awesome Plugin
* Description: A simple plugin to demonstrate internationalization.
* Version: 1.0.0
* Author: Your Name
*/
// 确保在 plugins_loaded 钩子上调用 load_plugin_textdomain
add_action( 'plugins_loaded', 'my_awesome_plugin_load_textdomain' );
function my_awesome_plugin_load_textdomain() {
load_plugin_textdomain(
'my-awesome-plugin',
false,
dirname( plugin_basename( __FILE__ ) ) . '/languages/'
);
}
function my_awesome_plugin_output_text() {
echo '<p>' . __( 'Hello, world!', 'my-awesome-plugin' ) . '</p>';
echo '<p>' . sprintf( __( 'You have %d new messages.', 'my-awesome-plugin' ), 5 ) . '</p>';
}
add_action( 'wp_footer', 'my_awesome_plugin_output_text' );
languages/my-awesome-plugin-zh_CN.po (中文翻译文件):
msgid ""
msgstr ""
"Project-Id-Version: My Awesome Pluginn"
"POT-Creation-Date: 2023-10-27 10:00+0000n"
"PO-Revision-Date: 2023-10-27 10:00+0000n"
"Last-Translator: Your Name <[email protected]>n"
"Language-Team: Chinese (Simplified) <[email protected]>n"
"Language: zh_CNn"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"
"Plural-Forms: nplurals=1; plural=0;n"
msgid "Hello, world!"
msgstr "你好,世界!"
msgid "You have %d new messages."
msgstr "您有 %d 条新消息。"
languages/my-awesome-plugin-zh_CN.mo (编译后的中文翻译文件):
(此文件是 .po
文件的二进制编译版本,无法直接查看)
在这个例子中:
- 文本域被设置为
my-awesome-plugin
。 load_plugin_textdomain
函数在plugins_loaded
钩子上被调用,确保在所有插件加载后执行。plugin_basename( __FILE__ )
返回插件主文件的路径。dirname()
函数用于获取插件目录的路径。- 相对路径被设置为
languages/
,表示翻译文件位于插件目录下的languages
文件夹中。 __()
函数用于包装需要翻译的文本。sprintf()
函数用于处理带有占位符的字符串。.po
文件包含了英文原文和中文翻译。.mo
文件是.po
文件的编译版本,WordPress 将使用它来显示翻译后的文本。
5. 国际化函数详解
WordPress 提供了多个国际化函数,用于包装需要翻译的文本。以下是一些常用的函数:
函数 | 描述 | 示例 |
---|---|---|
__() |
返回已翻译的字符串。如果找不到翻译,则返回原始字符串。 | echo __( 'Hello, world!', 'my-awesome-plugin' ); |
_e() |
输出已翻译的字符串。如果找不到翻译,则输出原始字符串。 | _e( 'Hello, world!', 'my-awesome-plugin' ); |
_x() |
返回带上下文的已翻译的字符串。上下文用于区分具有相同文本但含义不同的字符串。 | echo _x( 'Post', 'noun', 'my-awesome-plugin' ); |
_ex() |
输出带上下文的已翻译的字符串。上下文用于区分具有相同文本但含义不同的字符串。 | _ex( 'Post', 'noun', 'my-awesome-plugin' ); |
_n() |
返回单数或复数形式的已翻译的字符串,具体取决于给定的数量。 | echo sprintf( _n( '%d comment', '%d comments', $comment_count, 'my-awesome-plugin' ), $comment_count ); |
_nx() |
返回带上下文的单数或复数形式的已翻译的字符串,具体取决于给定的数量。 | echo sprintf( _nx( '%d item', '%d items', $item_count, 'shopping cart', 'my-awesome-plugin' ), $item_count ); |
esc_attr__() |
返回已翻译的字符串,并对其进行 HTML 属性转义。这对于在 HTML 属性中使用翻译后的字符串非常重要,以防止安全漏洞。 | <input type="text" value="<?php echo esc_attr__( 'Search...', 'my-awesome-plugin' ); ?>"> |
esc_html__() |
返回已翻译的字符串,并对其进行 HTML 转义。这对于在 HTML 内容中使用翻译后的字符串非常重要,以防止安全漏洞。 | <h1><?php echo esc_html__( 'Welcome!', 'my-awesome-plugin' ); ?></h1> |
esc_attr_e() |
输出已翻译的字符串,并对其进行 HTML 属性转义。 | <input type="text" value="<?php esc_attr_e( 'Search...', 'my-awesome-plugin' ); ?>"> |
esc_html_e() |
输出已翻译的字符串,并对其进行 HTML 转义。 | <h1><?php esc_html_e( 'Welcome!', 'my-awesome-plugin' ); ?></h1> |
translate() |
返回已翻译的字符串。这是所有其他国际化函数的基础。通常不直接使用此函数,而是使用 __() , _e() 等函数。 |
echo translate( 'Hello, world!', 'my-awesome-plugin' ); |
重要提示: 始终使用适当的转义函数(如 esc_attr__()
和 esc_html__()
)来处理翻译后的字符串,以防止 XSS 攻击。
6. 翻译文件的目录结构
WordPress 查找翻译文件的目录结构如下:
-
WP_LANG_DIR/plugins
(推荐):wp-content/languages/plugins/
目录。这是存储插件翻译文件的推荐位置。文件名应遵循textdomain-locale.mo
的格式,例如my-awesome-plugin-zh_CN.mo
。 -
插件的
languages
目录: 如果$plugin_rel_path
参数被传递给load_plugin_textdomain
函数,WordPress 将在插件目录下的指定路径中查找翻译文件。建议将翻译文件放在插件目录下的languages
文件夹中,并在此处指定相对路径。 -
WP_LANG_DIR
:wp-content/languages/
目录。WordPress 也会在此处查找翻译文件,但不建议将插件翻译文件放在此目录中,因为它主要用于存储 WordPress 核心的翻译文件。
WordPress 首先在 WP_LANG_DIR/plugins
目录中查找翻译文件。如果找不到,它将在插件的 languages
目录中查找(如果指定了 $plugin_rel_path
),最后在 WP_LANG_DIR
目录中查找。
7. 使用 WP-CLI 进行国际化
WP-CLI (WordPress Command Line Interface) 提供了一组命令,可以简化国际化过程。以下是一些常用的 WP-CLI 命令:
-
wp i18n make-pot
: 从 PHP 文件或主题/插件中提取翻译字符串,并创建一个.pot
文件。wp i18n make-pot ./my-awesome-plugin my-awesome-plugin.pot
-
wp i18n update-po
: 使用.pot
文件更新现有的.po
文件。wp i18n update-po my-awesome-plugin-zh_CN.po my-awesome-plugin.pot
-
wp i18n make-json
: 从 MO 文件生成 JSON 文件。这对于使用 JavaScript 进行国际化非常有用。wp i18n make-json languages/my-awesome-plugin-zh_CN.mo languages/
使用 WP-CLI 可以自动化许多国际化任务,从而节省时间和精力。
8. 调试国际化问题
当国际化没有按预期工作时,可以尝试以下调试步骤:
-
检查文本域: 确保在
load_plugin_textdomain
函数和国际化函数中使用的文本域一致。 -
检查 MO/PO 文件名: 确保 MO/PO 文件的文件名遵循
textdomain-locale.mo
的格式,并且 locale 正确。 -
检查 MO/PO 文件路径: 确保 MO/PO 文件位于正确的目录中,并且
$plugin_rel_path
参数(如果使用)指向正确的路径。 -
清除缓存: 清除 WordPress 缓存和浏览器缓存,以确保加载最新的翻译文件。
-
启用 WP_DEBUG: 在
wp-config.php
文件中启用WP_DEBUG
模式,以查看任何 PHP 错误或警告。 -
使用 Loco Translate 插件: Loco Translate 是一款流行的 WordPress 插件,可以简化翻译文件的管理和编辑。它还提供了一些调试工具,可以帮助你找到国际化问题。
9. 插件更新与国际化
当更新插件时,务必重新生成 .pot
文件,并将其提供给翻译人员,以便他们更新翻译文件。此外,确保在插件更新后清除 WordPress 缓存,以确保加载最新的翻译文件。
10. 最佳实践
以下是一些国际化的最佳实践:
- 使用唯一的文本域: 为你的插件选择一个唯一的文本域,以避免与其他插件或主题冲突。
- 使用国际化函数包装所有文本: 确保使用国际化函数 (
__()
,_e()
,_x()
,_n()
) 包装所有需要翻译的文本。 - 使用适当的转义函数: 始终使用适当的转义函数(如
esc_attr__()
和esc_html__()
)来处理翻译后的字符串,以防止 XSS 攻击。 - 提供高质量的翻译: 确保翻译准确、流畅,并且符合当地的文化习俗。
- 与翻译人员合作: 与专业的翻译人员合作,以确保翻译的质量。
- 使用 WP-CLI 自动化国际化任务: 使用 WP-CLI 可以自动化许多国际化任务,从而节省时间和精力。
- 定期更新翻译文件: 当更新插件时,务必重新生成
.pot
文件,并将其提供给翻译人员,以便他们更新翻译文件。 - 测试国际化: 在不同的语言和区域设置下测试你的插件,以确保国际化按预期工作。
加载翻译文件和使用国际化函数
load_plugin_textdomain
函数是 WordPress 插件国际化的关键,它将插件与翻译文件连接起来。通过正确使用此函数和相关的国际化函数,你可以轻松地将你的插件翻译成多种语言,并使其能够被全球用户使用。