子目录部署+伪静态+多语言叠加时最易出问题的是path_info未传递导致路由失效、lang/目录被误作url路径、语言包未加载;需显式配置nginx传path_info、lang/放项目根目录、严格小写命名、返回数组、优先用?lang=en切换。

子目录部署 + 伪静态 + 多语言,三者叠加时最容易出问题的不是某一个功能,而是 PATH_INFO 传不进去、lang/ 目录被错当成 URL 路径、或语言包根本没加载——ThinkPHP 不报错,只默默 fallback 到默认语言。
子目录下 Nginx 伪静态必须显式传 PATH_INFO
ThinkPHP 路由依赖 $_SERVER['PATH_INFO'] 解析 /user/login 这类路径。在子目录(如 /blog/)中,Nginx 默认不会把 /blog/user/login 的后半段自动塞进 PATH_INFO,导致路由全挂。
-
location /blog/ { alias /var/www/html/blog/public/; }中必须加fastcgi_param PATH_INFO $fastcgi_path_info;,缺了这行,index.php/user/login就变成执行index.php主脚本,后面路径直接丢弃 -
try_files $uri $uri/ /blog/index.php?$query_string;是安全写法,但仅靠它不够;$query_string只传 GET 参数,不传 PATH_INFO - 别用
rewrite ^/blog/(.*)$ /blog/index.php?s=$1 last;这种旧写法——s=是 ThinkPHP3 的入口参数,TP5/6 已弃用,且无法触发多语言自动识别
lang/ 目录不能放在子目录 URL 路径下
比如网站根域是 https://example.com/,子应用部署在 /shop/,那么 lang/ 必须放在物理路径 /var/www/html/shop/lang/,而不是试图让浏览器通过 https://example.com/shop/lang/zh-cn/common.php 访问——后者会被当静态资源拦截或 403,且框架压根不会去读。
- 语言包路径优先级:模块
lang/→ 应用lang/→ 框架默认;子目录项目就是“应用”,所以lang/必须在public同级(即项目根目录下),不是public/lang/ - 目录名严格小写:
zh-cn✅,ZH-CN❌,zh_CN❌;Linux 服务器上大小写敏感,错一个字母就静默失效 - 文件必须返回数组:
lang/zh-cn/common.php写return ['hello' => '你好'];,不能是echo json_encode([...])或空 echo
多语言切换在子目录里要绕开 URL 前缀干扰
开启 'lang_switch_on' => true 后,ThinkPHP 默认从 $_GET['lang'] 读取语言码。但如果伪静态规则把 /shop/ 当作前缀,而你又用 ?lang=en 切换,实际请求可能是 /shop/?lang=en ——这时没问题;但若规则重写成 /shop/en/user/login 这类路径,框架就收不到 lang 参数,除非你手动解析并调用 Lang::setLang('en')。
- 推荐方案:保持查询参数方式切换,即用
/shop/user/login?lang=en,不要在伪静态规则里硬编码语言段 - 如果必须用路径前缀(如
/shop/en/user/login),需在中间件里提前截取第一个路径段:$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $lang = explode('/', trim($path, '/'))[0] ?? 'zh-cn'; Lang::setLang($lang); -
app_host和url_domain_deploy对语言切换无影响,它们只控制url()辅助函数生成的链接格式
最易被忽略的是:子目录部署时,PATH_INFO 传不进去会导致路由失效,而路由失效又会让多语言自动识别逻辑(依赖路由参数)完全跳过——结果就是页面全显示默认语言,连错误提示都没有。先确认 $_SERVER['PATH_INFO'] 有值,再查语言包路径,最后看参数是否抵达,顺序不能乱。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











