Files
webman-buildadmin-mall/app/common/middleware/LoadLangPack.php
2026-03-30 11:47:32 +08:00

148 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\common\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Request;
use Webman\Http\Response;
/**
* 加载控制器语言包中间件Webman 迁移版,等价 ThinkPHP LoadLangPack
* 根据当前路由加载对应控制器的语言包到 Translator
*
* 对外 api/:优先请求头 langzh / zh-cn → 中文包 zh-cnen → 英文包),未传则 think-lang再默认 zh-cn不根据浏览器 Accept-Language
* admin/think-lang → Accept-Language → 配置默认
*/
class LoadLangPack implements MiddlewareInterface
{
public function process(Request $request, callable $handler): Response
{
$path = trim($request->path(), '/');
if (str_starts_with($path, 'api/') || str_starts_with($path, 'admin/')) {
$this->loadLang($request);
}
return $handler($request);
}
protected function loadLang(Request $request): void
{
$path = trim($request->path(), '/');
$isApi = str_starts_with($path, 'api/');
$isAdmin = str_starts_with($path, 'admin/');
$allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']);
$langSet = null;
// 对外 APIPlayX、H5 等):优先 lang 请求头,默认中文 zh-cn不跟随浏览器 Accept-Language
if ($isApi) {
$langHeader = $request->header('lang');
if (is_array($langHeader)) {
$langHeader = $langHeader[0] ?? '';
}
$langHeader = is_string($langHeader) ? trim($langHeader) : '';
if ($langHeader !== '') {
$langSet = $this->normalizeLangHeader($langHeader, $allowLangList);
}
}
// 与后台 Vue 一致的 think-lang对外 API 在 lang 未设置时仍可生效)
if ($langSet === null) {
$headerLang = $request->header('think-lang');
if (is_array($headerLang)) {
$headerLang = $headerLang[0] ?? '';
}
$headerLang = is_string($headerLang) ? trim($headerLang) : '';
if ($headerLang !== '') {
$normalized = str_replace('_', '-', strtolower($headerLang));
if (in_array($normalized, $allowLangList, true)) {
$langSet = $normalized;
}
}
}
if ($langSet === null) {
if ($isApi) {
$langSet = 'zh-cn';
} elseif ($isAdmin) {
$acceptLang = $request->header('accept-language', '');
if (is_array($acceptLang)) {
$acceptLang = $acceptLang[0] ?? '';
}
$acceptLang = is_string($acceptLang) ? $acceptLang : '';
if (preg_match('/^zh[-_]?cn|^zh/i', $acceptLang)) {
$langSet = 'zh-cn';
} elseif (preg_match('/^en/i', $acceptLang)) {
$langSet = 'en';
} else {
$langSet = config('lang.default_lang', config('translation.locale', 'zh-cn'));
}
$langSet = str_replace('_', '-', strtolower((string) $langSet));
} else {
$langSet = config('lang.default_lang', config('translation.locale', 'zh-cn'));
$langSet = str_replace('_', '-', strtolower((string) $langSet));
}
}
// 设置当前请求的翻译语言,使 __() 和 trans() 使用正确的语言
if (function_exists('locale')) {
locale($langSet);
}
$parts = explode('/', $path);
$app = $parts[0] ?? 'api';
$appLangDir = base_path() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . $app . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR;
if (!class_exists(\support\Translation::class)) {
return;
}
$translator = \support\Translation::instance();
// 1. 加载根级语言包zh-cn.php / en.php供 common 翻译使用
$rootLangFile = $appLangDir . $langSet . '.php';
if (is_file($rootLangFile)) {
$translator->addResource('phpfile', $rootLangFile, $langSet, 'messages');
}
// 2. 加载控制器专用语言包(如 zh-cn/auth/group.php供 get_route_remark 等使用
// 同时加载到 messages 域,使 __() 能正确翻译控制器内的文案(如安装页错误提示)
$controllerPath = get_controller_path($request);
if ($controllerPath) {
$controllerPathForFile = str_replace('.', '/', $controllerPath);
$controllerPathForFile = implode('/', array_map(function ($p) {
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $p));
}, explode('/', $controllerPathForFile)));
$controllerLangFile = $appLangDir . $langSet . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $controllerPathForFile) . '.php';
if (is_file($controllerLangFile)) {
$translator->addResource('phpfile', $controllerLangFile, $langSet, $controllerPath);
$translator->addResource('phpfile', $controllerLangFile, $langSet, 'messages');
}
}
}
/**
* 将 lang 请求头取值映射为语言包标识zh / zh-cn → zh-cnen → en
*/
private function normalizeLangHeader(string $raw, array $allowLangList): ?string
{
$s = str_replace('_', '-', strtolower(trim($raw)));
if ($s === '') {
return null;
}
if (in_array($s, $allowLangList, true)) {
return $s;
}
if (str_starts_with($s, 'en')) {
return in_array('en', $allowLangList, true) ? 'en' : null;
}
if ($s === 'zh' || str_starts_with($s, 'zh-')) {
return in_array('zh-cn', $allowLangList, true) ? 'zh-cn' : null;
}
return null;
}
}