各位观众老爷,大家好!今天咱们来聊聊 WordPress 翻译背后的功臣:load_textdomain() 函数。这玩意儿听起来高大上,但其实就像个辛勤的搬运工,负责把各种语言包(也就是 .mo 文件)搬到 WordPress 的大脑里,让你的网站能说多国语言。
咱们今天就来扒一扒它的源码,看看它是怎么工作的,以及我们作为开发者该如何正确使用它。准备好了吗?发车!
1. load_textdomain() 函数的身世背景
load_textdomain() 函数是 WordPress 内核中的一个核心函数,定义在 wp-includes/l10n.php 文件中。它的作用就是加载指定文本域(Text Domain)的翻译文件,让 WordPress 能够根据用户的语言设置显示相应的翻译文本。
简单来说,它就是个翻译器,把你的英文(或其他语言)代码里的文本,翻译成用户选择的语言。
2. 函数签名及参数详解
先来看看 load_textdomain() 的函数签名:
/**
* Loads a .mo file into the text domain.
*
* If the text domain already exists, the translations will be merged. If both
* sets of translations have the same string, the translation from the original
* text domain will be used.
*
* @since 1.5.0
*
* @global array $l10n An array of translations.
*
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param string $mofile Path to the MO file.
* @param string|null $locale Optional. Locale to load. If not set, uses the active locale.
* @return bool True on success, false on failure.
*/
function load_textdomain( $domain, $mofile, $locale = null ) {
// 函数体,后面再详细分析
}
参数解释:
$domain(string): 文本域。这是个非常重要的参数,它就像你的插件或主题的“名字”,WordPress 用它来区分不同的翻译文件。 建议使用插件或主题的slug命名,避免冲突。$mofile(string):.mo文件的完整路径。.mo文件是编译后的机器可读的翻译文件,包含了所有翻译信息。$locale(string, optional): 可选参数,指定要加载的语言区域设置。 如果为空(null),则使用 WordPress 当前的语言区域设置。
返回值:
bool: 成功加载返回true,失败返回false。
3. 源码深度解析:load_textdomain() 的工作流程
现在,让我们深入 load_textdomain() 的源码,看看它到底做了些什么:
function load_textdomain( $domain, $mofile, $locale = null ) {
global $l10n;
/**
* Filters the locale to use when loading a text domain.
*
* @since 4.7.0
*
* @param string|null $locale The locale to use. Null if the locale is not set.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param string $mofile Path to the MO file.
*/
$locale = apply_filters( 'load_textdomain_locale', $locale, $domain, $mofile );
if ( null === $locale ) {
$locale = determine_locale();
}
if ( ! is_readable( $mofile ) ) {
return false;
}
$l10n[ $domain ] = new MO();
if ( ! $l10n[ $domain ]->import_from_file( $mofile ) ) {
unset( $l10n[ $domain ] );
return false;
}
$l10n[ $domain ]->set_domain( $domain );
/**
* Fires after the text domain is loaded.
*
* @since 2.9.0
*
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param string $mofile Path to the MO file.
*/
do_action( 'load_textdomain', $domain, $mofile );
return true;
}
逐行分析:
-
global $l10n;: 声明全局变量$l10n。 这个全局数组是 WordPress 用来存储所有已加载的翻译信息的“大仓库”。 每个文本域对应一个MO对象,MO对象里包含了该文本域的所有翻译。 -
$locale = apply_filters( 'load_textdomain_locale', $locale, $domain, $mofile );: 应用load_textdomain_locale过滤器。 这个过滤器允许开发者修改要加载的语言区域设置。 比如,你可以根据用户的 IP 地址,动态选择加载不同的语言包。 -
if ( null === $locale ) { $locale = determine_locale(); }: 如果$locale为空,则使用determine_locale()函数获取 WordPress 当前的语言区域设置。determine_locale()函数会从 WordPress 的配置中读取WPLANG常量,如果WPLANG没有设置,则会使用默认的'en_US'。 -
if ( ! is_readable( $mofile ) ) { return false; }: 检查.mo文件是否存在且可读。 如果文件不存在或无法读取,则加载失败,直接返回false。 -
$l10n[ $domain ] = new MO();: 创建一个MO对象,并将其赋值给$l10n数组中以$domain为键的元素。MO类负责解析.mo文件,并将其中的翻译信息存储在内存中。 -
if ( ! $l10n[ $domain ]->import_from_file( $mofile ) ) { unset( $l10n[ $domain ] ); return false; }: 调用MO对象的import_from_file()方法,从.mo文件中导入翻译信息。 如果导入失败,则从$l10n数组中删除该文本域,并返回false。 -
$l10n[ $domain ]->set_domain( $domain );: 设置MO对象的文本域。 这主要是为了方便后续的翻译查找。 -
do_action( 'load_textdomain', $domain, $mofile );: 触发load_textdomain动作。 这个动作允许开发者在文本域加载完成后执行一些自定义操作,比如记录日志或更新缓存。 -
return true;: 加载成功,返回true。
4. 核心类:MO 类
MO 类是 WordPress 中处理 .mo 文件的核心类,它负责解析 .mo 文件,并将其中的翻译信息存储在内存中。 MO 类的源码位于 wp-includes/pomo/mo.php 文件中。
MO 类的主要方法包括:
import_from_file( $filename ): 从指定的文件中导入翻译信息。translate( $string ): 翻译指定的字符串。set_domain( $domain ): 设置文本域。
MO 类的内部实现比较复杂,涉及到文件读取、字节序转换、哈希表查找等技术。 这里就不深入分析了,有兴趣的同学可以自行研究。
5. 如何正确使用 load_textdomain()
要正确使用 load_textdomain(),需要注意以下几点:
- 选择合适的文本域: 文本域应该具有唯一性,通常使用插件或主题的 slug。
- 放置正确的
.mo文件:.mo文件应该放在插件或主题的languages目录下,并以[text-domain]-[locale].mo的格式命名。例如,my-plugin-zh_CN.mo。 - 在合适的时间调用
load_textdomain(): 建议在插件或主题的初始化阶段调用load_textdomain(),比如在plugins_loaded或after_setup_theme动作中。 - 使用
__()、_e()、_x()、_n()等翻译函数: 这些函数会自动使用已加载的翻译信息,将你的代码中的文本翻译成用户选择的语言。
6. 示例代码:在插件中使用 load_textdomain()
下面是一个简单的示例,演示如何在插件中使用 load_textdomain():
<?php
/**
* Plugin Name: My Awesome Plugin
* Description: A simple plugin to demonstrate how to use load_textdomain().
* Version: 1.0.0
*/
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() {
echo '<p>' . __( 'Hello, world!', 'my-awesome-plugin' ) . '</p>';
}
add_action( 'wp_footer', 'my_awesome_plugin_output' );
代码解释:
-
add_action( 'plugins_loaded', 'my_awesome_plugin_load_textdomain' );: 在plugins_loaded动作中注册my_awesome_plugin_load_textdomain()函数。 -
function my_awesome_plugin_load_textdomain() { ... }:my_awesome_plugin_load_textdomain()函数调用load_plugin_textdomain()函数加载翻译文件。 -
load_plugin_textdomain( 'my-awesome-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );:load_plugin_textdomain()函数是 WordPress 提供的一个便捷函数,用于加载插件的翻译文件。 它实际上是对load_textdomain()函数的封装。'my-awesome-plugin':文本域。false: 是否加载全局文本域。通常设置为false。dirname( plugin_basename( __FILE__ ) ) . '/languages/': 翻译文件的相对路径。
-
function my_awesome_plugin_output() { ... }:my_awesome_plugin_output()函数输出一个包含翻译文本的段落。 -
echo '<p>' . __( 'Hello, world!', 'my-awesome-plugin' ) . '</p>';:__()函数用于翻译字符串。 第一个参数是要翻译的字符串,第二个参数是文本域。
7. load_plugin_textdomain() 和 load_theme_textdomain()
WordPress 还提供了两个方便的函数,用于加载插件和主题的翻译文件:
load_plugin_textdomain( $domain, $deprecated, $plugin_rel_path ): 加载插件的翻译文件。load_theme_textdomain( $domain, $template_directory ): 加载主题的翻译文件。
这两个函数实际上是对 load_textdomain() 函数的封装,简化了参数的设置。
8. 翻译文件格式:.po 和 .mo
翻译文件有两种格式:.po 和 .mo。
- .po (Portable Object) 文件是人类可读的文本文件,包含了原始字符串和对应的翻译。 开发者可以使用
.po文件进行翻译。 - .mo (Machine Object) 文件是编译后的机器可读的文件,包含了所有翻译信息。 WordPress 使用
.mo文件进行翻译。
可以使用 Poedit 等工具创建和编辑 .po 文件,并将其编译成 .mo 文件。
9. 常见问题及解决方案
- 翻译不生效: 检查文本域是否正确,
.mo文件是否存在且可读,以及是否在合适的时间调用了load_textdomain()函数。 另外,确保 WordPress 的语言设置正确。 还可以尝试清除 WordPress 的缓存。 - 文本域冲突: 确保你的插件或主题的文本域与其他插件或主题不冲突。 建议使用插件或主题的 slug 作为文本域。
.mo文件损坏: 重新编译.po文件生成.mo文件。
10. 总结
load_textdomain() 函数是 WordPress 翻译机制的核心。 理解它的工作原理,可以帮助你更好地进行插件和主题的国际化。 记住,选择合适的文本域,放置正确的 .mo 文件,并在合适的时间调用 load_textdomain() 函数,就可以让你的网站说多国语言,走向世界!
今天的讲座就到这里,希望对大家有所帮助。 感谢收看!