fix(i18n): translate crm_lead.disqualification_reason, and guard select-field labels (#631) - #647
Merged
Conversation
…ct-field labels (#631) `crm_lead.disqualification_reason` had no entry in any of the four locale bundles, so a `required` field sitting on eight lead forms rendered its seven raw stored values (`not_a_fit`, `no_budget`, `wrong_persona`, `unreachable`, `duplicate`, `competitor`, `other`) inside an otherwise fully translated form. `en` looked correct only by accident: a missing entry falls back to the English `label` in code, so the one locale a reviewer is most likely to open is the one where the defect cannot be seen. Wording follows each bundle's own neighbours rather than a literal rendering — zh-CN translates `status: unqualified` as 未通过, so the reason field is 未通过原因; ja-JP pairs 不適格 with 不適格理由; es-ES pairs No Calificado with Motivo de No Calificación. Extends the action-label coverage guard (#494) to select fields: every select field on every object needs a `label` and a label for every option value, in every locale pack. The 34 fields already incomplete when this landed sit in a shrink-only `PENDING_SELECT_LABELS` ledger (the `PENDING_FLOWS` shape from test/runtime-coverage.test.ts) and are enumerated in #645 — a field added or extended from here on has nothing to hide behind. The ledger cannot rot: an entry since translated fails as stale, an entry naming a field or locale that does not exist fails as a ghost. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019SS7C5SXpniKeCApxgARyf
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-zhuang
marked this pull request as ready for review
August 2, 2026 18:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #631
Description
crm_lead.disqualification_reason在四个语言包里都没有条目。这是一个required字段,出现在 8 张 lead 表单上,所以它的七个选项在界面上直接渲染成数据库里存的原始值 ——not_a_fit、no_budget、wrong_persona、unreachable、duplicate、competitor、other—— 夹在一张其余部分完全翻译好的表单中间。en看起来正常纯属巧合:缺条目时解析器会回退到代码里的英文label,而在en这个回退和"翻译正确"根本无法区分。评审最可能打开的那个语言,恰好是唯一看不出这个 bug 的语言 —— 这正是它需要测试而不是靠人眼的原因。补翻译本身是机械活,这个 PR 的重点在第二部分:把产生这类遗漏的机制堵上。
Type of Change
Related Issues
Fixes #631
Related to #645(本 PR 扫出的既有缺口清单)、#494(action 标签的同型守卫)、#629(相邻的 duplicate 字段翻译)
Changes Made
1. 补齐四个语言包(
src/translations/{en,zh-CN,ja-JP,es-ES}.ts)disqualification_reason的 label +help+ 全部七个选项标签。用词跟着同一个包里的邻居走,而不是逐字直译:status: unqualified既有译法这两个字段在表单上就是上下相邻的,用词必须成对,否则读起来像两套说法拼在一起。
2. 覆盖守卫(
test/metadata-references.test.ts)新增
select fields are translated in every locale,把 #494 给 action 标签做的逐语种断言套到 全部对象的全部 select 字段 上:每个 select 字段在每个语言包里都必须有label,以及每一个选项值的标签。守卫范围是全量的 —— 15 个对象、53 个 select 字段,不只针对
crm_lead。它和文件里已有的两个相邻守卫是相反方向的检查:
picklist values never reach the UI unresolved检查"已存在的条目指向真实的东西",本守卫检查"条目存在与否"。两个都需要 —— 一个语言包可以形式完全正确同时内容是空的。3. 只减不增的既有豁免清单
扫描发现的缺口远不止这一个字段:34 个字段、111 个 (语种, 字段) 组合、约 380 条选项标签。按 PM 的要求没有在本 PR 里一次性补完 —— 那会把这个 PR 真正要修的那一个字段彻底淹没。
这些进入
PENDING_SELECT_LABELS,形状照抄test/runtime-coverage.test.ts的PENDING_FLOWS,并在 #645 里逐条列出。清单只能减不能增,而且两个方向都防腐烂:所以从此以后新增或扩展的 select 字段没有东西可以躲,会在引入它的那个 PR 上直接失败。
Testing
守卫做了变异测试 —— 一个不会失败的守卫等于没有守卫。四种失效模式逐个验证过:
option values with no translated label:ja-JP: crm_lead.disqualification_reason — unreachable, duplicateselect fields with no translated label:es-ES: crm_lead.fields.disqualification_reason.labelcrm_lead.status塞进清单these are now fully translated — remove them from PENDING_SELECT_LABELS:zh-CN: crm_lead.statusPENDING_SELECT_LABELS has entries that check nothing:crm_lead.no_such_field is not a select field on any objectcrm_account.type names unknown locale "fr-FR"另有一条 guard-the-guard 断言(
sees a non-trivial set of select fields and locales),防止stack.objects或语言包 flatten 失败时整组断言空转通过 —— 这个文件里的 navigation 守卫就是这么白白绿了一辈子的。Checklist
.changeset/lead-disqualification-reason-i18n.mdAdditional Notes
没有碰的东西:
content/docs/releases/(发布说明集中生成)、issue 的 assignee、以及 #645 里列的 34 个既有缺口 —— 后者是刻意留给独立 PR 的,按对象拆分是干净的切分单位,每个 PR 只删自己那几行清单,互不冲突。范围说明: 守卫只覆盖 select 字段(有
options的字段)。非 select 字段的 label 覆盖率是另一个类,本 PR 不扩张到那里。Generated by Claude Code