ThinkPHP多语言分页需手动透传lang参数并按语言过滤数据,否则翻页回退默认语言、总数不准、缓存污染、文案不翻译。正确做法:input取lang、where('lang',$lang)查询、query=>['lang'=>$lang]传参、缓存key含语言、render前用Lang::get()翻译文案、用total()获取总条数。

ThinkPHP 多语言分页不能靠自动识别语言参数,必须手动保留 lang 并透传到分页逻辑里,否则翻页就掉回默认语言。
分页 URL 必须显式拼接 lang 参数
ThinkPHP 的 paginate() 默认只认 page 和 size,完全不处理 lang。如果你的路由或中间件已设好当前语言(比如通过 Lang::setLocale('ja-jp')),但生成分页链接时没把 lang=ja-jp 带上,用户点“下一页”就会回到 app.default_lang 对应的内容。
正确做法是用 input() 提取当前语言,并在分页配置的 query 选项中固定传入:
$lang = input('lang', config('app.default_lang'));
$users = User::where('lang', $lang)->paginate(15, false, [
'page' => input('page/d', 1),
'query' => ['lang' => $lang],
]);
-
query保证所有分页链接(上一页、页码、下一页)都带?lang=xx-xx&page=N - 漏掉
false(即关闭自动解析 URL 参数)会导致page被重复读取,翻页错乱 - 别依赖
$_GET['lang']—— 如果语言来自 cookie 或 session,得先统一取值再塞进query
数据库查询要按 lang 字段过滤,不能只靠展示层翻译
多语言内容如果存在同一张表(如 articles 表含 lang 字段),paginate() 前必须加 where('lang', $lang)。否则 COUNT 和 LIMIT 都会跨语言混算,导致总数不准、页码跳变、第 2 页出现英文文章等现象。
立即学习“PHP免费学习笔记(深入)”;
- 错误写法:
User::paginate(10)—— 没限定语言,COUNT(*) 统计全表 - 正确写法:
User::where('lang', $lang)->paginate(10) - 如果用了缓存(如 Redis),缓存 key 必须包含语言标识,例如
users:en-us:page:3,否则不同语言用户共享缓存
分页器渲染时文案要走 Lang::get(),不能硬编码
$users->render() 输出的 HTML 里,“上一页”“下一页”“共 N 页”这些文字默认是英文或中文固定字符串,不会随语言切换变化。即使你调用了 Lang::setLocale(),内置模板也不调用翻译函数。
解决方式只有两个:
- 用
simple()+ 手写 HTML:{$users->simple()->render()},然后在自定义模板中用__('Previous')、__('Page :current of :last', ['current' => $users->currentPage(), 'last' => $users->lastPage()]) - 或彻底弃用
render(),直接用$users->currentPage()、$users->lastPage()、$users->hasPages()等方法自己拼结构 - 注意:省略号
…、页码范围提示(如 “显示第 1 到 10 条”)也得进语言包,否则切语言后只剩英文符号
分页后拿总数必须用 total(),且注意缓存污染
多语言场景下,$users->count() 返回的是当前页数据条数(比如 10),不是该语言下的总匹配数;而 $users->total() 才是分页过程中执行的 COUNT WHERE lang = ? 结果。
但要注意一个隐藏坑:如果多个语言共用同一个分页对象实例(比如没清空静态缓存或复用查询构造器),total() 可能返回上一次语言的缓存值。
- 安全做法:每次分页前确保查询条件明确含
where('lang', $lang) - 极端情况(如复杂子查询)下
total()不准,需手动查:User::where('lang', $lang)->count(),再传给paginate()的total选项 - 一旦对分页结果调用
toArray()或json(),render()就失效——对象转数组后丢失了分页上下文,这个动作必须在render()之后做



















