为了使您的应用程序中的字符串可以翻译,您必须将原始字符串打包到一组特殊功能的调用中。 ## Gettext简介 WordPress使用i18n的gettext库和工具。 如果你在网上看,你会看到`_()`函数,它引用了本地PHP gettext兼容的翻译功能。 使用WordPress,您应该使用`__()`WordPress定义的PHP函数。 如果您想获得更广泛和更深入的gettext视图,我们建议您阅读gettext在线手册。 ## 文字域 使用文本域来表示属于该插件的所有文本很重要。 文本域是唯一的标识符,可以确保WordPress能够区分所有加载的翻译。 这增加了可移植性,并通过已经存在的WordPress工具更好地发挥作用。 文本域必须与插件的插槽相匹配。 如果您的插件是一个名为my-plugin.php的文件,或者它包含在一个名为my-plugin的文件夹中,则域名应为my-plugin。 如果您的插件托管在wordpress.org上,那么它必须是插件URL(wordpress.org/plugins/ <slug>)中的一小部分。 文本域名必须使用破折号而不是下划线。 字符串示例: ``` __( 'String (text to be internationalized)', 'text-domain' ); ``` 将“文本域”更改为插件的插件。 >[warning] 警告:不要在gettext函数的文本域部分使用变量名。 不要做这个快捷方式:__('Translate me。',$ text_domain); 文本域也需要添加到插件头。 即使插件被禁用,WordPress也使用它来国际化你的插件元数据。 文本域应与加载文本域时使用的文本域相同。 标题示例: ``` /* * Plugin Name: My Plugin * Author: Plugin Author * Text Domain: my-plugin */ ``` ## 域路径 使用域路径,以便当插件被禁用时,WordPress知道在哪里找到翻译。 仅当翻译位于单独的语言文件夹中时才有用。 例如,如果.mo文件位于languages文件夹中,则Domain Path将是“/languages”,必须用第一个斜杠写入。 默认为插件的languages文件夹: 标题示例: ``` /* * Plugin Name: My Plugin * Author: Plugin Author * Text Domain: my-plugin * Domain Path: /languages */ ``` ## 基本字符串 最常用的是`__()`。 它只是返回其参数的翻译: ``` __( 'Blog Options', 'my-plugin' ); ``` 另一个简单的是_e(),它输出其参数的翻译。 而不是写: ``` echo __( 'WordPress is the best!', 'my-plugin' ); ``` 你可以使用较短的: ``` _e( 'WordPress is the best!', 'my-plugin' ); ``` ## 变量 如果您在字符串中使用变量,如下面的示例,您将使用占位符。 ``` echo 'Your city is $city.' ``` 解决方案是使用printf系列函数。 特别有用的是printf和sprintf。 以下是正确的解决方案: ``` printf( /* translators: %s: Name of a city */ __( 'Your city is %s.', 'my-plugin' ), $city ); ``` >[warning] 请注意,这里的翻译字符串只是模板“你的城市是%s”,这在源代码和运行时都是一样的。 如果字符串中有多个占位符,建议您使用参数交换。 在这种情况下,单引号(')是强制性的:双引号(“)将告诉php将$ s解释为s变量,这不是我们想要的。 ``` printf( /* translators: 1: Name of a city 2: ZIP code */ __( 'Your city is %1$s, and your zip code is %2$s.', 'my-plugin' ), $city, $zipcode ); ``` 这里的邮政编码正在城市名后显示。 在某些语言中,以相反的顺序显示邮政编码和城市更为合适。 在上面的例子中使用%s的前缀,就允许这样的情况。 因此,翻译可以写成: ``` printf( /* translators: 1: Name of a city 2: ZIP code */ __( 'Your zip code is %2$s, and your city is %1$s.', 'my-plugin' ), $city, $zipcode ); ``` 重要! 此代码不正确。 ``` // This is incorrect do not use. _e( "Your city is $city.", 'my-plugin' ); ``` 翻译的字符串是从源中提取出来的,所以翻译人员会得到这个短语:“你的城市是$ city”。 但是在应用程序中,将会被称为“你的城市是伦敦”。 gettext将不会找到适合的翻译,并返回其论点:“你的城市是伦敦”。 不幸的是,它没有正确翻译。 # 多个 ##基本多元化 如果在项目数量更改时有变化的字符串。 在英语中你有“一个评论”和“两个意见”。 在其他语言中,您可以有多个复数形式。 要在WordPress中处理这个问题,可以使用_n()函数。 ``` printf( _n( '%s comment', '%s comments', get_comments_number(), 'my-plugin' ), number_format_i18n( get_comments_number() ) ); ``` _n() 接受4个参数: - singular – 字符串的单数形式(注意,它可以用于某些语言中的一个以外的数字,因此应使用“%s项”而不是“一个项”) - plural – 字符串的复数形式 - count – 对象的数量,这将决定是否应该返回单数或复数形式(有多种语言,有两种以上的形式) - text domain – 插件文本域 功能的返回值是正确的翻译形式,对应于给定的计数。 ##稍后完成 您首先使用_n_noop()或_nx_noop()设置多个字符串。 ``` $comments_plural = _n_noop( '%s comment.', '%s comments.' ); ``` 然后在稍后的代码中,您可以使用translate_nooped_plural()来加载字符串。 ``` printf( translate_nooped_plural( $comments_plural, get_comments_number(), 'my-plugin' ), number_format_i18n( get_comments_number() ) ); ``` ## 背景消歧 有时一个术语在多个语境中被使用,虽然它是英文中同一个词,但是在其他语言中它必须被不同地翻译。 例如,Post可以用作动词“点击这里发表你的评论”,作为名词“编辑这篇文章”。 在这种情况下,应该使用_x()或_ex()函数。 它类似于__()和_e(),但它有一个附加的参数 - 上下文: ``` _x( 'Post', 'noun', 'my-plugin' ); _x( 'Post', 'verb', 'my-plugin' ); ``` 在这两种情况下使用此方法,我们将获得原始版本的字符串注释,但翻译器将看到两个用于翻译的注释字符串,每个字符串在不同的上下文中。 >[info] 请注意,与`__()`类似,`_x()`具有回调版本:`_ex()`。 前面的例子可以写成: ``` _ex( 'Post', 'noun', 'my-plugin' ); _ex( 'Post', 'verb', 'my-plugin' ); ``` 使用您觉得增强易读性和易于编码的任何一个。 ##说明 所以翻译人员知道如何翻译一个字符串__('g:i:s a'),你可以在源代码中添加一个澄清的注释。 它必须从翻译人员开始:在gettext调用之前成为最后一个PHP注释。 这是一个例子: ``` /* translators: draft saved date format, see http://php.net/date */ $saved_date_format = __( 'g:i:s a' ); ``` 它还用于解释字符串中的占位符,如_n_noop(`<strong>版本%1 $ s </ strong>`已解决%2 $ s错误,`<strong>版本%1 $ s </ strong>` “解决了%2 $ s的错误”)。 ``` /* translators: 1: WordPress version number, 2: plural number of bugs. */ _n_noop( '<strong>Version %1$s</strong> addressed %2$s bug.', '<strong>Version %1$s</strong> addressed %2$s bugs.' ); ``` ## 换行字符 Gettext不喜欢\ r(ASCII码:13)在可翻译的字符串,所以请避免它,并使用\ n代替。 ##空字符串 空字符串保留用于内部Gettext使用,您不得尝试将空字符串国际化。 它也没有任何意义,因为翻译者不会看到任何上下文。 如果您有一个有效的用例来使一个空字符串国际化,请添加上下文以帮助翻译人员,并与Gettext系统保持一致。 ## 处理JavaScript文件 使用wp_localize_script()将已翻译的字符串或其他服务器端数据添加到先前排入的脚本。 ##转义字符串 逃避所有的字符串是好的,这样翻译者就不能运行恶意代码。 有几个与国际化功能相结合的逃生功能。 ##本地化功能 ##基本功能 - __() - _e() - _x() - _ex() - _n() - _nx() - _n_noop() - _nx_noop() - translate_nooped_plural() ##翻译和退出功能 必须转义需要翻译并在html标签的属性中使用的字符串。 - esc_html__() - esc_html_e() - esc_html_x() - esc_attr__() - esc_attr_e() - esc_attr_x() ## 日期和数字功能 - number_format_i18n() - date_i18n() ## 写字符串的最佳做法 以下是编写字符串的最佳做法 - 使用体面的英式风格 - 尽量减少俚语和缩写。 - 使用整个句子 - 在大多数语言中,单词顺序与英语不同。 - 拆分段落 - 合并相关句子,但不要在一个字符串中包含整个文本页面。 - 不要将前导或尾随空格留在可翻译的短语中。 - 假设翻译时字符串的长度可以翻倍 - 避免不正常的标记和不寻常的控制字符 - 不要包含文本周围的标签 - 不要将不必要的HTML标记放入已翻译的字符串中 - 不要留下翻译的网址,除非他们可以使用其他语言的版本。 - 将变量作为占位符添加到字符串中,如在某些语言中,占位符更改位置。 ``` printf( __( 'Search results for: %s', 'my-plugin' ), get_search_query() ); ``` 使用格式字符串而不是字符串连接 - 翻译短语而不是单词 - ``` printf( __( 'Your city is %1$s, and your zip code is %2$s.', 'my-plugin' ), $city, $zipcode ); ``` 总是比: ``` __( 'Your city is ', 'my-plugin' ) . $city . __( ', and your zip code is ', 'my-plugin' ) . $zipcode; ``` 尝试使用相同的单词和相同的符号,因此不需要翻译多个字符串,例如`__('Posts:','my-plugin');`和`__('Posts','my-plugin');` ##将文本域添加到字符串 您必须将您的文本域作为参数添加到每个__(),_e()和__n()gettext调用中,否则您的翻译将无法正常工作。 例子: ``` __( 'Post' ) ``` 应该成为 ``` __( 'Post', 'my-theme' ) ``` ``` _e( 'Post' ) ``` 应该成为 ``` _e( 'Post', 'my-theme' ) ``` ``` _n( 'One post', '%s posts', $count ) ``` 应该成为 ``` _n( 'One post', '%s posts', $count, 'my-theme' ) ``` 如果您的插件中也有用于WordPress核心的字符串(例如“设置”),那么您还应该添加自己的文本域,否则如果核心字符串发生变化(如果发生),那么它们将变为非翻译。 手动添加文本域可能是一个负担,如果不是在编写代码时连续完成,这就是为什么你可以自动执行: 如果您的插件位于WordPress.org插件目录中,请转到您的“管理”页面,然后滚动到“添加域到Gettext呼叫”。 上传要添加文本域的文件。 点击“获取域文件”。 WordPress.org Plugin Admin区域 WordPress.org Plugin Admin区域 除此以外: 将add-textdomain.php脚本下载到要添加文本域的文件夹 在命令行中移动到文件所在的目录 运行此命令创建一个添加了文本域的新文件 ``` php add-textdomain.php my-plugin my-plugin.php > new-my-plugin.php ``` 如果您希望将add-textdomain.php放在不同的文件夹中,那么您只需要在命令中定义位置。 ``` php \path\to\add-textdomain.php my-plugin my-plugin.php > new-my-plugin.php ``` 如果您不想输出新文件,请使用此命令。 ``` php add-textdomain.php -i my-plugin my-plugin.php ``` 如果要更改目录中的多个文件,还可以将目录传递给脚本。 ``` php add-textdomain.php -i my-plugin my-plugin-directory ``` 完成后,文本域将被添加到文件中所有gettext调用的末尾。 如果存在现有的文本域,则不会被替换。 ## 加载文本域 >[warning] 注意:WordPress 4.6出来之后,翻译现在以translate.wordpress.org为优先,因此通过translate.wordpress.org翻译的插件不再需要load_plugin_textdomain()了。 如果您不想在您的插件中添加一个load_plugin_textdomain()调用,则必须将readme.txt中的至少要求至少为:。 您需要使用插件的翻译加载MO文件。 您可以通过调用函数load_plugin_textdomain()来加载它们。 此调用从插件的基本目录载入{text-domain} - {locale} .mo。 语言环境是常规设置下的站点语言设置的语言代码和/或国家/地区代码。 有关语言和国家/地区代码的更多信息,请参阅您的语言中的WordPress。 从上面的代码示例,文本域是my-plugin,因此德语MO和PO文件应该命名为my-plugin-de_DE.mo和my-plugin-de_DE.po。 例: ``` function my_plugin_load_plugin_textdomain() { load_plugin_textdomain( 'my-plugin', FALSE, basename( dirname( __FILE__ ) ) . '/languages/' ); } add_action( 'plugins_loaded', 'my_plugin_load_plugin_textdomain' ); ``` ## 语言包 如果您对语言包感兴趣,以及如何进行translate.wordpress.org的导入,请阅读关于翻译的Meta手册页面。