I18n for WordPress Developers

WordPress, 转自点点 6 年前 回复

, , ,

I18n for WordPress Developers:本文将介绍什么是I18n以及如何在Wordpress开发中使用它,以使插件和主题可以被翻译成多种语言。

1.什么是I18n?

I18n是Internationalization的缩写,因为I和n之间一共有18个字母,所以这么缩写。对WordPress来说,这意味着以特殊的方式标记的的字符串应该被翻译。

2.Gettext的简介

WordPress使用的是gettext库和i18n工具。需要注意的是,如果你看看网上,你会看到_()函数,它是指原生的PHP的gettext标准翻译功能,但对于WordPress ,你应该使用WordPress定义的函数来替代PHP的_()函数。

3.可翻译的字符串

为了使你的Wordpress主题的字符可以被翻译为多种语言,你应该用一个_()函数来处理它。

$hello = __( 'Hello, Suoling!', 'suoling-net-theme' );

如果这个字符是前台可见的,应该采用_e()函数了!如下:

$hello = _e( 'Hello, Suoling!', 'suoling-net-theme' );

4.POT文件

在源文件中标记字符串后, 一个叫xgettext的gettext工具将被用来提取原始字符串并建立一个后缀为.pot的主题字 符串翻译文件。下面是一个例子POT文件条目:

#: wp-admin/admin-header.php:49
    msgid "Sign Out"
    msgstr ""

5.PO文件

每个译者使用WordPress 主题的POT文件,用自己的语言转换原来的msgstr部分。其结果是和原来的POT文件格式相同的PO文件,这个PO文件已经被翻译并且可能会和原来的POT的头部不同。

6.MO文件

已经翻译的PO文件会创建一个MO文件。这是一个二进制文件,它包含了所有的原始字符串和相应的翻译。该文件使用msgfmt工具转换。一个典型的msgfmt命令看起来像这样:

msgfmt -o filename.po filename.mo

如果你一次要转换很多PO文件,就可以使用批处理运行它,例如,使用bash命令:

# Find PO files, process each with msgfmt and rename the result to MO
for file in `find . -name "*.po"` ; do msgfmt -o `echo$file | sed s/\.po/\.mo/` $file ; done

7.标记文本(前面这四个字在这一段当名词用)的作用

如果你翻译一个插件或主题,你需要使用一个标记文本来标记该插件/主题所有字符。这样可以提高便携性、并能与一寸的WordPress的主题或插件共同工作。 在一般情况下,Wordpress可以使用多个大型翻译逻辑模块和不同的MO文件。
标记文本可以用来区别不同的模块。
如果你想了解更多,我们建议您阅读了gettext在线手册

8.为翻译而标记文本(括号前面的这四个字是一个动词,区别于上一段)

翻译的字符串被包裹在一个呼叫的一个特殊功能的一组。最常用的一种是__ ( ) 。它只返回参数的翻译:

echo '<h2>' . __( 'Blog Options', 'my-text-domain' ) . '</h2>';

但是看起来_e()用的更广泛,下面这两行的效果是一样的:

echo __( Suoling.net is a nice website!', 'my-text-domain' );
_e( Suoling.net is a nice website!', 'my-text-domain' );

9.占位符

echo 'We deleted $count spam messages.'

你会如何i18n上面这行呢?让我们看看下面这一行:

_e( 'We deleted $count spam messages.', 'my-text-domain' );

试验后你会发现,上面这行是错误的,正确的写法如下:

printf( __( 'We deleted %d spam messages.', 'my-text-domain' ), $count );

问题在哪儿呢?因为_e()只是翻译字符串,所以,它把变量$count也作为字符串翻译,可能的结果是“我们删除了
$ count封垃圾邮件”,正确处理变量的方式是采用类似:

printf(__('字符字符%d字符字符'),$变量名)

使用两个占位符的例子:

printf( __( 'Your city is %1$s, and your zip code is %2$s.', 'my-text-domain' ), $city, $zipcode );

其中的%d是个整数型变量占位符,关于占位符,请点击后面:占位符

10.复数形式

让我们回到垃圾邮件的例子。如果我们只有一个垃圾邮件删除,该怎么办?输出将是:We deleted 1 spam messages,这是绝对不正确的英语,在许多其他语言中也肯定是不正确的。
在WordPress中,您可以使用_n()函数。

printf( _n( 'We deleted %d spam message.', 'We deleted %d spam messages.', $count, 'my-text-domain' ), $count );

_n()接受4个参数:
singular - 单数形式的字符串
plural - 复数形式的字符串
count - 对象的数量,这将决定应该返回单数还是复数形式(许多其他种类的自然语言远远超过2种形式)
text domain -是第四可选参数。函数的返回值是给定的数的正确的翻译的形式。

11.消除上下文歧义

有时候一个词在几个场合用,虽然是同一个英文单词,但它在其他语言中意义可能不同。例如Post一词可以用来作为一个动词(点击此处发表您的意见),名词(编辑这篇文章) 。在这种情况下可以使用_x ()函数来消除歧义。__( )也行,但它有一个额外的第二个参数 - the context:

if ( false === $commenttxt ) $commenttxt = _x( 'Comment', 'noun' );
    if ( false === $trackbacktxt ) $trackbacktxt = __( 'Trackback' );
    if ( false === $pingbacktxt ) $pingbacktxt = __( 'Pingback' );
    ...
    // 在代码某处替换
    echo _x( 'Comment', 'column name' );

使用下面这量种方法,我们将得到的字符串评论的原始版本,但会在不同的上下文中看到有两个翻译项。
text domain是第三个可选参数:

echo _x( 'Comment', 'column name', 'my-text-domain' );

同样需要注意的是__( ) , _x ( )可以被写成: _ex ( ) 。前面的例子可以写成:

_ex( 'Comment', 'column name', 'my-text-domain' );

你可以使用上面两种之中你觉得能提高易读性和易于编码的一种。

12.描述

翻译者可能不知道下面这一句该如何翻译的:

__( 'g:i:s a' )

在这种情况下,你可以在源代码中添加一个澄清评论。它应该以

translators:

开头,并应该是gettext转换前最后的PHP评论。下面是一个例子:

/* translators: 草稿保存的日期格式, see http://php.net/date */
    $draft_saved_date_format = __( 'g:i:s a' );

通过增加一个

translators:

评论你可以写“个人”的消息,让翻译者知道如何处理字符串翻译。

13.换行符

Gettext的不喜欢翻译字符串中存在\ r( ASCII码: 13 ),所以请避免使用它,可使用\ n代替。

14.空字符串

空字符串是保留给GETTEXT内部使用的,所以你一定不要尝试空字符串的国际化。它也没有任何意义,因为译者将不会看到任何上下文。
如果你必须使用空字符串,请添加翻译帮助并添加上下文并注意与Gettext系统的兼容性。

15.处理JavaScript文件

使用wp_localize_script()添加翻译的字符串或其他服务器端数据到先前排队的脚本中。

wp_enqueue_script( 'script-handle', … );
    wp_localize_script( 'script-handle', 'objectL10n', array(
    'speed' => $distance / $time,
    'submit' => __( 'Submit', 'my-text-domain' ),
    ) );

然后在JavaScript文件中,相应的script-handle ,你可以使用objectL10n.variable :

$('#submit').val(objectL10n.submit);
    $('#speed').val('{speed} km/h'.replace('{speed}', objectL10n.speed));

16.最佳实践

收集一些WordPress的具体例子,去阅读并理解它们,或者gettext手册中的优秀的文章。
总之,它看起来像这样:
规范的用词、用语。
整个句子在大多数语言中的词序是不同于英语。
合并有关的句子段落,但不要在一个字符串中包括一整页的文字。
使用格式字符串,而不是字符串在sprintf(__('替换%1 $ s的%2 $ s'的),$,$ b)中;
避免不寻常的标记和不寻常的控制字符。
不要在翻译的短语或尾部留下空白。

17.翻译插件

如果你想翻译插件,请谨记上述建议,例外如下:
你必须使用标记文本,这是你的插件的一个钩子
每个翻译都要调用调用__ ( '文字', '标记文本')
您的标记文本,可能会与你的插件名称相同,必须没有下划线。

18.选用和加载标记文本

标记文本是一个唯一的标识符,这使得WordPress可以区分所有已加载的翻译。
使用你的插件的名称或者其缩写,始终是一个不错的选择。
例如:如果你的插件是一个单一的文件称为shareadraft.php的,或者它在一个称为shareadraft的文件夹下,那么,以shareadraft作为标记文本似乎比较合适。
对于主题 - 建议以主题文件夹名作为标记文本。
标记文本也被用来和你的插件的翻译一起形成MO文件的名称。
你可以在调用plugins_loaded之前调用load_plugin_textdomain函数加载它们。

load_plugin_textdomain( $domain, $path_from_abspath, $path_from_plugins_folder )

实例:
此调用尝试从你的插件的基本目录加载my-plugin-{locale}.mo 。
语言环境的语言代码和/或国家代码被定义在wp-config.php中的WPLANG常量中。
例如,中国大陆的语言环境是'zh_CN',和丹麦的语言环境是'da_DK'。
从上面的代码示例文本域 'my-plugin' ,因此简体中文MO和PO文件应该被命名为my-plugin-zh_CN.mo ,丹麦语应该对应的是my-plugin-da_DK.po.
对于语言和国家代码的更多信息,请参阅安装WordPress-你的语言
WordPress 2.6及更新的版本中第三个参数是.mo文件相对于plugins目录所在的目录,它必须使用斜杠结束。如果你的插件并不需要与旧版本的WordPress的兼容性,您可以将第二个参数为空。
低于2.6的版本,第二个参数应该是.mo文件所在的目录。 (相对于ABSPATH的)。第三个参数是空白的。
主题亦相似:

load_theme_textdomain('my_theme');

在你的主题的functions.php文件中写入上面这句,它会搜索你的主题目录,并加载它的locale.mo (其中locale是当前语言,例如zh_CN.mo ) 。
当心
请确定MO文件名称为locale.mo(例如, zh_CN.mo )
不要将你MO文件命名为为my_theme zh_CN.mo
翻译的元数据
如果您添加了这样的一行,WordPress的插件或主题标题的主题或插件名称应该国际化的插件或主题的元数据时,它会显示你的插件管理界面:

Text Domain: my-text-domain

Worspress2.8及更新的版本中小工具的I18n
WordPress 2.8中采用了全新的Widget API ,只需要开发者来扩展标准的widget类和它的一些功能。有了这个API有没有init函数都行。然后使用窗口widget(), form()和update()方法是编码的插件,插件必须进行登记。widget被注册后,再载入标记文本(TEXTDOMAIN )。
例如:

// 注册Foo_Widget小工具   
    function Foo_Widget_init() {   
        return register_widget( 'Foo_Widget' );   
    }   
    add_action( 'widgets_init', 'Foo_Widget_init' );   
             
    $plugin_dir = basename( dirname( __FILE__ ) );   
    load_plugin_textdomain( 'foo_widget', null, $plugin_dir );

这个例子注册了一个名为Foo_Widget的小工具,然后设置插件目录变量和尝试加载的thefoo_widget locale.po文件的。
在主题和插件中标记字符串
上面的所有规则都适用于主题和插件,但还有一个,额外的规则规定,您必须添加标记文本作为每个__e和__ ngettext调用的一个参数,否则你的翻译将不起作用。
示例:

__('String') should become __('String', 'text_domain')   
_e('String') should become _e('String', 'text_domain')   
_n('String', 'Strings', $count) should become _n('String', 'Strings', $count, 'text_domain')

手工添加标记文本是一种负担,所以它会自动添加:
如果你的插件在官方资料库,登记您的帮助页面,并滚动到添加域Gettext的调用。
或者:
获取add-textdomain.php,像这样执行:

php add-textdomain.php -i domain phpfile phpfile ...

之后,标记文本将被添加到所有的gettext调用文件中。

支付宝打赏微信打赏

如果此文对你有帮助,欢迎打赏作者。

发表评论

欢迎回来 (打开)

(必填)

5096