早上好,各位代码农!今天咱们要聊聊WordPress的“翻译官”——translate()
函数。这可是WordPress国际化(i18n)和本地化(l10n)的幕后英雄,让你的网站能说各国语言,吸引全球粉丝!准备好迎接一场源码解剖之旅了吗?
一、translate()
函数:你的网站多语种的秘密武器
translate()
函数,顾名思义,就是用来翻译文本的。但它不仅仅是简单地替换单词,它还涉及到文本域(text domain)、复数形式处理等一系列复杂机制。简单来说,它的主要作用是:
- 查找翻译:根据提供的文本、文本域和可选的上下文,在已加载的翻译文件中查找对应的翻译。
- 返回翻译后的文本:如果找到翻译,则返回翻译后的文本;否则,返回原始文本。
- 支持复数形式:对于不同数量的物品,返回不同的翻译文本(例如,"1 comment" vs "2 comments")。
二、translate()
函数的语法结构
先来认识一下translate()
函数的基本语法:
<?php
/**
* 翻译文本。
*
* @since 2.1.0
*
* @param string $text 要翻译的文本。
* @param string $domain 文本域。应该与gettext函数加载的mo文件匹配。
* @param string $context (可选)文本的上下文,用于区分相同的字符串的不同含义。
* @return string 翻译后的文本。
*/
function translate( string $text, string $domain = 'default', string $context = null ): string {
global $l10n;
// 如果没有可用的翻译或者文本为空,则返回原始文本。
if ( empty( $l10n[ $domain ] ) || empty( $text ) ) {
return $text;
}
if ( isset( $context ) && is_scalar( $context ) ) {
$key = _get_context_key( $text, $context );
} else {
$key = $text;
}
// 查找翻译。
if ( isset( $l10n[ $domain ]->translations[ $key ] ) ) {
return $l10n[ $domain ]->translations[ $key ];
}
// 如果没有找到翻译,则返回原始文本。
return $text;
}
参数说明:
$text (string)
: 需要翻译的原始文本。这是你的“原文”,等待着被翻译成目标语言。$domain (string)
: 文本域。它就像一个分类标签,用于区分不同的翻译文件。 默认值是'default'
。 不同的插件或主题可以使用不同的文本域,避免翻译冲突。$context (string, optional)
: 上下文。这是一个可选参数,用于区分相同的文本在不同语境下的含义。例如,"Post" 可以是 "发布文章" 或 "邮局",上下文可以帮助翻译者选择正确的翻译。默认值为null
。
返回值:
(string)
: 翻译后的文本。如果找到了翻译,返回翻译后的文本;否则,返回原始文本。
三、translate()
函数源码剖析
现在,让我们深入 translate()
函数的源码,看看它是如何工作的:
-
全局变量
$l10n
:global $l10n;
$l10n
是一个全局数组,存储了已加载的翻译数据。它的结构大概是这样的:$l10n = [ 'default' => (object) [ 'domain' => 'default', 'headers' => [ /* ... */ ], 'entries' => [ /* ... */ ], 'translations' => [ 'Original Text' => 'Translated Text', 'Another Text' => 'Another Translated Text', ], ], 'my-plugin' => (object) [ 'domain' => 'my-plugin', 'headers' => [ /* ... */ ], 'entries' => [ /* ... */ ], 'translations' => [ 'Hello' => '你好', 'World' => '世界', ], ], // ... 更多文本域 ];
每个文本域(例如
'default'
或'my-plugin'
)都对应一个对象,其中'translations'
属性存储了原文和译文的键值对。 -
检查
$l10n
和$text
:if ( empty( $l10n[ $domain ] ) || empty( $text ) ) { return $text; }
首先,函数会检查
$l10n
数组中是否存在指定的文本域,以及要翻译的文本是否为空。如果文本域不存在,或者文本为空,则直接返回原始文本,不做任何翻译。 -
生成翻译键
$key
:if ( isset( $context ) && is_scalar( $context ) ) { $key = _get_context_key( $text, $context ); } else { $key = $text; }
这里,函数会根据是否提供了上下文(
$context
)来生成一个唯一的翻译键。如果提供了上下文,则使用_get_context_key()
函数生成键;否则,直接使用原始文本作为键。_get_context_key()
函数的作用是将文本和上下文组合成一个唯一的字符串,以区分相同的文本在不同语境下的含义。_get_context_key()
函数的源码如下:<?php /** * 为带上下文的字符串创建一个唯一的键。 * * @ignore * @since 3.0.0 * * @param string $string 原始字符串。 * @param string $context 字符串的上下文。 * @return string 带上下文的字符串的唯一键。 */ function _get_context_key( string $string, string $context ): string { return $string . "x04" . $context; }
它简单地将原始字符串和上下文用一个特殊的字符
x04
连接起来。这个字符不太可能出现在正常的文本中,所以可以保证生成的键是唯一的。 -
查找翻译:
if ( isset( $l10n[ $domain ]->translations[ $key ] ) ) { return $l10n[ $domain ]->translations[ $key ]; }
接下来,函数会在
$l10n
数组中查找与$key
对应的翻译。如果找到了翻译,则返回翻译后的文本。 -
返回原始文本:
return $text;
如果
$l10n
数组中没有找到与$key
对应的翻译,则返回原始文本。
四、translate()
函数的实际应用
translate()
函数通常与其他 gettext 函数(例如 __()
, _e()
, _x()
, _ex()
, _n()
, _nx()
)一起使用,来实现完整的国际化和本地化功能。
__()
: 返回翻译后的文本。_e()
: 输出翻译后的文本。_x()
: 返回带上下文的翻译后的文本。_ex()
: 输出带上下文的翻译后的文本。_n()
: 返回单复数形式的翻译后的文本。_nx()
: 返回带上下文的单复数形式的翻译后的文本。
例如:
<?php
// 使用 __() 函数翻译文本
$translated_text = __( 'Hello World', 'my-plugin' );
echo $translated_text; // 输出:你好世界 (如果已加载对应的翻译)
// 使用 _e() 函数输出翻译后的文本
_e( 'Welcome', 'my-theme' ); // 输出:欢迎 (如果已加载对应的翻译)
// 使用 _x() 函数翻译带上下文的文本
$translated_text = _x( 'Post', 'noun', 'my-plugin' ); // 'Post' 作为名词
echo $translated_text; // 输出:文章 (如果已加载对应的翻译)
$translated_text = _x( 'Post', 'verb', 'my-plugin' ); // 'Post' 作为动词
echo $translated_text; // 输出:发布 (如果已加载对应的翻译)
// 使用 _n() 函数翻译单复数形式的文本
$comment_count = 1;
$translated_text = sprintf( _n( '%s comment', '%s comments', $comment_count, 'my-theme' ), $comment_count );
echo $translated_text; // 输出:1 comment (如果已加载对应的翻译)
$comment_count = 5;
$translated_text = sprintf( _n( '%s comment', '%s comments', $comment_count, 'my-theme' ), $comment_count );
echo $translated_text; // 输出:5 comments (如果已加载对应的翻译)
// 使用 _nx() 函数翻译带上下文的单复数形式的文本
$book_count = 1;
$translated_text = sprintf( _nx( '%s book', '%s books', $book_count, 'book', 'my-plugin' ), $book_count );
echo $translated_text; // 输出:1 book (如果已加载对应的翻译)
$book_count = 10;
$translated_text = sprintf( _nx( '%s book', '%s books', $book_count, 'book', 'my-plugin' ), $book_count );
echo $translated_text; // 输出:10 books (如果已加载对应的翻译)
?>
五、文本域(Text Domain)的重要性
文本域是 WordPress 国际化的关键概念。它是一个唯一的标识符,用于区分不同的翻译文件。每个插件或主题都应该使用自己的文本域,以避免翻译冲突。
- 命名规范: 文本域通常使用插件或主题的 slug(简短的、URL 友好的名称)。例如,如果你的插件的名称是 "My Awesome Plugin",那么你的文本域可以是 "my-awesome-plugin"。
- 加载翻译文件: 你需要使用
load_plugin_textdomain()
或load_theme_textdomain()
函数来加载你的翻译文件。这些函数会将翻译数据加载到$l10n
全局数组中。
示例:
<?php
/**
* 加载插件的文本域。
*/
function my_awesome_plugin_load_textdomain() {
load_plugin_textdomain(
'my-awesome-plugin',
false,
dirname( plugin_basename( __FILE__ ) ) . '/languages/'
);
}
add_action( 'plugins_loaded', 'my_awesome_plugin_load_textdomain' );
?>
在这个例子中,load_plugin_textdomain()
函数加载了名为 "my-awesome-plugin" 的文本域的翻译文件。翻译文件位于插件目录下的 languages
文件夹中。
六、复数形式的处理
不同的语言对复数形式的处理方式不同。例如,英语只有单数和复数两种形式,而某些斯拉夫语言有多种复数形式。WordPress 使用 gettext 库来处理复数形式。
_n()
和 _nx()
函数可以根据数量返回不同的翻译文本。它们接受三个参数:
$single
: 单数形式的文本。$plural
: 复数形式的文本。$number
: 数量。$domain
: 文本域$context
: 上下文 (仅_nx()
函数)
WordPress 会根据当前的语言环境和数量,自动选择正确的复数形式。
七、性能考量
虽然 translate()
函数是 WordPress 国际化的核心,但过度使用它可能会影响网站的性能。每次调用 translate()
函数,都需要在 $l10n
数组中查找翻译。如果你的网站有很多文本需要翻译,这可能会导致性能瓶颈。
以下是一些优化建议:
- 缓存翻译: 可以使用对象缓存或瞬态缓存来缓存翻译后的文本,避免重复查找。
- 避免在循环中调用
translate()
函数: 尽量在循环外部获取翻译后的文本,然后在循环中使用。 - 使用静态分析工具: 可以使用静态分析工具来检查你的代码,找出潜在的性能问题。
八、调试技巧
如果你的网站的翻译不正确,或者某些文本没有被翻译,可以使用以下调试技巧:
- 检查文本域: 确保你使用的文本域是正确的,并且与你的翻译文件匹配。
- 检查翻译文件: 确保你的翻译文件已正确加载,并且包含所有需要翻译的文本。
- 检查缓存: 清除 WordPress 的缓存,以及浏览器缓存。
- 使用调试工具: 可以使用 WordPress 调试模式或插件(例如 "Loco Translate")来帮助你找到问题。
九、总结
translate()
函数是 WordPress 国际化的基石。理解它的工作原理,可以帮助你更好地构建多语种网站,吸引全球用户。记住,良好的国际化实践不仅可以提高用户体验,还可以提升你的网站的 SEO 排名。
希望今天的讲解对大家有所帮助! 现在,谁想分享一下自己在使用 translate()
函数时遇到的有趣经历或难题? 欢迎提问和讨论!