Files
new-api-analytics/lib/i18n.tsx
shangzy 9bb36432ba feat: global time range context with custom date picker
Lift time range state into a shared React context so the selected
range persists across page navigation and browser refreshes
(localStorage). Add a "Custom" option with a popover date picker
that lets users specify arbitrary start/end dates. All preset end
times now use endOf("day") (23:59:59) instead of the current moment.
2026-04-07 14:49:58 +08:00

216 lines
6.3 KiB
TypeScript

"use client";
import { createContext, useContext, useState, useEffect, type ReactNode } from "react";
export type Locale = "zh" | "en";
const translations = {
zh: {
// nav
"nav.overview": "总览",
"nav.rankings": "排名",
"nav.aggregation": "聚合",
"nav.logs": "日志",
// common
"common.loading": "加载中...",
"common.noData": "暂无数据",
"common.records": "条记录",
"common.systemOnline": "系统在线",
"common.back": "返回",
"common.backToRankings": "返回排名",
"common.prevPage": "上一页",
"common.nextPage": "下一页",
"common.share": "占比",
// time range
"time.today": "今日",
"time.7d": "7 天",
"time.30d": "30 天",
"time.all": "全部",
"time.custom": "自定义",
"time.startDate": "开始日期",
"time.endDate": "结束日期",
"time.confirm": "确认",
// granularity
"gran.day": "日",
"gran.week": "周",
"gran.month": "月",
// metrics
"metric.token": "Token",
"metric.calls": "调用量",
// dashboard
"dash.title": "仪表盘",
"dash.totalCalls": "调用次数",
"dash.tokenUsage": "Token 消耗",
"dash.activeUsers": "活跃用户",
"dash.activeModels": "活跃模型",
"dash.trend": "使用趋势",
"dash.userTop10": "用户 Top 10 — Token 消耗",
"dash.modelTop10": "模型 Top 10 — Token 消耗",
// table headers
"th.rank": "#",
"th.name": "名称",
"th.user": "用户",
"th.calls": "调用次数",
"th.input": "输入",
"th.output": "输出",
"th.totalToken": "总 Token",
"th.time": "时间",
"th.realModel": "真实模型",
"th.channel": "渠道",
"th.latency": "耗时",
// rankings
"rank.title": "排名",
"rank.user": "用户",
"rank.model": "模型",
"rank.channel": "渠道",
// aggregation
"agg.title": "用户聚合",
"agg.userCount": "用户数",
"agg.totalCalls": "总调用",
"agg.totalToken": "总 Token",
// logs
"logs.title": "日志明细",
"logs.filterUser": "用户名",
"logs.filterModel": "模型",
"logs.filterToken": "Token 名称",
// detail
"detail.user": "用户",
"detail.model": "模型",
"detail.channel": "渠道",
"detail.trend": "使用趋势",
"detail.modelDist": "模型分布",
"detail.userDist": "用户分布",
// theme
"theme.light": "浅色",
"theme.dark": "深色",
"theme.system": "系统",
// portal
"portal.subtitle": "智能 API 网关平台",
"portal.monitoring": "监控站",
"portal.monitoringDesc": "实时系统状态监控与告警通知",
"portal.docs": "文档中心",
"portal.docsDesc": "API 接口文档与集成指南",
"portal.analytics": "使用统计",
"portal.analyticsDesc": "API 调用数据分析与可视化看板",
"portal.enter": "进入",
},
en: {
"nav.overview": "Overview",
"nav.rankings": "Rankings",
"nav.aggregation": "Aggregation",
"nav.logs": "Logs",
"common.loading": "Loading...",
"common.noData": "No data",
"common.records": "records",
"common.systemOnline": "System Online",
"common.back": "Back",
"common.backToRankings": "Back to Rankings",
"common.prevPage": "Previous",
"common.nextPage": "Next",
"common.share": "Share",
"time.today": "Today",
"time.7d": "7 Days",
"time.30d": "30 Days",
"time.all": "All",
"time.custom": "Custom",
"time.startDate": "Start",
"time.endDate": "End",
"time.confirm": "Confirm",
"gran.day": "Day",
"gran.week": "Week",
"gran.month": "Month",
"metric.token": "Token",
"metric.calls": "Calls",
"dash.title": "Dashboard",
"dash.totalCalls": "Total Calls",
"dash.tokenUsage": "Token Usage",
"dash.activeUsers": "Active Users",
"dash.activeModels": "Active Models",
"dash.trend": "Usage Trend",
"dash.userTop10": "User Top 10 — Token Usage",
"dash.modelTop10": "Model Top 10 — Token Usage",
"th.rank": "#",
"th.name": "Name",
"th.user": "User",
"th.calls": "Calls",
"th.input": "Input",
"th.output": "Output",
"th.totalToken": "Total Token",
"th.time": "Time",
"th.realModel": "Real Model",
"th.channel": "Channel",
"th.latency": "Latency",
"rank.title": "Rankings",
"rank.user": "User",
"rank.model": "Model",
"rank.channel": "Channel",
"agg.title": "User Aggregation",
"agg.userCount": "Users",
"agg.totalCalls": "Total Calls",
"agg.totalToken": "Total Token",
"logs.title": "Log Details",
"logs.filterUser": "Username",
"logs.filterModel": "Model",
"logs.filterToken": "Token Name",
"detail.user": "User",
"detail.model": "Model",
"detail.channel": "Channel",
"detail.trend": "Usage Trend",
"detail.modelDist": "Model Distribution",
"detail.userDist": "User Distribution",
"theme.light": "Light",
"theme.dark": "Dark",
"theme.system": "System",
"portal.subtitle": "Intelligent API Gateway Platform",
"portal.monitoring": "Monitoring",
"portal.monitoringDesc": "Real-time system status monitoring & alerts",
"portal.docs": "Documentation",
"portal.docsDesc": "API reference docs & integration guides",
"portal.analytics": "Usage Analytics",
"portal.analyticsDesc": "API usage data analytics & visualization dashboard",
"portal.enter": "Enter",
},
} as const;
type TranslationKey = keyof typeof translations.zh;
interface I18nContextType {
locale: Locale;
setLocale: (l: Locale) => void;
t: (key: TranslationKey) => string;
}
const I18nContext = createContext<I18nContextType>({
locale: "zh",
setLocale: () => {},
t: (key) => key,
});
export function I18nProvider({ children }: { children: ReactNode }) {
const [locale, setLocale] = useState<Locale>("zh");
useEffect(() => {
const saved = localStorage.getItem("locale") as Locale | null;
if (saved && (saved === "zh" || saved === "en")) setLocale(saved);
}, []);
const handleSetLocale = (l: Locale) => {
setLocale(l);
localStorage.setItem("locale", l);
};
const t = (key: TranslationKey): string => {
return translations[locale][key] || key;
};
return (
<I18nContext.Provider value={{ locale, setLocale: handleSetLocale, t }}>
{children}
</I18nContext.Provider>
);
}
export function useI18n() {
return useContext(I18nContext);
}