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函數時,會自動加上語言路徑。使用時需要把除語言外的路徑寫完整。