Files
pangolin/web/usercenter/lib/i18n.ts
T
wangjia ec0942e1e7
Deploy Server / deploy-server (push) Successful in 2m47s
feat(usercenter): SSO /sso 落地页(拿票兑会话→自动登录)
App 打开 app.yanmeiai.com/sso?t=<ticket>&redirect=<路径>;本页 exchangeWebTicket→setSession
(与正常登录同路径)→跳白名单相对路径。镜像 jiu sso.njk。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-07 00:02:48 +08:00

150 lines
8.9 KiB
TypeScript

// i18n.ts — 穿山甲 Web 用户中心 · 双语字串(单显,绝不并排)
// 直接承袭 design/ui_kits/usercenter/ucparts.jsx 的 UCSTRINGS,并补充设置/设备/TOTP 键。
export type Lang = 'zh' | 'en';
type Entry = { zh: string; en: string };
export const STRINGS: Record<string, Entry> = {
navOverview: { zh: '概览', en: 'Overview' },
navSub: { zh: '订阅', en: 'Subscription' },
navRedeem: { zh: '兑换 & 购买', en: 'Redeem & buy' },
navInvite: { zh: '邀请返利', en: 'Referral' },
navSettings: { zh: '设置', en: 'Settings' },
signOut: { zh: '退出', en: 'Sign out' },
/* login */
loginTitle: { zh: '登录用户中心', en: 'Log in to your account' },
loginSub: { zh: '管理订阅、兑换激活码、查看用量', en: 'Manage subscription, redeem codes, track usage' },
emailLabel: { zh: '邮箱', en: 'Email' },
emailPh: { zh: '你的邮箱地址', en: 'your@email.com' },
pwLabel: { zh: '密码', en: 'Password' },
pwPh: { zh: '输入密码', en: 'Enter password' },
doLogin: { zh: '登录', en: 'Log in' },
forgotPw: { zh: '忘记密码?', en: 'Forgot password?' },
noAccount: { zh: '没有账户?在 App 内注册', en: 'No account? Sign up in the app' },
loginFailed: { zh: '邮箱或密码错误', en: 'Wrong email or password' },
loginLocked: { zh: '失败次数过多,账户已临时锁定', en: 'Too many attempts — account temporarily locked' },
lockedCountdown: { zh: '请于 {s} 秒后重试', en: 'Try again in {s}s' },
/* sso(App→网页免登录落地页) */
ssoTitle: { zh: '正在登录…', en: 'Signing in…' },
ssoMsg: { zh: '正在验证来自 App 的登录票据', en: 'Verifying the sign-in ticket from the app' },
ssoFailTitle: { zh: '登录跳转失败', en: 'Sign-in redirect failed' },
ssoFailHint: { zh: '即将跳转到登录页,请手动登录', en: 'Redirecting to the login page, please sign in manually' },
/* overview */
greeting: { zh: '欢迎回来', en: 'Welcome back' },
curPlan: { zh: '当前套餐', en: 'Current plan' },
freePlan: { zh: '免费版', en: 'Free' },
proMember: { zh: 'PRO 会员', en: 'PRO member' },
expires: { zh: '有效期至', en: 'Expires' },
renew: { zh: '续费 / 升级', en: 'Renew / Upgrade' },
quotaToday: { zh: '今日剩余时长', en: 'Time left today' },
dataToday: { zh: '今日已用流量', en: 'Data used today' },
devices: { zh: '在线设备', en: 'Devices online' },
quotaFree: { zh: '免费版 · 每日 10 分钟', en: 'Free · 10 min/day' },
usageTitle: { zh: '近 7 日流量 (GB)', en: 'Last 7 days (GB)' },
quickSub: { zh: '快速操作', en: 'Quick actions' },
qaSub: { zh: '获取订阅链接', en: 'Get subscription' },
qaRedeem: { zh: '兑换激活码', en: 'Redeem a code' },
qaApp: { zh: '下载 App', en: 'Download apps' },
/* subscription */
subTitle: { zh: '我的订阅', en: 'My subscription' },
subDesc: { zh: '订阅链接是你的专属凭证,泄露后他人可使用你的额度。请勿分享。', en: 'Your subscription link is a private credential. Never share it.' },
subCopy: { zh: '复制链接', en: 'Copy link' },
subCopied: { zh: '已复制', en: 'Copied' },
subReset: { zh: '重置链接', en: 'Reset link' },
subResetSub: { zh: '旧链接立即失效,所有设备需重新导入', en: 'Old link stops working; re-import on all devices' },
subResetOk: { zh: '已重置,请重新导入', en: 'Reset — re-import on your devices' },
scanTitle: { zh: '扫码导入', en: 'Scan to import' },
scanSub: { zh: '用穿山甲 App 或三方客户端扫码', en: 'Scan with the Pangolin app or a 3rd-party client' },
importTitle: { zh: '一键导入三方客户端', en: 'One-tap import' },
importSub: { zh: '已安装对应客户端时,点击即自动导入订阅。', en: 'If the client is installed, tapping imports the subscription automatically.' },
fmtNote: { zh: '同一链接同时兼容 sing-box / Clash.Meta / v2ray 格式。', en: 'One link serves sing-box / Clash.Meta / v2ray formats.' },
/* redeem */
redeemTitle: { zh: '兑换激活码', en: 'Redeem a code' },
redeemPh: { zh: '输入激活码', en: 'Enter activation code' },
redeemBtn: { zh: '激活', en: 'Redeem' },
redeemOk: { zh: '激活成功 · 套餐已到账', en: 'Activated — plan applied' },
buyTitle: { zh: '购买渠道', en: 'Where to buy' },
buySub: { zh: '本站不直接收款。通过以下渠道购买激活码,回到本页兑换即可:', en: 'We never take payment on this site. Buy a code via a channel below, then redeem here:' },
chStore: { zh: '自助发卡商店', en: 'Self-serve store' },
chStoreSub: { zh: '支付宝 / 微信 · 自动发码', en: 'Alipay / WeChat · instant code' },
chUsdtSub: { zh: '链上转账 · 最隐私 · 自动发码', en: 'On-chain · most private · instant code' },
chEmail: { zh: '邮箱客服', en: 'Email support' },
/* invite */
inviteTitle: { zh: '邀请返利', en: 'Referral' },
inviteSub: { zh: '好友通过你的链接注册并付费,你获得其首单 20% 余额返利,可抵扣续费。', en: 'When a friend signs up and pays via your link, you earn 20% of their first order as credit.' },
inviteLink: { zh: '我的邀请链接', en: 'My invite link' },
invited: { zh: '已邀请', en: 'Invited' },
paidUsers: { zh: '已付费', en: 'Converted' },
earned: { zh: '累计返利', en: 'Credit earned' },
inviteRecord: { zh: '邀请记录', en: 'History' },
recEmpty: { zh: '暂无邀请记录', en: 'No referrals yet' },
recRegistered: { zh: '已注册', en: 'Registered' },
recPaid: { zh: '已付费', en: 'Paid' },
/* 2FA login step */
twoFATitle: { zh: '双重认证', en: 'Two-factor auth' },
twoFAHint: { zh: '你的账户已开启双重认证。请输入身份验证器 App 中的 6 位动态码。', en: 'Two-factor auth is on for this account. Enter the 6-digit code from your authenticator app.' },
twoFAConfirm: { zh: '验证并登录', en: 'Verify & log in' },
twoFABack: { zh: '返回上一步', en: 'Back' },
twoFAWrong: { zh: '动态码不正确,请重试', en: 'Invalid code, try again' },
/* settings */
settingsTitle: { zh: '设置', en: 'Settings' },
prefTitle: { zh: '偏好', en: 'Preferences' },
prefLang: { zh: '显示语言', en: 'Language' },
prefTheme: { zh: '外观主题', en: 'Theme' },
themeLight: { zh: '浅色', en: 'Light' },
themeDark: { zh: '深色', en: 'Dark' },
/* devices */
devTitle: { zh: '设备管理', en: 'Devices' },
devSub: { zh: '管理已登录本账户的设备,移除后该设备需重新登录。', en: 'Devices signed in to your account. Removing one signs it out.' },
devCurrent: { zh: '当前设备', en: 'This device' },
devLastActive: { zh: '最近活跃', en: 'Last active' },
devRemove: { zh: '移除', en: 'Remove' },
devRemoveConfirmTitle: { zh: '移除此设备?', en: 'Remove this device?' },
devRemoveConfirmSub: { zh: '该设备将被登出,需重新输入凭证才能再次连接。', en: 'It will be signed out and must re-authenticate to connect again.' },
devEmpty: { zh: '暂无其他设备', en: 'No devices yet' },
cancel: { zh: '取消', en: 'Cancel' },
confirm: { zh: '确认移除', en: 'Remove' },
/* TOTP management */
totpTitle: { zh: '双重认证 (TOTP)', en: 'Two-factor auth (TOTP)' },
totpOff: { zh: '未开启', en: 'Off' },
totpOn: { zh: '已开启', en: 'On' },
totpDesc: { zh: '用身份验证器 App 生成的一次性动态码保护登录,显著提升账户安全。', en: 'Protect sign-in with one-time codes from an authenticator app.' },
totpEnable: { zh: '开启双重认证', en: 'Enable 2FA' },
totpDisableBtn: { zh: '关闭双重认证', en: 'Disable 2FA' },
totpStep1: { zh: '1. 用身份验证器扫码,或手动输入密钥', en: '1. Scan with an authenticator, or enter the key manually' },
totpSecretLabel: { zh: '手动密钥', en: 'Manual key' },
totpStep2: { zh: '2. 输入 App 显示的 6 位动态码以确认', en: '2. Enter the 6-digit code shown in the app to confirm' },
totpVerifyBtn: { zh: '确认开启', en: 'Confirm & enable' },
totpEnabledOk: { zh: '双重认证已开启', en: 'Two-factor auth enabled' },
totpDisabledOk: { zh: '双重认证已关闭', en: 'Two-factor auth disabled' },
totpDisableHint: { zh: '输入当前动态码以关闭双重认证。', en: 'Enter your current code to disable 2FA.' },
copyKey: { zh: '复制密钥', en: 'Copy key' },
/* generic errors */
errNetwork: { zh: '网络异常,请稍后重试', en: 'Network error, please retry' },
errUnknown: { zh: '操作失败,请稍后重试', en: 'Something went wrong, please retry' },
loading: { zh: '加载中…', en: 'Loading…' },
};
export type TFn = (key: string, vars?: Record<string, string | number>) => string;
export function makeT(lang: Lang): TFn {
return (key, vars) => {
const e = STRINGS[key];
let s = e ? e[lang] || key : key;
if (vars) for (const k of Object.keys(vars)) s = s.replace(`{${k}}`, String(vars[k]));
return s;
};
}