本文目录导读:

在PHP项目中实现语言包的加载和切换,常见的方式有以下几种,我会从简单到复杂,给出具体实现方案。
基础思路
语言包本质上是键值对存储,常见格式:
- PHP数组文件
- JSON文件
- INI文件
- 数据库存储
简单实现(PHP数组文件)
目录结构
project/
├── lang/
│ ├── zh_cn.php
│ ├── en.php
│ └── ja.php
├── includes/
│ └── language.php
└── index.php
语言文件示例
lang/zh_cn.php
<?php
return [
'welcome' => '欢迎光临',
'login' => '登录',
'logout' => '退出',
'hello' => '你好, :name',
'items_count' => '共有 :count 个项目'
];
lang/en.php
<?php
return [
'welcome' => 'Welcome',
'login' => 'Login',
'logout' => 'Logout',
'hello' => 'Hello, :name',
'items_count' => 'Total :count items'
];
语言加载类
includes/language.php
<?php
class Language {
private static $instance = null;
private $translations = [];
private $currentLang = 'zh_cn';
// 支持的语言列表
private $supportedLanguages = ['zh_cn', 'en', 'ja'];
private function __construct() {
$this->setLanguage($this->getBrowserLanguage());
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 设置当前语言
*/
public function setLanguage($lang) {
$lang = $this->sanitizeLanguage($lang);
$this->currentLang = $lang;
// 加载语言文件
$file = __DIR__ . '/../lang/' . $lang . '.php';
if (file_exists($file)) {
$this->translations = include $file;
} else {
// 默认加载中文
$this->translations = include __DIR__ . '/../lang/zh_cn.php';
}
}
/**
* 获取翻译文本
*/
public function get($key, $params = []) {
$text = isset($this->translations[$key])
? $this->translations[$key]
: $key; // 找不到返回key本身
// 替换参数
if (!empty($params)) {
foreach ($params as $key => $value) {
$text = str_replace(':' . $key, $value, $text);
}
}
return $text;
}
/**
* 获取浏览器首选语言
*/
private function getBrowserLanguage() {
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$preferred = substr($langs[0], 0, 5);
// 将浏览器语言映射到我们的语言代码
$map = [
'zh-CN' => 'zh_cn',
'zh-TW' => 'zh_tw',
'en-US' => 'en',
'en-GB' => 'en',
'ja-JP' => 'ja'
];
foreach ($map as $browser => $our) {
if (stripos($preferred, substr($browser, 0, 2)) !== false) {
return $our;
}
}
}
return 'zh_cn'; // 默认中文
}
/**
* 清理和验证语言代码
*/
private function sanitizeLanguage($lang) {
$lang = strtolower(str_replace('-', '_', $lang));
if (!in_array($lang, $this->supportedLanguages)) {
return 'zh_cn';
}
return $lang;
}
/**
* 获取当前语言
*/
public function getCurrentLanguage() {
return $this->currentLang;
}
}
// 辅助函数
function __($key, $params = []) {
return Language::getInstance()->get($key, $params);
}
使用示例
index.php
<?php
require_once 'includes/language.php';
// 初始化语言
$lang = Language::getInstance();
// 手动切换语言(例如通过URL参数)
if (isset($_GET['lang'])) {
$_SESSION['lang'] = $_GET['lang'];
$lang->setLanguage($_GET['lang']);
} elseif (isset($_SESSION['lang'])) {
$lang->setLanguage($_SESSION['lang']);
}
// 在模板中使用
?>
<!DOCTYPE html>
<html>
<head><?php echo __('welcome'); ?></title>
</head>
<body>
<h1><?php echo __('welcome'); ?></h1>
<p><?php echo __('hello', ['name' => '张三']); ?></p>
<p><?php echo __('items_count', ['count' => 5]); ?></p>
<!-- 语言切换链接 -->
<a href="?lang=zh_cn">中文</a>
<a href="?lang=en">English</a>
<a href="?lang=ja">日本語</a>
</body>
</html>
JSON文件实现
如果更喜欢JSON格式:
lang/en.json
{
"welcome": "Welcome",
"login": "Login",
"hello": "Hello, :name"
}
修改Language类
public function setLanguage($lang) {
$lang = $this->sanitizeLanguage($lang);
$this->currentLang = $lang;
$file = __DIR__ . '/../lang/' . $lang . '.json';
if (file_exists($file)) {
$json = file_get_contents($file);
$this->translations = json_decode($json, true);
} else {
$this->translations = [];
}
}
数据库存储(适合大型项目)
数据库表结构
CREATE TABLE translations (
id INT PRIMARY KEY AUTO_INCREMENT,
lang_code VARCHAR(10) NOT NULL,
translation_key VARCHAR(100) NOT NULL,
translation_value TEXT,
UNIQUE KEY unique_trans (lang_code, translation_key)
);
INSERT INTO translations (lang_code, translation_key, translation_value) VALUES
('zh_cn', 'welcome', '欢迎光临'),
('en', 'welcome', 'Welcome');
数据库加载类
class DatabaseLanguage {
private $translations = [];
private $db;
public function __construct($db, $lang) {
$this->db = $db;
$this->loadFromDatabase($lang);
}
private function loadFromDatabase($lang) {
$stmt = $this->db->prepare(
"SELECT translation_key, translation_value
FROM translations
WHERE lang_code = ?"
);
$stmt->execute([$lang]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$this->translations[$row['translation_key']] = $row['translation_value'];
}
}
}
框架集成(以ThinkPHP为例)
ThinkPHP自带多语言支持:
config/app.php
'lang_switch_on' => true, 'default_lang' => 'zh-cn', 'list' => ['zh-cn', 'en', 'ja'],
语言文件
- application/lang/zh-cn.php
- application/lang/en.php
使用
// 切换语言
session('lang', 'en');
cookie('lang', 'en');
// 获取翻译
lang('welcome');
lang('hello', ['name' => '张三']);
优化建议
-
缓存加载:生产环境可以缓存语言文件
// 使用文件缓存 $cacheFile = __DIR__ . '/../cache/lang_' . $lang . '.php'; if (file_exists($cacheFile)) { $this->translations = include $cacheFile; } else { // 加载并缓存 $this->translations = include $originalFile; file_put_contents($cacheFile, '<?php return ' . var_export($this->translations, true) . ';'); } -
懒加载:只加载需要的模块
public function get($key, $module = 'common') { if (!isset($this->translations[$module])) { $this->loadModule($module); } return $this->translations[$module][$key] ?? $key; } -
使用常量:提高性能
define('LANG_WELCOME', __('welcome'));
- 小项目:使用PHP数组文件,简单快速
- 中等项目:JSON文件,便于非技术人员编辑
- 大型项目:数据库存储,方便管理,支持在线翻译
- 框架项目:使用框架自带的多语言功能
选择哪种方式取决于项目规模和具体需求,核心思想都是一致的:将文本与代码分离,通过键值对实现动态切换。