一、场景痛点
度量衡是国际化的「隐性差异」:文案没翻译用户能看出来,但单位不对用户往往说不清哪里不对,只会觉得"这 App 不对劲"。
- 美国用户看到「250 克 无盐黄油」:知道是黄油,但完全无法估计 250 克是多少——他脑子里的单位是杯(cup)和盎司(oz);
- 中国用户看到「375°F」烤曲奇:温度直觉完全失效,375 是华氏,对应的摄氏是 190;
- 同一条数据在不同地区用户眼里数值含义完全不同:体重 150(磅还是斤?)、距离 5(公里还是英里?)、包裹 2(公斤还是磅?)。
更隐蔽的是单位名称本身也有文化差异:同一个 litre,法国写litres、英国写liters;中文的「公斤」与「千克」并存;日本用「合」(180ml)计量米、用「坪」计量面积——这些都不是简单的"英制 vs 公制"二分法能覆盖的。本应用以「国际食谱」为载体,把度量衡本地化从"技术细节"提升为"产品体验"。
二、典型用户故事
故事 A:留美学生小陈(zh_CN → en_US)
小陈在美国跟朋友学做曲奇,朋友的食谱写「8.8 oz unsalted butter」,她习惯「250 克」。她切到英文界面,食材名变成英文、用量变成盎司——但注意,她并不需要"换算",她需要的是用自己熟悉的体系读懂对方的食谱。反过来她把界面留在中文,英文食谱自动显示成克/毫升,她照做就行。
故事 B:法国用户 Marie(fr_FR)
Marie 打开食谱看到「250 grammes de beurre non salé」。她可能没意识到,这个grammes(复数 + 法语拼写)不是翻译软件翻出来的,而是 CLDR 数据按法语复数规则生成的。如果开发者在代码里写死250 grams,Marie 会看到英文式复数——细节决定"本地化"还是"半吊子翻译"。
故事 C:英国用户 Oliver(en_US 近似)
Oliver 看烤箱温度卡,默认看到 175°C。他点选 200°C,下方显示 392°F——英国家庭烤箱刻度同时印着两种单位。这个卡片解决了他最日常的困惑:网上找的食谱温度单位总跟自己烤箱不一样。
故事 D:跨境食谱作者 Alice
Alice 在博客发布曲奇食谱,读者遍布全球。她用这个工具验证同一个食谱在 5 种语言、公制/英制下的呈现,确认「经典曲奇」在美国读者眼中不是"250克黄油"而是"8.8 oz 黄油"——一篇文章,全球可读。
故事 E:日本用户 Yuki(ja_JP)
Yuki 是日式点心师傅。他看英文食谱时最头疼的不是语言,而是「1 cup flour」——日本菜谱习惯用「カップ(180ml)」「大さじ(15ml)」这类烹饪专用单位,而美国菜谱的「1 cup」是 236.6ml,日本家庭常备的量杯却按 200ml 刻度。他切到日语界面后,用量以克/毫升显示,立即避开「一杯」在不同国家体积不同的陷阱。这印证了本应用的设计理念:单位换算不是"转换数值",而是"转换度量语义"。
故事 F:回归测试工程师 Leo
Leo 的测试矩阵里有一列必查项:zh_CN / zh_TW / en_US / ja_JP / fr_FR 五种语言 × long/short/narrow 三档 × 公制/英制两体系,共 30 种组合,每个组合检查 5 条食材、2 个示例、2 个温度结果。他最喜欢本页的「单位显示方式」区块——把三档并排展示,他不用翻设置就能一次性核对三种形态是否正确。
三、适用使用环境
| 环境类型 | 适配说明 |
|---|---|
| 食谱/烹饪类 App | 容量与重量单位随地区切换,温度换算内嵌 |
| 天气 App | 温度按 locale 摄氏/华氏(美版 68°F、中版 20°C) |
| 健身/健康 App | 体重磅/千克、跑步距离英里/公里、卡路里格式 |
| 地图/导航 App | 距离单位随地区(美国英里、欧洲公里) |
| 物流/快递/电商 | 包裹重量磅/千克、体积单位、报关单换算 |
| 工程/科学工具 | 通用单位换算器,长度/面积/速度/压力全覆盖 |
单位体系的全球版图(为什么不是简单二分)
很多人以为世界只分"公制/英制",实际是一个光谱:
| 地区 | 官方/习惯体系 | 典型例子 |
|---|---|---|
| 中国、欧洲大陆、日本 | 公制为主 | 克、升、摄氏、公里 |
| 美国 | 英制为主(法定但未强制公制化) | 磅、盎司、华氏、英里 |
| 英国 | 混合 | 重量用公斤、距离用英里、液体用品脱 |
| 利比里亚、缅甸 | 英制/本地单位 | 磅、缅斤(viss) |
| 全球烹饪圈 | 混杂 | 美国杯、日本合、中国两、英国品脱 |
美国曾在 1975 年通过《公制转换法案》,但从未强制执行,所以至今磅/盎司/华氏仍是主流;英国 1970 年代推行公制后"距离仍用英里"是著名的半公制案例。做国际化产品不能假设"跟着 locale 走就对"——en_US是英制、en_GB却混合、ja_JP公制但菜谱用合/大さじ。这也是本应用用显式system字段而非"按国家代码推断"的原因。
四、目标用户画像
- 跨地区生活的用户:留学、外派、跨境家庭,一个用户同时接触两套单位体系;
- 面向全球发行的产品团队:需要把"单位本地化"做进产品而不是留给用户自己换算;
- 内容创作者:食谱、健身教程、DIY 指南作者,一份内容希望多地区读者无障碍阅读;
- 开发测试人员:回归验证 locale 切换下单位格式、复数、精度是否全部正确。
五、关键设计决策
1. 存储用 SI 基准单位,展示层换算
INGREDIENTS表存「250 克、240 毫升」等公制基准值,英制显示时才除以系数。理由:数据只有一份,展示可以有无数种。若按地区存多份数据,新增一个地区就要改数据;存基准值后,加语言只加映射,数据零改动。
2. 默认单位跟随 locale,允许用户手动覆盖
美国用户默认英制、欧洲用户默认公制——但"默认"不等于"强制"。真实产品(如天气 App)都会提供「°C/°F」手动切换,且用户的手动选择要单独持久化,不能被下一次 locale 变化覆盖:
@StorageLink(STORAGE_LOCALE)currentLocale:string=DEFAULT_LOCALE;// 用户手动覆盖的单位偏好应存另一个 key,如 i18n_series_09_unit_override3. 换算率与显示完全分层
toImperial()只做数学(250 ÷ 28.35 = 8.82),fmtUnit()只做呈现(“8.8 oz”)。换汇率更新(比如精度更高的系数)不会影响显示逻辑,改显示风格(long→short)不会碰换算——两层各自可独立测试:
// 换算层:纯函数,可单测expect(toImperial(28.35,'gram')).toBeCloseTo(1,5);// 格式化层:可单测expect(fmtUnit('fr_FR',250,'gram','long')).toBe('250 grammes');4. 单位显示粒度可调(三档)
同一数值在「句子」「标签」「图表刻度」三种场景需要三种形态。三档设计让一个组件通吃全文/表单/图表,避免每个场景各写一套格式代码。
5. 单位体系的"显性化"设计
本应用在语言徽章下方常驻一行"公制 / 英制: 英制"指示条——把隐藏在 locale 背后的单位体系选择明示给用户。这是场景设计的细节:用户切到英文发现数值从 250 克变成 8.8 oz,如果没有这行提示,他会以为是 bug;有了它,用户立刻理解"哦,英文界面默认英制"。真实产品里同样的手法用于时区(“当前时区:UTC+8”)、币种(“计价货币:USD”),把隐含规则变成可见信息,是降低国际化产品困惑度的通用技巧。
六、边界与降级
- 温度非线性:
cToF()(×9/5+32)与线性换算(×系数)分开处理,绝不能混入统一 rate 表——否则 175°C 会算出 315°F 而非 347°F; - 不支持的单位代码:
fmtUnit()内try/catch,非法 unit 回退「纯数字 + 单位代码」(如8.8 ounce),保证 UI 不空白不崩溃; - 未知 locale:
curCfg()用?? LANGS[0]兜底,找不到配置时按默认语言渲染; - 精度控制:
maximumFractionDigits: 1统一一位小数,避免8.81849...这种浮点尾差直接暴露给用户;换算内部不做舍入,舍入只发生在显示层; - 用户覆盖 vs 系统默认:手动选过的单位偏好与 locale 默认分开存储、分开生效,切换语言不清空用户偏好。
七、竞品对比(同类方案取舍)
| 方案 | 优点 | 缺点 | 本应用选择 |
|---|---|---|---|
| 手写单位字符串 + 条件判断 | 简单直接 | 每种语言 × 每种单位 × 每种档位都要写死,组合爆炸 | ❌ |
Intl style:'unit'(本应用) | CLDR 数据驱动,复数/空格/拼写全自动 | 依赖系统 CLDR 数据版本 | ✅ |
| 自建单位数据库(ICU4X 等) | 数据可控、离线一致 | 引入依赖、体积大 | 扩展方向 |
| 服务端下发单位文案 | 可热更新 | 依赖网络,离线不可用 | 扩展方向 |
关键认知:「8.8 oz」不是翻译出来的,是格式化出来的。把它当翻译文案管理(每种语言存一条),很快会撞上复数(ounce/ounces)、拼写(gramme/gram)、空格(8.8oz/8.8 oz/8.8 oz)的组合爆炸——交给 CLDR 数据才是正解。
八、扩展方向
- 更多单位维度:面积(平方米/平方英尺)、速度(km/h ↔ mph)、压力(hPa ↔ inHg)、体感温度(含湿度因子);
- 本地特殊单位:日本的合/坪、英制的杯/汤匙(体积烹饪单位)、中国的斤/两——CLDR 已覆盖多数,直接换
unit代码即可; - 单位偏好跨设备同步:登录后单位偏好存云端,手机/平板/手表一致;
- 语音播报本地化:TTS 朗读「250 grammes」时用 long 档(朗读需要完整单位名,narrow 档的 “250g” 会被读成 “250g”);
- 自动识别用户体系:不只看 locale,还结合系统地区、SIM 卡地区、GPS 位置综合推断(如常驻美国的中国用户看到英里但想切公里);
- 烹饪专用单位体系:
cup/tablespoon/teaspoon在美制(236.6ml/14.8ml/4.9ml)、英制(284.1ml/17.8ml/5.9ml)、日式(200ml 量杯)之间差异巨大,食谱类产品可在单位选单里提供"杯 = 美制/英制/日式"三选一,把隐性歧义显性化。
九、生产级注意事项
- 换算率带版本:若换算率从服务端下发,务必带版本号并本地缓存,避免数据源更新导致新旧客户端显示不一致;
- CLDR 数据版本差异:不同系统版本 CLDR 数据可能不同(如旧系统没有
fluid-ounce),上线前在目标最低系统版本上跑一遍全部unit代码的冒烟测试; - 精度策略分级:天气 0 位小数(20°C)、健身 1 位(68.0 kg)、工程 2 位(0.24 L)——按场景定义精度,不要全局一刀切;
- 方向性:阿拉伯语下数字与单位同样需要 RTL 排布(见应用 07),格式化结果直接放进 RTL 布局即可,但拼接「名称 + 数值」时注意语序;
- 可访问性:给朗读器提供 long 档单位名——屏幕阅读器读 “250g” 会念成 “250g”(字母),读 “250 grams” 才自然。
十、结语
度量衡本地化让「数据」在跨文化使用时依然有准确含义。它是天气、健康、物流、地图类产品国际化不可跳过的一环——用户可能容忍界面翻译不完美,但绝不会容忍自己的体重显示单位是错的。本应用用「国际食谱」这个最小闭环,把「存基准值、按体系换算、用 Intl 呈现」的完整链路跑通:数据只有一份,呈现却有 5 种语言 × 3 种档位 × 公制英制 2 种体系——这就是本地化的杠杆效应。