跳到主内容

国际化与合规

核心能力

国际化与合规

EnerOS v0.47.0 聚焦国际化与合规能力建设,新增中/英/日/西 4 语言 i18n 框架、GDPR/PIPL/CCPA 隐私合规自动化与 DL/T 698.45 中国电能表协议适配,覆盖国际部署全场景。合规能力由 eneros-i18neneros-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 / APPIeneros-compliance
电力协议DL/T 698.45 / DL/T 645 / IEC 62056eneros-iot
网络安全等保 2.0 / NERC CIP / IEC 62443eneros-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", &params)?;
// 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, &params)?;
// 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全球

区域合规矩阵

区域隐私法规电力协议网络安全数据本地化
中国PIPLDL/T 698等保 2.0数据不出境
欧盟GDPRENTSO-EIEC 62443数据不出境
美国CCPANERCNERC CIP美国优先
日本APPIJEAGISO 27001推荐本地化
巴西LGPDONSABNT 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 事件读取< 500ms100 条
数据本地化路由< 1ms规则匹配
合规审计(月度)< 5min全量检查

与其他能力的关系

  • 零信任与安全增强:合规底层安全支撑,详见 零信任与安全增强
  • 物联网泛在接入:DL/T 698.45 电表接入,详见 物联网泛在接入
  • 多租户与隔离:租户级合规隔离,详见 多租户与隔离
  • 高可用增强:跨区域数据复制受本地化约束
  • 审计链:合规审计使用 WORM 存储

相关文档