ec0942e1e7
Deploy Server / deploy-server (push) Successful in 2m47s
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
150 lines
8.9 KiB
TypeScript
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;
|
|
};
|
|
}
|