首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 國際化 (i18n) 實戰:gettext 工具鏈從安裝到部署的完整指南

     編輯:PHP 綜合知識

為什麼選擇 gettext?

  • GNU 標準,跨語言(C、Python、PHP、Java、Go 皆支援)。
  • 編譯後 .mo 二進制格式,查找極快(雜湊表/O(1))。
  • 工具鏈成熟:xgettext 提取、msgmerge 合併、msgfmt 編譯、poedit 圖形化編輯。
  • 支援複數形式、上下文、備註、過時標記。

1. 環境安裝

Linux (Debian/Ubuntu/CentOS)

# 系統庫
apt-get install -y gettext libgettextpo-dev

# PHP 擴展(通常內建,檢查 php -m | grep gettext)
# 若無:docker-php-ext-install gettext 或 pecl install gettext

# 重啟 PHP-FPM
systemctl reload php8.2-fpm

Windows

  • PHP 8.x 預設啟用 php_gettext.dll(php.ini 取消註釋 extension=gettext)。
  • 需 libintl.dll 放入 PATH(PHP 目錄或 System32)。

驗證

<?php phpinfo(); ?>
// 搜尋 "gettext" 區塊,顯示版本即成功

2. 程式碼標記:三個核心函數

函數用途範例
_($msg) / gettext($msg)單數翻譯echo _('Hello World');
ngettext($single, $plural, $count)複數形式printf(ngettext('%d apple', '%d apples', $n), $n);
pgettext($context, $msg)上下文區分echo pgettext('verb', 'View'); // 動詞 vs pgettext('noun', 'View'); // 名詞

慣例:function __($msg) { return gettext($msg); } 簡寫,配合 IDE 自動提取。

3. 域與目錄綁定

<?php
// bootstrap.php 或公共入口
$locale = $_GET['lang'] ?? 'zh_TW';
putenv("LANG=$locale");
setlocale(LC_ALL, $locale);

// 綁定域 -> 目錄
bindtextdomain('messages', __DIR__ . '/locale');
bind_textdomain_codeset('messages', 'UTF-8'); // 關鍵:避免亂碼
textdomain('messages');

目錄結構:

locale/
├── zh_TW/
│   └── LC_MESSAGES/
│       ├── messages.po
│       └── messages.mo
├── en_US/
│   └── LC_MESSAGES/
│       ├── messages.po
│       └── messages.mo
└── ja_JP/
    └── LC_MESSAGES/
        ├── messages.po
        └── messages.mo

4. 工作流:提取 → 翻譯 → 編譯 → 部署

步驟 1:提取字串產生 .pot 模板

xgettext --language=PHP \
    --keyword=_ \
    --keyword=__ \
    --keyword=ngettext:1,2 \
    --keyword=pgettext:1c,2 \
    --from-code=UTF-8 \
    --output=locale/messages.pot \
    -r src/
  • --keyword 定義提取函數名,支援自定義封裝函數。
  • --keyword=ngettext:1,2 表示第 1、2 參數為單複數字串。
  • --keyword=pgettext:1c,2 表示第 1 參數為 context,第 2 為字串。

步驟 2:初始化語言 .po

msginit --locale=zh_TW --input=locale/messages.pot --output=locale/zh_TW/LC_MESSAGES/messages.po

步驟 3:翻譯 .po(Poedit / VS Code / 文字編輯器)

# messages.po 片段
msgid "Hello World"
msgstr "你好,世界"

msgid "%d apple"
msgid_plural "%d apples"
msgstr[0] "%d 蘋果"
msgstr[1] "%d 蘋果"  # 中文無複數變化,複製即可

步驟 4:編譯 .mo

msgfmt locale/zh_TW/LC_MESSAGES/messages.po -o locale/zh_TW/LC_MESSAGES/messages.mo

步驟 5:程式碼更新時同步

# 重新提取
xgettext ... -o locale/messages.pot.new

# 合併保留舊翻譯
msgmerge --update locale/zh_TW/LC_MESSAGES/messages.po locale/messages.pot.new

# 重新編譯
msgfmt locale/zh_TW/LC_MESSAGES/messages.po -o locale/zh_TW/LC_MESSAGES/messages.mo

5. 進階:複數形式公式

.po 標頭需宣告 Plural-Forms:

# 中文
"Plural-Forms: nplurals=1; plural=0;\n"

# 英文
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

# 俄文 (3 種)
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

6. 框架整合

框架整合方式
Laravel__()、__n() 封裝 gettext,語言檔放 lang/{locale}/,php artisan lang:publish
SymfonyTranslation 組件原生支援 gettext,translator.add_resource('gettext', ...)
Yii2Yii::t() 支援 GettextMessageSource
WordPress__()、_n()、_x(),語言包放 wp-content/languages/plugins/

7. 效能優化與坑點

  • OpCache 衝突:修改 .mo 後需重啟 PHP-FPM 或 opcache_reset(),否則舊快取生效。
  • setlocale 線程安全:PHP-FPM 多進程無影響;CLI 多執行緒需注意(PHP 無原生執行緒)。
  • 編碼必須 UTF-8:bind_textdomain_codeset('messages', 'UTF-8') 少不了。
  • 大量字串記憶體:單域 > 5 萬條考慮拆分域(admin、frontend、api)。
  • 測試環境缺 locale:Docker 基底鏡像需 apt-get install -y locales && locale-gen zh_TW.UTF-8 en_US.UTF-8。

8. 替代方案對比

方案優點缺點適用
gettext標準、快、工具成熟、支援複數/上下文需編譯、部署稍繁瑣中大型專案、多語言、長期維護
PHP 陣列回傳簡單、無編譯、熱重載記憶體佔大、無複數支援、難合併小專案、少語言、快速原型
JSON 檔案前後端共用、易解析無標準複數、無上下文SPA 專案、前端主導翻譯
資料庫儲存動態管理、後台編輯查詢慢、需快取、一致性複雜SaaS 多租戶、用戶自定義語言

原文《利用gettext來實現PHP的國際化編程》重構,補充完整工具鏈流程、複數形式、框架整合、效能優化與替代方案對比。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved