diff --git a/frontend/src/components/ebook/BuyEbook.tsx b/frontend/src/components/ebook/BuyEbook.tsx
index 4c68f40..b242cdb 100644
--- a/frontend/src/components/ebook/BuyEbook.tsx
+++ b/frontend/src/components/ebook/BuyEbook.tsx
@@ -20,7 +20,7 @@ export function BuyEbook({ compact = false }: { compact?: boolean }) {
const features = getFeatures();
const enabled = features.payment?.checkout?.enabled !== false;
const productName = features.payment?.checkout?.productName || "Download Edition";
- const buttonText = features.payment?.checkout?.buttonText || "购买下载版";
+ const buttonText = features.payment?.checkout?.buttonText || t("payment.buyDownload");
useEffect(() => {
if (!token) return;
@@ -47,7 +47,6 @@ export function BuyEbook({ compact = false }: { compact?: boolean }) {
if (res.order_id) {
localStorage.setItem("nomadro-ebook-order", res.order_id);
}
- // DEV_AUTO_PAY or already-paid: confirm then go to thanks
if (res.status === "paid" && res.order_id) {
await api.completePayment(token, res.order_id).catch(() => null);
router.push(`/book/thanks?order_id=${encodeURIComponent(res.order_id)}`);
@@ -68,11 +67,12 @@ export function BuyEbook({ compact = false }: { compact?: boolean }) {
{t("payment.buyGet", { name: productName })}
{t("payment.buySub")}
{error ?
{error}
: null}
- 也可免费 在线阅读
+ {t("payment.orReadOnline")}{" "}
+ {t("thanks.purchaseContinue")}
);
diff --git a/frontend/src/lib/ebook/i18n/messages/en.ts b/frontend/src/lib/ebook/i18n/messages/en.ts
index 7d0a7ab..b985138 100644
--- a/frontend/src/lib/ebook/i18n/messages/en.ts
+++ b/frontend/src/lib/ebook/i18n/messages/en.ts
@@ -137,6 +137,9 @@ export const messages = {
payFailed: 'Payment failed',
buyGet: 'Get the {name}',
buySub: 'Read free online, or grab PDF & EPUB for offline and permanent access.',
+ buyDownload: 'Buy download edition',
+ ownedDownload: 'Owned · Downloads',
+ orReadOnline: 'Or read free',
checkoutFailed: 'Checkout failed',
},
thanks: {
diff --git a/frontend/src/lib/ebook/i18n/messages/zh.ts b/frontend/src/lib/ebook/i18n/messages/zh.ts
index 6fad094..cc08aba 100644
--- a/frontend/src/lib/ebook/i18n/messages/zh.ts
+++ b/frontend/src/lib/ebook/i18n/messages/zh.ts
@@ -137,6 +137,9 @@ export const messages = {
payFailed: '支付失败',
buyGet: '购买 {name}',
buySub: '可免费在线阅读,或购买 PDF 与 EPUB 离线永久保存。',
+ buyDownload: '购买下载版',
+ ownedDownload: '已购买 · 去下载',
+ orReadOnline: '也可免费',
checkoutFailed: '结账失败',
},
thanks: {
diff --git a/frontend/src/lib/i18n/dictionaries.ts b/frontend/src/lib/i18n/dictionaries.ts
index 2e675f5..88e6e49 100644
--- a/frontend/src/lib/i18n/dictionaries.ts
+++ b/frontend/src/lib/i18n/dictionaries.ts
@@ -595,7 +595,7 @@ export const zh = {
missingLesson: "课时不存在",
backCatalog: "返回课程目录",
dayGuide: "每日指南",
- dayGuideDesc: "从税务居民到落地验网,三天起步清单",
+ dayGuideDesc: "从税务居民到固定作息,七天落地清单",
back: "学院首页",
backCourse: "课程目录",
locked: "此课时需要 VIP",
@@ -757,6 +757,8 @@ export const zh = {
replyNeed: "请先写一点回复内容",
replyOk: "回复已发布",
replyFail: "回复失败",
+ likeFail: "点赞失败,请稍后重试",
+ replyShortcut: "Ctrl/⌘ + Enter 发送",
noRepliesYet: "还没有回复,来做第一个吧",
catAll: "全部",
catVisa: "签证",
@@ -769,6 +771,27 @@ export const zh = {
draftHint: "内容会自动保存在本机",
replyDraftRestored: "已恢复未发送的回复草稿",
},
+ bookThanks: {
+ title: "下载版",
+ needLogin: "请先登录后查看下载。",
+ checking: "正在确认订单…",
+ pending: "支付确认中,请稍后刷新;或联系支持核对订单。",
+ statusFail: "无法确认购买状态",
+ refresh: "刷新状态",
+ confirmedNoFiles: "购买已确认。PDF/EPUB 下载暂未开放。",
+ confirmedHint: "可先在线阅读完整版,或联系支持获取文件。",
+ continueRead: "继续在线阅读",
+ contact: "联系支持",
+ ready: "购买成功,可下载:",
+ },
+ blogDetail: {
+ back: "返回博客",
+ readTime: "{n} 分钟阅读",
+ related: "相关文章",
+ readMore: "阅读 →",
+ explore: "接着探索",
+ submit: "投稿",
+ },
gigs: {
tag: "💼 GIGS",
title: "赏金任务",
@@ -1908,7 +1931,7 @@ export const en: { [K in keyof typeof zh]: typeof zh[K] extends string ? string
missingLesson: "Lesson not found",
backCatalog: "Back to catalog",
dayGuide: "Daily guides",
- dayGuideDesc: "Tax residency to landing Wi‑Fi — a 3-day starter checklist",
+ dayGuideDesc: "Tax residency to daily rhythm — a 7-day landing checklist",
back: "Academy home",
backCourse: "Course catalog",
locked: "VIP required",
@@ -2070,6 +2093,8 @@ export const en: { [K in keyof typeof zh]: typeof zh[K] extends string ? string
replyNeed: "Write a reply first",
replyOk: "Reply posted",
replyFail: "Reply failed",
+ likeFail: "Couldn't like — try again",
+ replyShortcut: "Ctrl/⌘ + Enter to send",
noRepliesYet: "No replies yet — be the first",
catAll: "All",
catVisa: "Visa",
@@ -2082,6 +2107,27 @@ export const en: { [K in keyof typeof zh]: typeof zh[K] extends string ? string
draftHint: "Draft autosaves on this device",
replyDraftRestored: "Unsent reply draft restored",
},
+ bookThanks: {
+ title: "Download edition",
+ needLogin: "Sign in to view your downloads.",
+ checking: "Confirming your order…",
+ pending: "Payment is still confirming — refresh shortly or contact support.",
+ statusFail: "Could not confirm purchase status",
+ refresh: "Refresh status",
+ confirmedNoFiles: "Purchase confirmed. PDF/EPUB files are not configured yet.",
+ confirmedHint: "You can keep reading online, or contact support for files.",
+ continueRead: "Continue reading online",
+ contact: "Contact support",
+ ready: "Purchase complete — download:",
+ },
+ blogDetail: {
+ back: "Back to blog",
+ readTime: "{n} min read",
+ related: "Related posts",
+ readMore: "Read →",
+ explore: "Keep exploring",
+ submit: "Submit",
+ },
gigs: {
tag: "💼 GIGS",
title: "Bounty gigs",