Files
new-api-analytics/lib/i18n.tsx
shangzy 20a3d399d9 fix: resolve all eslint errors (set-state-in-effect, nested components, no-explicit-any)
- Wrap synchronous setState calls in useEffect with startTransition to avoid cascading renders
- Convert nested SortIcon components to renderSortIcon helper functions
- Replace all `any` types with proper interfaces (OverviewData, TrendPoint, RankItem)
- Remove unused formatTokens import in logs page
- Add no-any rule to CLAUDE.md
2026-04-07 15:19:10 +08:00

222 lines
6.8 KiB
TypeScript
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.
"use client";
import { createContext, useContext, useState, useEffect, startTransition, 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",
"agg.ratio": "转换率",
"agg.ratioTip": "输出Token / 输入Token反映每次请求的生成效率。>1 表示输出多于输入(如生成、写作),<1 表示输入多于输出(如分析、摘要)",
// 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",
"agg.ratio": "Out/In Ratio",
"agg.ratioTip": "Completion tokens / Prompt tokens. >1 means more output than input (generation, writing); <1 means more input than output (analysis, summarization)",
"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")) {
startTransition(() => 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);
}