一、多语言网站概述
多语言网站(也称为国际化网站)是指能够根据用户的语言偏好提供不同语言版本的网站。ThinkPHP提供了完善的多语言支持,包括:
- 语言包管理
- 自动语言检测
- 手动语言切换
- 模板多语言支持
- 数据库内容国际化
二、环境准备与配置
首先创建ThinkPHP项目并配置多语言支持:
composer create-project topthink/think tp-multilang
配置多语言支持(config/lang.php):
return [
// 默认语言
'default_lang' => 'zh-cn',
// 允许的语言列表
'allow_lang_list' => ['zh-cn', 'en-us', 'ja-jp'],
// 自动侦测浏览器语言
'auto_detect' => true,
// 使用Cookie记录语言
'use_cookie' => true,
// 扩展语言包
'extend_list' => [],
];
三、创建语言包
ThinkPHP的语言包文件位于app/lang目录下,按语言分目录存放:
1. 中文语言包(app/lang/zh-cn.php)
return [
// 公共语言
'welcome' => '欢迎访问我们的网站',
'home' => '首页',
'about' => '关于我们',
'contact' => '联系我们',
// 首页语言
'index_title' => '首页 - 多语言演示',
'index_content' => '这是一个支持多语言的网站演示',
// 用户相关
'login' => '登录',
'register' => '注册',
'logout' => '退出',
];
2. 英文语言包(app/lang/en-us.php)
return [
// Common
'welcome' => 'Welcome to our website',
'home' => 'Home',
'about' => 'About Us',
'contact' => 'Contact Us',
// Index page
'index_title' => 'Home - Multilingual Demo',
'index_content' => 'This is a multilingual website demo',
// User related
'login' => 'Login',
'register' => 'Register',
'logout' => 'Logout',
];
3. 日文语言包(app/lang/ja-jp.php)
return [
// 共通
'welcome' => '当サイトへようこそ',
'home' => 'ホーム',
'about' => '会社概要',
'contact' => 'お問い合わせ',
// トップページ
'index_title' => 'ホーム - 多言語デモ',
'index_content' => 'これは多言語対応のウェブサイトデモです',
// ユーザー関連
'login' => 'ログイン',
'register' => '会員登録',
'logout' => 'ログアウト',
];
四、在控制器中使用多语言
在控制器中可以使用Lang类来获取语言文本:
// app/controller/Index.php
namespace appcontroller;
use thinkfacadeLang;
use thinkfacadeView;
class Index
{
public function index()
{
// 获取语言文本
$welcome = Lang::get('welcome');
$title = Lang::get('index_title');
// 传递到视图
View::assign([
'title' => $title,
'welcome' => $welcome,
'content' => Lang::get('index_content')
]);
return View::fetch('index');
}
}
五、在模板中使用多语言
ThinkPHP模板支持多语言函数,可以直接在模板中使用:
<!-- view/index.html -->
<!DOCTYPE html>
<html lang="{:app('lang')}">
<head>
<meta charset="UTF-8">
<title>{$title}</title>
</head>
<body>
<header>
<h1>{:lang('welcome')}</h1>
<nav>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" >{:lang('home')}</a>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" >{:lang('about')}</a>
<a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" >{:lang('contact')}</a>
</nav>
</header>
<main>
<p>{$content}</p>
</main>
<footer>
<div class="language-switcher">
<a href="?lang=zh-cn" rel="external nofollow" >中文</a>
<a href="?lang=en-us" rel="external nofollow" >English</a>
<a href="?lang=ja-jp" rel="external nofollow" >日本語</a>
</div>
</footer>
</body>
</html>
六、实现语言切换功能
创建中间件处理语言切换:
// app/middleware/Lang.php
namespace appmiddleware;
use thinkfacadeLang;
use thinkfacadeCookie;
class Lang
{
public function handle($request, Closure $next)
{
// 获取语言参数
$lang = $request->param('lang');
// 如果URL中有语言参数
if ($lang && in_array($lang, config('lang.allow_lang_list'))) {
// 设置当前语言
Lang::setLangSet($lang);
// 保存到Cookie
Cookie::set('think_lang', $lang, 3600 * 24 * 30);
} else {
// 从Cookie获取语言
$cookieLang = Cookie::get('think_lang');
if ($cookieLang && in_array($cookieLang, config('lang.allow_lang_list'))) {
Lang::setLangSet($cookieLang);
}
}
return $next($request);
}
}
注册中间件(app/middleware.php):
return [
// 全局中间件
appmiddlewareLang::class
];
七、数据库内容国际化
对于数据库中的动态内容,我们可以采用以下方法实现国际化:
1. 多表关联方案
创建内容表和翻译表:
// 产品表(products)
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
image VARCHAR(255),
price DECIMAL(10,2),
created_at DATETIME
);
// 产品翻译表(product_translations)
CREATE TABLE product_translations (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT,
lang VARCHAR(10),
name VARCHAR(255),
description TEXT,
FOREIGN KEY (product_id) REFERENCES products(id)
);
2. 在模型中处理多语言内容
// app/model/Product.php
namespace appmodel;
use thinkModel;
class Product extends Model
{
// 定义关联
public function translations()
{
return $this->hasMany(ProductTranslation::class);
}
// 获取当前语言的产品信息
public function getLocalized($lang = null)
{
$lang = $lang ?: app('lang');
// 获取翻译
$translation = $this->translations()
->where('lang', $lang)
->find();
if ($translation) {
return [
'id' => $this->id,
'name' => $translation->name,
'description' => $translation->description,
'image' => $this->image,
'price' => $this->price
];
}
// 没有翻译时返回默认语言
$default = $this->translations()
->where('lang', config('lang.default_lang'))
->find();
return [
'id' => $this->id,
'name' => $default->name,
'description' => $default->description,
'image' => $this->image,
'price' => $this->price
];
}
}
3. 在控制器中使用
// app/controller/Product.php
public function index()
{
$products = Product::select();
$localizedProducts = [];
foreach ($products as $product) {
$localizedProducts[] = $product->getLocalized();
}
View::assign('products', $localizedProducts);
return View::fetch('product/index');
}
八、多语言路由配置
ThinkPHP支持多语言路由,可以为不同语言创建不同的URL:
// config/route.php
use thinkfacadeRoute;
// 多语言路由
Route::rule(':lang/index', 'index/index')
->pattern(['lang' => 'zh-cn|en-us|ja-jp']);
Route::rule(':lang/product/:id', 'product/index')
->pattern(['lang' => 'zh-cn|en-us|ja-jp', 'id' => 'd+']);
// 默认路由(不带语言前缀)
Route::rule('index', 'index/index');
九、最佳实践与常见问题
1. 最佳实践
- 使用语言常量代替硬编码文本
- 为所有用户可见的文本添加语言项
- 组织语言包按模块划分(如:app/lang/zh-cn/user.php)
- 提供默认语言回退机制
- 考虑语言方向(RTL/LTR)
2. 常见问题解决
问题1:语言包未生效
- 检查文件名和路径是否正确
- 确认中间件已注册
- 检查配置中的allow_lang_list
问题2:数据库内容翻译缺失
- 实现默认语言回退机制
- 添加翻译内容完整性检查
问题3:语言切换后URL不一致
- 使用统一的路由中间件处理语言参数
- 在模板中使用多语言路由函数
十、完整示例:多语言产品列表
<!-- view/product/index.html -->
<div class="product-list">
<h2>{:lang('product_list')}</h2>
<div class="products">
<?php foreach($products as $product): ?>
<div class="product">
<img src="{$product.image}" alt="{$product.name}">
<h3>{$product.name}</h3>
<p class="description">{$product.description}</p>
<p class="price">{:lang('price')}: {$product.price}</p>
</div>
<?php endforeach; ?>
</div>
</div>
多语言产品列表效果
智能手机
高端配置,超长续航
价格: ¥3999.00
项目结构总结
tp-multilang/ ├─ app/ │ ├─ controller/ │ │ ├─ Index.php │ │ ├─ Product.php │ ├─ model/ │ │ ├─ Product.php │ │ ├─ ProductTranslation.php │ ├─ middleware/ │ │ ├─ Lang.php │ ├─ lang/ │ │ ├─ zh-cn.php │ │ ├─ en-us.php │ │ ├─ ja-jp.php ├─ config/ │ ├─ lang.php │ ├─ middleware.php │ ├─ route.php ├─ view/ │ ├─ index.html │ ├─ product/ │ │ ├─ index.html
// 前端语言切换演示
function switchLang(lang) {
const translations = {
‘zh-cn’: {
name: ‘智能手机’,
desc: ‘高端配置,超长续航’,
price: ‘价格: ¥3999.00’
},
‘en-us’: {
name: ‘Smartphone’,
desc: ‘High-end configuration, long battery life’,
price: ‘Price: $599.00’
},
‘ja-jp’: {
name: ‘スマートフォン’,
desc: ‘ハイエンド構成、長いバッテリー寿命’,
price: ‘価格: ¥65,800’
}
};
document.getElementById(‘product-name’).textContent = translations[lang].name;
document.getElementById(‘product-desc’).textContent = translations[lang].desc;
document.getElementById(‘product-price’).textContent = translations[lang].price;
}

