EnerOS v0.26.0 版本说明
发布日期:2025-10-05 版本代号:Babel Git Tag:v0.26.0 支持状态:稳定(Stable) Crate 总数:67(新增 3 个) 测试用例数:8550+(新增 450+)
概述
EnerOS v0.26.0「Babel」是国际化(i18n)专项版本,使 EnerOS 能够服务全球不同地区的电力运营商。电力系统虽遵循通用的物理定律,但不同国家/地区在语言、单位制、电压等级、频率标准、监管要求、时区等方面存在显著差异。v0.26.0 将这些区域差异抽象为可配置的本地化层,使同一套内核代码能够无缝适配不同地区。
本版本引入了五大核心能力:国际化框架(i18n Framework)、多语言支持(Multi-language Support)、区域适配(Regional Adaptation)、时区处理(Timezone Handling)、本地化文档(Localized Documentation)。所有面向用户的字符串、日期、数值、单位均通过本地化层渲染,内核逻辑保持语言无关。
设计哲学上,v0.26.0 坚持「内核语言无关」——内核与智能体的业务逻辑不依赖任何特定语言;「区域配置驱动」——区域差异通过配置文件而非代码分支处理;「时区一等公民」——所有时间戳内部统一使用 UTC,仅在展示与交互时转换为本地时区。
关键数据
| 指标 | 数值 | 说明 |
|---|---|---|
| 支持语言 | 12 种 | 中英日韩德法等 |
| 支持时区 | 全部 IANA | 384 个 |
| 本地化条目 | 8000+ | UI 字符串 |
| 区域配置集 | 8 个 | 主要市场 |
| 新增 Crate | 3 | i18n 相关 |
| 新增测试 | 450+ | 含本地化测试 |
新特性
1. 国际化框架
引入 eneros-i18n Crate,提供统一的国际化框架。基于 Fluent(Project Fluent)实现,支持复数、性别、上下文等复杂语法。
基础用法
use eneros_i18n::{I18n, Locale};
let i18n = I18n::new()
.locale(Locale::zh_CN())
.fallback(Locale::en_US())
.load_dir("locales/")?;
// 翻译
let msg = i18n.t("alarm.voltage-high", |b| b
.arg("bus", "42")
.arg("voltage", "1.08"))?;
// 中文: "母线 42 电压 1.08pu 越上限"
// 英文: "Bus 42 voltage 1.08pu exceeds upper limit"
复数处理
// 复数形式自动适配
let msg = i18n.t("alarm.devices-offline", |b| b
.arg("count", 3))?;
// 中文: "3 台设备离线"
// 英文: "3 devices offline"
// 俄语: "3 устройства не в сети"(俄语有3种复数形式)
支持语言
| 语言 | 代码 | 完成度 | 主要市场 |
|---|---|---|---|
| 简体中文 | zh-CN | 100% | 中国大陆 |
| 英语 | en-US | 100% | 北美 |
| 英语 | en-GB | 95% | 英国 |
| 日语 | ja-JP | 92% | 日本 |
| 韩语 | ko-KR | 88% | 韩国 |
| 德语 | de-DE | 90% | 德国 |
| 法语 | fr-FR | 85% | 法国 |
| 西班牙语 | es-ES | 82% | 西班牙/拉美 |
| 葡萄牙语 | pt-BR | 80% | 巴西 |
| 俄语 | ru-RU | 78% | 俄罗斯 |
| 阿拉伯语 | ar-SA | 65% | 中东 |
| 印地语 | hi-IN | 60% | 印度 |
2. 多语言支持
引入 eneros-i18n-mo(Multi-language Orchestrator),支持运行时动态切换语言,无需重启。
动态切换
use eneros_i18n_mo::LanguageManager;
let lang_mgr = LanguageManager::new(&i18n);
// 按用户偏好切换
lang_mgr.set_locale(user_id, Locale::ja_JP()).await?;
// 按地区自动检测
let detected = lang_mgr.detect_from_region("JP")?;
lang_mgr.set_default(detected)?;
智能体多语言
// 智能体按用户语言响应
let agent = Agent::new("dispatch-assistant")
.language(LanguagePolicy::FollowUser);
// 中文用户提问
let reply = agent.chat("母线 42 电压为什么偏高?").await?;
// 中文回复
// 英文用户提问
let reply = agent.chat("Why is bus 42 voltage high?").await?;
// 英文回复
翻译流程
| 阶段 | 说明 | 工具 |
|---|---|---|
| 提取 | 从代码提取待翻译字符串 | xtr |
| 翻译 | 人工/机器翻译 | Crowdin |
| 编译 | 编译为 .ftl 文件 | fluent |
| 加载 | 运行时加载 | eneros-i18n |
| 验证 | 检查缺失/冲突 | 自研工具 |
3. 区域适配
引入 eneros-i18n-region Crate,提供区域差异适配。不同地区的电压等级、频率、单位制、保护配置均通过区域配置集管理。
区域配置
use eneros_i18n_region::{Region, RegionConfig};
let region = Region::from_code("CN")
.config(RegionConfig {
frequency_hz: 50.0,
voltage_levels: vec![110, 220, 500, 750, 1000],
voltage_unit: VoltageUnit::KV,
power_unit: PowerUnit::MW,
coordinate_system: CoordSystem::CGCS2000,
standard: Standard::GB,
});
manager.set_region(region)?;
区域差异表
| 区域 | 频率(Hz) | 电压等级(kV) | 单位制 | 坐标系 | 标准 |
|---|---|---|---|---|---|
| 中国 | 50 | 110/220/500/750/1000 | 公制 | CGCS2000 | GB |
| 美国 | 60 | 115/230/500/765 | 英制+公制 | NAD83 | IEEE/NERC |
| 欧洲 | 50 | 110/220/380 | 公制 | ETRS89 | EN/IEC |
| 日本 | 50/60 | 66/154/275/500 | 公制 | JGD2011 | JIS |
| 巴西 | 60 | 138/230/500/750 | 公制 | SIRGAS2000 | ABNT |
单位转换
use eneros_i18n_region::units::{Voltage, Power, Energy};
// 自动按区域转换
let v = Voltage::from_kv(220.0);
println!("{}", v.display(®ion)); // CN: "220.0 kV"
let p = Power::from_mw(500.0);
println!("{}", p.display(®ion)); // US: "500 MW"
let e = Energy::from_kwh(1000.0);
println!("{}", e.display(®ion)); // CN: "1000 kWh"
4. 时区处理
引入 eneros-i18n-tz Crate,提供完善的时区处理。所有内部时间戳统一使用 UTC 纳秒精度,仅在展示与交互时转换为本地时区。
时区转换
use eneros_i18n_tz::{Timestamp, TimeZone};
// 内部存储:UTC 纳秒
let event_time = Timestamp::now_utc();
// 展示:按用户时区
let tz = TimeZone::from_iana("Asia/Shanghai");
let local = event_time.to_local(&tz);
println!("事件时间: {}", local.format("%Y-%m-%d %H:%M:%S %Z"));
// "事件时间: 2025-10-05 14:30:00 CST"
// 跨时区对比
let ny = TimeZone::from_iana("America/New_York");
println!("纽约时间: {}", event_time.to_local(&ny).format(...));
// "纽约时间: 2025-10-05 02:30:00 EDT"
跨时区调度
// 跨时区运维编排
let maintenance_window = MaintenanceWindow::new()
.start("2025-10-05 02:00:00", TimeZone::America/New_York)
.duration(Duration::hours(4));
// 自动转换为各节点本地时间
for node in cluster.nodes() {
let local_start = maintenance_window.start_at(&node.timezone);
println!("{}: 本地开始 {}", node.id, local_start);
}
时区处理规则
| 场景 | 处理方式 | 说明 |
|---|---|---|
| 内部存储 | UTC 纳秒 | 统一基准 |
| 日志 | UTC | 便于排序 |
| UI 展示 | 用户时区 | 本地友好 |
| 调度 | 区域时区 | 按业务 |
| 告警 | 用户时区 | 即时通知 |
| 报表 | 区域时区 | 合规要求 |
5. 本地化文档
引入 eneros-i18n-docs Crate,提供文档本地化能力。技术文档、运维手册、API 参考均支持多语言版本。
文档构建
use eneros_i18n_docs::{DocBuilder, Locale};
let builder = DocBuilder::new()
.source("docs/")
.output("dist/docs/")
.locales(vec![Locale::zh_CN(), Locale::en_US(), Locale::ja_JP()]);
builder.build().await?;
文档翻译状态
| 文档类型 | zh-CN | en-US | ja-JP | 其他 |
|---|---|---|---|---|
| 快速开始 | 100% | 100% | 95% | 70% |
| 用户指南 | 100% | 95% | 80% | 60% |
| API 参考 | 100% | 100% | 60% | 30% |
| 运维手册 | 100% | 85% | 50% | 20% |
| 最佳实践 | 90% | 80% | 40% | 15% |
改进
- 字符串提取:新增
eneros-i18n-extract工具,自动提取代码中的待翻译字符串 - RTL 支持:阿拉伯语等从右向左书写语言获得完整 UI 适配
- 日期格式:支持各区域习惯的日期格式(YYYY-MM-DD / MM/DD/YYYY / DD/MM/YYYY)
- 数字格式:支持千分位、小数点符号的区域差异(1,000.00 / 1.000,00)
Bug 修复
- 修复
eneros-i18n在 Fluent 消息嵌套引用时的解析错误(#2605) - 修复
eneros-i18n-tz在夏令时切换边界的时间偏移问题(#2610) - 修复
eneros-i18n-region单位转换在英制/公制混合时的精度损失(#2615) - 修复
eneros-i18n-docs在构建多语言版本时的链接错误(#2620)
破坏性变更
Timestamp::now:重命名为Timestamp::now_utc,强调 UTC 语义format!调用:所有面向用户的字符串必须通过i18n.t()翻译,禁止硬编码
升级指南
- 执行
cargo update -p eneros-i18n - 将
Timestamp::now调用更新为Timestamp::now_utc - 将硬编码的面向用户字符串迁移至
.ftl文件 - 参考
docs/migration/v0.26.0.md获取详细迁移步骤