­

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'  ];
  1. 编辑controllerIndex.php,设置Index方法,返回上述语言包的lang字段,以便测试时识别当前选择的语言。
  1. 编辑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');  }
  1. 新建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);      }  }
  1. appmiddleware.php文件中添加注册中间件。
    return [          appmiddlewareLoadLangPack::class      ];
  1. 尝试访问。访问根目录时,应也会根据参数自动跳转到对应语言。
  1. 另外,还需要对如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函数时,会自动加上语言路径。使用时需要把除语言外的路径写完整。