跳转到内容

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(归一化后相同)

在进行哈希之前,字符串会先被归一化:

  1. Trim whitespace - 去除首尾空格
  2. Collapse internal whitespace - 多个空格 → 单个空格
  3. Unicode normalization - NFC 形式
  4. 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 范围内)
- id: greet
type: reply
config:
message_key: "i18n:v1:a5b9c3d7e8f0"
{
"type": "TextBlock",
"text": "{{i18n:i18n:v1:a5b9c3d7e8f0}}"
}
{{t "i18n:v1:a5b9c3d7e8f0"}}
Terminal window
greentic-i18n id "Hello, World!"
# Output: i18n:v1:b6c8d4e9f1a2
Terminal window
greentic-i18n verify "i18n:v1:b6c8d4e9f1a2" "Hello, World!"
# Output: Valid
// Before
{ "greeting.hello": "Hello" }
// After (auto-migration)
{ "i18n:v1:a5b9c3d7e8f0": "Hello" }
Terminal window
greentic-i18n migrate ./old-translations.json --output ./new-translations.json
  1. 始终使用 CLI 生成 ID
  2. 不要手动修改 ID - 如果源文本变化,请重新生成
  3. 将源字符串与翻译一并存储,便于参考
  4. 对翻译文件做版本管理 - 支持回滚
  5. 使用多个 locale 测试 - 及时发现缺失翻译