咳咳,各位观众老爷们,欢迎来到今天的“WordPress 源码大保健”讲座! 今天咱们要聊的是一个藏得比较深的家伙,但作用却举足轻重的函数:wp_maybe_load_translations_early()
。 名字有点长哈,但别怕,咱们一层层扒开它的底裤,看看它到底在干些什么见不得人的事情,啊不,是重要的工作。
一、 故事的开端:为啥要“Early”加载?
想象一下,你要去参加一个国际会议,结果到了现场,发现主办方只说当地语言,你一脸懵逼,啥也听不懂。 这时候,有个好心人递给你一个实时翻译耳机,瞬间世界都美好了。
wp_maybe_load_translations_early()
在 WordPress 里的作用,就有点像这个“实时翻译耳机”。 WordPress 本身是用英文写的,但为了服务全球用户,需要支持各种语言。 为了让用户在访问网站的时候,第一时间看到的就是自己熟悉的语言,而不是满屏的英文,我们就需要在 WordPress 启动的早期,就把核心翻译文件加载进来。
“Early”在这里,意味着尽可能早。 越早加载,用户体验越好。 想象一下,如果等你点开文章,甚至评论的时候才开始加载翻译,那用户体验会糟糕到什么程度!
二、 wp_maybe_load_translations_early()
的身世背景
这个函数是在 wp-settings.php
文件中被调用的,这个文件是 WordPress 启动的“心脏”。 咱们来看看它在 wp-settings.php
中的位置:
// Load early WordPress files.
require( ABSPATH . WPINC . '/load.php' );
require( ABSPATH . WPINC . '/default-constants.php' );
//... 一堆代码 ...
// Set internal encoding.
if ( function_exists( 'mb_internal_encoding' ) ) {
mb_internal_encoding( 'UTF-8' );
}
// Run wp_maybe_load_translations_early.
wp_maybe_load_translations_early();
//... 更多代码 ...
可以看到,它在一些核心文件加载之后,但在 WordPress 初始化之前被调用。 这保证了在 WordPress 核心功能启动之前,翻译文件已经准备就绪。
三、 wp_maybe_load_translations_early()
的源码剖析
好了,重头戏来了,咱们来看看 wp_maybe_load_translations_early()
函数的庐山真面目:
function wp_maybe_load_translations_early() {
/**
* Filters whether to load the translations early.
*
* Passing a non-null value will effectively short-circuit the function.
*
* @since 5.0.0
*
* @param null|bool $enable_loading Whether to enable loading the translations early. Default null.
*/
$enable_loading = apply_filters( 'enable_loading_translations_early', null );
if ( null !== $enable_loading ) {
if ( $enable_loading ) {
load_default_textdomain();
}
return;
}
if ( defined( 'WP_SETUP_CONFIG' ) || is_multisite() ) {
return;
}
if ( defined( 'DOING_AJAX' ) ) {
return;
}
if ( defined( 'XMLRPC_REQUEST' ) ) {
return;
}
if ( defined( 'REST_REQUEST' ) ) {
return;
}
if ( defined( 'WP_INSTALLING' ) ) {
return;
}
if ( ! is_admin() ) {
load_default_textdomain();
}
}
是不是感觉有点长? 别怕,咱们慢慢拆解:
-
Filter钩子:
enable_loading_translations_early
$enable_loading = apply_filters( 'enable_loading_translations_early', null ); if ( null !== $enable_loading ) { if ( $enable_loading ) { load_default_textdomain(); } return; }
首先,它使用了一个 Filter钩子
enable_loading_translations_early
。 这个钩子允许开发者通过插件或主题,来控制是否提前加载翻译文件。 如果这个钩子返回了非null
的值,那么函数就会根据这个值来决定是否加载翻译,并直接返回。 也就是说,开发者可以通过这个钩子来“短路”这个函数,自定义加载策略。举个例子,如果你想禁用提前加载翻译,可以在你的插件或主题的
functions.php
文件中添加如下代码:add_filter( 'enable_loading_translations_early', '__return_false' );
反之,如果你想强制提前加载翻译,可以这样:
add_filter( 'enable_loading_translations_early', '__return_true' );
这个钩子的存在,给了开发者很大的灵活性。
-
各种条件判断:避免不必要的加载
if ( defined( 'WP_SETUP_CONFIG' ) || is_multisite() ) { return; } if ( defined( 'DOING_AJAX' ) ) { return; } if ( defined( 'XMLRPC_REQUEST' ) ) { return; } if ( defined( 'REST_REQUEST' ) ) { return; } if ( defined( 'WP_INSTALLING' ) ) { return; }
接下来,函数进行了一系列的条件判断。 这些判断的目的,是避免在一些特定的情况下,进行不必要的翻译文件加载。 具体来说:
WP_SETUP_CONFIG
: 如果在运行安装程序(wp-config.php
未配置),就不加载。is_multisite()
: 如果是多站点环境,通常由主站点处理翻译,避免重复加载。DOING_AJAX
: 如果是 AJAX 请求,通常不需要立即加载翻译,可以延迟加载。XMLRPC_REQUEST
: 如果是 XML-RPC 请求,同样可以延迟加载翻译。REST_REQUEST
: 如果是 REST API 请求,也可以延迟加载翻译。WP_INSTALLING
: 如果 WordPress 正在安装过程中,也不需要加载翻译。
这些判断都是为了优化性能,避免在不需要的时候浪费资源。
-
最终的加载:
load_default_textdomain()
if ( ! is_admin() ) { load_default_textdomain(); }
最后,如果以上条件都不满足,并且不在后台管理界面(
! is_admin()
),那么函数就会调用load_default_textdomain()
函数来加载默认的文本域的翻译文件。load_default_textdomain()
函数负责加载 WordPress 核心的翻译文件。为什么要排除后台管理界面呢? 因为后台管理界面的翻译文件通常由当前用户的语言设置决定,而不是默认的站点语言。 在后台管理界面,会使用
load_textdomain()
函数加载用户的语言设置对应的翻译文件。
四、 load_default_textdomain()
函数深入
既然提到了 load_default_textdomain()
,咱们也顺便看看它做了些什么:
function load_default_textdomain( $locale = null ) {
global $l10n, $locale;
// Allow for the $locale to be passed in from the constant.
if ( null === $locale ) {
$locale = get_locale();
}
// wp-config.php defines install language.
if ( defined( 'WPLANG' ) ) {
$locale = WPLANG;
}
/**
* Filters the locale to load early.
*
* @since 5.0.0
*
* @param string $locale The locale to load.
*/
$locale = apply_filters( 'default_textdomain_locale', $locale );
if ( empty( $locale ) ) {
return false;
}
$mofile = WP_LANG_DIR . '/languages/'. determine_locale() . '.mo';
if ( ! file_exists( $mofile ) ) {
return false;
}
$loaded = load_textdomain( 'default', $mofile );
if ( $loaded ) {
return true;
}
return false;
}
-
获取 Locale:确定语言
if ( null === $locale ) { $locale = get_locale(); } if ( defined( 'WPLANG' ) ) { $locale = WPLANG; } $locale = apply_filters( 'default_textdomain_locale', $locale );
首先,它会尝试获取当前的 Locale(语言区域设置)。 Locale 决定了要加载哪个翻译文件。 获取 Locale 的顺序是:
- 如果传入了
$locale
参数,则使用该参数。 - 否则,使用
get_locale()
函数获取 WordPress 的默认 Locale。 - 如果定义了
WPLANG
常量(通常在wp-config.php
中定义),则使用该常量的值。 - 最后,使用
default_textdomain_locale
过滤器,允许开发者自定义 Locale。
get_locale()
函数会从 WordPress 的选项表中获取WPLANG
选项的值,如果没有设置,则返回 ‘en_US’。 - 如果传入了
-
构建 MO 文件路径
$mofile = WP_LANG_DIR . '/languages/'. determine_locale() . '.mo';
接下来,它会构建 MO 文件的完整路径。 MO 文件是 machine object 的缩写,是编译后的二进制翻译文件,WordPress 使用 MO 文件来加载翻译。
WP_LANG_DIR
常量定义了存放翻译文件的目录,通常是wp-content/languages
。determine_locale()
函数会返回有效的 Locale,并确保其格式正确。
-
加载翻译文件
if ( ! file_exists( $mofile ) ) { return false; } $loaded = load_textdomain( 'default', $mofile ); if ( $loaded ) { return true; } return false;
最后,它会检查 MO 文件是否存在,如果存在,则调用
load_textdomain()
函数来加载翻译文件。load_textdomain()
函数会将翻译文件中的翻译内容加载到$l10n
全局变量中。如果加载成功,则返回
true
,否则返回false
。
五、 核心流程总结
为了方便大家理解,我把整个流程用表格的形式总结一下:
函数 | 作用 | 关键步骤 |
---|---|---|
wp_maybe_load_translations_early() |
尝试在 WordPress 启动早期加载核心翻译文件。 | 1. 使用 enable_loading_translations_early 过滤器,允许开发者控制是否提前加载翻译。2. 进行一系列条件判断,避免在不必要的场景下加载翻译(如安装程序、多站点、AJAX 请求等)。 3. 如果条件都满足,且不在后台管理界面,则调用 load_default_textdomain() 函数。 |
load_default_textdomain() |
加载默认文本域的翻译文件。 | 1. 确定 Locale,决定要加载哪个翻译文件。 2. 构建 MO 文件的完整路径。 3. 检查 MO 文件是否存在,如果存在,则调用 load_textdomain() 函数加载翻译文件。4. 将翻译内容加载到 $l10n 全局变量中。 |
load_textdomain() |
真正执行翻译文件加载的函数。 | 1. 解析 MO 文件,将翻译字符串存储到全局 $l10n 数组中。2. 将翻译文件与特定的文本域(text domain)关联起来。文本域是用于标识一组翻译字符串的唯一名称,例如 ‘default’ 用于 WordPress 核心,插件和主题可以使用自定义的文本域。 3. 允许通过 load_textdomain 过滤器修改加载行为。 |
get_locale() |
获取 WordPress 的默认 Locale。 | 1. 从数据库的 options 表中获取 WPLANG 选项的值。2. 如果 WPLANG 选项不存在或者为空,则返回默认的 Locale ‘en_US’。 |
determine_locale() |
确定并规范化 Locale 字符串。 | 1. 从 get_locale() 获取的 Locale 字符串中提取语言代码和区域代码。2. 将 Locale 字符串转换为标准格式,例如 ‘en_US’、’zh_CN’。 3. 确保 Locale 字符串是有效的,并且存在对应的翻译文件。 |
六、 总结与思考
wp_maybe_load_translations_early()
函数虽然看起来不起眼,但它却保证了 WordPress 在启动的早期就能加载核心翻译文件,从而为用户提供更好的本地化体验。
通过分析源码,我们了解了它的工作原理,以及它如何通过 Filter钩子和条件判断来优化性能。 我们还深入了解了 load_default_textdomain()
函数,以及它如何加载翻译文件。
希望今天的讲座能帮助大家更好地理解 WordPress 的本地化机制。 记住,源码是最好的老师! 多看源码,多思考,你也能成为 WordPress 大神!
好了,今天的讲座就到这里,感谢大家的收听! 咱们下期再见!