ThinkPHP 6.0 实现二级目录多语言功能
- 2019 年 10 月 6 日
- 筆記
前言
ThinkPHP内置了多语言功能,但是它是通过判断URL参数、Cookies、HTTP_ACCEPT_LANGUAGE
请求参数来返回语言包的,由于多种语言的URL固定的,在搜索引擎抓取页面时,页面返回哪种语言取决于爬虫所带的请求头,这种方法对SEO有一定的影响,难以全面收录各种语言的版本。例如Google webmaster support的“管理多区域和多语言网站”一文中提及到:
Google 建议对每种语言版本的网页使用不同的网址,而不是使用 Cookie 或浏览器设置来调整网页上的内容语言。 如果您希望根据语言设置来动态更改内容或重新路由用户,则请注意,Google 可能无法找到并抓取您的所有变体。这是因为,Googlebot 抓取工具通常来自美国。另外,该抓取工具在发送 HTTP 请求时并不会在请求标头中设置 Accept-Language。
实现
示例项目可在文章底部下载。 1. 进入tp6项目目录,首先在configlang.php
设置默认语言
及允许的语言列表
。我设置了允许简体中文、繁体中文以及英文。

2. 设置configroute.php
中的路由配置,打开强制路由url_route_must
以及完全匹配route_complete_match
以避免设置后可能导致的冲突问题。 3. 进入app
目录,新建lang
目录,编写语言包。
//zh_cn.php <?php return [ 'lang' => '简体中文' ];
//zh_tw.php <?php return [ 'lang' => '繁體中文' ];
//en_us.php <?php return [ 'lang' => 'English' ];
- 编辑
controllerIndex.php
,设置Index方法,返回上述语言包的lang字段,以便测试时识别当前选择的语言。

- 编辑
routeapp.php
路由配置,替换为以下内容。后续添加路由可参照下方Route::get的方法。 这里没有用路由分组功能,以避免访问根目录(如http://localhost/zh-cn/
)时提示路由不正确,但是不加上末尾的斜杠又可匹配的问题(http://localhost/zh-cn
)。
use thinkfacadeRoute; use thinkfacadeConfig; Route::get('/', 'index/index'); $langs = Config::get('lang.allow_lang_list'); foreach($langs as $lang){ Route::get($lang . '/', 'index/index'); }
- 新建
appmiddleware
目录,增加LoadLangPack.php
中间件。
<?php declare (strict_types = 1); namespace appmiddleware; use Closure; use thinkApp; use thinkLang; use thinkRequest; class LoadLangPack { public function handle($request, Closure $next, Lang $lang, App $app) { $path = explode('/', $request->pathinfo()); if(sizeof($path) > 0){ if(empty($path[0])){ $langset = $lang->detect(); return redirect('/' . $langset . '/'); }else{ $langset = $path[0]; } $lang->setLangSet($langset); $lang->load([ $app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php', ]); $app->LoadLangPack($langset); } return $next($request); } }
- 在
appmiddleware.php
文件中添加注册中间件。
return [ appmiddlewareLoadLangPack::class ];
- 尝试访问。访问根目录时,应也会根据参数自动跳转到对应语言。



- 另外,还需要对如
url()
助手函数等涉及到URL生成的函数进行重写。以url()
助手函数为例,打开appcommon.php
,写入以下代码:
use thinkfacadeLang; use thinkfacadeRoute; use thinkrouteUrl as UrlBuild; function url(string $url = '', array $vars = [], $suffix = true, $domain = false): UrlBuild { $lang = Lang::getLangSet(); return Route::buildUrl('/' . $lang . '/' . $url, $vars)->suffix($suffix)->domain($domain); }
这样在调用url函数时,会自动加上语言路径。使用时需要把除语言外的路径写完整。