122 行
3.9 KiB
PHP
122 行
3.9 KiB
PHP
<?php
|
|
if (!defined('IN_APP')) exit('Forbidden');
|
|
class Lang
|
|
{
|
|
private static $locale = 'zh_CN';
|
|
private static $cache = [];
|
|
private static $dir;
|
|
public static function setDir($dir)
|
|
{
|
|
self::$dir = rtrim($dir, '/\\');
|
|
}
|
|
public static function getLocale()
|
|
{
|
|
return self::$locale;
|
|
}
|
|
public static function setLocale($locale)
|
|
{
|
|
$file = self::$dir . DIRECTORY_SEPARATOR . $locale . '.json';
|
|
if (!file_exists($file)) return false;
|
|
self::$locale = $locale;
|
|
if (isset(self::$cache[$locale])) unset(self::$cache[$locale]);
|
|
return true;
|
|
}
|
|
public static function detectLocale()
|
|
{
|
|
if (!empty($_SESSION['lang'])) {
|
|
$lang = preg_replace('/[^a-zA-Z0-9_]/', '', $_SESSION['lang']);
|
|
if (self::setLocale($lang)) return;
|
|
}
|
|
if (!empty($_GET['lang'])) {
|
|
$lang = preg_replace('/[^a-zA-Z0-9_]/', '', $_GET['lang']);
|
|
if (self::setLocale($lang)) {
|
|
$_SESSION['lang'] = $lang;
|
|
setcookie('fnw_lang', $lang, time() + 31536000, '/');
|
|
return;
|
|
}
|
|
}
|
|
if (!empty($_COOKIE['fnw_lang'])) {
|
|
$lang = $_COOKIE['fnw_lang'];
|
|
if (self::setLocale($lang)) return;
|
|
}
|
|
self::$locale = 'zh_CN';
|
|
}
|
|
public static function trans($key, ...$args)
|
|
{
|
|
$data = self::load(self::$locale);
|
|
$value = self::getNested($data, $key);
|
|
if ($value === null) {
|
|
if (self::$locale !== 'zh_CN') {
|
|
$dataZh = self::load('zh_CN');
|
|
$value = self::getNested($dataZh, $key);
|
|
}
|
|
if ($value === null) return $key;
|
|
}
|
|
if (!empty($args)) {
|
|
$value = self::replacePlaceholders($value, $args);
|
|
}
|
|
return $value;
|
|
}
|
|
public static function available()
|
|
{
|
|
$list = [];
|
|
if (!is_dir(self::$dir)) return $list;
|
|
foreach (glob(self::$dir . DIRECTORY_SEPARATOR . '*.json') as $f) {
|
|
$code = pathinfo($f, PATHINFO_FILENAME);
|
|
$data = json_decode(file_get_contents($f), true);
|
|
if (isset($data['_meta']['name'])) {
|
|
$list[] = [
|
|
'code' => $code,
|
|
'name' => $data['_meta']['name'],
|
|
'direction' => $data['_meta']['direction'] ?? 'ltr',
|
|
];
|
|
}
|
|
}
|
|
return $list;
|
|
}
|
|
public static function htmlLang()
|
|
{
|
|
$map = ['zh_CN' => 'zh-CN', 'en_US' => 'en'];
|
|
return $map[self::$locale] ?? substr(self::$locale, 0, 2);
|
|
}
|
|
private static function load($locale)
|
|
{
|
|
if (isset(self::$cache[$locale])) return self::$cache[$locale];
|
|
$file = self::$dir . DIRECTORY_SEPARATOR . $locale . '.json';
|
|
if (!file_exists($file)) return [];
|
|
$json = file_get_contents($file);
|
|
self::$cache[$locale] = json_decode($json, true) ?: [];
|
|
return self::$cache[$locale];
|
|
}
|
|
private static function getNested($arr, $key)
|
|
{
|
|
$keys = explode('.', $key);
|
|
$val = $arr;
|
|
foreach ($keys as $k) {
|
|
if (!is_array($val) || !array_key_exists($k, $val)) return null;
|
|
$val = $val[$k];
|
|
}
|
|
return is_string($val) || is_numeric($val) ? (string)$val : null;
|
|
}
|
|
private static function replacePlaceholders($text, $args)
|
|
{
|
|
if (count($args) === 1 && is_array($args[0])) {
|
|
$map = $args[0];
|
|
foreach ($map as $k => $v) {
|
|
$text = str_replace('{' . $k . '}', $v, $text);
|
|
}
|
|
} else {
|
|
foreach ($args as $i => $v) {
|
|
$text = str_replace('{' . $i . '}', $v, $text);
|
|
}
|
|
}
|
|
return $text;
|
|
}
|
|
}
|
|
if (!function_exists('__')) {
|
|
function __($key, ...$args)
|
|
{
|
|
return Lang::trans($key, ...$args);
|
|
}
|
|
}
|