WordPress 多语言及本地化的实现方法
多语言和本地化支持在 WordPress 主题和插件的开发中是一项经常会遇到的任务,当处理与用户接口相关代码的时候,需要根据 WordPress 当前设置的语言环境,显示相适配的语言文字,本篇文章就来介绍一下这方面的有关内容。
WordPress 基于 GNU gettext 项目来支持应用的多语言和本地化,通过封装用于 i18n 处理的 gettext 库和工具并提供一组方便易用的接口函数供程序调用。
为了区别来自于不同的主题、插件的语言翻译实现,WordPress 提出并使用了一个叫做 “Text Domains” 的概念,这个 “Text Domains” 用来控制每项翻译的作用域,从而确保每个主题和插件的语言翻译之间不产生冲突。Text Domains 需要同语言文件关联并装载后才能在程序中使用。
下面说明一下 WordPress 几个主要的本地化文本输出函数:
一、基本的文本输出函数
__() 和 _e() 函数返回对应当前语言的文本内容,两个函数的使用方法都一样,区别是 __() 常用于给变量赋值,而 _e() 直接显示文本,相当于 echo __(),经常用于输出 Html 内容。
__|_e(‘Text Name’, ‘Text Domain’),其中第一参数是要输出文本的名称,在语言文件中定义(后面会介绍),第二参数是文本域。
$site_name = __(‘Site Name’, ‘kflyo’);
<h1><?php _e(‘Site Name’, ‘kflyo’) ?></h1> 或者 <h1><?php echo $site_name ?></h1>
在语言文件中可以建立一个条目对应译文:
msgid “Site Name”
msgstr “客飞翱”
二、上下文感知的文本输出函数
_x() 和 _ex() 函数返回对应当前语言的上下文感知的文本内容,适用于同样的文本名称所对应的文本内容放在不同语义的上下文中所代表的意思是不同的,两个函数的使用方式同上面的两个函数一样。
_x|_ex(‘Text Name’, $context, ‘Text Domain’),其中第一个和第三个参数同上面两个函数的意思一样,第二参数是关联上下文的文本。
<button type=”button”><?php _ex(‘Comment’, ‘Submit’, ‘kflyo’) ?></button>
<span><?php _ex(‘Comment’, ‘on Post’, ‘kflyo’) ?></span>
上面的文本名称 “Comment” 在第一行的代码中表示提交评论(名词),第二行代码表示评论一篇文章(动词),在语言文件中可以分别建立两个条目对应不同语义上下文的翻译:
#动词上下文
msgctxt “Submit”
msgid “Comment”
msgstr “提交评论”
#名词上下文
msgctxt “on Post”
msgid “Comment”
msgstr “评论文章”
使用同样的文本名称 “Comment”,在不同的上下文中将得到不同的翻译文本。
三、参数化的文本输出函数
sprintf() 和 printf() 函数返回对应当前语言的文本内容,不同的是这两个函数可以对输出的文本做格式化处理,而且可以使用参数和变量。使用方式同上面的函数。
语法:sprintf|printf(Output text, Variables),其中第一个参数是要输出的文本,可以包含格式描述,第二个参数是变量,可以替换输出文本中格式描述所在位置的内容。
<?php
echo sprintf( __( ‘This site name is %s.’, ‘kflyo’ ) , $site_name );
printf( __( ‘This site name is %s.’, ‘kflyo’ ) , $site_name );
printf( __( ‘This site name is %1$s, and email is %2$s.’, ‘kflyo’ ) , $site_name, $email );
?>
上面例子中的第三行使用了两个变量,可以根据需要使用更多的变量,然后在格式化串中使用对应的数字编号即可。在语言文件中建立的翻译条目如下:
msgid “This site name is %s.”
msgstr “站点名称是 %s。”
msgid “This site name is %1$s, and email is %2$s.”
msgstr “站点名称是 %1$s,邮件地址是 %2$s。”
四、Html 文本处理函数
esc_html__|esc_html_e(‘Text Name’, ‘Text Domains’):对翻译文本做 Html 有效性处理,确保能正常地显示。
esc_html_x(‘Text Name’, $context, ‘Text Domains’):对翻译文本做 Html 有效性处理,语义上下文感知。
esc_attr__|esc_attr_e(‘Text Name’, ‘Text Domains’):对翻译文本做预处理,确保在标签的属性部分中可以正常使用。
esc_attr_x(‘Text Name’, $context, ‘Text Domains’ ):语义上下文感知的标签属性部分文本预处理。
五、其它函数
WordPress 还提供了一些其它的多语言处理有关的函数,不经常使用,详细内容可以参考官网上的说明。
_n|_nx(‘single’, ‘plural’, $number, ‘Text Domains’):单复数处理函数,第三个参数的数值用来确定是选择第一个还是第二个翻译。
_n_noop|_nx_noop(‘single’, ‘plural’, ‘Text Domains’):获取翻译数据,后面确定比较用的数值后再使用。
WordPress 从版本 5.0 开始可以实现 JavaScript 脚本的本地化处理,方法是首先对要使用多语言的 JavaScript 脚本进行注册时声明 “wp-i18n” 依赖。
wp_register_script(‘jscript’, plugins_url( ‘js/jscript.js’, FILE ), array( ‘wp-i18n’ ),’0.1′);
然后关联 JavaScript 脚本和翻译,第一个参数是上面注册脚本时的 ID,第二个参数是文本域(Text Domains),第三个参数是翻译文件的位置。
wp_set_script_translations(‘jscript’, ‘kflyo’);
上述步骤完成后就可以在后端生成的 JavaScript 脚本中使用之前介绍过的本地化处理函数了。
const { __, _x, _n, sprintf } = wp.i18n;
var site_name = __(‘Site Name’, ‘kflyo’);
最后要介绍一下翻译文件,程序代码中所使用的语言相关的文本都存放在这些文件中,翻译文件有三个,扩展名分别是 .pot、.po 和 .mo。
POT:翻译文件模板,可读的文本文件,用于创建翻译文件的模板,包含基本的声明信息以及所有要翻译的文本名称的定义。POT 一般头部声明如下:
Copyright (C) 2021 Kflyo
msgid “”
msgstr “”
“Project-Id-Version: Kflyo 1.0\n”
“Report-Msgid-Bugs-To: https://www.kflyo.com\n”
“POT-Creation-Date: 2021-03-25 15:00+0008\n”
“PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n”
“Last-Translator: FULL NAME \n”
“Language-Team: \n”
“Language: zh_CN\n”
“Plural-Forms: nplurals=1; plural=0;\n”
“MIME-Version: 1.0\n”
“Content-Type: text/plain; charset=UTF-8\n”
“Content-Transfer-Encoding: 8bit\n”
“X-Generator: Poedit 2.4.2\n”
“X-Poedit-SourceCharset: UTF-8\n”
“X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;”
“_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_ex:1,2c;”
“esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n”
“X-Poedit-Basepath: .\n”
“X-Poedit-SearchPath-0: .\n”
“X-Poedit-SearchPath-1: ..\n”
#: header.php:56
msgid “site_name”
msgstr “”
PO:翻译文件,可读的文本文件,从模板文件中生成,存放所有的翻译文本。
MO:翻译文件,不可读的二进制格式,是 PO 文件的编译版本,供在程序中使用。
创建、编辑和维护翻译文件可以使用工具 Poedit,能把 PO 文件编译成 MO 文件。
使用翻译文件之前需要装载,并且和 Text Domain 关联,比如在插件中装载。
function kflyo_load_init() {
load_plugin_textdomain( ‘kflyo’, FALSE, basename( dirname( __FILE__ ) ) . ‘/languages/’ );
}
add_action( ‘plugins_loaded’, ‘kflyo_load_init’ );
语言文件的名称需要同文本域的名称保持一致,比如 kflyo-zh_CN.po。建立其它语言文件的方法都一样,文件名按照语言代码和国家代码的标准格式命名即可。