WordPress国际化:wp_i18n
与PO/MO文件的多语言实践
各位同学,大家好。今天我们来深入探讨WordPress的国际化(i18n)和本地化(l10n),重点讲解如何利用WordPress内置的wp_i18n
函数和PO/MO文件来实现主题和插件的多语言支持。
1. 国际化(i18n)与本地化(l10n)的概念区分
首先,我们需要明确国际化(i18n)和本地化(l10n)的区别:
- 国际化 (i18n):指的是在软件设计和开发阶段,使其能够适应不同地区用户的语言、文化和技术要求的过程。简单来说,就是让你的代码具备支持多种语言的能力,而无需修改代码本身。
- 本地化 (l10n):指的是根据特定地区或语言的需要,对软件进行修改和定制的过程。例如,将文本翻译成中文、调整日期格式、货币符号等。
在WordPress中,国际化主要通过wp_i18n
函数来实现,本地化则主要通过PO/MO文件来存储翻译后的文本。
2. wp_i18n
函数:国际化的基石
wp_i18n
提供了一系列函数,用于标记需要翻译的文本。这些函数会根据当前WordPress设置的语言环境,查找对应的翻译文本,并将其显示出来。
以下是一些常用的wp_i18n
函数:
函数名 | 功能描述 |
---|---|
__() |
最基础的翻译函数。用于获取翻译后的文本,并直接输出。 |
_e() |
与__() 类似,但直接输出翻译后的文本。 |
_x() |
带上下文的翻译函数。当同一个词在不同上下文中有不同的含义时,可以使用此函数区分。 |
_ex() |
与_x() 类似,但直接输出翻译后的文本。 |
_n() |
用于处理单复数形式的翻译。根据数量的不同,选择不同的翻译文本。 |
_nx() |
带上下文的单复数翻译函数。 |
esc_attr__() |
翻译并转义HTML属性值。 |
esc_attr_e() |
翻译并转义HTML属性值,并直接输出。 |
esc_html__() |
翻译并转义HTML内容。 |
esc_html_e() |
翻译并转义HTML内容,并直接输出。 |
translate() |
底层翻译函数。接受文本、域 (text domain) 和上下文 (context) 作为参数,返回翻译后的文本。 |
load_theme_textdomain() |
加载主题的翻译文件。 |
load_plugin_textdomain() |
加载插件的翻译文件。 |
get_locale() |
获取当前的语言环境。 |
is_rtl() |
判断当前的语言环境是否为从右向左书写。 |
2.1 使用__()
和_e()
这两个函数是最常用的翻译函数。__()
返回翻译后的文本,_e()
则直接输出翻译后的文本。
<?php
// 使用 __()
$translated_text = __('Hello, world!', 'my-theme');
echo '<p>' . $translated_text . '</p>';
// 使用 _e()
_e('Welcome to my website!', 'my-theme');
?>
2.2 使用_x()
和_ex()
当同一个词在不同上下文中具有不同的含义时,可以使用_x()
函数来指定上下文。
<?php
// "Post" 作为名词
$noun_post = _x('Post', 'noun', 'my-theme');
echo '<p>' . $noun_post . '</p>';
// "Post" 作为动词
$verb_post = _x('Post', 'verb', 'my-theme');
echo '<p>' . $verb_post . '</p>';
?>
2.3 使用_n()
和_nx()
_n()
函数用于处理单复数形式的翻译。它接受三个参数:单数形式、复数形式和数量。
<?php
$item_count = 5;
$message = sprintf( _n( '%s item', '%s items', $item_count, 'my-theme' ), number_format_i18n( $item_count ) );
echo '<p>' . $message . '</p>';
?>
_nx()
函数是_n()
的带上下文版本。
<?php
$item_count = 1;
$message = sprintf( _nx( '%s comment', '%s comments', $item_count, 'comments', 'my-theme' ), number_format_i18n( $item_count ) );
echo '<p>' . $message . '</p>';
$item_count = 5;
$message = sprintf( _nx( '%s comment', '%s comments', $item_count, 'comments', 'my-theme' ), number_format_i18n( $item_count ) );
echo '<p>' . $message . '</p>';
?>
2.4 转义函数
为了防止XSS攻击,建议在使用翻译后的文本时进行转义。
esc_attr__()
和esc_attr_e()
:用于转义HTML属性值。esc_html__()
和esc_html_e()
:用于转义HTML内容。
<?php
// 转义HTML属性值
$title = esc_attr__('My Awesome Title', 'my-theme');
echo '<a href="#" title="' . $title . '">Link</a>';
// 转义HTML内容
$content = esc_html__('This is some awesome content.', 'my-theme');
echo '<p>' . $content . '</p>';
?>
3. PO/MO文件:存储翻译文本
PO (Portable Object) 文件和 MO (Machine Object) 文件是用于存储翻译文本的标准格式。
- PO文件:是人类可读的文本文件,包含了原始文本和对应的翻译文本。
- MO文件:是PO文件的编译版本,是机器可读的二进制文件,用于WordPress快速加载翻译文本。
3.1 创建PO文件
可以使用Poedit等工具创建和编辑PO文件。
- 安装Poedit: 下载并安装Poedit (https://poedit.net/)。
- 创建新的目录: 在你的主题或插件目录下创建一个
languages
目录 (例如:my-theme/languages/
)。 - 创建PO文件: 打开 Poedit,选择 "File" -> "New from POT file…"。
-
生成POT文件: 首先,我们需要生成一个POT文件,它是一个包含所有需要翻译文本的模板文件。可以使用命令行工具
wp i18n make-pot
来生成POT文件。wp i18n make-pot . languages/my-theme.pot
这个命令会在当前目录下扫描所有PHP文件,提取需要翻译的文本,并将其保存到
languages/my-theme.pot
文件中。 - 从POT创建PO: 在Poedit中选择刚刚生成的
my-theme.pot
文件。 - 选择语言: Poedit会提示你选择语言。选择你想要翻译的语言 (例如:中文 – 简体中文)。
- 编辑翻译: Poedit会显示一个包含所有原始文本的列表。你可以逐个编辑,输入对应的翻译文本。
- 保存PO文件: 将PO文件保存到
languages
目录下,并以语言代码命名 (例如:zh_CN.po
)。
3.2 编辑PO文件
在Poedit中,你可以看到原始文本和对应的翻译文本。在"Translation"列中输入对应的翻译文本。
3.3 生成MO文件
Poedit会自动生成MO文件。当你保存PO文件时,Poedit会自动创建一个同名的MO文件 (例如:zh_CN.mo
)。如果没有自动生成,你可以选择 "File" -> "Compile to MO" 来手动生成MO文件。
3.4 PO文件格式
PO文件是一个文本文件,包含一系列的"msgid"和"msgstr"对。
msgid
:原始文本。msgstr
:翻译后的文本。
#: template-parts/content.php:20
msgid "Read More"
msgstr "阅读更多"
#: functions.php:35
msgid "Posted on %s by %s"
msgstr "发表于 %s,作者 %s"
#: functions.php:40
msgid "Edit"
msgstr "编辑"
4. 加载翻译文件
为了让WordPress加载你的翻译文件,需要在主题或插件的functions.php
文件中添加以下代码:
<?php
/**
* 加载主题的翻译文件
*/
function my_theme_load_textdomain() {
load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'my_theme_load_textdomain' );
//对于插件
/**
* 加载插件的翻译文件
*/
function my_plugin_load_textdomain() {
load_plugin_textdomain( 'my-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
}
add_action( 'plugins_loaded', 'my_plugin_load_textdomain' );
?>
load_theme_textdomain()
:用于加载主题的翻译文件。'my-theme'
:是文本域 (text domain),用于区分不同的翻译文件。get_template_directory() . '/languages'
:是翻译文件所在的目录。
load_plugin_textdomain()
:用于加载插件的翻译文件。'my-plugin'
:是文本域 (text domain)。dirname( plugin_basename( __FILE__ ) ) . '/languages/'
:是翻译文件所在的目录。
5. 文本域 (Text Domain)
文本域 (Text Domain) 是一个用于区分不同主题和插件的翻译文件的唯一标识符。建议使用你的主题或插件的名称作为文本域。
在wp_i18n
函数中,需要指定文本域。例如:
<?php
__('Hello, world!', 'my-theme');
?>
在这个例子中,'my-theme'
就是文本域。
6. 更新翻译
当你的主题或插件中的文本发生变化时,需要更新翻译文件。
- 更新POT文件: 运行
wp i18n make-pot
命令重新生成POT文件。 - 更新PO文件: 使用Poedit打开PO文件,Poedit会自动检测到POT文件中的变化,并提示你更新翻译。
- 编译MO文件: 保存PO文件,Poedit会自动编译MO文件。
7. 示例:一个简单的国际化主题
我们创建一个简单的WordPress主题,并对其进行国际化。
7.1 创建主题文件
创建一个名为 my-theme
的主题目录,并在该目录下创建以下文件:
style.css
index.php
functions.php
languages/
(空目录,用于存放翻译文件)
7.2 style.css
/*
Theme Name: My Theme
Text Domain: my-theme
*/
7.3 index.php
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<title><?php wp_title(); ?></title>
</head>
<body>
<h1><?php _e('Hello, world!', 'my-theme'); ?></h1>
<p><?php _e('Welcome to my website!', 'my-theme'); ?></p>
<?php
$item_count = 5;
$message = sprintf( _n( '%s item', '%s items', $item_count, 'my-theme' ), number_format_i18n( $item_count ) );
echo '<p>' . $message . '</p>';
?>
</body>
</html>
7.4 functions.php
<?php
/**
* 加载主题的翻译文件
*/
function my_theme_load_textdomain() {
load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'my_theme_load_textdomain' );
?>
7.5 生成POT文件
wp i18n make-pot . languages/my-theme.pot
7.6 创建并编辑PO文件
使用Poedit打开 languages/my-theme.pot
文件,选择中文 (简体中文) 作为语言,创建 zh_CN.po
文件,并添加以下翻译:
#: index.php:8
msgid "Hello, world!"
msgstr "你好,世界!"
#: index.php:9
msgid "Welcome to my website!"
msgstr "欢迎来到我的网站!"
#: index.php:12
msgid "%s item"
msgstr "%s 个项目"
#: index.php:12
msgid "%s items"
msgstr "%s 个项目"
7.7 生成MO文件
保存PO文件,Poedit会自动生成 zh_CN.mo
文件。
7.8 设置WordPress语言
在WordPress后台,选择 "设置" -> "常规",将站点语言设置为 "中文 (简体中文)"。
7.9 验证
刷新你的网站,你应该看到翻译后的文本。
8. 插件国际化
插件的国际化过程与主题类似,主要区别在于加载翻译文件的函数和目录。
8.1 创建插件文件
创建一个名为 my-plugin
的插件目录,并在该目录下创建以下文件:
my-plugin.php
(插件主文件)languages/
(空目录,用于存放翻译文件)
8.2 my-plugin.php
<?php
/**
* Plugin Name: My Plugin
* Text Domain: my-plugin
*/
function my_plugin_output() {
echo '<p>' . __('This is my plugin!', 'my-plugin') . '</p>';
}
add_action( 'wp_footer', 'my_plugin_output' );
/**
* 加载插件的翻译文件
*/
function my_plugin_load_textdomain() {
load_plugin_textdomain( 'my-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
}
add_action( 'plugins_loaded', 'my_plugin_load_textdomain' );
?>
8.3 生成POT文件
wp i18n make-pot . languages/my-plugin.pot
8.4 创建并编辑PO文件
使用Poedit打开 languages/my-plugin.pot
文件,选择中文 (简体中文) 作为语言,创建 zh_CN.po
文件,并添加以下翻译:
#: my-plugin.php:7
msgid "This is my plugin!"
msgstr "这是我的插件!"
8.5 生成MO文件
保存PO文件,Poedit会自动生成 zh_CN.mo
文件。
8.6 激活插件
在WordPress后台激活你的插件。
8.7 验证
刷新你的网站,你应该在页脚看到翻译后的文本。
9. 其他注意事项
- 编码: 确保你的PO文件和MO文件使用UTF-8编码。
- 语言代码: 使用正确的语言代码 (例如:
zh_CN
,en_US
,fr_FR
)。 - 翻译质量: 翻译质量直接影响用户体验,建议聘请专业的翻译人员进行翻译。
- 动态文本: 对于包含变量的动态文本,可以使用
sprintf()
函数进行格式化,并在PO文件中包含格式化字符串。 - JavaScript国际化: WordPress也支持JavaScript的国际化,可以使用
wp_localize_script()
函数将翻译后的文本传递给JavaScript。具体可以参考WordPress官方文档。 - GlotPress: 可以使用GlotPress来协同翻译WordPress主题和插件。
代码规范和最佳实践
- 始终使用
wp_i18n
函数: 避免在代码中直接硬编码文本。 - 正确使用文本域: 确保所有
wp_i18n
函数都使用了正确的文本域。 - 保持POT文件最新: 定期更新POT文件,以确保包含所有需要翻译的文本。
- 提供详细的上下文: 在使用
_x()
函数时,提供清晰的上下文描述,以便翻译人员理解文本的含义。 - 测试不同语言环境: 在发布主题或插件之前,在不同的语言环境下进行测试,以确保翻译正确显示。
总结来说:
- 利用
wp_i18n
函数进行国际化标记,为多语言支持打下基础。 - 通过Poedit等工具创建和编辑PO/MO文件,存储不同语言的翻译文本。
- 使用
load_theme_textdomain()
或load_plugin_textdomain()
加载翻译文件,让WordPress识别并应用翻译。
希望今天的讲解能够帮助大家更好地理解和应用WordPress的国际化和本地化技术。 谢谢大家。