I18nId 规范
I18nId v1 规范定义了如何将字符串转换为用于国际化的确定性、抗冲突标识符。
i18n:v1:<hash>其中:
i18n- 协议标识符v1- 规范版本<hash>- 归一化字符串的 BLAKE3 哈希(hex 编码,16 个字符)
| 源字符串 | I18nId |
|---|---|
| ”Hello” | i18n:v1:a5b9c3d7e8f0 |
| ”Hello, World!” | i18n:v1:b6c8d4e9f1a2 |
| ” Hello “ | i18n:v1:a5b9c3d7e8f0(归一化后相同) |
在进行哈希之前,字符串会先被归一化:
- Trim whitespace - 去除首尾空格
- Collapse internal whitespace - 多个空格 → 单个空格
- Unicode normalization - NFC 形式
- Lowercase(可选,可配置)
fn normalize(input: &str) -> String { input .trim() .split_whitespace() .collect::<Vec<_>>() .join(" ")}use blake3::Hasher;
fn generate_i18n_id(text: &str) -> String { let normalized = normalize(text); let hash = blake3::hash(normalized.as_bytes()); let hex = hex::encode(&hash.as_bytes()[..8]); // First 8 bytes = 16 hex chars format!("i18n:v1:{}", hex)}相同输入总是产生相同输出:
assert_eq!( generate_i18n_id("Hello"), generate_i18n_id("Hello"));采用 64 位的 BLAKE3 可提供约 2^32 的生日攻击抗性,适用于大多数应用场景。
ID 在以下情况下保持稳定:
- 不同平台
- 不同编程语言
- 不同版本(在 v1 范围内)
在 Greentic 中的用法
Section titled “在 Greentic 中的用法”Flow 消息
Section titled “Flow 消息”- id: greet type: reply config: message_key: "i18n:v1:a5b9c3d7e8f0"{ "type": "TextBlock", "text": "{{i18n:i18n:v1:a5b9c3d7e8f0}}"}{{t "i18n:v1:a5b9c3d7e8f0"}}CLI 工具
Section titled “CLI 工具”greentic-i18n id "Hello, World!"# Output: i18n:v1:b6c8d4e9f1a2greentic-i18n verify "i18n:v1:b6c8d4e9f1a2" "Hello, World!"# Output: Valid从其他系统迁移
Section titled “从其他系统迁移”从基于键的方式迁移
Section titled “从基于键的方式迁移”// Before{ "greeting.hello": "Hello" }
// After (auto-migration){ "i18n:v1:a5b9c3d7e8f0": "Hello" }greentic-i18n migrate ./old-translations.json --output ./new-translations.json- 始终使用 CLI 生成 ID
- 不要手动修改 ID - 如果源文本变化,请重新生成
- 将源字符串与翻译一并存储,便于参考
- 对翻译文件做版本管理 - 支持回滚
- 使用多个 locale 测试 - 及时发现缺失翻译