咳咳,各位观众老爷们,晚上好!今天咱们来聊聊WordPress里一个看似简单,实则暗藏玄机的函数:__('string', 'text-domain')
。别看它只有短短一行,却是WordPress多语言支持的核心部件。今天咱们就把它扒个精光,看看它到底是怎么把英语变成各国语言的。
第一幕:初识__()
函数,Hello World的全球之旅
首先,让我们来看一个最简单的例子:
<?php
echo __('Hello World!', 'my-theme');
?>
这段代码的意思很简单:输出 "Hello World!" 这个字符串。但是,重点来了,这个 "Hello World!" 并不是直接输出的,而是先经过了 __()
函数的处理。__()
函数会根据当前 WordPress 的语言设置,以及 my-theme
这个文本域,去查找对应的翻译,然后输出翻译后的字符串。
如果当前语言是中文,并且 my-theme
文本域下有 "Hello World!" 的中文翻译,那么这段代码就会输出 "你好,世界!"。如果没有找到翻译,那么就会原样输出 "Hello World!"。
第二幕:__()
函数的真面目:代码解剖
__()
函数实际上是 translate()
函数的别名。也就是说,__('string', 'text-domain')
等同于 translate('string', 'text-domain')
。
那么,translate()
函数又是什么呢?让我们来看看 WordPress 的源码(位于 wp-includes/l10n.php
文件中):
function translate( $text, $domain = 'default' ) {
global $l10n;
if ( isset( $l10n[ $domain ] ) ) {
return $l10n[ $domain ]->translate( $text );
}
return $text;
}
这段代码看起来是不是很简洁?其实它干的事情也不复杂:
- 全局变量
$l10n
: 这个变量保存了所有已加载的文本域的翻译信息。它是一个数组,key 是文本域的名字 (例如 ‘my-theme’,’default’),value 是一个Translation_Entry
对象,这个对象负责实际的翻译工作。 - 检查文本域是否存在:
isset( $l10n[ $domain ] )
这行代码会检查$l10n
数组中是否存在以$domain
为 key 的元素。如果不存在,说明这个文本域还没有被加载,直接返回原始的$text
。 - 调用
Translation_Entry
对象的translate()
方法: 如果文本域存在,那么就调用$l10n[ $domain ]
对象的translate()
方法,将$text
传递给它进行翻译。 - 返回翻译后的字符串:
Translation_Entry
对象的translate()
方法会返回翻译后的字符串。
第三幕:Translation_Entry
对象的秘密:PO/MO 文件
那么,Translation_Entry
对象又是如何进行翻译的呢?这就涉及到 WordPress 的翻译机制了。WordPress 使用 PO 和 MO 文件来存储翻译数据。
- PO (Portable Object) 文件: PO 文件是文本文件,包含原始字符串和对应的翻译。它通常由开发者创建和维护。
- MO (Machine Object) 文件: MO 文件是 PO 文件的二进制版本,用于提高翻译查找的效率。它是 WordPress 实际使用的翻译文件。
Translation_Entry
对象会加载 MO 文件,并将原始字符串与 MO 文件中的翻译进行匹配,如果找到匹配的翻译,就返回翻译后的字符串。
让我们来看一个简单的 PO 文件例子:
msgid "Hello World!"
msgstr "你好,世界!"
msgid "Welcome to my website!"
msgstr "欢迎来到我的网站!"
在这个 PO 文件中,msgid
表示原始字符串,msgstr
表示对应的翻译。
第四幕:文本域 (Text Domain) 的作用:翻译的隔离区
文本域 (Text Domain) 在 WordPress 多语言支持中扮演着非常重要的角色。它可以将不同主题或插件的翻译隔离开来,避免冲突。
例如,你的主题使用了 my-theme
文本域,而你的插件使用了 my-plugin
文本域。即使它们都包含 "Hello World!" 这个字符串,它们的翻译也不会互相干扰。
在 __()
函数中,文本域是第二个参数:__('string', 'text-domain')
。
第五幕:加载翻译文件:load_theme_textdomain()
和 load_plugin_textdomain()
在 WordPress 中,我们需要手动加载主题或插件的翻译文件。这通常通过 load_theme_textdomain()
和 load_plugin_textdomain()
函数来实现。
load_theme_textdomain()
: 用于加载主题的翻译文件。通常在主题的functions.php
文件中使用。load_plugin_textdomain()
: 用于加载插件的翻译文件。通常在插件的主文件中使用。
例如,在主题的 functions.php
文件中,你可以这样加载 my-theme
文本域的翻译文件:
<?php
function my_theme_setup() {
load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'my_theme_setup' );
?>
这段代码会在主题初始化完成后,加载 my-theme
文本域的翻译文件。翻译文件位于主题目录下的 languages
文件夹中,文件名通常是 my-theme-zh_CN.mo
(中文简体)。
在插件的主文件中,你可以这样加载 my-plugin
文本域的翻译文件:
<?php
/**
* Plugin Name: My Plugin
*/
function my_plugin_load_textdomain() {
load_plugin_textdomain( 'my-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
add_action( 'plugins_loaded', 'my_plugin_load_textdomain' );
?>
这段代码会在插件加载完成后,加载 my-plugin
文本域的翻译文件。翻译文件位于插件目录下的 languages
文件夹中,文件名通常是 my-plugin-zh_CN.mo
(中文简体)。
第六幕:更高级的用法:复数形式和上下文
__()
函数只是最基本的翻译函数。WordPress 还提供了其他一些更高级的翻译函数,用于处理复数形式和上下文。
-
_n()
: 用于处理复数形式。它接受两个字符串参数:单数形式和复数形式。WordPress 会根据数量选择正确的形式。<?php $count = 5; echo sprintf( _n( '%d comment', '%d comments', $count, 'my-theme' ), $count ); ?>
这段代码会根据
$count
的值输出不同的字符串。如果$count
是 1,那么输出 "1 comment"。如果$count
大于 1,那么输出 "5 comments"。 -
_x()
: 用于处理具有相同字符串但不同含义的翻译。它接受一个字符串参数和一个上下文参数。<?php echo _x( 'Post', 'noun', 'my-theme' ); // 输出 "文章" echo _x( 'Post', 'verb', 'my-theme' ); // 输出 "发布" ?>
在这个例子中,"Post" 既可以作为名词 (文章),也可以作为动词 (发布)。
_x()
函数允许我们为不同的上下文提供不同的翻译。
第七幕:总结:__()
函数的生命周期
让我们来总结一下 __()
函数的生命周期:
- 开发者在代码中使用
__()
函数: 例如__('Hello World!', 'my-theme')
。 - WordPress 加载主题或插件的翻译文件: 通过
load_theme_textdomain()
或load_plugin_textdomain()
函数。 - 当代码执行到
__()
函数时,translate()
函数被调用。 translate()
函数在全局变量$l10n
中查找对应的文本域。- 如果找到文本域,
translate()
函数调用Translation_Entry
对象的translate()
方法。 Translation_Entry
对象在 MO 文件中查找对应的翻译。- 如果找到翻译,
translate()
函数返回翻译后的字符串。否则,返回原始字符串。 - 最终,翻译后的字符串被输出。
为了更清晰地理解整个流程,我们可以用表格来表示:
步骤 | 函数/对象 | 作用 | 数据来源 |
---|---|---|---|
1 | __() |
标记需要翻译的字符串 | 开发者代码中的字符串和文本域 |
2 | load_theme_textdomain() /load_plugin_textdomain() |
加载 MO 文件到 $l10n 全局变量 |
主题/插件目录下的 MO 文件 |
3 | translate() |
在 $l10n 中查找翻译,并调用 Translation_Entry |
$l10n 全局变量,原始字符串和文本域 |
4 | Translation_Entry |
实际进行翻译查找和替换 | 加载的 MO 文件 |
5 | 返回翻译后的字符串或原始字符串 | 最终输出的字符串 |
第八幕:彩蛋:一些需要注意的点
- 编码问题: 确保你的 PO 和 MO 文件使用 UTF-8 编码。
- 缓存问题: WordPress 会缓存翻译数据。如果你修改了 PO 或 MO 文件,需要清除缓存才能看到效果。
- 文本域命名: 文本域的名字应该具有唯一性,避免与其他主题或插件冲突。
- 翻译工具: 可以使用 Poedit 或 Loco Translate 等工具来编辑 PO 文件。
第九幕:总结中的总结
好了,今天的讲座就到这里。希望通过今天的讲解,大家对 WordPress 的 __()
函数有了更深入的理解。记住,__()
函数不仅仅是一个简单的翻译函数,它是 WordPress 多语言支持的核心部件,也是我们构建国际化网站的重要工具。掌握它,你就能让你的网站走向世界,拥抱全球用户!
散会! 记得给个好评哦! 😉