建议使用下方文章中的扩展包,它对本文中实现的多语言功能中间件进行了封装,同时计划加入更多相关功能。
前言
ThinkPHP内置了多语言功能,但是它是通过判断URL参数、Cookies、HTTP_ACCEPT_LANGUAGE
请求参数来返回语言包的,由于多种语言的URL固定的,在搜索引擎抓取页面时,页面返回哪种语言取决于爬虫所带的请求头,这种方法对SEO有一定的影响,难以全面收录各种语言的版本。例如Google webmaster support的“管理多区域和多语言网站”一文中提及到:
Google 建议对每种语言版本的网页使用不同的网址,而不是使用 Cookie 或浏览器设置来调整网页上的内容语言。
如果您希望根据语言设置来动态更改内容或重新路由用户,则请注意,Google 可能无法找到并抓取您的所有变体。这是因为,Googlebot 抓取工具通常来自美国。另外,该抓取工具在发送 HTTP 请求时并不会在请求标头中设置 Accept-Language。
实现
示例项目可在文章底部下载。
1. 进入tp6项目目录,首先在config\lang.php
设置默认语言
及允许的语言列表
。我设置了允许简体中文、繁体中文以及英文。
2. 设置config\route.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'
];
- 编辑
controller\Index.php
,设置Index方法,返回上述语言包的lang字段,以便测试时识别当前选择的语言。
- 编辑
route\app.php
路由配置,替换为以下内容。后续添加路由可参照下方Route::get的方法。
这里没有用路由分组功能,以避免访问根目录(如http://localhost/zh-cn/
)时提示路由不正确,但是不加上末尾的斜杠又可匹配的问题(http://localhost/zh-cn
)。
use think\facade\Route;
use think\facade\Config;
Route::get('/', 'index/index');
$langs = Config::get('lang.allow_lang_list');
foreach($langs as $lang){
Route::get($lang . '/', 'index/index');
}
- 新建
app\middleware
目录,增加LoadLangPack.php
中间件。
<?php
declare (strict_types = 1);
namespace app\middleware;
use Closure;
use think\App;
use think\Lang;
use think\Request;
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);
}
}
- 在
app\middleware.php
文件中添加注册中间件。
return [
\app\middleware\LoadLangPack::class
];
- 尝试访问。访问根目录时,应也会根据参数自动跳转到对应语言。
- 另外,还需要对如
url()
助手函数等涉及到URL生成的函数进行重写。以url()
助手函数为例,打开app\common.php
,写入以下代码:
use think\facade\Lang;
use think\facade\Route;
use think\route\Url 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函数时,会自动加上语言路径。使用时需要把除语言外的路径写完整。
发表回复