## 什么是國際化?
國際化是開發您的主題的過程,因此可以很容易地將其翻譯成其他語言。 國際化通常縮寫為i18n(因為i和n之間有18個字母)。
## 為什么國際化很重要?
WordPress在世界各地使用,這是一個很好的主意,準備WordPress主題,以便他們可以很容易地翻譯成其他語言。 作為開發人員,您可能沒有一個輕松的時間為所有用戶提供本地化,但是任何翻譯人員都可以在不修改源代碼的情況下成功本地化主題。
## 如何使您的主題國際化?
要使您的應用程序中的字符串可以翻譯,您必須將原始字符串打包到一組特殊功能的調用中。
## Gettext簡介
WordPress使用i18n的gettext庫和工具。 請注意,如果您在線查看,您將看到`_()`函數,它引用了本機PHP gettext兼容的翻譯函數,而是使用WordPress,您應該使用`_()`WordPress定義的PHP函數。 如果您想獲得更廣泛和更深入的gettext視圖,我們建議您閱讀gettext在線手冊。
## 文字域
您需要使用文本域來表示屬于該主題的所有文本。 文本域是唯一的標識符,可以確保WordPress能夠區分所有加載的翻譯。 這增加了可移植性,并且已經存在的WordPress工具更好。
文本域必須匹配主題的塊。 如果您的主題名稱My Theme在style.css中定義,或者它包含在名為my-theme的文件夾中,則域名應該是my-theme。 文本域名必須使用破折號而不是下劃線并且小寫。
字符串示例:
```
__( 'text', 'text-domain' );
```
```
__( 'String or text to be internationalized', 'text-domain' );
```
將“文本域”更改為主題。
文本域也需要添加到style.css標題中。 即使主題被禁用,WordPress也會使用它來國際化您的主題元數據。 文本域應與加載文本域時使用的文本域相同。
標題示例:
```
/*
* Theme Name: My Theme
* Author: Theme Author
* Text Domain: my-theme
*/
```
## 域路徑
域路徑被使用,所以當主題被禁用時,WordPress知道在哪里找到翻譯。
僅當翻譯位于語言文件夾中被命名為不同于語言的語言文件夾時才有用。 例如,如果.mo文件位于languages文件夾中,則Domain Path將是/languages,必須用第一個斜杠寫入。 默認為主題中的languages文件夾。
標題示例:
```
/*
* Theme Name: My Theme
* Author: Theme Author
* Text Domain: my-theme
* Domain Path: /languages
*/
```
## 基本字符串
最常用的函數是`__()`。 它返回其參數的翻譯:
```
__( 'Blog Options', 'my-theme' );
```
另一個簡單的是`_e()`,它輸出其參數的翻譯。 而不是寫:
```
echo __( 'WordPress is the best!', 'my-theme' );
```
你可以使用較短的:
```
_e( 'WordPress is the best!', 'my-theme' );
```
## 變量
如果您使用字符串中的變量,類似于下面的示例,您需要使用占位符。
```
echo 'Your city is $city.'
```
使用printf系列函數。 特別有用的是printf和sprintf。 例如:
```
printf(
__( 'Your city is %s.', 'my-theme' ),
$city
);
```
>[warning] 請注意,用于翻譯的字符串是“您的城市是%s”的模板,源和運行時都是相同的。
如果字符串中有多個占位符,建議您使用參數交換。 在這種情況下,單引號(')是必需的:雙引號(“)告訴PHP將$s解釋為s變量,這不是我們想要的。
```
printf(
__( 'Your city is %1$s, and your zip code is %2$s.', 'my-theme' ),
$city,
$zipcode
);
```
這里的郵政編碼顯示在城市名稱之后。 在某些語言中,以相反的順序顯示郵政編碼和城市是比較合適的。 使用%s前綴,如上例所示,允許這樣做。 翻譯可以寫成:
```
printf(
__( 'Your zip code is %2$s, and your city is %1$s.', 'my-theme' ),
$city,
$zipcode
);
```
以下示例告訴您什么不做
>[warning] 警告:這是不正確的。
```
// 這不正確不要使用。
_e( 'Your city is $city.', 'my-theme' );
```
用于翻譯的字符串從源中提取而不執行與之關聯的PHP。 例如:變量$ city可能是溫哥華,所以當模板運行時,你的字符串將會顯示為“你的城市是溫哥華”,但是gettext不會提前知道PHP變量里面是什么。
由于當您的字符串被翻譯時變量的值是未知的,所以需要翻譯器知道變量$ country的每個案例。 這不是理想的,最好刪除動態內容,并允許翻譯者專注于靜態內容。
## 基本多元化
如果您的項目數量更改時有一個字符串更改。 在英語中你有“一個評論”和“兩個意見”。 在其他語言中,您可以有多個復數形式。 要在WordPress中處理這個問題,可以使用`_n()`函數。
```
printf(
_n(
'One comment',
'%s comments',
get_comments_number(),
'my-theme'
),
number_format_i18n( get_comments_number() )
);
```
`_n()` 接受4個參數:
- singular – 字符串的單數形式
- plural – 字符串的復數形式
- count – 對象的數量,這將決定是否應該返回單數或復數形式(有多種語言,有兩種以上的形式)
- text domain – 主題的文本域
功能的返回值是正確的翻譯形式,對應于給定的計數。
## 稍后進行多元化
您首先使用`_n_noop()`或`_nx_noop()`設置多個字符串。
```
$comments_plural = _n_noop(
'One comment.',
'%s comments.'
);
```
在稍后的代碼中,您可以使用`translate_nooped_plural`來加載字符串。
```
printf(
translate_nooped_plural(
$comments_plural,
get_comments_number(),
'my-theme'
),
number_format_i18n( get_comments_number() )
);
```
## 背景消歧
有時一個術語在多個上下文中使用,并且必須以其他語言單獨翻譯,即使用英文每個語境使用相同的單詞。 例如,Post可以用作動詞“點擊這里發表你的評論”,作為名詞“編輯這篇文章”。 在這種情況下,應該使用`_x()`或`_ex`函數。 它類似于`__()`和`_e()`,但它有一個附加參數 - 上下文:
```
_x( 'Post', 'noun', 'my-theme' );
_x( 'post', 'verb', 'my-theme' );
```
在這兩種情況下使用這種方法,我們得到原始版本的字符串注釋。 然而,翻譯者將看到兩個用于翻譯的注釋字符串,每個字符串在不同的上下文中。
以德文版WordPress為例:Post isBeitr?ge。 德語中相應的動詞形式是beitragen。
>[danger] 請注意,類似于`__()`, `_x()`有一個回聲版本:`_ex()`。 前面的例子可以寫成:
```
_ex( 'Post', 'noun', 'my-theme' );
_ex( 'post', 'verb', 'my-theme' );
```
使用你覺得增強易讀性和易于編碼的。
## 描述
您可以在源代碼中添加一個澄清的注釋,所以翻譯人員知道如何翻譯一個字符串`__('g:i:s a')`。 它必須以翻譯者的語言開頭:并且是gettext調用之前的最后一個PHP注釋。 這是一個例子:
```
/* translators: draft saved date format, see http://php.net/date */
$saved_date_format = __( 'g:i:s a' );
```
## 換行字符
Gettext不喜歡`\r`(ASCII碼:13)在可翻譯的字符串,所以避免它,并使用`\n`代替。
## 空字符串
空字符串保留用于內部Gettext使用,您不得嘗試將空字符串國際化。 它也沒有任何意義,因為翻譯者不會有上下文。
如果您有一個有效的用例來使一個空字符串國際化,請添加上下文以幫助翻譯人員,并與Gettext系統保持一致。
## 處理JavaScript文件
使用`wp_localize_script()`將已翻譯的字符串或其他服務器端數據添加到先前排入的腳本。
## 逃避字符串
逃避所有的字符串是很好的,防止翻譯者運行惡意代碼。 有幾個與國際化功能相結合的逃生功能。
```
<a title="<?php esc_attr_e( 'Skip to content', 'my-theme' ); ?>" class="screen-reader-text skip-link" href="#content" >
<?php _e( 'Skip to content', 'my-theme' ); ?>
</a>
```
```
<label for="nav-menu">
<?php esc_html_e( 'Select Menu:', 'my-theme' ); ?>
</label>
```
## 基本功能
- __()
- _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-theme' ),
get_search_query()
);
```
使用格式字符串而不是字符串連接 - 翻譯短語而不是單詞 -
```
printf(
__( 'Your city is %1$s, and your zip code is %2$s.', 'my-theme' ),
$city,
$zipcode
);
```
總是比好
```
__( 'Your city is ', 'my-theme' ) . $city . __( ', and your zip code is ', 'my-theme' ) . $zipcode;
```
嘗試使用相同的單詞和符號來防止翻譯多個相似的字符串(例如,請勿執行以下操作)
```
__( 'Posts:', 'my-theme' ); and __( 'Posts', 'my-theme' );
```
## 將文本域添加到字符串
您必須將您的Text域作為參數添加到每個`__()`,`_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' )
```
## 加載文本域
您需要使用主題翻譯加載MO文件。 您可以通過調用load_theme_textdomain()函數加載它們。 此調用從您的主題基礎目錄或{text-domain} - {locale} .mo從WordPress主題語言文件夾中加載{locale} .mo。
語言環境是您在文件wp-config.php中的常量WPLANG中定義的語言代碼和/或國家/地區代碼。 例如,德語的語言環境是de_DE。 所以代碼需要wp-config.php將被定義('WPLANG','de_DE');. 有關語言和國家/地區代碼的更多信息,請參閱您的語言中的WordPress。
小心
將MO文件命名為{locale} .mo(例如de_DE.po&de_DE.mo),如果將翻譯添加到主題文件夾。
將您的MO文件命名為{text-domain} - {locale} .mo(例如my-theme-de_DE.po&my-theme-de_DE.mo),如果要將翻譯添加到WordPress主題語言文件夾。
例:
```
function my_theme_load_theme_textdomain() {
load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'my_theme_load_theme_textdomain' );
```
這個功能最好在主題'function.php中運行
>[danger] 注意:WordPress 4.6發布后,翻譯現在以translate.wordpress.org為優先,因此通過translate.wordpress.org翻譯的主題不再需要load_theme_textdomain()了。 但是,沒有任何傷害離開這條線。
## 資源
- Video: i18n: Preparing Your WordPress Theme for the World
- Video: On Internationalization: Plugins and themes for the whole world Slides
- 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
- Translating custom page template names
- 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
- Loading WordPress language files the right way
- 簡介
- 主題開發
- WordPress許可證
- 什么是主題
- 開發環境
- 主題開發示例
- 主題基礎
- 模板文件
- 主樣式表(style.css)
- 文章類型
- 規劃主題文件
- 模板層級
- 模板標簽
- 循環
- 主題函數
- 連接主題文件和目錄
- 使用CSS和JavaScript
- 條件標簽
- 類別,標簽和自定義分類
- 模板文件
- 內容模板文件
- 頁面模板文件
- 附件模板文件
- 自定義內容類型
- 部分和其他模板文件
- 評論模板
- 分類模板
- 404頁面
- 主題功能
- 核心支持的功能
- 管理菜單
- 自定義Headers
- 自定義Logo
- 文章格式
- 置頂文章
- Sidebars
- Widgets
- 導航菜單
- 分頁
- 媒體
- Audio
- Images
- Galleries
- Video
- 精選圖片和縮略圖
- 國際化
- 本地化
- 輔助功能
- 主題選項 – 自定義API
- 定制對象
- 改進用戶體驗的工具
- 定制JavaScript API
- JavaScript / Underscore.js渲染的自定義控件
- 高級用法
- 主題安全
- 數據消毒/逃避
- 數據驗證
- 使用隨機數
- 常見漏洞
- 高級主題
- 子主題
- UI最佳實踐
- JavaScript最佳做法
- 主題單元測試
- 驗證你的主題
- Plugin API Hooks
- 發布你的主題
- 所需的主題文件
- 測試
- 主題評論指南
- 寫文檔
- 提交你的主題到WordPress.org
- 參考文獻
- 模板標簽列表
- 條件標簽列表
- 編碼標準
- HTML編碼標準
- CSS編碼標準
- JavaScript編碼標準
- PHP編碼標準
- 插件開發
- 插件開發簡介
- 什么是插件
- 插件基礎
- 頭部要求
- 包括軟件許可證
- 啟用 / 停用 Hooks
- 卸載方法
- 最佳做法
- 插件安全
- 檢查用戶功能
- 數據驗證
- 保護輸入
- 保護輸出
- 隨機數
- Hooks
- Actions
- Filters
- 自定義Hooks
- 高級主題
- 管理菜單
- 頂級菜單
- 子菜單
- 短代碼
- 基本短碼
- 封閉短碼
- 帶參數的短代碼
- TinyMCE增強型短碼
- 設置
- 設置API
- 使用設置API
- 選項API
- 自定義設置頁面
- 元數據
- 管理帖子元數據
- 自定義元數據
- 渲染元數據
- 自定義文章類型
- 注冊自定義文章類型
- 使用自定義文章類型
- 分類
- 使用自定義分類
- 在WP 4.2+中使用“split術語”
- 用戶
- 創建和管理用戶
- 使用用戶元數據
- 角色和功能
- HTTP API
- JavaScript
- jQuery
- Ajax
- 服務器端PHP和入隊
- Heartbeat API
- 概要
- 計劃任務
- 了解WP-Cron計劃
- 安排WP-Cron 事件
- 將WP-Cron掛接到系統任務計劃程序中
- WP-Cron簡單測試
- 國際化
- 本地化
- 如何國際化您的插件
- 國際化安全
- WordPress.org
- 詳細插件指南
- 規劃您的插件
- 如何使用Subversion
- 插件開發者常見問題
- 開發工具
- Debug Bar 和附加組件
- 輔助插件
- REST API手冊
- 資源
- 文章
- 文章修訂
- 文章類型
- 文章狀態
- 類別
- 標簽
- 頁面
- 評論
- 分類
- 媒體
- 用戶
- 設置
- 使用REST API
- 全局參數
- 分頁
- 鏈接和嵌入
- 發現
- 認證
- 經常問的問題
- 骨干JavaScript客戶端
- 客戶端庫
- 擴展REST API
- 添加自定義端點
- 自定義內容類型
- 修改回應
- 模式
- 詞匯表
- 路由和端點
- 控制器類