---
title: "Copy deck"
description: "Every client string by key, in en and zh-Hans; generated from strings.json."
source: "design/copy.md"
---

> Part of [Brand and design](/design/llms.txt). Every page: [llms.txt](/llms.txt).

# Copy deck — en + zh-Hans (v1)

> **Generated** from `design/tools/strings.py` by `python3 design/tools/build.py`. Edit the catalog, not this file.
> Machine-readable twin: [`strings.json`](/design/strings.json) (xcstrings-shaped: `strings[key].localizations[en|zh-Hans].stringUnit.value`, `**bold**` markdown, `\n` newlines) — convert 1:1 into `Localizable.xcstrings`.

ADR-001 D13: the product is multilingual. **UI locale** (`en`, `zh-Hans`) and **practice language** (the article's language) are independent. Every key below has a real value in both UI locales — neither column is a gloss.

## Where strings come from

| Source | Examples | Localized by |
|---|---|---|
| **Client catalog** (this file) | buttons, titles, hints, empty/error states, accessibility labels, notification bodies | Device / `settings.ui_locale` → `Localizable.xcstrings` |
| **API strings** | `Home.greeting`, `Home.local_date_label`, `steps[].label`, `Topic.name`/`glyph`, `Level.title`, `band_label`, dimension `label`, micro-skill `Focus.title`/`instruction`, `comparison.verdict_label`, `Settlement.headline`/`subline`, `WeeklyQuests.quests[].title`, `Achievement.title`/`description`, `Growth.next_unlock`, `Paywall.benchmark_label`, `products[].badge`, `Exemplar.label`, `error.message`, `TextLength.label` | Server, from the request's `Accept-Language` (fallback `en`) — the client sends its UI locale on every request |
| **Content** | article title/body/byline/reading_hint, transcript, `Assessment.summary`, dimension `note`, `Evidence.*`, `one_action.*`, key points, exemplar text + voice | The **article's language** (`session.language`), regardless of UI locale. Rendered with `lang=` / `.environment(\.locale)` so VoiceOver picks the right voice |

Rules: specifiers follow Apple format (`%@`, `%lld`, positional `%1$@` where word order differs). Never concatenate fragments; never hard-code units — lengths come from `TextLength.label` ("301 字" / "300 words"), dates from `Date.FormatStyle` (`10月24日` / `Oct 24`), prices from StoreKit `displayPrice`. English runs ~1.6× longer than Chinese: every layout wraps; nothing truncates.

Conditional copy is listed as separate keys per variant (e.g. `complete.headline.*` per verdict, `unreliable.*` per reason, `record.button.*` per recorder state).


## Global

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `app.name` | Shuke | 述刻 | yes |
| `app.tagline` | Ten minutes a day to explain complex things clearly. | 每天十分钟，把复杂的事讲清楚。 | runtime / notifications |
| `common.continue` | Continue | 继续 | yes |
| `common.back` | Back | 返回 | yes |
| `common.close` | Close | 关闭 | runtime / notifications |
| `common.cancel` | Cancel | 取消 | yes |
| `common.retry` | Retry | 重试 | yes |
| `common.later` | Not now | 以后再说 | yes |
| `common.ok` | OK | 好的 | yes |
| `common.see_all` | See all | 查看全部 | yes |
| `common.all` | All | 全部 | yes |
| `common.today` | Today | 今天 | yes |
| `common.step_of.a11y` | Step %lld of %lld | 第 %lld 步，共 %lld 步 | yes |
| `common.read_seconds` | %lld sec read | 约 %lld 秒 | yes |
| `common.read_minutes` | %lld min read | 约 %lld 分钟 | yes |
| `common.read_min_sec` | %lld min %lld sec read | 约 %lld 分 %lld 秒 | runtime / notifications |
| `common.xp_plus` | +%lld XP | +%lld XP | runtime / notifications |
| `common.points` | %lld pts | %lld 分 | runtime / notifications |
| `common.seconds_shorter` | %lld s shorter | 少用 %lld 秒 | yes |
| `common.seconds_longer` | %lld s longer | 多用 %lld 秒 | yes |
| `common.same_duration` | Same length | 用时相同 | runtime / notifications |
| `common.difficulty` | Level %lld | 难度 %lld | yes |
| `common.error_code_retryable` | Error %@ · retryable | 错误代码 %@ · 可重试 | yes |
| `common.date_range` | %@ – %@ | %@ – %@ | yes |
| `tab.home` | Home | 首页 | yes |
| `tab.library` | Practice | 练习 | yes |
| `tab.growth` | Progress | 成长 | yes |
| `tab.profile` | Me | 我的 | yes |
| `tab.nav.a11y` | Main navigation | 主导航 | yes |

## Languages

Language names are shown in their own script (endonyms) in both UIs, as iOS does.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `lang.en` | English | English | yes |
| `lang.zh-Hans` | 中文（简体） | 中文（简体） | yes |
| `lang.short.en` | EN | EN | yes |
| `lang.short.zh-Hans` | 中 | 中 | yes |
| `lang.all` | All languages | 全部语言 | yes |
| `lang.follow_system` | Follow system | 跟随系统 | runtime / notifications |

## Score bands, dimensions, micro-skills

The API sends `band_label`, dimension `label` and micro-skill `title` localized by Accept-Language; these are the client fallbacks and the paywall's derived band.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `band.retry` | Needs practice | 需要再练 | runtime / notifications |
| `band.basic` | Good foundation | 基础不错 | yes |
| `band.clear` | Clear | 讲清楚了 | runtime / notifications |
| `band.excellent` | Excellent | 出色 | runtime / notifications |
| `dimension.key_info` | Key information | 关键信息 | yes |
| `dimension.structure` | Structure | 逻辑结构 | yes |
| `dimension.efficiency` | Efficiency | 表达效率 | yes |
| `dimension.fluency` | Fluency | 流畅度 | yes |
| `dimension.weights` | Weights 35 / 30 / 20 / 15 | 权重 35 / 30 / 20 / 15 | yes |
| `dimension.insufficient` | Not enough evidence · score unaffected | 依据不足 · 不影响分数 | yes |
| `micro.conclusion_first` | Conclusion first | 先说结论 | runtime / notifications |
| `micro.three_points` | Three points | 三点结构 | runtime / notifications |
| `micro.cut_fillers` | Cut fillers | 删掉口头禅 | runtime / notifications |
| `micro.keep_constraints` | Keep the caveats | 保留关键限制 | runtime / notifications |
| `micro.one_example` | One example | 一个例子 | runtime / notifications |
| `micro.name_the_claim` | Name the claim | 先点明观点 | runtime / notifications |
| `micro.drop_repeats` | No repeats | 不重复 | runtime / notifications |

## Onboarding

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `onboarding.progress.a11y` | Step %lld of %lld | 第 %lld 步，共 %lld 步 | yes |
| `onboarding.welcome.title` | Ten minutes a day.<br>Say complex things clearly. | 每天十分钟，<br>把复杂的事讲清楚。 | yes |
| `onboarding.welcome.body` | Read a short piece and retell it in your own words. AI points out one thing to change. Say it again and see the difference. | 读一篇短文，用自己的话讲一遍。AI 只指出一件要改的事，你再讲一遍，看见变化。 | yes |
| `onboarding.welcome.cta` | Get started | 开始 | yes |
| `onboarding.welcome.legal` | By continuing you agree to the %@ and %@. Recordings are transcribed and assessed by third-party AI services and never used to train models. | 继续即表示同意 %@ 和 %@。录音由第三方 AI 服务转写和评估，不会用于训练模型。 | yes |
| `onboarding.welcome.illo.meta` | Today · Product · 2 min read | 今日文章 · 产品 · 约 1 分钟 | yes |
| `onboarding.welcome.illo.oa` | Next time, lead with your conclusion. | 下一遍先说结论，再讲原因。 | yes |
| `onboarding.welcome.illo.first` | First take | 第一次 | yes |
| `onboarding.welcome.illo.again` | Second take | 再讲一次 | yes |
| `onboarding.language.title` | Which language do you want to practise? | 你想练习哪种语言？ | yes |
| `onboarding.language.subtitle` | You'll read and speak in this language. You can add more later in Settings. | 你会用这种语言阅读和复述。之后可以在设置里添加更多。 | yes |
| `onboarding.language.en.sub` | Read and retell in English | 英文文章，用英文复述 | yes |
| `onboarding.language.zh-Hans.sub` | Read and retell in Chinese | 中文文章，用中文复述 | yes |
| `onboarding.language.ui_note` | The app’s language follows your device (%@). Change it any time in Settings. | 界面语言跟随系统（%@），可在设置中修改。 | yes |
| `onboarding.goal.title` | What do you most want to improve? | 你最想提升哪一点？ | yes |
| `onboarding.goal.subtitle` | Pick the one that matters most. You can change it later. | 选一个最重要的，之后可以改。 | yes |
| `onboarding.goal.report_clearly` | Explain clearly at work | 汇报时讲清楚 | yes |
| `onboarding.goal.report_clearly.sub` | Meetings, updates, proposals | 开会、汇报、解释方案 | yes |
| `onboarding.goal.remember_more` | Remember what I read | 读完记得住 | yes |
| `onboarding.goal.remember_more.sub` | If you can say it, you understood it | 把读过的内容讲出来，才算懂 | yes |
| `onboarding.goal.create_content` | Create content | 做内容表达 | yes |
| `onboarding.goal.create_content.sub` | Better on video, podcasts and live | 视频、播客、直播里讲得更好 | yes |
| `onboarding.goal.speak_concisely` | Be more concise | 说话更简洁 | yes |
| `onboarding.goal.speak_concisely.sub` | Get to the point in the first sentence | 少绕弯，第一句就到点子上 | yes |
| `onboarding.scenario.title` | Where do you need to speak most? | 你常在哪里需要表达？ | yes |
| `onboarding.scenario.subtitle` | We’ll pick articles and advice to match. | 我们会按场景挑选文章和建议。 | yes |
| `onboarding.scenario.work_meeting` | Meetings and updates | 工作会议 / 汇报 | yes |
| `onboarding.scenario.work_meeting.sub` | Make one thing clear in a few minutes | 需要在几分钟内讲清一件事 | yes |
| `onboarding.scenario.study` | Study and exams | 学习 / 考试复述 | yes |
| `onboarding.scenario.study.sub` | Summarise and defend what you read | 读完材料后要复述、答辩 | yes |
| `onboarding.scenario.creator` | Video and podcasts | 做视频 / 播客 | yes |
| `onboarding.scenario.creator.sub` | Talking to a camera or a mic | 对着镜头或麦克风讲 | yes |
| `onboarding.scenario.social` | Everyday conversations | 日常交流 | yes |
| `onboarding.scenario.social.sub` | Explaining things to friends and family | 跟朋友、家人讲清楚一件事 | yes |
| `onboarding.scenario.topics.title` | Topics you like | 感兴趣的话题 | yes |
| `onboarding.scenario.topics.hint` | Optional · pick any | 可多选，可跳过 | yes |
| `onboarding.level.title` | How do you speak today? | 你现在讲得怎么样？ | yes |
| `onboarding.level.subtitle` | Go with your gut. The diagnostic will be more precise. | 凭感觉选就好，诊断会给出更准的结果。 | yes |
| `onboarding.level.beginner` | I often lose the thread | 经常讲着讲着就乱了 | yes |
| `onboarding.level.beginner.sub` | I say things as they come and get lost | 想到哪说到哪，自己也会绕晕 | yes |
| `onboarding.level.sometimes_clear` | Sometimes clear, sometimes rambling | 有时清楚，有时会绕 | yes |
| `onboarding.level.sometimes_clear.sub` | Fine when prepared, messy on the spot | 准备过的能讲好，临场容易乱 | yes |
| `onboarding.level.mostly_clear` | Mostly clear, want it tighter | 大多清楚，想更简洁 | yes |
| `onboarding.level.mostly_clear.sub` | I get there, just not crisply | 能讲明白，但还不够利落 | yes |
| `onboarding.commitment.title` | How many days a week? | 每周想练几天？ | yes |
| `onboarding.commitment.subtitle` | About 10 minutes each. Change it any time. | 每次大约 10 分钟。之后随时可以改。 | yes |
| `onboarding.commitment.unit.easy` | days · easy | 天 · 轻松 | yes |
| `onboarding.commitment.unit.steady` | days · steady | 天 · 稳定 | yes |
| `onboarding.commitment.unit.challenge` | days · stretch | 天 · 挑战 | yes |
| `onboarding.commitment.days.a11y` | %lld days a week | 每周 %lld 天 | yes |
| `onboarding.commitment.reminder.title` | When should we remind you? | 什么时候提醒你？ | yes |
| `onboarding.commitment.reminder.hint` | At most one a day, at the time you pick. | 每天最多 1 条，在你选的时间。 | yes |
| `onboarding.commitment.reminder.a11y` | Reminder time %@ | 提醒时间 %@ | yes |
| `onboarding.notify.title` | One reminder a day | 每天提醒你一次 | yes |
| `onboarding.notify.subtitle` | Only at the time you chose. No noise. | 只在你选的时间提醒，不会打扰。 | yes |
| `onboarding.notify.preview.a11y` | Notification preview | 通知预览 | yes |
| `onboarding.notify.point1` | Never more than one a day | 每天最多 1 条 | yes |
| `onboarding.notify.point2` | A gentle nudge at 8 pm only if you haven’t practised | 晚上 8 点前还没练，才会温和提醒一次 | yes |
| `onboarding.notify.point3` | Turn it off any time in Settings | 随时在「设置」里关闭 | yes |
| `onboarding.notify.allow` | Turn on reminders | 开启提醒 | yes |

## Diagnostic

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `diag.intro.badge` | About 3 minutes | 约 3 分钟 | yes |
| `diag.intro.title` | Start with a<br>quick diagnostic | 先做一次<br>表达诊断 | yes |
| `diag.intro.body` | See where you are today. Your 14-day plan will target the area that needs it most. | 看看你现在讲得怎么样。之后的 14 天计划会针对你最需要的那一项。 | yes |
| `diag.intro.step1` | Read a short article | 读一篇短文 | yes |
| `diag.intro.step1.sub` | About a minute — just understand it | 约 1 分钟，读懂就行 | yes |
| `diag.intro.step2` | Retell it in your own words | 用自己的话讲一遍 | yes |
| `diag.intro.step2.sub` | Up to 90 seconds | 最长 90 秒 | yes |
| `diag.intro.step3` | Get your 4 scores | 看你的 4 项表达分 | yes |
| `diag.intro.step3.sub` | Plus the one thing to fix first | 以及最该先改的一件事 | yes |
| `diag.intro.honesty` | This is a real assessment, not a demo. Recording starts only when you tap. The diagnostic is free. | 这是真实评估，不是演示。录音只在你点击后开始，诊断免费。 | yes |
| `diag.intro.lang` | Practice language: %@ | 练习语言：%@ | yes |
| `diag.intro.cta` | Start the diagnostic | 开始诊断 | yes |
| `diag.intro.privacy_link` | How we handle your recording | 我们如何处理你的录音 | yes |
| `diag.read.nav` | Diagnostic · Read | 诊断 · 阅读 | yes |
| `diag.record.nav` | Diagnostic · Retell | 诊断 · 复述 | yes |
| `diag.processing.nav` | Diagnostic · Results | 诊断 · 生成结果 | yes |
| `diag.record.cta` | Done — see my results | 完成，查看诊断结果 | yes |
| `diag.result.nav` | Your diagnostic | 你的诊断结果 | yes |
| `diag.result.ring_label` | Score | 诊断 | yes |
| `diag.result.cta` | See my 14-day plan | 看看我的 14 天计划 | yes |
| `mic_sheet.title` | Next, we’ll need your microphone | 接下来需要用麦克风 | yes |
| `mic_sheet.point1` | Recording starts only when you tap, and an indicator stays on screen the whole time. | 只在你点按录音后才开始，录音时屏幕上一直有提示。 | yes |
| `mic_sheet.point2` | Third-party AI services transcribe and assess it. It is <b>never used to train models</b>. | 录音由第三方 AI 服务转写和评估，<b>不会用于训练模型</b>。 | yes |
| `mic_sheet.point3` | Kept for <b>%lld days</b> by default. Change it to 7 days or 1 year, or delete it any time. | 默认保存 <b>%lld 天</b>，可在设置里改为 7 天或 1 年，或随时删除。 | yes |
| `mic_sheet.skip` | Not now | 现在不用 | yes |

## Plan

Plan day titles come from `Plan.days[].title` (server, localized).

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `plan.eyebrow` | Made for you | 为你定制 | yes |
| `plan.title` | Your 14-day plan | 你的 14 天计划 | yes |
| `plan.focus_label` | Focus | 重点练习 | yes |
| `plan.baseline` | Starting at %@ | 起点 %@ 分 | yes |
| `plan.reason` | Your diagnostic shows %@ needs the most work: %@. | 诊断里，你的「%@」最需要加强：%@。 | yes |
| `plan.weekly_days` | %lld days a week | 每周 %lld 天 | yes |
| `plan.reminder` | Reminder at %@ | 每天 %@ 提醒 | yes |
| `plan.week` | Week %lld | 第 %lld 周 | yes |
| `plan.review` | Review | 复盘 | yes |
| `plan.retest` | Re-test | 复测 | yes |
| `plan.note` | The plan only changes each day’s focus — the routine stays the same. Missed a day? Just carry on. | 计划只调整每天的练习重点，训练流程不变。漏掉的日子不用补，接着练就好。 | yes |

## Paywall

Prices, periods and trial length always come from StoreKit; never write them into copy.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `paywall.restore` | Restore | 恢复购买 | yes |
| `paywall.eyebrow` | Your diagnostic | 你的诊断 | yes |
| `paywall.weakest` | Work on first: %@ | 最需要练：%@ | yes |
| `paywall.title` | 14 days to master<br>“%@” | 14 天，练好<br>「%@」 | yes |
| `paywall.k.label` | How many days a week? | 每周练几天？ | yes |
| `paywall.k.value` | %lld days | %lld 天 | yes |
| `paywall.k.a11y_value` | %lld days a week | 每周 %lld 天 | yes |
| `paywall.projection` | People who started at %@ and practised %@ days a week averaged %@ after 14 days (%lld people). | 起点 %@的用户，每周练 %@ 天，14 天后平均达到 %@（样本 %lld 人）。 | yes |
| `paywall.projection.bucket.range` | %lld–%lld | %lld–%lld 分 | yes |
| `paywall.projection.bucket.below50` | below 50 | 50 分以下 | yes |
| `paywall.projection.bucket.80plus` | 80 or more | 80 分以上 | yes |
| `paywall.projection.score` | %lld | %lld 分 | yes |
| `paywall.projection.weakest_delta` | %@ rose by %lld on average. | 其中「%@」平均提升 %lld 分。 | yes |
| `paywall.projection.insufficient` | Not enough people with a similar start practised %lld days a week (%lld so far), so we won’t predict. | 起点相近、每周练 %lld 天的用户还不够多（%lld 人），暂不给出预测。 | yes |
| `paywall.projection.insufficient.note` | We don’t show numbers below %lld people. | 样本少于 %lld 人时我们不展示数字。 | yes |
| `paywall.projection.you_now` | You now | 你现在 | yes |
| `paywall.projection.day14` | Day-14 average | 14 天后平均 | yes |
| `paywall.projection.disclaimer` | Based on people with a similar start. Your results will differ. Not a promise. | 来自起点相近的用户，个人结果会有差异，不是承诺。 | yes |
| `paywall.calendar.title` | Your 14 days | 你的 14 天 | yes |
| `paywall.calendar.rest` | Rest | 休息 | yes |
| `paywall.calendar.retest` | Re-test | 复测 | yes |
| `paywall.calendar.dow` | M,T,W,T,F,S,S | 一,二,三,四,五,六,日 | yes |
| `paywall.calendar.legend.today` | Today | 今天 | yes |
| `paywall.calendar.legend.practice` | Practice day | 练习日 | yes |
| `paywall.calendar.legend.streak` | Streak milestone | 连续天数里程碑 | yes |
| `paywall.calendar.legend.retest` | Re-test | 复测 | yes |
| `paywall.calendar.streak3` | 3-day streak | 连续 3 天 | yes |
| `paywall.calendar.streak7` | 7-day streak | 连续 7 天 | yes |
| `paywall.calendar.billing` | Billing starts | 开始计费 | yes |
| `paywall.calendar.day.a11y` | %@, day %lld, %@ | %@，第 %lld 天，%@ | yes |
| `paywall.calendar.practice.a11y` | practice: %@ | 练习：%@ | yes |
| `paywall.timeline.trial_start` | Free trial starts — day 1 begins now | 免费试用开始，马上开练第 1 天 | yes |
| `paywall.timeline.trial_reminder` | We’ll remind you a day before it ends (if notifications are on) | 提醒你试用还剩 1 天（如已开启通知） | yes |
| `paywall.timeline.billing.trial` | Your %@ plan starts at %@ — cancel before then and pay nothing | 开始按%@订阅 %@，此前取消不收费 | yes |
| `paywall.timeline.billing.now` | %@ plan at %@ — cancel any time | 按%@订阅 %@，随时可取消 | yes |
| `paywall.timeline.billing.loading` | Billing starts (loading price) | 开始计费（价格加载中） | yes |
| `paywall.timeline.retest` | Day-14 re-test against your starting %lld | 第 14 天复测，和起点 %lld 分对比 | yes |
| `paywall.period.year` | annual | 年 | yes |
| `paywall.period.month` | monthly | 月 | yes |
| `paywall.per.year` | year | 年 | yes |
| `paywall.per.month` | month | 月 | yes |
| `paywall.plans.title` | Choose a plan | 选择方案 | yes |
| `paywall.plan.annual` | Annual | 年度 | yes |
| `paywall.plan.annual.trial` | %lld-day free trial · about %@/month | 先免费试用 %lld 天 · 约 %@ / 月 | yes |
| `paywall.plan.annual.no_trial` | Billed yearly · about %@/month | 按年付费 · 约 %@ / 月 | yes |
| `paywall.plan.monthly` | Monthly | 月度 | yes |
| `paywall.plan.monthly.sub` | Billed monthly · cancel any time | 按月付费，随时取消 | yes |
| `paywall.plan.suffix.year` | /yr | /年 | yes |
| `paywall.plan.suffix.month` | /mo | /月 | yes |
| `paywall.fineprint` | Subscriptions renew automatically. Cancel any time in iPhone Settings › Apple Account › Subscriptions; cancel during the trial and you won’t be charged. App Store pricing applies. | 订阅自动续期。可随时在 iPhone「设置 › Apple 账户 › 订阅」中取消；试用期内取消不收费。价格以 App Store 显示为准。 | yes |
| `paywall.terms` | Terms | 服务条款 | yes |
| `paywall.privacy` | Privacy | 隐私政策 | yes |
| `paywall.plans.a11y` | Subscription plans | 订阅方案 | yes |
| `paywall.cta.trial` | Start %lld-day free trial | 免费试用 %lld 天 | yes |
| `paywall.cta.trial.caption` | Then %2$@ from %1$@ per %3$@. Cancel before then and pay nothing. | %@起 %@/%@，此前随时取消不收费 | yes |
| `paywall.cta.subscribe` | Subscribe for %@/%@ | 订阅 %@/%@ | yes |
| `paywall.cta.subscribe.caption` | Renews automatically · cancel any time in the App Store | 自动续期，随时可在 App Store 取消 | yes |
| `paywall.cta.loading` | Loading prices… | 正在获取价格… | yes |
| `paywall.cta.loading.caption` | Prices come from the App Store | 价格来自 App Store | yes |
| `paywall.cta.purchasing` | Connecting to the App Store… | 正在连接 App Store… | yes |
| `paywall.cta.purchasing.caption` | Confirm in the system sheet | 请在系统弹窗中确认 | yes |
| `paywall.failed.title` | Purchase didn’t go through. You weren’t charged. | 购买没有完成，没有扣费。 | yes |
| `paywall.failed.body` | We couldn’t reach the App Store. Please try again. | App Store 暂时无法连接，请稍后重试。 | yes |
| `paywall.failed.caption` | Not charged · try another plan or try later | 未扣费 · 可以换个方案或稍后再试 | yes |
| `paywall.restored.toast` | Subscription restored | 已恢复你的订阅 | yes |
| `paywall.restored.cta` | Start today’s session | 开始今天的训练 | yes |
| `paywall.restored.caption` | Restored: %@ | 已恢复：%@ | yes |
| `paywall.expired.eyebrow` | Welcome back | 欢迎回来 | yes |
| `paywall.expired.title` | %@, your trial<br>ended on %@ | %@，你的试用<br>在 %@ 结束了 | yes |
| `paywall.expired.records` | Everything you’ve done is still here | 你的记录都还在 | yes |
| `paywall.expired.stat.sessions` | Sessions | 完成训练 | yes |
| `paywall.expired.stat.ability` | Ability | 能力分 | yes |
| `paywall.expired.stat.focus` | Focus | 当前重点 | yes |
| `paywall.expired.note` | Subscribe to pick up where you left off — your plan and history are kept. | 订阅后从上次停下的地方继续，计划和历史不会丢。 | yes |
| `paywall.expired.question` | What if you keep going? | 继续练下去，会怎样？ | yes |
| `paywall.source.pilot` | Pilot data | 试点数据 | yes |

## Home

`greeting`, `local_date_label`, `steps[].label`, quick-pick titles and topic names come from the server (Accept-Language).

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `home.greeting.format` | %@, %@ | %@，%@ | yes |
| `home.streak.a11y.done` | %lld-day streak, done today | 连续 %lld 天，今天已完成 | yes |
| `home.streak.a11y.todo` | %lld-day streak, not yet today | 连续 %lld 天，今天还没练 | yes |
| `home.level.a11y` | Level %lld | 等级 %lld | yes |
| `home.level.xp` | %lld / %lld XP | %lld / %lld XP | yes |
| `home.level.progress.a11y` | Level progress | 本级经验 | yes |
| `home.quest.label` | Today’s session | 今日任务 | yes |
| `home.quest.plan_day` | 14-day plan · Day %lld | 14 天计划 · 第 %lld 天 | yes |
| `home.quest.focus.last` | Last advice: %@ | 上次建议：%@ | yes |
| `home.quest.focus.diagnostic` | From your diagnostic: %@ | 诊断建议：%@ | yes |
| `home.quest.path.a11y` | Progress: %lld of 3 done | 训练进度：完成 %lld / 3 | yes |
| `home.quest.cta.start` | Start today’s session | 开始今日训练 | yes |
| `home.quest.cta.resume.compress` | Continue: second take | 继续：压缩重讲 | yes |
| `home.quest.cta.resume.read` | Continue: read | 继续：阅读 | runtime / notifications |
| `home.quest.cta.resume.retell` | Continue: retell | 继续：复述 | runtime / notifications |
| `home.quest.cta.resume.processing` | Check feedback progress | 查看反馈进度 | runtime / notifications |
| `home.freeze_used` | A streak freeze covered yesterday, so your streak is safe. | 昨天用掉了 1 次连续保护，连续天数保住了。 | runtime / notifications |
| `home.quest.done.tag` | Done | 已完成 | yes |
| `home.quest.done.xp` | %@ XP earned | %@ XP 已到账 | yes |
| `home.quest.done.more` | Practise another (free practice) | 再练一篇（自由练习） | yes |
| `home.quest.empty.title` | Today’s article isn’t ready yet | 今天的文章还在准备中 | yes |
| `home.quest.empty.body` | Pick one from the library — rewards and your streak count as usual. | 先去练习库挑一篇，奖励和连续天数照常计算。 | yes |
| `home.quest.empty.cta` | Open the library | 去练习库 | yes |
| `home.risk.title` | Not yet today — 10 minutes is enough | 今天还没练，10 分钟就够 | yes |
| `home.risk.body.freeze` | Finish now for day %lld. If today doesn’t work out, you still have %lld streak freeze. | 练完就是连续第 %lld 天。今天来不及也没关系，你还有 %lld 次连续保护。 | yes |
| `home.offline` | Offline · showing data from %@ | 离线 · 显示 %@ 缓存的数据 | yes |
| `home.picks.title` | Practise by topic | 按兴趣练习 | yes |
| `home.picks.topics.a11y` | Topics | 话题 | yes |
| `home.picks.empty.title` | %@ articles are on the way | %@话题的文章还在编写中 | yes |
| `home.picks.empty.body` | Try another topic for now — new ones will show up here. | 先看看其他话题，上新后会出现在这里。 | yes |
| `home.picks.empty.cta` | Browse all articles | 看看全部文章 | yes |
| `home.error.title` | Home didn’t load | 首页暂时没加载出来 | yes |
| `home.error.body` | Our server is busy. Your progress is safe — try again in a moment. | 服务器有点忙，你的记录都在。稍后重试一下。 | yes |
| `home.loading.a11y` | Loading home | 正在加载首页 | yes |

## Library

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `library.title` | Library | 练习库 | yes |
| `library.subtitle` | Pick one and make it clear today. | 选一篇，今天就讲清楚它。 | yes |
| `library.filter.language.a11y` | Filter by language | 按语言筛选 | yes |
| `library.filter.topic.a11y` | Filter by topic | 按话题筛选 | yes |
| `library.filter.status.a11y` | Status | 状态 | yes |
| `library.filter.status.unseen` | New | 未读 | yes |
| `library.filter.status.completed` | Practised | 已练 | yes |
| `library.row.status.unseen` | New | 未读 | yes |
| `library.row.status.in_progress` | In progress | 进行中 | yes |
| `library.row.status.best` | Best %lld | 最好 %lld | yes |
| `library.row.locked` | Unlocks at ability 80 | 能力分达到 80 解锁 | yes |
| `library.footer.tier3` | Level 3 articles unlock at an ability score of 80 | 难度 3 的文章在能力分达到 80 后解锁 | yes |
| `library.empty.title` | No %@ articles yet | %@话题还没有文章 | yes |
| `library.empty.body` | Our editors are on it. Try another topic? | 编辑部正在写。先试试其他话题？ | yes |
| `library.empty.cta` | Clear filter | 清除筛选 | yes |
| `library.error.title` | Articles didn’t load | 文章列表没加载出来 | yes |
| `library.error.body` | Check your connection or try again. Today’s article is still available on Home. | 检查一下网络，或稍后重试。已下载的今日文章仍可在首页打开。 | yes |

## Read

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `read.nav` | Read | 阅读 | yes |
| `read.tag.daily` | Today | 今日任务 | yes |
| `read.tag.free` | Free practice | 自由练习 | yes |
| `read.tag.diagnostic` | Diagnostic | 诊断 | yes |
| `read.hint.title` | As you read | 阅读提示 | yes |
| `read.source` | Source: %@ · v%lld | 来源：%@ · 第 %lld 版 | yes |
| `read.cta` | I’m ready — start retelling | 我读好了，开始复述 | yes |
| `read.cta.caption` | The text will be hidden. Just say what you understood. | 下一步会隐藏原文，凭理解讲就好 | yes |
| `read.load_error` | The article didn’t load. Try again or pick another one. | 文章没加载出来，换一篇或稍后重试。 | runtime / notifications |

## Record

Round 1, round 2 and the diagnostic share these.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `record.nav.round1` | Retell | 复述 | yes |
| `record.nav.round2` | Second take | 压缩重讲 | yes |
| `record.chip.round1` | First take | 第一次 | yes |
| `record.chip.round2` | Second take | 第二次 | yes |
| `record.title.round1` | Now, say it in your own words. | 现在，用自己的话讲一遍。 | yes |
| `record.sub.round1` | No need to quote it. Explain it to a colleague who hasn’t read it. | 不需要复述原句。像讲给一位没看过文章的同事听。 | yes |
| `record.focus.round1` | Today’s focus: %@ | 今天的重点：%@ | yes |
| `record.title.round2` | This time, just the core. | 这次，只讲主干。 | yes |
| `record.sub.round2` | Last take: %@. Keep the key points, drop the repeats — shorter isn’t the goal. | 上一遍用了 %@。保留要点，删掉重复，不必刻意求短。 | yes |
| `record.advice.label` | Your advice from last take | 上一遍的建议 | yes |
| `record.button.start` | Start recording | 开始录音 | yes |
| `record.button.pause` | Pause recording | 暂停录音 | yes |
| `record.button.resume` | Resume recording | 继续录音 | yes |
| `record.button.stopped` | Recording ended | 录音已结束 | yes |
| `record.button.denied` | Microphone unavailable | 麦克风不可用 | yes |
| `record.indicator.recording` | Recording | 录音中 | yes |
| `record.indicator.paused` | Paused · paused time doesn’t count | 已暂停 · 暂停时间不计入 | yes |
| `record.hint.idle` | Tap the mic to start. Nothing is recorded until you do. | 轻触麦克风开始，录音只在你点击后进行 | yes |
| `record.hint.need_more` | %lld more seconds before you can submit | 还差 %lld 秒可以提交 | runtime / notifications |
| `record.hint.ready` | Tap below when you’re done. Stops automatically at %@. | 讲完了就点下方按钮；%@ 时会自动停止 | yes |
| `record.hint.paused` | Tap to continue, or submit now | 轻触继续；你也可以直接提交 | yes |
| `record.rerecord` | Start over | 重录 | yes |
| `record.cta.round1` | Done — get feedback | 完成，查看反馈 | yes |
| `record.cta.round2` | Finish session | 完成训练 | yes |
| `record.cta.caption` | At least 20 s · up to %@ | 至少 20 秒 · 最长 %@ | yes |
| `record.autostop.title` | You reached %@ — recording stopped | 已到 %@ 上限，录音已自动停止 | yes |
| `record.autostop.body` | Everything is saved. Submit it for feedback, or start over. | 这段录音已完整保存。确认后开始生成反馈；也可以重录一遍。 | yes |
| `record.autostop.effective` | Recorded time %@ | 有效时长 %@ | yes |
| `record.autostop.submit` | Submit this recording | 提交这段录音 | yes |
| `record.short.title` | That’s under 20 seconds | 这段还不到 20 秒 | yes |
| `record.short.body` | You recorded %@. We need at least %@ for reliable feedback. Keep going — the timer picks up where it stopped. | 有效录音 %@，至少需要 %@ 才能给出可靠反馈。接着讲完就好，不会重新计时。 | yes |
| `record.short.continue` | Keep going | 接着讲 | yes |
| `record.denied.title` | Microphone access is off | 麦克风权限已关闭 | yes |
| `record.denied.body` | Retelling needs the microphone. Turn it on and come back — your article and progress are kept. | 复述需要录音。打开权限后回到这里，就能直接开始；文章和进度都保留着。 | yes |
| `record.denied.step1` | Open Settings | 打开「设置」 | yes |
| `record.denied.step2` | Find Shuke | 找到「述刻」 | yes |
| `record.denied.step3` | Turn on Microphone | 打开「麦克风」 | yes |
| `record.denied.cta` | Open Settings | 打开设置 | yes |
| `record.denied.back` | Back to the article | 返回阅读 | yes |
| `record.interrupted.title` | A call paused your recording | 录音因来电暂停了 | yes |
| `record.interrupted.body` | %@ is saved on this phone. Continue, or start over? | 已保存 %@ 的录音在本机。想接着讲，还是重新来一遍？ | yes |
| `record.leave.title` | Leave this take? | 要离开吗？ | yes |
| `record.leave.body` | Recording paused. %@ is saved on this phone — continue or redo it when you’re back. | 录音已暂停。%@ 的录音会保存在本机，回来可以继续或重录。 | yes |
| `record.leave.stay` | Keep recording | 继续录音 | yes |
| `record.leave.save` | Save and leave | 保存并离开 | yes |
| `record.leave.discard` | Discard and leave | 丢弃录音并离开 | yes |

## Processing

Unreliable reasons map from `attempt.unreliable_reason`; the floor (40 chars / 30 words) is per language (D2).

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `processing.nav.round1` | Feedback | AI 反馈 | yes |
| `processing.stage.upload` | Upload | 上传录音 | yes |
| `processing.stage.transcribe` | Transcribe | 转写语音 | yes |
| `processing.stage.assess` | Assess | 生成反馈 | yes |
| `processing.title.upload` | Uploading your recording | 正在上传录音 | yes |
| `processing.title.transcribe` | Transcribing your retelling | 正在转写你的复述 | yes |
| `processing.title.assess` | Preparing your feedback | 正在生成反馈 | yes |
| `processing.sub.upload` | Uploading %@ of audio | 正在上传 %@ 的录音 | yes |
| `processing.sub.transcribe` | Listening to what you said | 正在听你说了什么 | yes |
| `processing.sub.assess` | Checking against the article’s key points | 对照文章要点逐项评估 | yes |
| `processing.done.upload` | Uploaded | 已上传 | yes |
| `processing.done.transcribe` | Transcribed %@ | 已转写 %@ | yes |
| `processing.eta` | About %lld s left | 大约还需 %lld 秒 | yes |
| `processing.tip.title` | While you wait | 等的时候想一想 | yes |
| `processing.tip.body` | If you had one sentence, how would you sum up this article? | 如果只能说一句话，你会怎么概括这篇文章？ | yes |
| `processing.leave_ok` | You can leave — results will wait for you on Home | 可以离开这个页面，结果会保存在首页 | yes |
| `processing.slow.title` | This is taking longer than usual | 比平时慢了一些 | yes |
| `processing.slow.waited` | Waiting for %lld min | 已等待 %lld 分钟 | yes |
| `processing.slow.body` | Your results will be saved automatically. Feel free to leave — you’ll find them under Continue on Home. | 结果生成后会自动保存。你可以先去做别的，回到首页点「继续训练」就能看到。 | yes |
| `processing.slow.later` | Check later | 稍后查看 | yes |
| `processing.slow.wait` | Keep waiting | 继续等待 | yes |
| `processing.offline.title` | You’re offline | 网络断开了 | yes |
| `processing.offline.sub` | We’ll continue when you’re back online | 联网后会自动继续 | yes |
| `processing.offline.waiting` | Waiting for network · saved on this phone | 等待网络 · 已保存在本机 | yes |
| `processing.offline.body` | Your recording is safe on this phone. It uploads automatically when you’re back online — no need to record again. | 录音已安全保存在本机，不会丢失。恢复网络后会自动上传，无需重录。 | yes |
| `processing.failed.title` | Something went wrong with your feedback | 生成反馈时出了点问题 | yes |
| `processing.failed.body` | %@ Your recording is already uploaded, so retrying won’t need a new one. | %@你的录音已经上传，重试不需要重新录。 | yes |
| `processing.failed.stage` | Assessment service unavailable | 评估服务暂时不可用 | yes |
| `processing.failed.code` | Error %@ · stage %@ | 错误代码 %@ · 阶段 %@ | yes |
| `processing.failed.rerecord` | Record again | 重新录一遍 | yes |
| `processing.unreliable.title` | We couldn’t assess this reliably | 这段录音没法可靠评估 | yes |
| `processing.unreliable.sub` | No score, and no effect on XP or your streak. Just record it again. | 不计分，也不影响 XP 和连续天数。重录一遍就好。 | yes |
| `processing.unreliable.reason_label` | Why | 原因 | yes |
| `processing.unreliable.stage` | Not enough speech | 有效内容不足 | yes |
| `processing.unreliable.tip` | Tip: hold the phone about 20 cm away, like on a call. | 小提示：手机离嘴 20 厘米左右，像打电话一样说话。 | yes |
| `processing.unreliable.play.a11y` | Play this recording | 播放这段录音 | yes |
| `unreliable.too_short.title` | Too little speech to assess | 识别到的有效内容太少 | yes |
| `unreliable.too_short.body` | We only caught %@ (at least %@ needed). You may have been far from the mic, or paused for a long time. | 这次只识别出 %@（至少需要 %@）。可能是离麦克风太远，或者中间停顿太久。 | yes |
| `unreliable.no_speech.title` | We didn’t hear any speech | 没有检测到说话声 | runtime / notifications |
| `unreliable.no_speech.body` | The recording is mostly silence or background noise. Find a quiet spot and try again closer to the phone. | 录音里大部分是安静或环境声。换个安静的地方，靠近手机再试一次。 | runtime / notifications |
| `unreliable.language_mismatch.title` | Wrong language for this article | 语言和文章不一致 | runtime / notifications |
| `unreliable.language_mismatch.body` | This is a %@ article, so please retell it in %@. To switch languages, pick an article in another language from the library. | 这篇是%@文章，请用%@复述。想换语言，可以在练习库里选另一种语言的文章。 | runtime / notifications |
| `unreliable.low_audio_quality.title` | The audio isn’t clear enough | 录音不够清楚 | runtime / notifications |
| `unreliable.low_audio_quality.body` | Background noise or clipping made the transcript unreliable, so we didn’t score it. | 背景声音太大或有爆音，转写可能不准，所以这次不打分。 | runtime / notifications |
| `unreliable.transcript_incomplete.title` | Transcript incomplete | 转写不完整 | runtime / notifications |
| `unreliable.transcript_incomplete.body` | Part of the recording couldn’t be transcribed. Record again and we’ll reassess. | 有一部分录音没能转写出来。重录一遍，我们会重新评估。 | runtime / notifications |

## Feedback

Summary, notes, evidence, one-action and exemplar text are content in the ARTICLE's language.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `feedback.nav` | Feedback | AI 反馈 | yes |
| `feedback.ring_label` | Score | 本次 | yes |
| `feedback.achieved` | <b>You did it ✓ Last advice:</b> %@ | <b>做到了 ✓ 上次的建议：</b>%@ | yes |
| `feedback.not_achieved` | Last advice “%@” didn’t land this time — try it again below. | 上次的建议「%@」这次还没做到，下面再试一次。 | yes |
| `feedback.low_confidence` | <b>We’re less sure about this one.</b> %@ | <b>这次评估不太确定。</b>%@ | yes |
| `feedback.dims.title` | Four dimensions | 四个维度 | yes |
| `feedback.one_action.basis` | Based on | 依据 | yes |
| `feedback.one_action.listen` | Hear a reference version | 听参考表达 | yes |
| `feedback.evidence.title` | Evidence | 依据 | yes |
| `feedback.evidence.hint` | Tap to hear your own words | 轻点回放你的原话 | yes |
| `feedback.evidence.pause.a11y` | Pause | 暂停 | yes |
| `feedback.evidence.expired` | This audio was deleted under your retention setting. The text is still here. | 录音已按保留设置删除，文字依据仍可查看。 | runtime / notifications |
| `feedback.keypoints.title` | Key points | 文章要点 | yes |
| `feedback.keypoints.count` | Covered %lld / %lld | 讲到 %lld / %lld | yes |
| `feedback.exemplar.title` | Model answer | 示范表达 | yes |
| `feedback.exemplar.tag` | Reference | 参考表达 | yes |
| `feedback.exemplar.intro` | One way to say it using “%@”. Use your own words — don’t memorise it. | 按“%@”重新组织的一种讲法。用你自己的话，不用背。 | yes |
| `feedback.exemplar.pending` | Generating a reference version — usually about 10 seconds | 正在生成参考表达，通常需要 10 秒左右 | yes |
| `feedback.exemplar.failed` | The audio didn’t generate. Here’s the text for now. | 语音暂时没生成出来，文字版可以先看。 | yes |
| `feedback.exemplar.play.a11y` | Play reference version | 播放参考表达 | yes |
| `feedback.helpful.title` | Was this feedback helpful? | 这条反馈有帮助吗？ | yes |
| `feedback.helpful.yes.a11y` | Helpful | 有帮助 | yes |
| `feedback.helpful.no.a11y` | Not helpful | 没帮助 | yes |
| `feedback.helpful.reason.title` | What was off? | 哪里不对？ | runtime / notifications |
| `feedback.helpful.reason.inaccurate_transcript` | The transcript was wrong | 转写不准 | runtime / notifications |
| `feedback.helpful.reason.unfair_score` | The score felt unfair | 分数不公平 | runtime / notifications |
| `feedback.helpful.reason.unclear_advice` | The advice was unclear | 建议看不懂 | runtime / notifications |
| `feedback.helpful.reason.other` | Something else | 其他 | runtime / notifications |
| `feedback.helpful.thanks` | Thanks — this helps us improve the assessment. | 谢谢，我们会用它改进评估。 | runtime / notifications |
| `feedback.meta` | Rubric %@ · %@ · confidence %@ | 评估 %@ · %@ · 置信度%@ | yes |
| `feedback.confidence.high` | high | 高 | yes |
| `feedback.confidence.medium` | medium | 中 | runtime / notifications |
| `feedback.confidence.low` | low | 低 | yes |
| `feedback.cta` | Try again with this advice | 带着建议重讲一次 | yes |

## Complete

`Settlement.headline`/`subline` are server strings per verdict; the keys below are fallbacks when null.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `complete.headline.improved` | You explained it more clearly today. | 今天讲得更清楚了。 | runtime / notifications |
| `complete.headline.same` | You completed a full session today. | 今天完成了一次完整训练。 | runtime / notifications |
| `complete.headline.shorter_but_lost_points` | Shorter, but a key point went missing. | 更短了，但漏了一个要点。 | runtime / notifications |
| `complete.headline.regressed` | Session complete. The second take was weaker — that happens. | 今天完成了一次完整训练。第二遍不如第一遍，很正常。 | runtime / notifications |
| `complete.eyebrow.daily` | Today’s session complete | 今日任务完成 | yes |
| `complete.eyebrow.replayed` | Session record | 训练记录 | yes |
| `complete.close.a11y` | Close and go home | 关闭，回到首页 | yes |
| `complete.ba.first` | First take | 第一次 | yes |
| `complete.ba.second` | Second take | 压缩重讲 | yes |
| `complete.ba.a11y` | First take %lld, second take %lld | 第一次 %lld 分，压缩重讲 %lld 分 | yes |
| `complete.ba.delta` | This session %@ | 本次 %@ 分 | yes |
| `complete.lost_points` | <b>Missed:</b> %@ | <b>漏掉的要点：</b>%@ | yes |
| `complete.stat.xp` | XP | XP | yes |
| `complete.stat.xp.replayed` | XP earned | 已获得 XP | yes |
| `complete.stat.streak` | Day streak | 连续天数 | yes |
| `complete.stat.ability` | Ability | 能力分 | yes |
| `complete.stat.baseline` | Building baseline | 建立基线中 | yes |
| `complete.xp.level` | Lv.%lld %@ | Lv.%lld %@ | yes |
| `complete.xp.round1` | First take | 首次复述 | yes |
| `complete.xp.round2` | Second take | 压缩重讲 | yes |
| `complete.xp.complete` | Session complete | 完成训练 | yes |
| `complete.xp.improve` | Improvement bonus | 进步奖励 | yes |
| `complete.xp.improve.missed` | Improvement bonus (when take two scores higher) | 进步奖励（第二次得分更高时） | yes |
| `complete.xp.cap_hit` | You’ve hit today’s 165 XP cap. More tomorrow. | 今天的 XP 已达上限（165），明天继续。 | runtime / notifications |
| `complete.xp.repeat` | You practised this article in the last 7 days, so XP is halved. | 7 天内练过这篇，XP 减半。 | runtime / notifications |
| `complete.xp.weekly_quest` | Weekly quest reward | 周任务奖励 | runtime / notifications |
| `complete.weekly.title` | This week | 本周任务 | yes |
| `complete.next.label` | Next focus | 下次的重点 | yes |
| `complete.cta.growth` | See progress | 查看成长 | yes |
| `complete.cta.home` | Back to Home | 回到首页 | yes |
| `complete.replayed.banner` | You completed this session on %@. Rewards were already added and won’t be counted twice. | 这是你 %@ 完成的训练，奖励已经发放过，不会重复计算。 | yes |
| `levelup.eyebrow` | Level up | 升级 | yes |
| `levelup.title` | You’re now a %@ | 你现在是「%@」 | yes |
| `levelup.sub` | %1$lld XP total · %3$lld more to Lv.%2$lld | 累计 %lld XP · 距离 Lv.%lld 还需 %lld XP | yes |
| `levelup.a11y` | Reached level %lld | 升级到 %lld 级 | yes |
| `achievement.eyebrow` | Achievement unlocked | 解锁成就 | yes |
| `achievement.plan_day` | 14-day plan · Day %lld done | 14 天计划 · 第 %lld 天完成 | yes |

## Growth

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `growth.title` | Progress | 我的成长 | yes |
| `growth.range.a11y` | Time range | 时间范围 | yes |
| `growth.range.4w` | 4 wk | 4 周 | yes |
| `growth.range.8w` | 8 wk | 8 周 | yes |
| `growth.range.12w` | 12 wk | 12 周 | yes |
| `growth.languages.a11y` | View by language | 按语言查看 | yes |
| `growth.ability.label` | Ability score | 当前能力分 | yes |
| `growth.ability.delta` | %@ in 30 days | %@ 近 30 天 | yes |
| `growth.ability.meta` | From %lld sessions · %@ | 基于 %lld 次训练 · %@ | yes |
| `growth.baseline.label` | Ability score | 能力分 | yes |
| `growth.baseline.title` | Building your baseline %lld/3 | 建立基线中 %lld/3 | yes |
| `growth.chart.title` | Speaking ability | 表达能力 | yes |
| `growth.chart.a11y` | Weekly ability trend | 每周能力分趋势 | yes |
| `growth.trend.up` | Rising steadily | 稳定上升 | yes |
| `growth.trend.flat` | Holding steady | 基本持平 | runtime / notifications |
| `growth.trend.down` | Dipping | 有所回落 | runtime / notifications |
| `growth.trend.insufficient` | Not enough data | 样本不足 | yes |
| `growth.chart.note` | One point per week (weeks start Monday) · empty weeks stay empty — nothing is filled in | 每周一个点（周一开始）· 没有训练的周留空，不补数据 | yes |
| `growth.chart.gap` | None | 无训练 | yes |
| `growth.chart.point` | Week of %@: %lld · %lld sessions | %@ 当周 %lld 分 · %lld 次训练 | yes |
| `growth.chart.gap.a11y` | No sessions the week of %@ | %@ 当周没有训练 | yes |
| `growth.chart.pending` | %lld session this week — one more shows this week’s point | 本周已练 %lld 次，再练 1 次显示趋势点 | yes |
| `growth.dims.title` | Breakdown | 能力拆解 | yes |
| `growth.dims.note` | 30-day change | 近 30 天变化 | yes |
| `growth.dims.pending` | Shown after 3 sessions | 满 3 次后显示 | yes |
| `growth.skills.title` | Micro-skills | 表达小技巧 | yes |
| `growth.skills.window` | Last 10 sessions | 近 10 次训练 | yes |
| `growth.skill.counts` | Suggested %lld · done %lld | 建议 %lld 次 · 做到 %lld 次 | yes |
| `growth.skill.never` | Not suggested yet | 还没被建议过 | yes |
| `growth.skill.focus` |  · current focus |  · 当前重点 | yes |
| `growth.achievements.title` | Achievements | 成就 | yes |
| `growth.achievement.unlocked` | Unlocked | 已解锁 | yes |
| `growth.recent.title` | Recent sessions | 最近训练 | yes |
| `growth.empty.title` | Your progress chart appears after your first session | 完成第一次训练后，这里会出现你的成长曲线 | yes |
| `growth.empty.body` | Every session records four scores. After three, you’ll see your ability score. | 每次训练都会记录 4 个维度的分数。练满 3 次，就能看到你的能力分。 | yes |

## Profile & settings

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `profile.title` | Me | 我的 | yes |
| `profile.settings.a11y` | Settings | 设置 | yes |
| `profile.stat.streak` | Day streak | 连续天数 | yes |
| `profile.stat.sessions` | Sessions | 完成训练 | yes |
| `profile.stat.ability` | Ability | 能力分 | yes |
| `profile.stat.ability.baseline` | Baseline | 基线中 | runtime / notifications |
| `profile.siwa.title` | Keep your progress safe | 保存你的训练记录 | yes |
| `profile.siwa.body` | Sign in with Apple so a new phone doesn’t mean starting over. | 用 Apple 登录，换手机也不会丢。 | yes |
| `profile.siwa.cta` | Sign in | 登录 | yes |
| `siwa.sheet.title` | Save your %lld sessions to your Apple Account | 把 %lld 次训练保存到你的 Apple 账户 | yes |
| `siwa.sheet.body` | Right now your progress lives only on this device. Sign in to keep your streak, scores and history if you switch phones or reinstall. | 现在你的记录只和这台设备绑定。登录后，换手机或重装也能找回连续天数、能力分和历史。 | yes |
| `siwa.sheet.point1` | We never show your name or email | 不会公开你的姓名或邮箱 | yes |
| `siwa.sheet.point2` | You can choose Hide My Email | 可以选择「隐藏邮件地址」 | yes |
| `siwa.sheet.point3` | Your subscription comes with you | 当前订阅会一起保留 | yes |
| `siwa.sheet.cta` | Sign in with Apple | 通过 Apple 登录 | yes |
| `profile.weekly.title` | This week | 本周任务 | yes |
| `profile.account.title` | Account | 账户 | yes |
| `profile.sub.name` | Shuke Pro · Annual | 述刻 Pro · 年度 | yes |
| `profile.sub.trial` | Free trial · annual plan starts %@ | 试用中 · %@ 开始按年订阅 | yes |
| `profile.reminder` | Daily reminder | 每日提醒 | yes |
| `profile.languages` | Languages | 语言 | yes |
| `profile.privacy` | Privacy & AI | 隐私与 AI 说明 | yes |
| `profile.settings` | Settings | 设置 | yes |
| `weekly.nav` | This week | 本周任务 | yes |
| `weekly.range` | %@ (Mon) – %@ (Sun) | %@（周一）– %@（周日） | yes |
| `weekly.reset` | Resets Monday at 00:00. Recordings we couldn’t assess don’t count. | 每周一 00:00 重置。无效录音（无法可靠评估）不计入。 | yes |
| `weekly.rule.retell_5` | Each assessed first take counts once | 每完成一次第一轮复述（有效评估）计 1 次 | yes |
| `weekly.rule.compress_3` | Each assessed second take counts once | 每完成一次压缩重讲（有效评估）计 1 次 | yes |
| `weekly.rule.follow_advice_3` | Counts when your take follows the previous advice | 评估判定你做到了上一次的建议，计 1 次 | yes |
| `weekly.note` | Quest rewards are added when a session is settled and count toward the 165 XP daily cap. | 任务奖励在完成当次训练结算时一起发放，计入每日 165 XP 上限。 | yes |
| `settings.nav` | Settings | 设置 | yes |
| `settings.section.language` | Language | 语言 | yes |
| `settings.ui_language` | App language | App 语言 | yes |
| `settings.ui_language.value` | Follow system · %@ | 跟随系统 · %@ | yes |
| `settings.practice_languages` | Practice languages | 练习语言 | yes |
| `settings.practice_languages.note` | Daily sessions and the library only suggest articles in these languages | 每日任务和练习库只推荐这些语言的文章 | yes |
| `settings.language.primary` | Primary | 主要 | yes |
| `settings.language.add_note` | The first one is your primary language, used for the diagnostic and daily sessions. | 第一个是主要练习语言，诊断和每日任务优先用它。 | yes |
| `settings.section.reminders` | Reminders | 提醒 | yes |
| `settings.reminders` | Daily reminder | 每日提醒 | yes |
| `settings.reminder_time` | Reminder time | 提醒时间 | yes |
| `settings.streak_alert` | 8 pm streak reminder | 晚 8 点连续天数提醒 | yes |
| `settings.streak_alert.note` | Only if you haven’t practised; never more than one notification a day in total | 当天还没练时提醒一次；和每日提醒合计每天最多 1 条 | yes |
| `settings.notifications_off` | Notifications are off in iOS Settings. Turn them on there. | 通知已在系统中关闭。前往「设置」开启。 | runtime / notifications |
| `settings.section.data` | Recordings & data | 录音与数据 | yes |
| `settings.retention` | Keep recordings for | 录音保留时间 | yes |
| `settings.retention.note` | Audio is deleted automatically. Transcripts and feedback stay until you delete them. | 到期自动删除音频；文字转写和反馈会保留，直到你删除 | yes |
| `settings.retention.7` | 7 days | 7 天 | yes |
| `settings.retention.30` | 30 days | 30 天 | yes |
| `settings.retention.365` | 1 year | 1 年 | yes |
| `settings.delete_data` | Delete all training data | 删除全部训练数据 | yes |
| `settings.section.account` | Account & subscription | 账户与订阅 | yes |
| `settings.manage_sub` | Manage subscription | 管理订阅 | yes |
| `settings.restore` | Restore purchases | 恢复购买 | yes |
| `settings.delete_account` | Delete account | 删除账户 | yes |
| `settings.version` | Shuke %@ (%@) · rubric %@ | 述刻 %@ (%@) · 评估规则 %@ | yes |
| `delete_data.title` | Delete all training data? | 删除全部训练数据？ | yes |
| `delete_data.body` | This deletes the recordings, transcripts, feedback and rewards from <b>%lld sessions</b>. Your ability score, streak and level will be recalculated (reset to zero).<br><br>Your account and subscription stay. Backups are purged within 30 days. This can’t be undone. | 将删除 <b>%lld 次训练</b>的录音、转写、反馈和奖励记录，能力分、连续天数和等级会重新计算（归零）。<br><br>账户和订阅会保留。备份会在 30 天内清除。此操作无法撤销。 | yes |
| `delete_data.confirm` | Delete training data | 删除训练数据 | yes |
| `delete_account.title` | Delete your account? | 删除账户？ | yes |
| `delete_account.body` | Your account and all training data will be permanently deleted; backups are purged within 30 days.<br><br><b>Your subscription is not cancelled automatically.</b> Cancel it in the App Store first, or it will keep renewing. | 账户和所有训练数据会被永久删除，备份在 30 天内清除。<br><br><b>订阅不会自动取消</b>：请先在 App Store 中取消，否则仍会续费。 | yes |
| `delete_account.manage` | Manage subscription first | 先去管理订阅 | yes |
| `delete_account.confirm` | Delete permanently | 永久删除账户 | yes |
| `privacy.nav` | Privacy & AI | 隐私与 AI 说明 | yes |
| `privacy.title` | How your recordings are handled | 你的录音怎么被处理 | yes |
| `privacy.intro` | Shuke has to hear you to give feedback. Here’s what we do — and don’t do. | 述刻需要听你说话才能给反馈。下面是我们做什么、不做什么。 | yes |
| `privacy.mic.title` | Recording starts only when you tap | 录音只在你点击后开始 | yes |
| `privacy.mic.body` | An indicator is always on screen while recording. Leaving the screen stops recording immediately. | 录音时屏幕上始终有提示。离开页面会立即停止录音和计时。 | yes |
| `privacy.ai.title` | Processed by third-party AI | 由第三方 AI 服务处理 | yes |
| `privacy.ai.body` | Recordings go to speech-to-text and AI assessment services (such as Whisper and Claude), along with the article’s language. Neither they nor we use your recordings to train models. | 录音会发送给语音转写服务和 AI 评估服务（如 Whisper、Claude），并告知它们文章的语言。服务商不会用你的录音训练模型，我们也不会。 | yes |
| `privacy.retention.title` | Recordings are kept 30 days by default | 录音默认保存 30 天 | yes |
| `privacy.retention.body` | Switch to 7 days or 1 year. Audio is deleted automatically; transcripts and feedback stay until you delete them. | 可改为 7 天或 1 年。到期自动删除音频；文字转写和反馈会保留，直到你删除。 | yes |
| `privacy.delete.title` | Delete any time | 你可以随时删除 | yes |
| `privacy.delete.body` | Delete one session, all training data or your whole account. Recordings, transcripts, feedback and rewards go with it; backups are purged within 30 days. | 可删除单次训练、全部训练数据或整个账户。删除会连带录音、转写、反馈和奖励记录，备份在 30 天内清除。 | yes |
| `privacy.analytics.title` | Analytics never include content | 分析数据不含内容 | yes |
| `privacy.analytics.body` | We count usage (like how many sessions you finish). We never send recordings, articles or transcripts to analytics. | 我们只统计使用行为（比如完成了几次训练），不会上传你的录音、文章或转写内容到分析平台。 | yes |
| `privacy.age.title` | Age | 适用年龄 | yes |
| `privacy.age.body` | Shuke is for people aged 13 and over. | 述刻面向 13 岁及以上用户。 | yes |
| `privacy.current` | Current retention: <b>%@</b> · rubric %@ | 当前录音保留：<b>%@</b> · 评估规则 %@ | yes |
| `privacy.full_policy` | Full privacy policy | 完整隐私政策 | yes |

## Global sheets, toasts, fatal states

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `resume.eyebrow` | You have an unfinished session | 上次的训练还没完成 | yes |
| `resume.stage` | Stopped at: %@ (step %lld) · %@ | 停在：%@（第 %lld 步）· %@ | yes |
| `resume.round1` | First take | 第一次复述 | yes |
| `resume.cta` | Continue | 继续训练 | yes |
| `resume.abandon` | Abandon this session | 放弃这次训练 | yes |
| `resume.abandon.note` | No penalty, and no rewards for this session. | 放弃不扣分，也不会发放这次的奖励。 | yes |
| `resume.a11y` | Continue your last session | 继续上次的训练 | yes |
| `toast.offline` | Offline · recordings are saved on this phone | 网络已断开 · 录音会先存在本机 | yes |
| `toast.online` | Back online — uploading | 网络已恢复，正在上传 | runtime / notifications |
| `error.entitlement_required` | Your subscription has ended. Renew to keep training. | 订阅已到期，续订后继续训练。 | runtime / notifications |
| `error.rate_limited` | Too many requests. Wait a moment and try again. | 操作太频繁了，稍等一下再试。 | runtime / notifications |
| `error.generic.title` | Something went wrong | 出了点问题 | yes |
| `error.generic.body` | That step didn’t finish, but your data is safe. Try again or head back home. | 这一步没有完成，你的数据没有丢失。可以重试，或者先回到首页。 | yes |
| `error.generic.home` | Go to Home | 回到首页 | yes |
| `error.generic.request` | Error %@ · request %@ | 错误代码 %@ · 请求 %@ | yes |
| `force_update.title` | Please update Shuke | 请更新述刻 | yes |
| `force_update.body` | Version %@ is no longer supported. Update to %@ or later to continue — your progress is safe. | 当前版本 %@ 已不再支持，更新到 %@ 或更高版本后继续。你的训练记录都在，不会丢失。 | yes |
| `force_update.cta` | Update in the App Store | 前往 App Store 更新 | yes |

## Shared states

Patterns from states.md that are not drawn as separate mockups.

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `state.inline_error` | Couldn’t load | 没加载出来 | runtime / notifications |
| `state.offline.diagnostic` | The diagnostic needs a connection. Connect to start. | 诊断需要联网，连上网络后就能开始。 | runtime / notifications |
| `state.offline.subscribe` | Connect to the internet to subscribe | 连上网络后才能订阅 | runtime / notifications |
| `state.offline.settle` | Done — rewards will be added when you’re back online. | 已完成，联网后会自动结算奖励。 | runtime / notifications |
| `state.offline.needs_network` | Needs a connection | 需要联网 | runtime / notifications |
| `state.offline.delete` | Connect to the internet to delete | 连上网络后才能删除 | runtime / notifications |
| `state.offline.language` | Connect to the internet to change languages | 连上网络后才能切换语言 | runtime / notifications |
| `state.appstore_unavailable` | The App Store isn’t available right now | 暂时无法连接 App Store | runtime / notifications |
| `state.delete_failed` | Couldn’t delete. Nothing was changed. | 没有删除成功，数据没有变化。 | runtime / notifications |
| `state.plan_pending` | Building your plan… | 正在生成你的计划… | runtime / notifications |
| `state.recording_unrecoverable` | That recording couldn’t be recovered. Please record again. | 这段录音没能恢复，需要重录一遍。 | runtime / notifications |
| `state.locked_toast` | This article isn’t unlocked yet | 这篇还没解锁 | runtime / notifications |
| `delete_data.done` | Training data deleted | 训练数据已删除 | runtime / notifications |
| `delete_session.title` | Delete this session? | 删除这次训练？ | runtime / notifications |
| `delete_session.body` | Its recording, transcript and feedback will be deleted and your stats recalculated. | 录音、转写和反馈会一起删除，统计会重新计算。 | runtime / notifications |
| `delete_session.confirm` | Delete | 删除 | runtime / notifications |
| `settings.language.saved` | Language updated | 语言已更新 | runtime / notifications |

## Notifications

Max one notification per local day in total (engagement.md).

| Key | en | zh-Hans | Used in screens |
|---|---|---|---|
| `notif.daily.title` | Shuke | 述刻 | yes |
| `notif.daily.body` | Today’s 10 minutes: %@ | 今天的 10 分钟：%@ | yes |
| `notif.daily.body.plan` | Plan day %lld · today: %@ | 计划第 %lld 天 · 今天练「%@」 | runtime / notifications |
| `notif.daily.body.focus` | Try “%@” today: %@ | 今天试试「%@」：%@ | runtime / notifications |
| `notif.risk.body` | %lld days in a row. There’s still time today — 10 minutes is enough. | 连续 %lld 天了。今天还有时间，10 分钟就够。 | runtime / notifications |
| `notif.risk.body.freeze` | If today doesn’t work out, you still have %lld streak freeze. | 今天来不及也没关系，你还有 %lld 次连续保护。 | runtime / notifications |
| `notif.result_ready.body` | Your feedback is ready: %@ | 反馈好了：%@ | runtime / notifications |
| `notif.trial_ending.body` | Your trial ends tomorrow. Cancel in the App Store today if you don’t want to continue — you won’t be charged. | 试用明天结束。不想继续的话，今天在 App Store 取消就不会扣费。 | runtime / notifications |

---
605 keys. Keys marked *runtime / notifications* are not visible in the static mockups (notifications, alternate reasons, fallbacks) but ship in v1.
