93 lines
3.4 KiB
PHP
93 lines
3.4 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
namespace app\api\util;
|
||
|
||
use support\Request;
|
||
|
||
/**
|
||
* API 多语言(兼容 Webman 多语言配置)
|
||
* 根据请求头 lang(zh=中文,en=英文)返回对应文案;
|
||
* 无 lang 请求头时使用 config('translation.locale') 推断(zh_CN/zh→中文,en→英文)
|
||
*/
|
||
class ApiLang
|
||
{
|
||
private const LANG_HEADER = 'lang';
|
||
private const LANG_EN = 'en';
|
||
private const LANG_ZH = 'zh';
|
||
|
||
/** @var array<string, array<string, string>> locale => [ 中文 => 译文 ] */
|
||
private static array $messages = [];
|
||
|
||
/**
|
||
* 从请求中获取语言:优先读 header lang,否则按 Webman config('translation.locale') 推断
|
||
*/
|
||
public static function getLang(?Request $request = null): string
|
||
{
|
||
$request = $request ?? (function_exists('request') ? request() : null);
|
||
if ($request !== null) {
|
||
$lang = $request->header(self::LANG_HEADER);
|
||
if ($lang !== null && $lang !== '') {
|
||
$lang = strtolower(trim((string) $lang));
|
||
if ($lang === self::LANG_EN) {
|
||
return self::LANG_EN;
|
||
}
|
||
if ($lang === self::LANG_ZH || $lang === 'chs') {
|
||
return self::LANG_ZH;
|
||
}
|
||
}
|
||
}
|
||
$locale = (string) (function_exists('config') ? config('translation.locale', 'zh_CN') : 'zh_CN');
|
||
return stripos($locale, 'en') !== false ? self::LANG_EN : self::LANG_ZH;
|
||
}
|
||
|
||
/**
|
||
* 翻译文案:lang=zh 返回原文(中文),lang=en 返回英文映射
|
||
* 语言文件优先从 Webman resource/translations/api/{locale}.php 加载,否则从 app/api/lang 加载
|
||
*/
|
||
public static function translate(string $message, ?Request $request = null): string
|
||
{
|
||
$lang = self::getLang($request);
|
||
if ($lang !== self::LANG_EN) {
|
||
return $message;
|
||
}
|
||
$map = self::loadMessages(self::LANG_EN);
|
||
return $map[$message] ?? $message;
|
||
}
|
||
|
||
/**
|
||
* 加载某语言的 API 文案(key=中文,value=译文)
|
||
*/
|
||
private static function loadMessages(string $locale): array
|
||
{
|
||
if (isset(self::$messages[$locale])) {
|
||
return self::$messages[$locale];
|
||
}
|
||
$path = null;
|
||
if (function_exists('config')) {
|
||
$base = rtrim((string) config('translation.path', ''), DIRECTORY_SEPARATOR);
|
||
if ($base !== '') {
|
||
$path = $base . DIRECTORY_SEPARATOR . 'api' . DIRECTORY_SEPARATOR . $locale . '.php';
|
||
}
|
||
}
|
||
if (($path === null || !is_file($path)) && $locale === self::LANG_EN) {
|
||
$path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . 'en.php';
|
||
}
|
||
self::$messages[$locale] = ($path !== null && is_file($path)) ? (require $path) : [];
|
||
return self::$messages[$locale];
|
||
}
|
||
|
||
/**
|
||
* 带占位符的翻译,如 translateParams('当前玩家余额%s小于%s无法继续游戏', [$coin, $minCoin])
|
||
* 先翻译再替换(en 文案使用 %s 占位)
|
||
*/
|
||
public static function translateParams(string $message, array $params = [], ?Request $request = null): string
|
||
{
|
||
$translated = self::translate($message, $request);
|
||
if ($params !== []) {
|
||
$translated = sprintf($translated, ...$params);
|
||
}
|
||
return $translated;
|
||
}
|
||
}
|