咳咳,各位观众老爷们,晚上好!今天咱们来聊聊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 多语言支持的核心部件,也是我们构建国际化网站的重要工具。掌握它,你就能让你的网站走向世界,拥抱全球用户!
散会! 记得给个好评哦! 😉