各位观众老爷们,晚上好!我是今天的主讲人,咱们今晚来聊聊 WordPress 插件国际化的核心:load_plugin_textdomain()
。相信大家对这个函数都不陌生,但真正深入了解它的工作原理,才能更好地掌控插件的国际化,让你的插件走向世界,俘获更多用户的心!
第一部分:load_plugin_textdomain()
的基本认识——“你是谁?从哪儿来?要到哪儿去?”
首先,我们得搞清楚 load_plugin_textdomain()
究竟是个什么玩意儿。 简单来说,它就是一个负责加载插件翻译文件的函数,让你的插件能够根据用户的语言设置,显示不同的文字。
它的原型是这样的:
<?php
function load_plugin_textdomain( string $domain, bool $deprecated = false, string $plugin_rel_path = '' ) : bool {}
?>
-
$domain
(string, required): 这是你的插件的文本域名(text domain)。 文本域名是用来区分不同插件的翻译文件的唯一标识符。 就像你的身份证号码一样,保证你的翻译不会张冠李戴。通常,建议你使用插件的名称作为文本域名,并且全部小写,用短横线连接。 比如你的插件叫 "Awesome Plugin",那么文本域名可以是awesome-plugin
。 -
$deprecated
(bool, optional): 这个参数已经被废弃了, 别管它! 直接设置为false
就行了。 历史的尘埃,我们不捡! -
$plugin_rel_path
(string, optional): 这是翻译文件相对于插件主文件的路径。 默认情况下,WordPress 会在wp-content/languages/plugins/{$domain}/{$domain}-{locale}.mo
和wp-content/plugins/{plugin-directory}/languages/{$domain}-{locale}.mo
路径下查找翻译文件。如果你的翻译文件放在了其他地方,就需要通过这个参数来指定。
返回值:
bool
: 如果成功加载翻译文件,则返回true
;否则返回false
。
第二部分:load_plugin_textdomain()
源码剖析——“扒开它的皮,看看里面长啥样”
接下来,我们来深入源码,看看 load_plugin_textdomain()
到底是怎么工作的。 源码位于 wp-includes/l10n.php
文件中, 咱们把它简化一下, 抓住核心逻辑:
<?php
function load_plugin_textdomain( string $domain, bool $deprecated = false, string $plugin_rel_path = '' ) : bool {
global $l10n, $wp_plugin_paths;
// 1. 获取当前语言环境 (locale)
$locale = determine_locale();
// 2. 如果没有语言环境,就直接返回 false
if ( empty( $locale ) ) {
return false;
}
// 3. 构建翻译文件的路径
// 3.1 获取插件目录
$plugin_path = WP_PLUGIN_DIR . '/' . dirname( plugin_basename( __FILE__ ) ); // 注意:此处需要替换为实际的插件主文件路径
// 3.2 默认的翻译文件路径
$mofile = $plugin_path . '/languages/' . $domain . '-' . $locale . '.mo';
// 3.3 如果指定了 $plugin_rel_path,则使用指定的路径
if ( ! empty( $plugin_rel_path ) ) {
$mofile = WP_PLUGIN_DIR . '/' . $plugin_rel_path . '/' . $domain . '-' . $locale . '.mo';
}
// 4. 检查翻译文件是否存在
if ( ! is_readable( $mofile ) ) {
return false;
}
// 5. 加载翻译文件
if ( isset( $l10n[ $domain ] ) ) {
unload_textdomain( $domain ); // 先卸载之前的翻译
}
$l10n[ $domain ] = new MO(); // 创建一个 MO 对象,用于加载翻译数据
$loaded = $l10n[ $domain ]->import_from_file( $mofile ); // 从 .mo 文件导入翻译数据
// 6. 如果加载成功,则返回 true;否则返回 false
return $loaded;
}
?>
我们来逐行解读一下:
- 获取当前语言环境 (locale):
determine_locale()
函数负责获取当前的语言环境。 语言环境决定了使用哪种语言的翻译。 WordPress 会根据用户的设置、站点的设置以及浏览器的设置,来确定最终的语言环境。 - 检查语言环境是否为空: 如果没有语言环境,说明没有设置任何语言,那就没必要加载翻译文件了,直接返回
false
。 -
构建翻译文件的路径: 这是最关键的一步。 我们需要根据文本域名和语言环境,构建出翻译文件的完整路径。 WordPress 默认会在两个地方查找翻译文件:
wp-content/languages/plugins/{$domain}/{$domain}-{locale}.mo
: 这是全局的翻译文件目录,可以存放所有插件的翻译文件。wp-content/plugins/{plugin-directory}/languages/{$domain}-{locale}.mo
: 这是插件自身的翻译文件目录,建议将翻译文件放在这里,方便管理。
如果指定了
$plugin_rel_path
参数,则使用指定的路径。 - 检查翻译文件是否存在:
is_readable()
函数检查翻译文件是否存在并且可读。 如果文件不存在,或者没有读取权限,那就无法加载翻译,返回false
。 -
加载翻译文件: 这是真正加载翻译数据的步骤。
- 如果已经加载了相同文本域名的翻译,先使用
unload_textdomain()
函数卸载之前的翻译,避免冲突。 - 创建一个
MO
对象。MO
是 Message Object 的缩写,是 WordPress 用来处理翻译数据的类。 - 调用
MO
对象的import_from_file()
方法,从.mo
文件导入翻译数据。.mo
文件是编译后的二进制翻译文件,效率更高。
- 如果已经加载了相同文本域名的翻译,先使用
- 返回加载结果:
import_from_file()
方法返回一个布尔值,表示是否成功加载翻译文件。 将这个值作为load_plugin_textdomain()
函数的返回值。
第三部分:load_plugin_textdomain()
的使用方法——“怎么用它才能让我的插件说外语?”
现在我们知道了 load_plugin_textdomain()
的原理,接下来看看如何在插件中使用它。
- 确定文本域名: 选择一个合适的文本域名,建议使用插件名称的小写形式,用短横线连接。 比如
awesome-plugin
。 - 创建翻译文件: 创建
.po
文件和.mo
文件。.po
文件是纯文本的翻译文件,方便编辑。.mo
文件是编译后的二进制文件,效率更高。 可以使用 Poedit 等工具来创建和编辑翻译文件。.po
文件的命名格式为{$domain}-{$locale}.po
,例如awesome-plugin-zh_CN.po
。.mo
文件的命名格式为{$domain}-{$locale}.mo
,例如awesome-plugin-zh_CN.mo
。- 建议将翻译文件放在插件目录下的
languages
目录中,例如awesome-plugin/languages/awesome-plugin-zh_CN.po
和awesome-plugin/languages/awesome-plugin-zh_CN.mo
。
-
调用
load_plugin_textdomain()
函数: 在插件的主文件中,调用load_plugin_textdomain()
函数,加载翻译文件。 建议在插件激活时或者在plugins_loaded
动作钩子上调用。<?php /** * Plugin Name: Awesome Plugin * Description: A super awesome plugin. * Version: 1.0.0 */ add_action( 'plugins_loaded', 'awesome_plugin_load_textdomain' ); function awesome_plugin_load_textdomain() { load_plugin_textdomain( 'awesome-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); } ?>
- 第一个参数是文本域名
awesome-plugin
。 - 第二个参数是
$deprecated
,设置为false
。 - 第三个参数是翻译文件相对于插件主文件的路径,这里使用了
dirname( plugin_basename( __FILE__ ) ) . '/languages/'
来获取插件目录下的languages
目录。
- 第一个参数是文本域名
-
在代码中使用翻译函数: 使用
__()
、_e()
、_x()
、_ex()
等翻译函数,将需要翻译的文本包裹起来。<?php echo __( 'Hello, world!', 'awesome-plugin' ); _e( 'Welcome to my plugin!', 'awesome-plugin' ); ?>
__()
函数返回翻译后的文本。_e()
函数输出翻译后的文本。- 第二个参数是文本域名
awesome-plugin
。
第四部分:案例分析——“实战演练,让你看得更明白”
我们来举一个实际的例子,假设我们有一个名为 "My Contact Form" 的插件, 它的主要功能是显示一个联系表单。 我们希望让这个插件支持中文。
-
文本域名: 我们选择
my-contact-form
作为文本域名。 -
创建翻译文件: 我们在插件目录下的
languages
目录中创建my-contact-form-zh_CN.po
和my-contact-form-zh_CN.mo
文件。-
my-contact-form-zh_CN.po
文件的内容如下:msgid "" msgstr "" "Project-Id-Version: My Contact Formn" "POT-Creation-Date: 2023-10-27 12:00+0800n" "PO-Revision-Date: 2023-10-27 12:00+0800n" "Language-Team: Chinese (Simplified)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" "X-Generator: Poedit 3.0.1n" msgid "Your Name" msgstr "您的姓名" msgid "Your Email" msgstr "您的邮箱" msgid "Message" msgstr "留言" msgid "Send" msgstr "发送"
-
使用 Poedit 等工具将
my-contact-form-zh_CN.po
文件编译成my-contact-form-zh_CN.mo
文件。
-
-
调用
load_plugin_textdomain()
函数: 在插件的主文件中,调用load_plugin_textdomain()
函数。<?php /** * Plugin Name: My Contact Form * Description: A simple contact form plugin. * Version: 1.0.0 */ add_action( 'plugins_loaded', 'my_contact_form_load_textdomain' ); function my_contact_form_load_textdomain() { load_plugin_textdomain( 'my-contact-form', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); } function my_contact_form_display() { ?> <form> <label for="name"><?php _e( 'Your Name', 'my-contact-form' ); ?></label> <input type="text" id="name" name="name"> <label for="email"><?php _e( 'Your Email', 'my-contact-form' ); ?></label> <input type="email" id="email" name="email"> <label for="message"><?php _e( 'Message', 'my-contact-form' ); ?></label> <textarea id="message" name="message"></textarea> <button type="submit"><?php _e( 'Send', 'my-contact-form' ); ?></button> </form> <?php } add_shortcode( 'contact_form', 'my_contact_form_display' ); ?>
-
效果: 当用户的语言环境设置为中文时,联系表单的标签和按钮上的文字将显示为中文。
第五部分:注意事项——“细节决定成败,别踩坑!”
在使用 load_plugin_textdomain()
函数时,有一些注意事项需要牢记:
- 文本域名必须唯一: 确保你的插件的文本域名与其他插件不冲突。 建议使用插件名称的小写形式,用短横线连接。
- 翻译文件命名要规范: 翻译文件的命名格式必须正确, 否则 WordPress 无法识别。
.po
文件的命名格式为{$domain}-{$locale}.po
,.mo
文件的命名格式为{$domain}-{$locale}.mo
。 - 翻译文件必须存在并且可读: 确保翻译文件存在并且具有读取权限。
- 使用正确的翻译函数: 使用
__()
、_e()
、_x()
、_ex()
等翻译函数,将需要翻译的文本包裹起来。 - 清理缓存: 在修改翻译文件后,可能需要清理 WordPress 的缓存,才能看到最新的翻译效果。
- 插件更新: 在插件更新时,需要注意更新翻译文件,保持翻译的完整性和准确性。
第六部分:高级技巧——“更上一层楼,玩转国际化”
除了基本的使用方法,还有一些高级技巧可以帮助你更好地实现插件的国际化:
- 使用
load_muplugin_textdomain()
函数加载 MU 插件的翻译文件: MU 插件 (Must-Use Plugins) 是 WordPress 自动加载的插件,不需要手动激活。 可以使用load_muplugin_textdomain()
函数加载 MU 插件的翻译文件。 - 使用
load_child_theme_textdomain()
函数加载子主题的翻译文件: 子主题是基于父主题创建的,可以自定义主题的外观和功能。 可以使用load_child_theme_textdomain()
函数加载子主题的翻译文件。 - 使用
wp_set_script_translations()
函数加载 JavaScript 文件的翻译: 可以使用wp_set_script_translations()
函数加载 JavaScript 文件的翻译,让你的 JavaScript 代码也支持国际化。 - 利用在线翻译平台: 可以使用 Loco Translate 等在线翻译平台,方便地管理和编辑翻译文件,并与其他翻译者协作。
第七部分:常见问题解答——“解疑答惑,扫清障碍”
-
为什么我的翻译没有生效?
- 检查文本域名是否正确。
- 检查翻译文件是否存在并且可读。
- 检查翻译文件命名是否规范。
- 检查是否使用了正确的翻译函数。
- 清理 WordPress 的缓存。
-
如何更新翻译文件?
- 修改
.po
文件。 - 使用 Poedit 等工具将
.po
文件编译成.mo
文件。 - 上传新的
.mo
文件到服务器。 - 清理 WordPress 的缓存。
- 修改
-
如何让我的插件支持多种语言?
- 为每种语言创建一个
.po
文件和.mo
文件。 - 确保翻译文件命名正确,例如
awesome-plugin-zh_CN.po
、awesome-plugin-en_US.po
、awesome-plugin-fr_FR.po
等。 - WordPress 会根据用户的语言环境,自动加载对应的翻译文件。
- 为每种语言创建一个
表格总结
函数/方法 | 描述 |
---|---|
load_plugin_textdomain() |
加载插件的翻译文件。 |
load_muplugin_textdomain() |
加载 MU 插件的翻译文件。 |
load_child_theme_textdomain() |
加载子主题的翻译文件。 |
wp_set_script_translations() |
加载 JavaScript 文件的翻译。 |
__() |
返回翻译后的文本。 |
_e() |
输出翻译后的文本。 |
_x() |
返回带有上下文的翻译后的文本。 |
_ex() |
输出带有上下文的翻译后的文本。 |
.po 文件 |
纯文本的翻译文件,方便编辑。 |
.mo 文件 |
编译后的二进制翻译文件,效率更高。 |
希望今天的讲解能够帮助大家更深入地了解 WordPress 插件的国际化,让你的插件能够走向世界,服务更多的用户。 记住,国际化不仅仅是翻译文字,更是一种对不同文化的尊重和理解。 谢谢大家!
有问题欢迎提问,咱们下期再见!