- 区块链
- DeFi
- 前端
- 移动开发
【免费下载链接】interface
🦄 Open source interfaces for the Uniswap protocol
导读
Uniswap Interface 仓库(interface)的.i18n/glossary/目录承载着 AI 翻译流水线所依赖的"术语级联"(terminology cascade):它决定每个语言环境下哪些词必须保留英文、哪些词必须使用特定译法、哪些译法属于硬性禁用。本篇指南以仓库内的 .i18n/glossary/README.md 为主线,结合实际词条文件与校验脚本,讲解术语表的"替换不合并"加载优先级、目录分层结构、词条字段格式,以及让错误词条在 PR 阶段而非翻译运行时被拦截的 CI 校验机制。读完后你将能准确回答:一个新术语应该写进哪个文件、一个翻译修正应该落成词条还是直接改译文、以及为什么误删一个 YAML 文件会静默影响所有语种的翻译结果。
术语级联:替换而非合并的加载优先级
@uniswap/i18n-cli(内部工具包)在为应用字符串执行翻译时,会加载一个"术语级联":它由core/(跨语种通用词条)与locales/(各语种词条)两部分组成,对应仓库内的.i18n/glossary/core/与.i18n/glossary/locales/目录。
这一级联整体替换CLI 包内部内置的"种子术语表"(seed glossary),而不是与种子合并。因此:
- 本目录中的词条只可能被新增(added),绝不会被种子整体覆盖(never wholesale replaced);
- 本目录最初是种子术语表的逐字节拷贝(byte-for-byte copy);
- 一旦某个文件被删除,该文件的词条就会从每一次翻译运行中静默消失——因为"替换"语义下没有备份可回退。
从源码结构看,这一设计意图是让术语治理完全由仓库掌控:CLI 只负责在加载时解析文件,词条的增删改全部以.i18n/glossary/下的内容为准,保证同一份词条同时作用于 Web、Mobile 等多个应用端。
替换语义的两个直接后果
后果一:CLI 种子更新不再自动流入本仓库
由于是"替换不合并",一旦.i18n/glossary/目录存在,新版本@uniswap/i18n-cli内置种子术语表的改进不会自动进入本仓库。文档明确指出:即使升级I18N_CLI_VERSION,看起来像是更新了术语,实际上没有任何效果。因此:
- 升级 CLI 版本的人,应当把该包
seed/glossary与.i18n/glossary/做一次 diff,将有价值的改进手工移植进本目录; - 这个动作没有自动化保障,属于人工职责,是维护本目录最容易踩的坑。
后果二:未使用的 locale 文件有意保留
目录中保留了例如locales/fil-PH.yml这样没有对应应用 locale 映射的文件(仓库的Locale枚举中并不存在菲律宾语)。文档解释这是刻意为之:
- 这些文件在运行时零成本;
- 让目录始终是种子的严格超集(strict superset),"拷贝保真度"(copy-fidelity)这件事才是可验证、可检查的。
也就是说,fil-PH.yml的存在不是为了某个实际语种,而是为了维护"本目录 = 种子 + 仓库增量"这一可审计的对应关系。
style 指南路径注释:为保真而保留的"死链接"
locales/*.yml文件头部注释中会出现../../style/locales/*.md这样的路径,例如fr-FR.yml中的(see ../../style/locales/fr-FR.md)。这些路径指向随@uniswap/i18n-cli包分发的各语种风格指南,刻意不复制进本仓库:
- 对 CLI 而言,这些路径在它自己的安装目录下可以正常解析;
- 对仓库而言,它们是无效路径(
.i18n/下并无style/目录); - 注释保持原样,是为了让词条文件与种子术语表保持逐字节一致。
因此阅读这些文件时,风格指南需要从已安装的 CLI 包内查看,而不是在仓库中寻找。
目录结构与词条形态
三层结构
.i18n/glossary/下只允许存在三个 tier 目录(由校验脚本中的KNOWN_TIERS常量锁定):
| 目录 | 作用 |
|---|---|
core/ | 跨所有语种生效的通用词条,典型如 DNT(Do-Not-Translate,不可翻译)品牌词 |
domains/ | 预留的领域级词条层(当前仓库未使用该目录) |
locales/ | 各语种专属词条,文件名即 locale 代码,如zh-CN.yml、fr-FR.yml |
根目录只允许README.md这一个文件。除此之外,任何散落在根目录的.yml或未知 tier 目录都会被校验脚本拒绝,因为它们会被 CLI 加载器静默忽略——看起来提交了,实际对任何一次运行都没有贡献。
core:全局 DNT 品牌词
.i18n/glossary/core/crypto.yml 是核心词条的代表。它收录的是"每个语种都必须保留英文"的词:品牌名(Uniswap、Unichain、Ethereum)、协议术语(calldata、gas)、产品名(Uniswap Wallet、Uniswap Web App)等。机制上,DNT 掩码器(DNT masker)会在模型看到源文本之前把这些词替换为占位符,翻译完成后再还原,从而在机制上杜绝误译。审计曾实际捕获过这类失败模式:
calldata被译成"通话数据"(phone-call data 的直译);NFT被展开成"非同质化代币"这种"圈内没人说的正式学术展开"。
词条还体现了长短语优先掩码的排序约定:Uniswap Wallet作为一个整体被掩码,保证单元完整性,而单独的Uniswap和wallet各自走自己的规则。同族的Uniswap Interface、Uniswap Mobile、Uniswap Extension、UniswapX、Trading API以及Touch ID、Windows Hello、Apple Pay、Google Pay、PayPal等品牌均如此处理(其中Twitter还带forbidden,用于拦截供应商把品牌提前改写成 "X" 的行为)。
协议与交易术语同样在 core 中做了 DNT 处理:Tick(集中流动性价格网格原语)、Timelock/Time lock、bps、FDV、MC、Spread(区分大小写,大写标签是术语、小写散文自由翻译)、Flags(v4 hook 权限位域)、Call data、bug bounty等,每条都记录了供应商误译的实例作为佐证。
locales:preferred / forbidden 双轨约束
各语种文件在 core 之上叠加preferred(推荐译法)与forbidden(硬性禁用译法)两套规则。以 .i18n/glossary/locales/zh-CN.yml 为例:
- 基础词条:
wallet→ 钱包、swap→ 兑换、slippage→ 滑点、TVL→ 总锁仓量、seed phrase→ 种子短语; - 营销关键主张词条:
app fee必须译为 "App 手续费"(保持 App 为拉丁字母、手续费=交易手续费),并forbidden掉 "应用费用""应用程序费用""应用程序手续费"三个字面译法,因为 "Zero app fees" 是核心营销主张; - 审计修复型词条:
report(数据质量反馈)必须用"报告"而非"举报"(举报在大陆语境带执法/投诉色彩,会劝退用户反馈错误数据);claim(unitags 首次注册用户名)必须用"申领"而非"认领"(认领是领取遗失物);bid(Toucan 拍卖竞价)必须用"竞价"而非"出价";passcode必须用 "PIN 码" 以与文本凭据password(密码)区分; - 安全词条:
passkey→ 通行密钥(forbidden掉裸英文 "passkey")、private keys→ 私钥; onchain从 core 的全局 DNT 中重新划定到 locale 层:对 zh-CN 而言,"链上"才是地道且对应用商店受众更可读的译法,同时用forbidden: ["onchain", "on-chain"]防止英文回归。
fr-FR.yml则展示了更复杂的治理链:swap按角色拆分(role-split)——动词/CTA 本地化为 "Échanger",而作为品牌功能标签的英文 "Swap" 保留;wrap/unwrap/mint经母语评审后保留英文,因为法语直译(envelopper/déballer/frapper)全是假朋友(false friend);yield系列(yield/earnings/rewards)则建立了 Earn 域财务概念分类法,用termType区分 rate 与 amount。每个词条都记录了来源(Notion 指南、原生评审、bug-bash、TLM 裁定)与日期,形成完整的 provenance 链。
词条字段速查
综合core/crypto.yml、locales/*.yml与校验脚本中的枚举定义,一条词条可携带的字段如下:
| 字段 | 含义 | 典型取值 |
|---|---|---|
term | 要匹配的源词 | 任意字符串,必填且非空 |
doNotTranslate | 是否掩码保留英文 | true |
preferred | 各语种推荐译法 | { zh-CN: "钱包" } |
forbidden | 各语种硬性禁用译法 | { zh-CN: ["应用费用"] } |
caseSensitive | 大小写敏感匹配 | true |
partOfSpeech | 词性 | noun/verb/adjective/acronym/phrase |
termType | 术语类型枚举 | rate/amount/activity/action/phrase/name |
status | 词条状态枚举 | draft/corpus-derived/native-ratified/legal-approved |
gender | 语法性别(拉丁语系) | masculine/feminine |
description | 治理说明(来源、反例、适用范围) | 自由文本 |
校验脚本 scripts/i18n-glossary.test.ts 中复制了 CLI 加载器的枚举定义:TERM_TYPES = ['rate', 'amount', 'activity', 'action', 'phrase', 'name']、GLOSSARY_STATUSES = ['draft', 'corpus-derived', 'native-ratified', 'legal-approved']。该脚本注释特别说明:如果 CLI 升级扩展了这些枚举,需要同步扩展脚本中的拷贝;过期拷贝会 fail-closed(拒绝 CLI 本可接受的值),绝不会 fail-open。另注意,仅有description而无任何匹配/掩码字段的词条,解析为上下文注释(context note):它只会进入翻译/审校 prompt 作为策略指引,不参与掩码或扫描。
CI 校验:让坏词条死在 PR 里
@uniswap/i18n-cli在加载词条时会执行一组校验,仓库将同一组校验镜像到了 scripts/i18n-glossary.test.ts,在 PR CI 中运行。这样格式错误的词条会在PR 阶段失败,而不是拖到下一次定时翻译运行才爆雷(文档明确写道:a malformed entry fails the PR instead of the next scheduled translation run)。
脚本用Bun.YAML解析(无需 node_modules,与该 CI 步骤的其他测试一致),逐文件执行与 CLI 加载器(@uniswap/i18n-cli的src/glossary/load.ts)完全相同的检查:
- 每个
.yml/.yaml文件顶层必须是YAML 数组; - 每条词条必须是对象,且
term为非空字符串; termType/status若出现,必须是合法枚举值;- 目录布局检查:只允许
core/domains/locales三个 tier 目录;根目录除README.md外不得有散落文件;tier 目录内只允许 YAML 文件; - 目录非空检查:空词条库会静默回落到 CLI 种子,因此
yamlFiles().length > 0是硬性断言。
测试输出形如${file} entry [${idx}] is missing a non-empty string "term",精确到文件与数组下标,便于定位。运行方式为bun test scripts/i18n-glossary.test.ts。配套的 scripts/i18n-memory.test.ts 则守护.i18n/memory/<locale>.json翻译记忆分片(v1 shard 结构、locale 自洽、字节数上限与工作流环境变量I18N_MEMORY_MAX_BYTES联动),并明确将自身定位为 glossary 校验的姊妹闸门。
内容治理:什么该进词条、什么不该进
文档给出了清晰的判定标准:
- 术语修正(terminology corrections)——来自翻译 PR 评审中发现的错误或不一致的术语渲染——应当落成词条,这样修复会作用于每一次未来的运行,而不是只改一条字符串。
zh-CN.yml中report/claim/bid等"审计快速修复"条目即属此类,每条都注明了受影响的 key 命名空间(如reporting.*.data.*、unitags.*、transaction.status.submitBid.*)。 - 一次性语气/措辞调整(one-off tone or phrasing fixes)——应当保留为人类在 locale 文件里的直接编辑。手工编辑过的字符串会被视为未跟踪(untracked),不会重新排队,流水线不会覆盖它。
- 自动扫描(automated sweep)——可以提议词条,但绝不允许自动提交(must never auto-commit):一条错误的
forbidden词条会导致整轮运行失败,因此每条词条都必须经过人工评审。这解释了为什么词条文件中的status存在draft→native-ratified→legal-approved的评审状态演进,以及大量词条标注 "pending native confirmation"。
与翻译流水线的衔接:配置文件与记忆分片
词条级联只是整个 i18n 流水线的一环。仓库根部的 i18n.config.ts 定义了 CLI 的其余输入:
- 源语言为
en-US,源文件指向packages/uniswap/src/i18n/locales/source/en-US.json; - 目标模板为
packages/uniswap/src/i18n/locales/translations/{locale}.json; - locale 列表不从配置文件手写,而是从
packages/uniswap/src/features/language/constants.ts的Locale枚举派生(getLocaleTranslationKey会把zh-Hans→zh-CN、zh-Hant→zh-TW、所有es-*变体 →es-ES),再剔除英文源并排序——这解释了为什么locales/目录下存在es-MX.yml却不存在es-419.yml等对应关系; - 该配置文件由 CLI 用裸
bun import()加载且不带本仓库 node_modules,因此 scripts/i18n-config.test.ts 强制其依赖图只含相对导入、无外部依赖。
翻译记忆(translation memory)则记录每次翻译单元的哈希与状态:.i18n/memory/zh-CN.json中每条目携带sourceHash、glossaryHash、styleHash与status: clean、approvedBy: agent等字段——词条内容的变化会反映为glossaryHash的更新,驱动已译字符串的失效重译。glossary、memory、config 三者共同构成这套可审计、可回滚的翻译治理体系。
小结
.i18n/glossary/不是一份普通的翻译对照表,而是一套以"替换不合并"为基石的术语治理系统:core 层锁定全球通用的品牌与术语(DNT 掩码机制杜绝误译),locales 层用 preferred/forbidden 双轨约束每个语种的地道表达与禁区,CI 镜像校验让格式错误在 PR 阶段暴露,翻译记忆与词条哈希联动保证已译内容随词条变更正确失效。维护者需要记住三条铁律:升级 CLI 版本时必须手工 diff 种子词条;删除任何词条文件等于静默移除全部语种的对应规则;自动扫描只能提议、永远不能自动提交词条。
- 区块链
- DeFi
- 前端
- 移动开发
【免费下载链接】interface
🦄 Open source interfaces for the Uniswap protocol
相关推荐
OpenDesign 国际化(i18n)完整指南:从新增语言翻译到地区术语与 CI 校验
OpenDesign 国际化(i18n)完整指南:从新增语言翻译到地区术语与 CI 校验 本篇技术指南围绕 OpenDesign 仓库根目录的 TRANSLAT
AI 应用人工智能AI 技能设计系统媒体生成OpenMed 多语言文档术语表与翻译一致性治理:从 Canonical Renderings 到 README Drift 校验
OpenMed 多语言文档术语表与翻译一致性治理:从 Canonical Renderings 到 README Drift 校验 OpenMed 是一个本地优
人工智能NLP医疗健康数据脱敏本地部署大模型AI 应用MCP 服务联邦学习Vibe 项目多语言翻译指南:i18n 目录结构、语言添加流程与校验机制
Vibe 项目多语言翻译指南:i18n 目录结构、语言添加流程与校验机制 Vibe("Transcribe on your own!")是一款本地优先的语音转文
人工智能语音本地部署桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考