本文目录导读:

我来详细介绍PHP实现语言包(国际化/i18n)的几种常用方法:
最简单的数组方式
基础实现
<?php
// lang/en.php
return [
'welcome' => 'Welcome to our website',
'hello' => 'Hello, :name',
'login' => 'Login',
'logout' => 'Logout',
];
// lang/zh.php
return [
'welcome' => '欢迎访问我们的网站',
'hello' => '你好,:name',
'login' => '登录',
'logout' => '退出',
];
使用类封装
<?php
class Translator {
private static $translations = [];
private static $defaultLang = 'zh';
public static function load($lang) {
$file = __DIR__ . "/lang/{$lang}.php";
if (file_exists($file)) {
self::$translations = require $file;
}
}
public static function setLang($lang) {
self::load($lang);
}
public static function t($key, $params = []) {
$text = self::$translations[$key] ?? $key;
// 替换参数
foreach ($params as $name => $value) {
$text = str_replace(":{$name}", $value, $text);
}
return $text;
}
}
// 使用示例
Translator::setLang($_GET['lang'] ?? 'zh');
echo Translator::t('welcome'); // 欢迎访问我们的网站
echo Translator::t('hello', ['name' => '张三']); // 你好,张三
使用Gettext扩展
安装配置
// php.ini 中开启 extension=gettext // 创建翻译文件目录 // locale/zh_CN/LC_MESSAGES/messages.po
Gettext使用示例
<?php
// 初始化gettext
function initGettext($lang = 'zh_CN') {
$locale = $lang . '.UTF-8';
putenv("LANG={$locale}");
setlocale(LC_ALL, $locale);
$domain = 'messages';
bindtextdomain($domain, __DIR__ . '/locale');
textdomain($domain);
}
// 使用gettext
initGettext('zh_CN');
echo gettext("Welcome to our website");
echo _("Hello, World!"); // _() 是 gettext() 的简写
// 带变量的翻译
printf(_("Hello, %s"), '张三');
PO文件示例
# locale/zh_CN/LC_MESSAGES/messages.po msgid "Welcome" msgstr "欢迎" msgid "Hello, %s" msgstr "你好,%s"
使用第三方库 - Symfony Translation
安装
composer require symfony/translation
使用示例
<?php
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Loader\PhpFileLoader;
$translator = new Translator('zh_CN');
// 添加加载器
$translator->addLoader('php', new PhpFileLoader());
$translator->addLoader('array', new ArrayLoader());
// 加载翻译文件
$translator->addResource('php', __DIR__ . '/lang/zh.php', 'zh_CN');
$translator->addResource('php', __DIR__ . '/lang/en.php', 'en');
// 使用翻译
echo $translator->trans('welcome');
echo $translator->trans('hello', ['%name%' => '张三']);
// 复数形式
echo $translator->trans('apple', ['%count%' => 5], 'messages', 'zh_CN');
完整的语言包管理系统
<?php
class LanguageManager {
private $langDir;
private $currentLang;
private $translations = [];
private static $instance = null;
private function __construct() {
$this->langDir = __DIR__ . '/lang/';
$this->currentLang = $this->detectLanguage();
$this->loadLanguage();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
private function detectLanguage() {
// 从会话获取
if (isset($_SESSION['lang'])) {
return $_SESSION['lang'];
}
// 从Cookie获取
if (isset($_COOKIE['lang'])) {
return $_COOKIE['lang'];
}
// 从浏览器语言自动检测
$browserLang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '', 0, 2);
return in_array($browserLang, ['zh', 'en']) ? $browserLang : 'zh';
}
public function setLanguage($lang) {
if (file_exists($this->langDir . $lang . '.php')) {
$this->currentLang = $lang;
$_SESSION['lang'] = $lang;
setcookie('lang', $lang, time() + 3600 * 24 * 365);
$this->loadLanguage();
}
}
private function loadLanguage() {
$file = $this->langDir . $this->currentLang . '.php';
$this->translations = file_exists($file) ? require $file : [];
}
public function t($key, $params = []) {
$text = $this->translations[$key] ?? $key;
if (!empty($params)) {
foreach ($params as $name => $value) {
$text = preg_replace('/\{' . $name . '\}|:' . $name . '/i', $value, $text);
}
}
return $text;
}
public function getCurrentLang() {
return $this->currentLang;
}
public function getAllTranslations() {
return $this->translations;
}
}
// 使用示例
$lang = LanguageManager::getInstance();
echo $lang->t('welcome'); // 自动检测语言并翻译
echo $lang->t('hello', ['name' => '李四']);
语言切换功能
<?php
// 语言切换链接
$currentLang = LanguageManager::getInstance()->getCurrentLang();
?>
<div class="language-switcher">
<a href="?lang=zh" <?php echo $currentLang == 'zh' ? 'class="active"' : ''; ?>>中文</a>
<a href="?lang=en" <?php echo $currentLang == 'en' ? 'class="active"' : ''; ?>>English</a>
</div>
<?php
// 处理切换请求
if (isset($_GET['lang'])) {
$allowed = ['zh', 'en', 'ja', 'fr'];
$requested = $_GET['lang'];
if (in_array($requested, $allowed)) {
LanguageManager::getInstance()->setLanguage($requested);
header('Location: ' . str_replace('?lang=' . $requested, '', $_SERVER['REQUEST_URI']));
}
}
数据库存储语言包
<?php
class DatabaseTranslator {
private $db;
private $translations = [];
public function __construct($pdo) {
$this->db = $pdo;
$this->loadTranslations();
}
public function loadTranslations($lang) {
$stmt = $this->db->prepare("
SELECT t.key, t.value
FROM translations t
WHERE t.language = :lang
");
$stmt->execute(['lang' => $lang]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$this->translations[$row['key']] = $row['value'];
}
}
public function t($key) {
return $this->translations[$key] ?? $key;
}
// 缓存翻译到文件
public function cacheToFile($lang) {
$cacheFile = __DIR__ . "/cache/{$lang}.php";
$content = "<?php\nreturn " . var_export($this->translations, true) . ";\n";
file_put_contents($cacheFile, $content);
}
}
最佳实践建议
- 命名规范:使用点号分隔层级,如
menu.home.title - 参数化:避免拼接字符串,使用占位符
- 缓存机制:生产环境可以合并缓存语言文件
- 自动检测:根据用户浏览器语言自动选择
- 回退机制:找不到翻译时返回原始键名
选择哪种方案取决于项目需求:
- 简单项目用数组方式
- 需要系统级支持用Gettext
- 大型项目用Symfony等成熟库