WordPress插件開發(fā)教程手冊 — 國際化和本地化
本文詳細(xì)介紹了WordPress插件開發(fā)中的國際化和本地化過程,解釋了i18n和l10n的概念及其重要性。文章還提供了生成POT、PO和MO文件的方法,幫助開發(fā)者輕松實(shí)現(xiàn)插件多語言支持,擴(kuò)展全球市場。
國際化
什么是國際化?
國際化是插件開發(fā)的一個過程,國際化后,插件可以很方便的翻譯成其他語言,國際化通??s寫為 i18n(Internationalization 中的第一個字母 i 和最后一個字母 n 中間有 18 個字母)。
為什么要進(jìn)行國際化
WordPress 在世界各地使用,很多國家的主要語言不是英語,WordPress插件中的字符需要用特殊的方式進(jìn)行編碼,以便可以很容易翻譯成其他語言。作為開發(fā)者,我們不可能為所有的用戶提供本地化服務(wù),插件進(jìn)行了國際化后,使用各種語言的翻譯者不用修改代碼就可以為插件或主題提供本地化翻譯。
進(jìn)一步了解國際化可以閱讀 “怎么國際化我們的插件文章“。
資源
- Video: i18n: Preparing Your WordPress Theme for the World
- Video: On Internationalization: Plugins and themes for the whole worldSlides
- Video: Big in Japan: A Guide for Themes and Internationalization
- Video: Lost in Translation—i18n and WordPress
- Internationalizing And Localizing Your WordPress Theme
- Internationalization: You’re probably doing it wrong
- More Internationalization Fun
- Use wp_localize_script, It Is Awesome
- Understanding _n_noop()
- Language Packs 101 – Prepwork
- Translating WordPress Plugins and Themes: Don’t Get Clever
- How to load theme and plugin translations
本地化
什么是本地化?
本地化是插件國際化之后,翻譯為各種本地語言的過程,本地化的縮寫為 l10n (localization 第一個字母 l 和最后一個字母 n 之間有 10 個字母)。
本地?fù)Q文件
POT (Portable Object Template,便攜對象模版) 文件
該文本包含插件中的原始字符串(英文),下面是一個 POT 文件的片段。
#: plugin-name.php:123
msgid Page Title
msgstr
PO (Portable Object 便攜對象) 文件
每個翻譯者都將使用 POT 文件,把 msgstr 部分翻譯為自己的語言。翻譯的結(jié)果就是 PO 文件,PO 文件的格式和 POT 文件相同,但帶有翻譯后的字符串和一些特定的頭信息,每種語言都有一個對應(yīng)的 PO 文件。
MO (Machine Object 機(jī)器對象) 文件
每個翻譯后的 PO 文件最終都會被 msgfmt 工具編譯成 MO 文件。MO 文件是供機(jī)器讀取的二進(jìn)制文件,由 gettext 函數(shù)使用(機(jī)器不關(guān)心 PO 和 POT 文件)。根據(jù)需要,應(yīng)用程序中多個不同的模塊可以使用自己的 MO 文件(比如 WordPress 內(nèi)核、插件、主題都有自己的 MO 文件),各個模塊之間通過文本域(text domain)區(qū)分。
生成 POT 文件
POT 文件是我們需要交給翻譯人員的文件,以便他們根據(jù)此文件進(jìn)行翻譯,POT 和 PO 文件可以很容易的進(jìn)行轉(zhuǎn)換,直接修改文件名就可以了。把 POT 文件包含在插件中通常是一個不錯的做法,這樣翻譯人員就可以直接使用該文件進(jìn)行翻譯了,有幾種方法可以為我們的插件生成一個 POT 文件。
插件目錄管理工具
如果我們的插件托管在 WordPress.org 插件目錄,打開插件的 “Admin” 頁面,然后在 “Generate POT file” 區(qū)域,點(diǎn)擊 ‘Continue’ 按鈕。

然后點(diǎn)擊 Get POT 按鈕下載 POT 文件。

WordPress i18n 工具
如果我們的插件不在 WordPress插件目錄中,我們可以可以中 SVN 中檢出 WordPress Trunk 目錄(使用方法參見 Using Subversion 文章)。我們需要檢出整個主干,因?yàn)?nbsp;wordpress-i18n 工具 使用 WordPress 核心代碼來生成 POT 文件。運(yùn)行下面的命令之前,我們需要安裝 gettext(GNU國際化實(shí)用程序)工具和 PHP。
打開命令行并切換到插件的 language 文件夾。
cd plugin-name/languages
然后,使用下面命令生成 POT 文件
php path/to/makepot.php wp-plugin path/to/your-plugin-directory
使用 Poedit 軟件
翻譯插件時,我們可以使用 Poedit 軟件,這是一個開軟的翻譯工具,支持所有主流操作系統(tǒng)。免費(fèi)版本支持使用 Gettext 函數(shù)手動掃描所有源代碼。專業(yè)版還可以幫我們掃描 WordPress插件并生成 POT 文件,在保存的時候,Poedit 會自動幫我們編譯 MO 文件,該文件不是必須的,我們可以刪除這個文件。如果不像買專業(yè)版,我們可以下載一個空白 POT 文件,把空白 POT 文件放入語言文件夾,然后點(diǎn)擊 Poedit 中的 “更新” 按鈕來掃描插件文件更新 POT 文件。Poedit 的界面如下。

Grunt 任務(wù)
如果我么之前使用過 Grunt,有一些 Grunt 任務(wù)可以幫助我們創(chuàng)建 POT 文件. grunt-wp-i18n 和 grunt-pot,使用這些工具我們需要安裝 node.js。然后在插件目錄中安裝 Grunt 工具。安裝通過命令行完成. 這里有一個Grunt.js 和 package.json 模版,我們可以放到插件的根目錄中,然后我們可以使用一個簡單的命令生成 POT 文件。
翻譯 PO 文件
有很多種方式來翻譯 PO 文件。
我們可以直接在文本編輯器中翻譯。比如,未翻譯的 PO 文件片段如下:
#: plugin-name.php:123
msgid Page Title
msgstr
翻譯的時候,我們直接把譯文輸入到 msgstr 的引號中間就可以了,如下:
#: plugin-name.php:123
msgid Page Title
msgstr 頁面標(biāo)題
我們也可以使用 Poedit 軟件打開 PO 文件直接翻譯。
除了在本地翻譯 PO 文件,我們還可以使用一些在線翻譯服務(wù)。整體思路是上傳 POT 文件,然后授權(quán)用戶或翻譯人員翻譯我們的插件。這中方法可以保持我們的翻譯始終是最新的,避免重復(fù)翻譯。
Fran?ois-XavierBénard 正在運(yùn)行 WP-Translations,一個 “譯者與開發(fā)人員會面” 的社區(qū)。它在 Transifex 上運(yùn)行,你可以作為開發(fā)者提交翻譯項(xiàng)目讓翻譯人員翻譯,或者把現(xiàn)有的插件或主題翻譯為自己的語言。
下面是其他可以用來在線翻譯 POT 文件的工具。
我們甚至可以使用 WordPress插件來進(jìn)行翻譯。
翻譯后的文件將被保存為 my-plugin-{locale}.mo 文件,locale 是我們在 wp-config.php 中定義的語言代碼/國家代碼,例如,簡體中文的語言環(huán)境是 zh_CN,在上面的示例中,文本域是 my-plugin,那么簡體中文的 PO 和 MO 文件應(yīng)該為 my-plugin-zh_CN.po 和 my-plugin-zh-CN.mo。有關(guān)語言和國家代碼的更多信息,請參閱以您的語言安裝 WordPress。
生成 MO 文件
通過命令行
我們使用 msgfmt 來生成 MO 文件。 msgfmt 是 Gettext 工具包的一部分。否則,典型的 msgfmt 命令使用方法如下:
msgfmt -o filename.mo filename.po
如果我們有很多語言的 PO 文件需要生成,可以使用 bash 命令批量操作。
# Find PO files, process each with msgfmt and rename the result to MO
for file in `find . -name *.po` ; do msgfmt -o ${file/.po/.mo} $file ; done
使用 Poedit
Poedit 軟件集成了 msgfmt,可以讓我們來生成 MO 文件,我們可以在軟件設(shè)置中啟用這禁用這個功能。

Grunt 命令
有一個 grunt-po2mo 可以幫我們轉(zhuǎn)換所有 PO 文件。
良好翻譯小提示
不要直譯,要意譯
每種語言都有不同的語言習(xí)慣和結(jié)構(gòu),翻譯為中文的時候,我們不應(yīng)該按照英文的語言結(jié)構(gòu)來做翻譯,應(yīng)該提取英文所表達(dá)的意思,然后用自然的中文表達(dá)出來。不要使用直接復(fù)制機(jī)器翻譯工具的翻譯結(jié)果,機(jī)器翻譯目前還沒有發(fā)展到能夠照顧到我們語言習(xí)慣的程度。
盡量保持同樣的翻譯風(fēng)格
每條語句都可以是非正式的或正式的,太正式的語氣會讓用戶有距離感,太不正式的語氣又會讓用戶覺得不嚴(yán)謹(jǐn)。WordPress 中的用于傾向于保持有禮貌的非正式語氣,在翻譯的時候,我們可以使用同樣感覺的語氣。
不要使用俚語或方言詞匯
一些俚語或方言詞匯,離開了某個地方,能聽懂的人就比較少了,在 WordPress 中,盡量不要使用這樣的詞匯來翻譯,因?yàn)?WordPress 是一個國際化的平臺,世界各地都有人在使用。如果有一些術(shù)語很難翻譯,保持原樣會讓使用者更加容易理解。比如 WordPress 中的 pingback、trackback 或 feed 等。
參考其他主題或插件的本地化翻譯
如果我們剛接觸 WordPress 本地化,或者對本地化用語沒有把握,可以參考 WordPress 核心、或者其他優(yōu)秀主題、插件的本地化翻譯,看他們是如何對一些字段進(jìn)行翻譯的。
使用本地化文件
我們可以把本地化文件放到插件目錄中,WordPress 3.7 以后,我們也可以把翻譯文件提取出來,放到 WordPress 的 wp-content/languanges 目錄中,后者可以避免自定義翻譯文件在插件更新時被覆蓋。
從 WordPress 4.0 開始,我們可以在 “常規(guī)設(shè)置” 中更改語言,如果在選項(xiàng)中看不到自己需要的語言,說明語言文件沒有下載。比如我們想切換到法語,可以通過下面幾個步驟實(shí)現(xiàn)。
- 在 wp-config.php 文件中定義需要使用的語言代碼常量 WPLANG ,如,我們需要切換到法語,在 wp-config.php 中加入 define (‘WPLANG’, ‘fr_FR’);
- 然后打開 wp-admin/options-general.php 或 “設(shè)置” -> “常規(guī)”
- 在 “站點(diǎn)語言” 下拉選項(xiàng)中選擇我們需要的語言
- 開發(fā) wp-admin/update-core.php
- 點(diǎn)擊 “更新翻譯”
- WordPress 會幫我們下載對應(yīng)的語言文件
資源
- 為主題或插件創(chuàng)建 POT 文件
- 怎么國際化 WordPress插件
- 翻譯WordPress主題
- 空白 WordPress POT 文件
- 增強(qiáng)的 WordPress i18n 工具
- 怎么快速更新翻譯
- GitHub/Transifex 協(xié)同工作流程
- Gist: 完整的本地化 Grunt 任務(wù)
- WordPress.tv 標(biāo)簽: i18n, internationalization 和 translation
怎么國際化插件
為了讓我們程序中的字符可以翻譯為其他語言,我們需要將原始字符放到一個特殊函數(shù)中。
Gettext 函數(shù)
WordPress 使用 i18n 的 gettext 庫和工具來實(shí)現(xiàn)國際化,如果我們在代碼中看到 _() 函數(shù),該函數(shù)使用的就是本地的 PHP Gettext 兼容翻譯功能。在 WordPress 中,我們應(yīng)該使用WordPress 定義的 __() 函數(shù),如果我們想獲得更廣泛更深入的 Gettext 功能,建議閱讀一下 Gettext 手冊。
文本域
一個文本可能在多個主題或插件中出現(xiàn),我們使用文本域來區(qū)分這些文本的來源,文本域是一個唯一標(biāo)識符,用來確保 WordPress 可以區(qū)分加載的所有翻譯。這種機(jī)制增強(qiáng)了可移植性,可以更好的和現(xiàn)有的 WordPress 工具結(jié)合。插件的文本域必須和插件的 Slug 相同,如果我們的插件主文件為 my-plugin.php 文件,或者包含在一個名為 my-plugin.php 文件夾中,文本域應(yīng)該是 my-plugin。如果我們的插件托管在 wordpress.org,文本域必須是插件 URL(wordpress.org/plugins/<slug>)中的 <slug>,文本域必須使用英文破折號而不是下劃線。
字符串示例:
__( 'String (text to be internationalized)', 'text-domain' );
在實(shí)際的代碼中,需要修改 “text-domain” 為我們的插件 slug。
文本域同時需要添加到插件頭,及時在插件被禁用的情況下,WordPress 也會使用他來實(shí)現(xiàn)元數(shù)據(jù)的國際化。文本域應(yīng)該與 加載文本域 中使用的相同。示例如下:
/*
* Plugin Name: My Plugin
* Author: Plugin Author
* Text Domain: my-plugin
*/
文本域路徑
我們需要設(shè)置一個文本域路徑,以便 WordPress 知道在插件停用時從哪里可以找到翻譯,文本域路徑僅在插件使用單獨(dú)的語言文件夾時才有用。例如,如果 .mo 文件位于插件的 languages 文件夾中,Domain Path 應(yīng)該寫成 “/languages”,路徑的第一個字符必須為 /,代表插件的根目錄。示例如下:
/*
* Plugin Name: My Plugin
* Author: Plugin Author
* Text Domain: my-plugin
* Domain Path: /languages
*/
基本字符串
在 WordPress 國際化的時候,我們使用最多的是 __() 函數(shù),用來返回參數(shù)的翻譯:
__( 'Blog Options', 'my-plugin' );
另外一個比較常用的是 _e() 函數(shù),用來直接輸入?yún)?shù)的翻譯,相當(dāng)于是下面代碼的一個快捷方式。
echo __( 'WordPress is the best!', 'my-plugin' );
可以直接寫成:
_e( 'WordPress is the best!', 'my-plugin' );
變量
如果我們需要在字符串中使用變量,需要使用占位符來代替變量。如下面的代碼:
echo 'Your city is $city.'
在國際化的時候,我們需要使用 printf 和 sprintf 來輸入帶變量的字符串。如下:
printf(
/* translators: %s: Name of a city */
__( 'Your city is %s.', 'my-plugin' ),
$city
);
注意,上面的字符串中,可以翻譯的只是字符串中不包含占位符的部分,占位符 %s 在翻譯時保持不變,頁面中顯示時,所代表的字符串也不變。
如果我們的字符串中有多個占位符,可以使用參數(shù)交換,在這種情況下,必須使用單引號,雙引號會把 $s 當(dāng)作 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
);
在上面的代碼中, % 和 $ 中間的數(shù)字代表后面變量的位置,%1$s 對應(yīng) $city, %2$s 對應(yīng) $zipcode,有時候,我們需要把后面變量 $zipcode 顯示在前面, 這種情況下,交互一下翻譯模版中 %1$s 和 %2$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' );
翻譯字符串是從源代碼中提取的,所以翻譯人員翻譯的時候會看到 Your city is $city. 的源字符串。
在應(yīng)用程序中,如果翻譯函數(shù) _e() 找不到源字符串對應(yīng)的翻譯,顯示的時候會直接使用源字符串。如 “Your city is London”,而翻譯人員翻譯的時候沒有翻譯這個字符串,gettext 函數(shù)會直接返回這個字符串。
復(fù)數(shù)
基本復(fù)數(shù)
如果我們的字符串在數(shù)量為復(fù)數(shù)是發(fā)生變化。比如在英文中的 One comment 和 Two comments,在其他語言中,可能會有更多復(fù)數(shù)形式。在 WordPress 國際化和本地化的時候,我們可以使用_n() 函數(shù)。
printf(
_n(
'%s comment',
'%s comments',
get_comments_number(),
'my-plugin'
),
number_format_i18n( get_comments_number() )
);
_n() 函數(shù)接受 4 個參數(shù):
- singular –字符串的單數(shù)形式(請注意,在某些語言中,可以用數(shù)字以為的字符表示,所以 ‘%s item’ 應(yīng)該寫成 ‘One item’)
- plural – 字符串的復(fù)數(shù)形式
- count – 對象的數(shù)量,這將決定返回單數(shù)或復(fù)數(shù)形式(有些語言中,有兩種以上的形式)
- text domain – 插件的文本域
函數(shù)會根據(jù)函數(shù)指定的數(shù)量確定返回值是單數(shù)還是復(fù)數(shù)形式。
推遲的復(fù)數(shù)形式
首先,我們需要使用 _n_noop() 或 _nx_noop() 設(shè)置復(fù)數(shù)字符串。
$comments_plural = _n_noop(
'%s comment.',
'%s comments.'
);
在稍后的代碼中,我們可以使用 translate_nooped_plural() 函數(shù)來皆在字符串。
printf(
translate_nooped_plural(
$comments_plural,
get_comments_number(),
'my-plugin'
),
number_format_i18n( get_comments_number() )
);
上下文消除歧義
有時候,一個字符串可能會在多個語境中使用,盡管該字符串是相同的,他們表達(dá)的意思卻不同,在其他語言中對應(yīng)的翻譯也不同。舉個例子,Post 這個詞,既可以作為動詞使用 “Click here to post comment”,也可以作為名詞使用 “Edit the post”,在這種情況下,我們應(yīng)該使用 _x() 或 _ex() 函數(shù),這兩個函數(shù)類似于 __() 和 _e(),但是有一個附加的語境參數(shù)。如下:
_x( 'Post', 'noun', 'my-plugin' );
_x( 'Post', 'verb', 'my-plugin' );
這個語境參數(shù)會作為注釋顯示給翻譯人員,翻譯人員翻譯的時候,會根據(jù)這個注釋,選擇合適的翻譯本文。
和 __(), _x() 一樣,echo _x 可以直接寫為 _ex(),上面的例子在直接輸出的時候,可以直接寫為:
_ex( 'Post', 'noun', 'my-plugin' );
_ex( 'Post', 'verb', 'my-plugin' );
翻譯說明
有時候,翻譯人員會不明白某些字符串所表達(dá)的意思,我們需要在代碼中添加說明來幫助翻譯人員理解,增加翻譯說明的方法是在翻譯字符串的前面一行加一個 PHP 當(dāng)行注釋,注釋以字符 “translators:” 開頭,示例如下:
/* translators: draft saved date format, see http://php.net/date */
$saved_date_format = __( 'g:i:s a' );
翻譯注釋也可以用來解釋字符串中的占位符,如下:
/* 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.' );
換行符
在字符串需要標(biāo)記另起一行的時候,使用換行符號 \n,不要使用 \r,在 Gettext 中使用這個字符換行會有問題。
空字符串
空字符串是 Gettext 中的內(nèi)部保留字符,所以不要嘗試國際化一個空字符串,也不需要這樣做,因?yàn)榧幢惴g了,用戶看到的效果也是一樣的。如果我們有一個有效的用例來使一個空字符串國際化,則可以同時添加上下文來幫助譯員,并與Gettext系統(tǒng)保持和諧。
處理 JavaScript 文件
JavaScript 是在前端運(yùn)行的,所以我們沒辦使用 Gettext 來國際化 JavaScript 文件,如果需要,使用 wp_localize_script() 來添加翻譯字符串到前端,然后通過 JavaScript 的國際化方法來對 JavaScript 文件進(jìn)行國際化。
轉(zhuǎn)義字符
轉(zhuǎn)義所有的字符串是好事,這樣翻譯者就沒有機(jī)會運(yùn)行惡意代碼。WordPress 提供了一些與國際化相結(jié)合的轉(zhuǎn)義函數(shù)。
基本函數(shù)
翻譯并轉(zhuǎn)義的函數(shù)
用于 HTML 標(biāo)簽屬性的字符串必須被轉(zhuǎn)義,國際化的時候也一樣,使用下面的函數(shù)確保這些字符在國際化的時候被轉(zhuǎn)義。
- esc_html__()
- esc_html_e()
- esc_html_x()
- esc_attr__()
- esc_attr_e()
- esc_attr_x()
日期和數(shù)字函數(shù)
撰寫字符串的最佳實(shí)踐
下面是一下撰寫國際化字符串的最佳實(shí)踐
- 使用正式英式風(fēng)格 – 盡量不要使用俚語和縮寫。
- 使用整個句子 – 在大多數(shù)語言中,詞序與英語中的不同。
- 合并相關(guān)句子,但不要在一個字符串中包含整個頁面的文本。
-
不要將前導(dǎo)或尾隨空白留在可翻譯的短語中。
- 假設(shè)翻譯時,字符串的長度會加倍
- 避免不常用的標(biāo)記和不常用的控制字符 – 不要包含文字周圍的標(biāo)簽
-
不要將不必要的HTML標(biāo)記放入翻譯的字符串中
- 除非可以使用其他語言的版本,否則不要在字符中包含 URL。
- 將變量作為占位符添加到字符串中,就像在某些語言中占位符更改位置一樣。
- 使用格式字符串,而不是字符串連接 – 翻譯短語而不是單詞
- 不同位置相同的字符串只需要翻譯一個,使用相同的單詞和符號,可以減少字符串?dāng)?shù)量,減少翻譯人員的工作量例如。如:
__( 'Posts:', 'my-plugin' );和__( 'Posts', 'my-plugin' );
加載文本域帶字符串
我們必須把文本域添加在 __(), _e() 和 __n() 等國際化函數(shù)中,否則我們的翻譯不會工作。如:__( 'Post' ) 應(yīng)該為 __( 'Post', 'my-theme' )
如果插件中的字符串也在 WordPress 核心中使用(如 “Settings”,我們也需要添加自己的文本域到國際化函數(shù)),否則如果 WordPress 核心字符串發(fā)生了變化,我們的字符串會變成未翻譯的了。
在編寫代碼時不斷地添加文本域可能是一個負(fù)擔(dān),我們可以自動執(zhí)行該操作:
- 如果我們的插件位于 WordPress.org 插件目錄中,轉(zhuǎn)到 “管理” 頁面,滾動到 “Add Domain to Gettext Calls”。
- 上傳要需要添加文本域的文件。
- 然后點(diǎn)擊 “Get domainified file”。

另外,我們也可以通過下面的方法在本地添加。
- 下載
add-textdomain.php文件到我們想要添加文本域的文件夾中。 - 運(yùn)行下面的命令 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
完成后,文本域?qū)⒈惶砑拥剿?gettext 函數(shù)的結(jié)尾。如果有一個現(xiàn)有的文本域,上面的命令不會替換他。
加載文本域
最后,我們需要在插件中通過load_plugin_textdomain() 加載翻譯后的 MO 文件,該函數(shù)從我們的指定插件文件夾中加載 {text-domain}-{locale}.mo,locale 是 WordPress 設(shè)置的國家/地區(qū)代碼,有關(guān)語言和國家代碼的更多信息,請參閱以您的語言安裝 WordPress。
在上面的代碼示例中,文本域是 my-plugin,因此簡體中文的 MO 和 PO 文件應(yīng)該被命名為 my-plugin-zh_CN.mo 和 my-plugin-zh_CN.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' );
語言包
如果您對語言包感興趣,以及怎么將語言包導(dǎo)入到 translate.wordpress.org 中,請閱讀 關(guān)于翻譯的 Meta Handbook 頁面。
國際化安全問題
在進(jìn)行 WordPress 國際化時,安全問題往往會被忽視,有一些重要事項(xiàng)需要在這里提一下。
檢查垃圾信息和其他惡意字符串
翻譯人員向我們提交本地化信息時,要確認(rèn)一下,他們的翻譯中是否包含垃圾廣告信息和其他惡意字符串,我們可以使用 Google 翻譯將其翻譯為我們的母語,然后比較一下原始字符串和翻譯后的字符串。
轉(zhuǎn)義國際化字符串
我們不能相信翻所有開發(fā)者只會添加正常的翻譯文字,如果有一些開發(fā)者不懷好意,他們可以添加具有破壞性的 JavaScript 或其他代碼。為了防止這種情況,我們需要向處理其他用戶輸入一樣處理國際化字符串。
如果我們需要輸入字符串,我們應(yīng)該在輸入的時候進(jìn)行轉(zhuǎn)義。
不安全的:
<?php _e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' ); ?>
安全的:
<?php esc_html_e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' ); ?>
另外,有些開發(fā)者選擇依靠翻譯驗(yàn)證機(jī)制而不是轉(zhuǎn)義來避免這個問題,一個例子就是給予 WordPress Polyglotes 團(tuán)隊(duì)在 translate.wordpress.org 的編輯角色。這樣做會確保不受信任的貢獻(xiàn)者提交的任何翻譯在被接受之前都已經(jīng)被受信任的翻譯人員驗(yàn)證過了。
對 URL 使用占位符
不要在國際化字符串中包含網(wǎng)址,因?yàn)椴粦押靡獾姆g人員可能會把這些網(wǎng)站修改掉,指向其他網(wǎng)址。正確的做法是使用 printf() 或 sprintf()占位符。
不安全的做法:
<?php _e(
'Please <a href=https://wordpress.org/support/register.php>
register for a WordPress.org account</a>.',
'your-text-domain'
); ?>
安全的做法:
<?php printf(
__(
'Please <a href=%s>register for a WordPress.org account</a>.',
'your-text-domain'
),
'https://wordpress.org/support/register.php'
); ?>
編譯自己的 MO 文件
翻譯人員通常會把翻譯后的 MO 文件和 PO 文件一起發(fā)送給我們,我們應(yīng)該丟棄他們的 MO 文件,而自己編譯一份。因?yàn)?MO 文件是二進(jìn)制的,我們無法查看他們發(fā)送的 MO 文件是由相同的 PO 文件編譯的,還是由包含垃圾信息和其他惡意字符串的 PO 文件翻譯的。
使用 Poedit 生成的二進(jìn)制文件將覆蓋 .po 文件中的頭信息,所以最好使用命令行編譯。
msgfmt -cv -o /path/to/output.mo /path/to/input.po