fix(i18n): de 包 20 个值把德语开引号 „ 配到 ASCII 直引号,收尾引号改回 „…“ (#3876) - #3918
Merged
Conversation
`packages/i18n/src/locales/de.ts` 里 20 个 key 用德语低九分号开引号 `„`(U+201E)
开场,却用 ASCII 直引号 `"`(U+0022)收尾,德语用户读到的是
`Registerkarte „Alle Datensätze" anzeigen`。`search.resultsCount` 最直观:值以
`„{{query}}""` 结尾,错配的收引号紧挨着 TS 字符串的结束符。
这从来不是本包约定 —— 修前同一文件里已有 23 处写成正确的 `„…“`,两种写法在同
namespace 的邻键里并排坐着。现在所有错配收引号统一为 `“`(U+201C),与德语正字法
(DUDEN R11)和文件里的多数派一致。en 与其余九包一字未动(en-drift 门实测
0 en value(s) changed)。
落地重数,两种单位都记下来:卡片说「20 个值」、分诊复扫说「22 处错配」,两者各自
都对 —— 20 个 key 承载 22 处错配,因为 `navigationSync.renamedPage` 与
`navigationSync.renamedDashboard` 各在一句里引两个名字("Seite „alt“ in „neu“
umbenannt"),各贡献 2 处。全文件计数 修前 → 修后:`„` 45 → 45,`“` 25 → 47,
`”` 2 → 2,`"` 28 → 6。
持久不变量没有采用卡片提议的 `count(„) === count(“)` —— 那条在**正确修完的文件
上是假的**(45 vs 47):`grid.import.savedMappingHint` 与
`grid.import.savedMappingPreviewNote` 两个值仍是未翻译的英文散文、按英文风格用
`“…”`,它们的两个 `“` 是合法的**开**引号。改钉成配对本身(每个 `„` 后第一个引号
字符必须是 `“`),外加算术恒等式 `count(“) === count(„) + count(”)` —— 那两个值
将来被译成德语它依然成立(47 === 47 + 0),而错配一旦回填立刻红。两者都带 presence
防空转断言。
`residue-namespaces-3546.test.tsx` 里那条断言是卡片正文点名「这一单落地时必须回头
看的地方」:它原本钉住邻键的错配形态以说明切片七的刻意分歧,现在改钉**收敛后**的
一致形态,并在注释里留下这段来历。
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
原注释写「constants 用转义写、字面量只出现在期望表里」,实际两处都用字面量。 改成如实描述,并给四个常量都补上 U+ 码位 —— U+201E 与 U+201C 在多数编辑器字体里 只差一个像素,这个 bug 能活下来正是因为它们看起来一样。仅注释,无行为改动。
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 #3876
packages/i18n/src/locales/de.ts里 20 个 key 用德语低九分号开引号„(U+201E)开场,却用 ASCII 直引号"(U+0022)收尾。德语用户今天读到的是Registerkarte „Alle Datensätze" anzeigen。search.resultsCount最直观:值以„{{query}}""结尾 —— 错配的收引号紧挨着 TS 字符串的结束符。这从来不是本包约定:修前同一文件里已有 23 处写成正确的
„…“,两种写法在同 namespace 的邻键里并排坐着。现在所有错配收引号统一为“(U+201C),与德语正字法(DUDEN R11)和文件里的多数派一致。落地重数(两种单位都对,差异记进代码)
卡片说「20 个值」、分诊在
b750823复扫说「22 处错配」。两者各自都对,只是单位不同,这份差异现在写进了钉子文件的文件头,不再留给下一个人猜:差 2 的原因:
navigationSync.renamedPage与navigationSync.renamedDashboard各在一句里引两个名字("Seite „alt“ in „neu“ umbenannt"),各贡献 2 处。分诊当时在
b750823量到 44ׄ/ 24ד;本单在2937bcf7d实测 45 / 25 —— 切片七(#3546)那个刻意写成正确配对的empty.interfacePageSourceMissing之后又合进来一对,两边都不算错。全文件计数 修前 → 修后:„U+201E“U+201C”U+201D"U+0022取证用
\p{L}+u的 Unicode 属性类正则(#3866 教训:\w/[A-Za-z]会静静漏掉德语引号里满是的 ä ö ü ß,于是方法本身少报、文件看起来是干净的),并用一个独立的「逐字符找最近引号」扫描器交叉核对,两者同为 22。20 个值逐值人工复核过:每一处被改的"都是德语散文里的收尾引号(视图名、Tab 名、搜索词、应用名),没有一处是代码/JSON/CLI 引用需要保留 ASCII。持久不变量:没有采用卡片提议的 count(„) == count(“)
卡片建议钉
count(„) === count(“)。那条在正确修完的文件上是假的(45 vs 47),照抄会让下一个读者去追一个不存在的 bug。原因:本包还有两个值是未翻译的英文散文,按英文风格用“…”—grid.import.savedMappingHintgrid.import.savedMappingPreviewNote它们的两个
“是合法的开引号,正是 45/47 那 2 的缺口。钉子改成配对本身:每个„之后第一个引号字符必须是“,外加算术恒等式—— 每个德语
„由“收尾,每个多出来的“是被”应答的英文开引号。那两个值将来被译成德语它依然成立(47 === 47 + 0),错配一旦回填立刻红(46 !== 47)。两条都带 presence 防空转断言(2914 个字符串值、不少于 40 个„),import 坏掉或文件被改名不会静静空转变绿。为什么必须落钉子
三道 i18n 门禁按设计都读不到值:
all-locales-key-parity比键名集合与占位符形状,check-i18n-call-site-keys.mjs只判 key 能否解析,check-i18n-en-drift.mjs只在 en 值变化时要求九包跟随 —— 这些值从落地起就是错的,不存在「变化」事件。没有一条值域断言,下一次回填还会从邻键把错配抄过去,这 20 个就是这么攒起来的。派单写的是「⛔ 不碰 3546 家族测试」,但 issue 正文明确点名这一处:
residue-namespaces-3546.test.tsx:707原本toContain('„{{name}}"')—— 它钉住的正是本单要删掉的错配形态。切片七已经合进 main(不是在飞),不改它 CI 必红。按 fixture 三分法这是「re-spell」:改钉收敛后的一致形态(两个姊妹值现在都是„{{name}}“),覆盖面没有减少(仍钉邻键的配对),注释里留下这段来历与指向新钉子文件的指针。共 1 行断言 + 注释,请 PM 复核这次越面。反向验证(方向先预判后运行)
预判:把任一错配还原,配对钉必须红并点名 key —— 这里不存在反转或「计数归零而空过」的情形,因为断言直接钉修后字节,且缺陷计数是 0 → 1 并有 presence 兜底。
实跑还原
empty.objectNotFoundDescription+empty.pageNotFoundDescription两个值:7 个测试红、2 个文件,与预判逐条对上;唯一保持绿的是 en 未受影响那条(正确,它管的是 en):顺带发现:pack-wide 那条原先先跑算术、后跑点名清单,还原时先炸的是
expected 43 to be 45(不点名)。已把点名清单的断言提到算术之前,失败第一行就说出是哪个 key、哪句话。验证
消费半径 =
packages/i18n全包:en-drift 门(本单的关键否证项,en 必须一字未动):
其余:
check-i18n-call-site-keys.mjs2320/2320 解析;全仓turbo run type-check --concurrency=278/78 successful;@object-ui/i18nlint 0 errors(33 条 warning 全在未触及文件);scripts/check-control-bytes.mjsOK(3794 文件),另按仓规自扫grep -naP控制字节零命中 —— 本单写钉子时确实在String.fromCharCode(10)那行落进过一个裸 NUL,导致整个文件被 grep 当二进制(零命中、无信号),自扫抓到并已清除。范围
只改
de。其余九包一字未动;es等按各自约定用 ASCII 双侧引号(residue 测试 701 行已钉),不是缺陷。fr/zh/ja卡片已量干净,未扩包面。发现但未在本 PR 修(另立单):
approvalsInbox三个值(rejectOneTitle/inlineApproved/inlineRejected)用 ASCII 直引号双侧成对,而同族兄弟approvalsInbox.approveOneTitle是正确的„…“—— 这是另一种缺陷形态(一致的 ASCII 对,不是错配对),本单的不变量按设计也扫不到它(没有„)。已在钉子文件里把这 3 个 key 钉成显式清单,数目漂了会红,将来修它的人必须回来更新这份清单。Generated by Claude Code