国际化与合规
EnerOS v0.47.0 聚焦国际化与合规能力建设,新增中/英/日/西 4 语言 i18n 框架、GDPR/PIPL/CCPA 隐私合规自动化与 DL/T 698.45 中国电能表协议适配,覆盖国际部署全场景。合规能力由 eneros-i18n 与 eneros-compliance 两个 crate 协同提供。
合规架构
┌──────────────────────────────────────────────────────────────┐
│ 国际化层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ zh_CN │ │ en_US │ │ ja_JP │ │ es_ES │ │
│ │ 简体中文 │ │ 英语 │ │ 日语 │ │ 西班牙语 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└────────┬─────────────────────────────────────────────────────┘
│
┌────────▼─────────────────────────────────────────────────────┐
│ 隐私合规层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ GDPR │ │ PIPL │ │ CCPA │ │ APPI │ │
│ │ 欧盟 │ │ 中国 │ │ 加州 │ │ 日本 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└────────┬─────────────────────────────────────────────────────┘
│
┌────────▼─────────────────────────────────────────────────────┐
│ 电力协议适配层 │
│ DL/T 698.45 / DL/T 645 / IEC 62056 / Modbus │
└────────┬─────────────────────────────────────────────────────┘
│
┌────────▼─────────────────────────────────────────────────────┐
│ 数据本地化层 │
│ 中国数据不出境 / 欧盟数据不出境 / 美国优先 │
└──────────────────────────────────────────────────────────────┘
| 维度 | 覆盖范围 | 实现 |
|---|
| 语言 | 4 种(中英日西) | eneros-i18n |
| 隐私 | GDPR / PIPL / CCPA / APPI | eneros-compliance |
| 电力协议 | DL/T 698.45 / DL/T 645 / IEC 62056 | eneros-iot |
| 网络安全 | 等保 2.0 / NERC CIP / IEC 62443 | eneros-trust |
| 数据本地化 | 中/欧/美/日 | eneros-compliance |
i18n 国际化
多语言框架
EnerOS 内置 i18n 框架,支持消息翻译、复数形式、日期时间格式化、数字格式化:
use eneros_i18n::{I18n, Locale, Translator};
use std::collections::HashMap;
let i18n = I18n::new()
.locale(Locale::zh_CN)
.fallback(Locale::en_US)
.load_dir("/etc/eneros/locales")?
.strict(false); // 缺失翻译不报错
// 翻译(带参数)
let mut params = HashMap::new();
params.insert("bus", "5");
params.insert("voltage", "1.08");
let msg = i18n.t("alert.voltage_high", ¶ms)?;
// zh_CN: "5 号母线电压过高: 1.08 pu"
// en_US: "Bus 5 voltage high: 1.08 pu"
// ja_JP: "5番母線電圧高: 1.08 pu"
// es_ES: "Tensión de barra 5 alta: 1.08 pu"
// 复数形式
let msg = i18n.tn("alert.devices_offline", count, ¶ms)?;
// 1 device offline / 5 devices offline
// 日期格式化
let date_str = i18n.format_date(timestamp, Format::Long)?;
// zh_CN: 2026年7月6日
// en_US: July 6, 2026
// ja_JP: 2026年7月6日
// es_ES: 6 de julio de 2026
// 数字格式化
let num_str = i18n.format_number(1234567.89)?;
// zh_CN: 1,234,567.89
// en_US: 1,234,567.89
// es_ES: 1.234.567,89
支持语言
| Locale | 语言 | 状态 | 覆盖率 |
|---|
| zh_CN | 简体中文 | ✅ 完整 | 100% |
| en_US | 英语 | ✅ 完整 | 100% |
| ja_JP | 日语 | ✅ 完整 | 95% |
| es_ES | 西班牙语 | ✅ 完整 | 90% |
| zh_TW | 繁体中文 | 🚧 进行中 | 60% |
| fr_FR | 法语 | 🚧 进行中 | 40% |
| de_DE | 德语 | 📋 计划中 | - |
| ko_KR | 韩语 | 📋 计划中 | - |
动态切换
// 按用户偏好
let user_locale = user.preferred_locale();
i18n.set_locale(user_locale).await?;
// 按租户配置
tenant.set_default_locale(Locale::ja_JP).await?;
// 按请求 Header
let locale = request.accept_language().best_match();
// 按地理位置(基于 IP)
let locale = geoip.lookup(client_ip).best_match_locale();
翻译文件格式
翻译文件采用 YAML 格式,按语言分目录:
/etc/eneros/locales/
├── zh_CN/
│ ├── common.yml
│ ├── alerts.yml
│ └── reports.yml
├── en_US/
│ ├── common.yml
│ ├── alerts.yml
│ └── reports.yml
├── ja_JP/
│ └── ...
└── es_ES/
└── ...
zh_CN/alerts.yml 示例:
alert:
voltage_high: "{bus} 号母线电压过高: {voltage} pu"
voltage_low: "{bus} 号母线电压偏低: {voltage} pu"
overload: "{line} 线路过载: {ratio}%"
devices_offline:
one: "{count} 台设备离线"
other: "{count} 台设备离线"
隐私合规
GDPR(欧盟)
use eneros_compliance::gdpr::{GdprCompliance, DataSubjectRequest, Pseudonymize};
use std::time::Duration;
let gdpr = GdprCompliance::new()
.dpo_contact("dpo@eneros.com") // 数据保护官
.retention(Duration::from_secs(86400 * 365 * 2)) // 2 年保留
.pseudonymize(Pseudonymize::personal_data()
.algorithm(HashAlgo::Sha256)
.salt_from_kms("gdpr-salt"))
.consent_required(true)
.cross_border_restriction(true);
// 处理数据主体请求
match request {
DataSubjectRequest::Access(user_id) => {
// 数据可携带性 - 导出用户所有数据
let data = gdpr.export_user_data(user_id).await?;
return Json(data);
}
DataSubjectRequest::Erasure(user_id) => {
// 被遗忘权 - 删除用户数据
gdpr.erase_user_data(user_id).await?;
}
DataSubjectRequest::Portability(user_id) => {
// 数据可携带性 - JSON 导出
let export = gdpr.portable_export(user_id)
.format(ExportFormat::Json)
.await?;
return File(export);
}
DataSubjectRequest::Rectify(user_id, corrections) => {
// 数据更正权
gdpr.rectify(user_id, corrections).await?;
}
DataSubjectRequest::Restrict(user_id) => {
// 处理限制权
gdpr.restrict_processing(user_id).await?;
}
DataSubjectRequest::Object(user_id, purpose) => {
// 反对权
gdpr.object_processing(user_id, purpose).await?;
}
}
PIPL(中国个人信息保护法)
use eneros_compliance::pipl::{PiplCompliance, Consent, Purpose, TransferType};
let pipl = PiplCompliance::new()
.separate_storage(true) // 个人信息单独存储
.cross_border_audit(true) // 跨境传输评估
.minimization(true) // 最小必要原则
.anonymize_after_retention(true); // 保留期满后匿名化
// 同意管理
let consent = Consent::new(user_id)
.purposes(vec![Purpose::Operation, Purpose::Analytics])
.expiry(Duration::from_secs(86400 * 365)) // 1 年有效期
.withdrawable(true);
pipl.record_consent(consent).await?;
// 检查同意状态
let status = pipl.check_consent(user_id, Purpose::Analytics).await?;
if !status.valid {
return Err(Error::ConsentRequired);
}
// 跨境传输评估
let assessment = pipl.cross_border_transfer_assessment(
data,
dest_country: "US",
TransferType::CloudStorage,
).await?;
if !assessment.approved {
return Err(Error::CrossBorderDenied);
}
CCPA(加州消费者隐私法)
use eneros_compliance::ccpa::{CcpaCompliance, ConsumerRequest};
let ccpa = CcpaCompliance::new()
.opt_out_sale(true) // 默认禁止销售
.notice_at_collection("我们收集以下信息...")
.retention(Duration::from_secs(86400 * 365 * 2));
match request {
ConsumerRequest::Know(consumer_id) => {
// 知情权 - 收集了哪些数据
let data = ccpa.collect(consumer_id).await?;
let categories = ccpa.categories(consumer_id).await?;
}
ConsumerRequest::Delete(consumer_id) => {
// 删除权
ccpa.delete(consumer_id).await?;
}
ConsumerRequest::OptOut(consumer_id) => {
// 选择退出销售
ccpa.opt_out_sale(consumer_id).await?;
}
ConsumerRequest::NonDiscrimination(consumer_id) => {
// 非歧视权 - 不会因行使权利而歧视
ccpa.ensure_non_discrimination(consumer_id).await?;
}
}
隐私法规对比
| 法规 | 区域 | 数据主体权利 | 跨境限制 | 罚款上限 |
|---|
| GDPR | 欧盟 | 7 项 | 严格 | 营收 4% |
| PIPL | 中国 | 6 项 | 严格 | 营收 5% |
| CCPA | 加州 | 4 项 | 无 | $7,500/次 |
| APPI | 日本 | 5 项 | 中等 | 1 亿日元 |
| LGPD | 巴西 | 9 项 | 中等 | 营收 2% |
DL/T 698.45 电能表协议
适配中国电力行业标准 DL/T 698.45(基于 IPv6 的电能表通信协议),支持多种安全等级:
use eneros_iot::dlt698::{Dlt698Client, Frame, Apdu, Security, Authentication};
let client = Dlt698Client::new(meter_addr)
.security(Security::aes128()
.key_from_kms("dlt698-key"))
.auth(Authentication::high("password"))
.timeout(Duration::from_secs(5))
.retry(3);
// 读取电能量
let energy = client.read("0x00010000").await?; // 总电能量
println!("总电能量: {} kWh", energy);
// 读取电压
let voltage = client.read("0x02010100").await?;
println!("电压: {} V", voltage);
// 读取电流
let current = client.read("0x02020100").await?;
println!("电流: {} A", current);
// 读取功率因数
let pf = client.read("0x02060100").await?;
println!("功率因数: {}", pf);
// 读取事件记录
let events = client.read_events(Range::last(Duration::from_secs(86400))).await?;
for event in &events {
println!("[{}] {:?}: {}",
event.timestamp, event.event_type, event.description);
}
// 控制命令(需高权限)
client.control("0x0F000001", Action::PowerOff).await?;
DL/T 698.45 安全等级
| 等级 | 认证 | 加密 | 适用 |
|---|
| 0 | 无 | 无 | 测试 |
| 1 | 低(密码) | 无 | 内网 |
| 2 | 中(密码 + MAC) | AES-128 | 普通场景 |
| 3 | 高(ESAM) | AES-128 | 关键计量 |
协议支持
| 协议 | 标准 | 用途 | 适用区域 |
|---|
| DL/T 698.45 | 中国 | 智能电表(IPv6) | 中国 |
| DL/T 645 | 中国 | 智能电表(串口) | 中国 |
| IEC 62056 / DLMS | 国际 | 电能表 | 国际 |
| Modbus | 国际 | 通用 | 全球 |
| IEC 61850 | 国际 | IED | 全球 |
区域合规矩阵
| 区域 | 隐私法规 | 电力协议 | 网络安全 | 数据本地化 |
|---|
| 中国 | PIPL | DL/T 698 | 等保 2.0 | 数据不出境 |
| 欧盟 | GDPR | ENTSO-E | IEC 62443 | 数据不出境 |
| 美国 | CCPA | NERC | NERC CIP | 美国优先 |
| 日本 | APPI | JEAG | ISO 27001 | 推荐本地化 |
| 巴西 | LGPD | ONS | ABNT NBR | 推荐 |
数据本地化
按区域法规要求数据存储位置,自动路由:
use eneros_compliance::localization::{DataResidency, Region, Rule};
let residency = DataResidency::new()
.rule(Rule::new("cn")
.region(Region::CnOnly) // 中国数据不出境
.replication(Replication::None)
.backup(BackupTarget::LocalOnly))
.rule(Rule::new("eu")
.region(Region::EuOnly) // 欧盟数据不出境
.replication(Replication::WithinEu))
.rule(Rule::new("us")
.region(Region::UsPreferred) // 美国优先
.replication(Replication::Any))
.rule(Rule::new("jp")
.region(Region::JapanPreferred)
.replication(Replication::WithinJapan));
// 数据自动路由到合规区域
residency.route(personal_data).await?;
// 检查数据存储合规性
let audit = residency.audit_storage().await?;
for violation in &audit.violations {
println!("违规: {} 数据存储在 {}",
violation.data_type, violation.actual_region);
}
合规审计
use eneros_compliance::audit::{ComplianceAudit, AuditReport};
let audit = ComplianceAudit::new()
.standard(Standard::GDPR)
.standard(Standard::PIPL)
.standard(Standard::NERC_CIP)
.period(Range::last(Duration::from_secs(86400 * 30)));
let report: AuditReport = audit.run().await?;
println!("合规状态: {}", if report.compliant { "合规" } else { "违规" });
println!("检查项: {}", report.total_checks);
println!("通过: {}", report.passed);
println!("失败: {}", report.failed);
for finding in &report.findings {
println!("[{}] {}: {}",
finding.severity, finding.standard, finding.description);
}
性能指标
| 操作 | 延迟 | 备注 |
|---|
| i18n 翻译查找 | < 1μs | 内存缓存 |
| 语言切换 | < 10ms | 含文件加载 |
| GDPR 数据导出 | < 5s | 单用户全量 |
| PIPL 同意记录 | < 5ms | 含审计 |
| CCPA 删除 | < 30s | 含级联删除 |
| DL/T 698.45 读取 | < 100ms | 单点 |
| DL/T 698.45 事件读取 | < 500ms | 100 条 |
| 数据本地化路由 | < 1ms | 规则匹配 |
| 合规审计(月度) | < 5min | 全量检查 |
与其他能力的关系
- 零信任与安全增强:合规底层安全支撑,详见 零信任与安全增强
- 物联网泛在接入:DL/T 698.45 电表接入,详见 物联网泛在接入
- 多租户与隔离:租户级合规隔离,详见 多租户与隔离
- 高可用增强:跨区域数据复制受本地化约束
- 审计链:合规审计使用 WORM 存储
相关文档