多语言

This commit is contained in:
zhang zhuo 2025-12-05 16:42:57 +08:00
parent 81ee0d339d
commit ae018d803f
10 changed files with 144 additions and 24 deletions

View File

@ -10,6 +10,7 @@ use App\Event\LogEvent;
use App\Model\Account;
use App\Model\AccountLog;
use App\Model\Online;
use App\Model\Translation as tModel;
use App\Utils\Param;
use App\Utils\Str;
use App\Utils\Token;
@ -216,4 +217,14 @@ class Login extends Base
]
);
}
#[GetMapping(path: "translations")]
#[Auth(needLogin: false)]
public function translations()
{
// 获取多语言信息
$locale = $this->request->input("locale", "zh-cn");
$data = tModel::getLang($locale);
return $this->success('ok', $data);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Middleware;
use Hyperf\Context\ApplicationContext;
use Hyperf\Contract\TranslatorInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class LanguageMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$lang = $request->getHeaderLine('Accept-Language') ?: 'zh_cn';
$lang = str_replace('-', '_', strtolower($lang));
$translator = ApplicationContext::getContainer()->get(TranslatorInterface::class);
$translator->setLocale($lang);
return $handler->handle($request);
}
}

View File

@ -7,13 +7,13 @@ namespace App\Model;
use Hyperf\DbConnection\Db;
/**
* @property int $translation_id
* @property string $group
* @property string $translation_key
* @property string $remark
* @property string $create_time
* @property string $update_time
* @property string $deleted_at
* @property int $translation_id
* @property string $group
* @property string $translation_key
* @property string $remark
* @property string $create_time
* @property string $update_time
* @property string $deleted_at
*/
class Translation extends Model
{
@ -48,6 +48,34 @@ class Translation extends Model
->paginate((int)$param['limit']);
}
public static function getLangValue(string $locale, string $key): string|null
{
list($group, $key) = explode('.', $key);
return (new self())->setTable("t")
->from("translation as t")
->join("translation_value as tv", "tv.translation_id", "=", "t.translation_id")
->where("t.group", $group)
->where("t.translation_key", $key)
->where("tv.lang_code", strtolower(str_replace("_", "-", $locale)))
->value("tv.lang_value");
}
public static function getLang(string $locale)
{
$data = self::with(["values" => function ($query) use ($locale) {
var_dump(strtolower(str_replace("_", "-", $locale)));
$query->where('lang_code', strtolower(str_replace("_", "-", $locale)))->select(['lang_value','translation_id']);
}])->select(['group', 'translation_key', 'translation_id'])
->get()
->toArray();
// 组合数据
$json = [];
foreach ($data as $item) {
$json[$item['group']][$item['translation_key']] = count($item['values']) > 0 ? $item['values'][0]['lang_value'] : "";
}
return $json;
}
public function values()
{
return $this->hasMany(TranslationValue::class, 'translation_id', 'translation_id');

View File

@ -0,0 +1,45 @@
<?php
namespace App\Service;
use Hyperf\Cache\Cache;
use Hyperf\Contract\TranslatorInterface;
use Hyperf\Contract\TranslatorLoaderInterface;
use Hyperf\Translation\Translator;
use App\Model\Translation as tModel;
use Psr\Container\ContainerInterface;
use function Hyperf\Config\config;
class TranslationService extends Translator implements TranslatorInterface
{
protected Cache $cache;
public function __construct(TranslatorLoaderInterface $loader, ContainerInterface $container)
{
parent::__construct($loader, 'zh_CN');
$this->cache = $container->get(Cache::class);
}
public function get($key, array $replace = [], $locale = null, $fallback = true): array|string
{
$locale = $locale ?: $this->getLocale();
$cacheKey = "lang:{$locale}:{$key}";
// 先查缓存
$cached = $this->cache->get($cacheKey);
if ($cached !== null) {
return $this->makeReplacements($cached, $replace);
}
// 查数据库
$value = tModel::getLangValue($locale, $key);
if ($value) {
$this->cache->set($cacheKey, $value, (int)config("translation.ttl"));
return $this->makeReplacements($value, $replace);
}
// 文件翻译
$fallbackValue = parent::get($key, $replace, $locale, $fallback);
// fallback 结果也缓存
$this->cache->set($cacheKey, $fallbackValue, (int)config("translation.ttl"));
return $fallbackValue;
}
}

View File

@ -151,4 +151,13 @@ class Str
return "other";
}
}
static function splitKey(string $key): array
{
$parts = explode('.', $key);
$first = array_shift($parts);
$rest = implode('.', $parts);
return [$first, $rest];
}
}

View File

@ -31,6 +31,7 @@
"hyperf/process": "~3.1.0",
"hyperf/rate-limit": "^3.1",
"hyperf/redis": "~3.1.0",
"hyperf/translation": "^3.1",
"hyperf/validation": "^3.1",
"hyperf/view": "^3.1",
"hyperf/websocket-server": "^3.1",

View File

@ -1,13 +1,10 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
use Hyperf\Contract\TranslatorInterface;
return [
// 多语言翻译
TranslatorInterface::class => \App\Service\TranslationService::class,
];

View File

@ -4,13 +4,6 @@ declare(strict_types=1);
use function Hyperf\Support\env;
/**
* This file is part of hyperf-ext/jwt
*
* @link https://github.com/hyperf-ext/jwt
* @contact eric@zhu.email
* @license https://github.com/hyperf-ext/jwt/blob/master/LICENSE
*/
return [
// 公钥
'public' => env('JWT_PUBLIC_KEY'),
@ -21,5 +14,5 @@ return [
// 使用者
'aud' => 'member',
// 过期时间
'ttl' => 30 * 24 * 60 *60
'ttl' => 30 * 24 * 60 * 60
];

View File

@ -13,6 +13,7 @@ return [
'http' => [
Hyperf\Validation\Middleware\ValidationMiddleware::class,
App\Middleware\JWTMiddleware::class,
App\Middleware\CorsMiddleware::class
App\Middleware\CorsMiddleware::class,
App\Middleware\LanguageMiddleware::class,
],
];

View File

@ -0,0 +1,12 @@
<?php
return [
// 默认语言
'locale' => 'zh_CN',
// 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本
'fallback_locale' => 'en',
// 语言文件存放的文件夹
'path' => BASE_PATH . '/static/languages',
// 缓存时长
'ttl' => 30 * 24 * 60 * 60
];