thinkphp多语言+二级域名必须在应用启动最早期手动绑定语言,因语言包在框架初始化早期已加载,lang::setlang()需在middleware首行执行并关闭allow_url_lang,否则域名判断失效。

ThinkPHP 多语言 + 二级域名不能靠自动识别,必须手动在请求最开始就绑定语言,否则 lang() 调用时语言包早已加载完毕,改也白改。
为什么二级域名访问还是中文?
典型现象:访问 en.example.com 页面文字全是中文,但加 ?lang=en-us 就变英文——说明语言判断逻辑被 URL 参数或默认配置劫持了。
-
allow_url_lang默认为true,会优先读取$_GET['lang'],导致域名判断被跳过 -
Lang::detect()不看域名,只认lang=xxx、Accept-Language和 session(需手动扩展) - 语言包在框架初始化早期就载入,比如验证器提示、系统错误文案,都在中间件执行前已固定
-
$_SERVER['HTTP_HOST']在 HTTPS 或本地调试时可能带端口(如localhost:8080),直接字符串匹配会失败
怎么让 en.example.com 自动用 en-us 语言包?
必须在应用启动最早期完成语言设置,推荐在 app/middleware.php 注册全局中间件,且 handle() 第一行就执行判断。
- 先清理
HTTP_HOST:用parse_url($_SERVER['HTTP_HOST'], PHP_URL_HOST)提取纯净域名 - 用配置数组映射域名与语言码,例如
config/lang_domains.php:['zh.example.com' => 'zh-cn', 'en.example.com' => 'en-us'] - 查不到匹配时 fallback 到
default_lang,避免空语言导致翻译全失效 - 调用
\think\Lang::setLang($lang),不是setLocale()—— 后者只影响后续新加载项,对已载入的验证规则等无效 - 务必关闭
allow_url_lang,否则?lang=xxx会覆盖域名判断
伪静态规则写错,二级域名直接 404
Nginx 或 Apache 的重写规则必须把请求精准导向 public/index.php,且保留 PATH_INFO;套用其他框架模板(比如 Laravel 的规则)会导致 ThinkPHP 完全收不到路由参数。
- ThinkPHP 6+ PATHINFO 模式要求重写目标含
?s=参数,例如:rewrite ^(.*)$ /index.php?s=$1 last; - 二级域名本身不改变伪静态逻辑,但如果你把站点部署在子目录(如
/myapp/),Nginx 的location必须显式匹配该路径,不能只写location / { ... } - Apache 下确保
.htaccess在public/目录,且AllowOverride All已开启,否则规则不生效 - Windows IIS 用户注意:
web.config中的<rule></rule>必须包含<action type="Rewrite" url="index.php?s={R:1}"></action>,不能只留空匹配
多应用模式下,域名 + 语言 + 路由全乱套
TP6+ 多应用不认 config/app.php 里的 domain_bind,那个配置只对单应用有效。你得在 public/index.php 入口里手动绑定应用和语言。
- 绑定应用必须在
App::run()前,且要在autoload.php之后、任何框架类实例化之前 - 每个应用(如
app/admin/)必须有独立的lang/目录,结构为app/admin/lang/zh-cn/common.php,不能共用根lang/ - 静态资源路径(
static()函数)不感知当前应用,static('css/app.css')永远指向public/static/,不会自动加/admin/前缀 - 如果用了泛域名(如
{user}.example.com),语言映射得用正则提取子域,再查配置表,不能硬编码
真正容易被忽略的是:语言设置时机比你想的更早,Lang::setLang() 必须出现在所有 lang() 调用之前,包括模型验证、中间件日志、甚至 __construct() 里的提示文案——晚一毫秒,那部分就固化成默认语言了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











