本文目录导读:

在 PHP 中实现本地化(i18n,即国际化)主要有以下几种方法,从简单到复杂:
使用 gettext 扩展(最标准)
安装配置
# Ubuntu/Debian sudo apt-get install php-gettext gettext # Windows 需要在 php.ini 中启用 extension=php_gettext.dll
实现示例
<?php
// 设置语言环境
$locale = 'zh_CN'; // 或者 'en_US', 'fr_FR' 等
putenv("LANG=$locale");
setlocale(LC_ALL, $locale);
// 指定翻译文件目录
bindtextdomain('messages', './locale');
bind_textdomain_codeset('messages', 'UTF-8');
textdomain('messages');
// 使用翻译函数
echo _("Hello World"); // 将根据语言环境显示翻译内容
echo gettext("Welcome"); // 同上
创建翻译文件
# 1. 创建 po 文件 xgettext -n -o locale/zh_CN/LC_MESSAGES/messages.po source.php # 2. 编辑 po 文件添加翻译 # 3. 编译为 mo 文件 msgfmt -o locale/zh_CN/LC_MESSAGES/messages.mo messages.po
使用数组/配置文件(简单方案)
<?php
class Translator {
private $lang = 'zh_CN';
private $translations = [];
public function __construct($lang = 'zh_CN') {
$this->lang = $lang;
$this->loadTranslations();
}
private function loadTranslations() {
$file = "lang/" . $this->lang . ".php";
if (file_exists($file)) {
$this->translations = include $file;
}
}
public function translate($key) {
return isset($this->translations[$key])
? $this->translations[$key] : $key;
}
public function __call($name, $args) {
if ($name === 't') {
return $this->translate($args[0]);
}
}
}
// 语言文件 lang/zh_CN.php
return [
'hello' => '你好',
'welcome' => '欢迎',
'goodbye' => '再见',
// 带参数的情况
'greeting' => '您好, %s!',
];
// 使用示例
$tr = new Translator('zh_CN');
echo $tr->t('hello'); // 输出: 你好
printf($tr->t('greeting'), '张三'); // 输出: 您好, 张三!
使用 JSON 文件(推荐)
<?php
class I18n {
private static $instance = null;
private $translations = [];
private $lang;
private function __construct($lang = 'zh') {
$this->lang = $lang;
$this->load();
}
public static function getInstance($lang = null) {
if ($lang === null) {
$lang = isset($_SESSION['lang']) ? $_SESSION['lang'] : 'zh';
}
if (self::$instance === null || self::$instance->lang !== $lang) {
self::$instance = new self($lang);
}
return self::$instance;
}
private function load() {
$file = "lang/{$this->lang}.json";
if (file_exists($file)) {
$this->translations = json_decode(file_get_contents($file), true);
}
}
public function t($key, $params = []) {
$text = isset($this->translations[$key])
? $this->translations[$key] : $key;
foreach ($params as $k => $v) {
$text = str_replace('{' . $k . '}', $v, $text);
}
return $text;
}
public function getLang() {
return $this->lang;
}
}
?>
<!-- lang/zh.json -->
{
"hello": "你好",
"welcome": "欢迎来到我们的网站",
"greeting": "您好, {name}!",
"cart_items": "购物车中有 {count} 件商品"
}
<!-- 使用示例 -->
<?php
$i18n = I18n::getInstance($_SESSION['lang']);
echo $i18n->t('hello'); // 你好
echo $i18n->t('greeting', ['name' => '张三']); // 您好, 张三!
echo $i18n->t('cart_items', ['count' => 3]); // 购物车中有 3 件商品
?>
使用 Composer 库
推荐几个流行的库:
# Symfony Translation 组件 composer require symfony/translation # 或者使用 simpler 的 php-array-translator composer require php-array-translator/translator
Symfony Translation 示例
<?php
require 'vendor/autoload.php';
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
$translator = new Translator('zh_CN');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
'hello' => '你好',
'welcome' => '欢迎访问'
], 'zh_CN');
echo $translator->trans('hello'); // 你好
完整的本地化实现示例
<?php
class Localization {
private $lang;
private $data;
public function __construct() {
$this->detectLanguage();
$this->loadLanguageData();
}
private function detectLanguage() {
// 1. 检查 URL 参数
if (isset($_GET['lang'])) {
$this->lang = $_GET['lang'];
$_SESSION['lang'] = $this->lang;
}
// 2. 检查 Session
elseif (isset($_SESSION['lang'])) {
$this->lang = $_SESSION['lang'];
}
// 3. 检查 Cookie
elseif (isset($_COOKIE['lang'])) {
$this->lang = $_COOKIE['lang'];
}
// 4. 检查浏览器语言
else {
$browserLang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'en', 0, 2);
$this->lang = in_array($browserLang, ['zh', 'en', 'fr']) ? $browserLang : 'en';
}
}
private function loadLanguageData() {
$file = __DIR__ . "/lang/{$this->lang}.json";
$this->data = file_exists($file) ?
json_decode(file_get_contents($file), true) : [];
}
public function lang() {
return $this->lang;
}
public function __invoke($key, $params = []) {
$text = $this->data[$key] ?? $key;
foreach ($params as $k => $v) {
$text = str_replace('{' . $k . '}', $v, $text);
}
return $text;
}
// 添加语言切换方法
public function switchLanguage($lang) {
$_SESSION['lang'] = $lang;
setcookie('lang', $lang, time() + 3600*24*30);
$this->lang = $lang;
$this->loadLanguageData();
}
}
// 使用
$t = new Localization();
echo $t('hello');
echo $t('greeting', ['name' => 'John']);
高级技巧
复数形式处理
function plural($n, $forms) {
// 英文复数规则
if ($forms[1] && $n != 1) return $forms[1];
// 中文没有复数形式
return $forms[0];
}
// 使用
echo sprintf(plural($count, ['%d item', '%d items']), $count);
动态语言切换 HTML
<!-- 语言切换器 --> <a href="?lang=zh">中文</a> | <a href="?lang=en">English</a> | <a href="?lang=fr">Français</a>
最佳实践建议
- 使用统一函数名:如
t()或 - 分离语言文件:每个语言一个 JSON 文件
- 使用缓存:缓存加载的语言文件
- 错误处理:找不到翻译时返回原始键名
- 编码统一:使用 UTF-8 编码
选择哪种方案取决于项目需求:
- 小型项目:使用 JSON 文件方案
- 中型项目:使用 gettext
- 大型企业:使用 Symfony 等成熟框架的组件