Skip to content

逐条评估:每种元数据类型的国际化需求 #945

@hotlong

Description

@hotlong

评估方法

对每种类型,我从 4 个维度评估:

  1. 当前状态 — 代码里实际怎么写的
  2. 翻译覆盖en.ts/zh.ts 里有没有
  3. Salesforce 做法 — 它翻不翻,怎么翻
  4. ObjectStack 建议 — 要不要做,怎么做

1️⃣ Object Label(对象显示名)

代码现状:

label: 'Order Item'    // 纯字符串
维度 状况
翻译文件 objects.order_item.label: '订单明细' — 已有
运行时 ❌ 未接入,页面标题仍显示英文
Salesforce <CustomObjectTranslation><label> — 每对象必翻
主流低代码 Airtable/Notion: 不分语言。Salesforce/Dynamics: 必翻
优先级 P0 — 最高频可见
评估结论 必须做。用户进入任何列表页第一眼看到的就是这个

额外优化:Salesforce 还支持 pluralLabel(复数形式),如 "Accounts" vs "Account"。ObjectStack 当前不需要,因为 React 端不区分单复数标题,但翻译节点可预留此能力。


2️⃣ Object Description(对象描述)

维度 状况
翻译文件 objects.order_item.description: '客户订单中的单个行项目' — 已有
运行时 ❌ 未接入
Salesforce ✅ 翻(对象详情页、帮助提示)
优先级 P1 — 用户偶尔看到(对象详情头部、搜索结果)
评估结论 做。已有翻译数据,接入成本为 0

3️⃣ Field Label(字段显示名)

代码现状:

unit_price: Field.number({ label: 'Unit Price', ... })
维度 状况
翻译文件 fields.order_item.unit_price: '单价' — 已有,覆盖全部 ~98 个字段
运行时 ❌ 表头、表单都显示英文
Salesforce <fields><name>...<label> — 核心翻译项
优先级 P0 — 最高频可见
评估结论 必须做。这是截图中问题最明显的地方:Name / Order / Product / Quantity 全是英文

4️⃣ Field Description / Help Text(字段帮助文本)

代码现状:
Spec 的 FormFieldSchema 支持 helpText

interface FormField {
  field: string;
  label?: string;
  placeholder?: string;
  helpText?: string;       // ← 存在但 CRM 对象未使用
}
维度 状况
CRM 对象定义 ❌ 当前无任何对象使用 helpText
翻译文件 ❌ 无
Salesforce <fields><helpText> — 鼠标悬停时的帮助提示
主流低代码 OutSystems: 支持。Appsmith: 支持 tooltip
优先级 P3 — 未来扩展
评估结论 暂不做。CRM 示例没用 helpText,但翻译节点应预留 _helpText 位置。当元数据开始使用 helpText 时,翻译框架自动就能覆盖

建议:在 ObjectTranslationNode 里预留:

_helpText?: Record<string, string>;  // field_name → translated help text

5️⃣ Field Placeholder(字段占位符文本)

代码现状: Spec FormFieldSchema 支持 placeholder,但 CRM 示例同样未使用。

维度 状况
CRM 使用 ❌ 无
Salesforce ❌ 不翻(placeholder 不在 Translation Workbench 范围)
主流低代码 多数不翻 placeholder
优先级 P3 — 未来扩展
评估结论 暂不做。但如果 CRM 开始用 placeholder,应纳入 _placeholder 节点

6️⃣ Select / Picklist Option Label(选项值翻译)

代码现状:

role: Field.select([
  { value: 'decision_maker', label: 'Decision Maker', color: 'red' },
  { value: 'influencer', label: 'Influencer', color: 'blue' },
])
维度 状况
翻译文件 fieldOptions.opportunity_contact.role.decision_maker: '决策者' — 覆盖全部 ~47 个选项
运行时 ❌ 表格里的 Badge(Product / Service)仍显示英文
Salesforce <fields><picklistValues><translation> — 核心翻译项
主流低代码 所有平台都翻。这是国际化最容易漏的地方
优先级 P0
评估结论 必须做。截图中 "Product" / "Service" Badge 正是选项值未翻译的体现

额外优化:Salesforce 的 Global Value Set(全局选项集)可以跨对象复用。当 lead_source 同时出现在 Contact 和 Opportunity 时,翻译只需写一次。ObjectStack 的 fieldOptions 当前是按对象隔离的,存在重复(如 contact.lead_sourceopportunity.lead_source 值完全相同)。

建议:增加 _globalOptions 节点,用于跨对象复用的选项集翻译,避免重复维护。


7️⃣ View / List View Label(视图标签)

代码现状:

listViews: {
  all: { label: 'All Opportunities', ... },
  pipeline: { label: 'Pipeline', type: 'kanban', ... },
}
维度 状况
翻译文件 views.opportunity.pipeline: '管道' — 已有
运行时 ❌ 视图切换 Tab 显示英文
Salesforce <layouts><sections> + ListView label
优先级 P1
评估结论 做。视图 Tab 是用户高频交互点

8️⃣ Form Section Title(表单分区标题)

代码现状:

{ label: 'Deal Information', columns: '2', fields: [...] }
{ label: 'Financials & Stage', columns: '2', fields: [...] }
维度 状况
翻译文件 formSections.opportunity.dealInfo: '交易信息' — 已有
运行时 ❌ 表单分区标题显示英文
Salesforce <layouts><sections> — Layout section labels
优先级 P1
评估结论 做。编辑记录时必经之路

注意问题: 当前翻译 key 用的是 formSections.opportunity.dealInfo(camelCase),但 section 在 view 元数据中没有显式 name 字段——它���由 label 字符串隐式标识的。这意味着 runtime 需要建立 label→sectionId 的映射。建议在 view 定义中给每个 section 加一个 nameid 字段。


9️⃣ Action Label(操作按钮标签)

代码现状:

name: 'event_send_invitation',
label: 'Send Invitation',
维度 状况
翻译文件 actions.event_send_invitation.label: '发送邀请' — 已有
运行时 ❌ 未接入
Salesforce ✅ Quick Actions label 可翻
优先级 P1
评估结论 做。按钮是核心操作交互

🔟 Action confirmText(操作确认提示)

代码现状:

confirmText: 'Are you sure you want to cancel this event?'
维度 状况
翻译文件 actions.event_cancel.confirmText: '确定要取消此事件吗?'
Salesforce ⚠️ Salesforce 的 confirm 是标准化组件,不需要自定义文本翻译
Dynamics 365 ✅ Custom confirmation dialog text 可翻
优先级 P2
评估结论 做。但优先级低于按钮标签本身

1️⃣1️⃣ Action successMessage(操作成功提示)

维度 状况
翻译文件 actions.event_cancel.successMessage: '事件已取消'
Salesforce ❌ 不翻(Toast 是系统级)
优先级 P2
评估结论 做。ObjectStack 自定义了 toast 消息,需要翻译

1️⃣2️⃣ Action Param Label(操作参数标签) ⚠️ 被遗漏的类型

代码现状:

params: [
  { name: 'subject', label: 'Subject', type: 'text', required: true },
  { name: 'body', label: 'Message', type: 'textarea' },
]
维度 状况
翻译文件 actionParams.subject: '主题' — 已有但是全局 flat 结构,未按对象/action 分组
运行时 ❌ 弹窗参数表单显示英文
Salesforce ✅ Quick Action param labels 可翻
优先级 P1 — 用户执行操作时必然会看到参数弹窗
评估结论 必须做。且当前 key 设计有问题

关键问题: 当前 actionParams 是全局 flat 的(actionParams.subject: '���题'),但不同 action 的 "subject" 参数可能需要不同翻译。例如"发送邮件"的 subject 是"主题","日志"的 subject 可能是"标题"。应该改为按 action 分组。


1️⃣3️⃣ Action Param Validation Message(参数验证错误)

代码现状:

newErrors[p.name] = `${p.label} is required`;   // 硬编码英文!
维度 状况
翻译文件 ❌ 无
Salesforce ✅ Validation rule errorMessage 可翻
优先级 P2
评估结论 做。当前 "${p.label} is required" 是硬编码英文,应该改为 t('validation.required', { field: translatedLabel })

这不是元数据翻译,是框架级 UI 文案翻译,属于不同层面的问题。


1️⃣4️⃣ Confirm Dialog Button Text(确认弹窗按钮文案)

代码现状:

<Button variant="outline" onClick={onCancel}>Cancel</Button>    // 硬编码
<Button onClick={handleSubmit}>Continue</Button>                // 硬编码
维度 状况
Salesforce confirm.confirmText / confirm.cancelText 可翻
Spec 支持 ActionSchema.confirm.confirmText / cancelText 已有类型定义
翻译文件 ❌ 无
优先级 P2
评估结论 做,但分两层:① 元数据层的自定义 confirmText/cancelText ② 框架默认 "Cancel"/"Continue"

1️⃣5️⃣ Navigation Section Label(导航分组标题)

代码现状: CRM App 导航有分组(Sales / Reports),在 crm.app.ts 中作为 NavigationArea.label 定义。

维度 状况
翻译文件 navigation.sales: '销售', navigation.reports: '报表'
运行时 已生效(Navigation 已用 I18nLabel)
优先级 已完成 ✅

1️⃣6️⃣ Dashboard Title / Description / Widget Title

维度 状况
运行时 Title 和 Widget Title 已生效(已用 I18nLabel)
Description ❌ 仍为纯字符串 'Revenue metrics, pipeline analytics...'
优先级 P2(description)
评估结论 Description 补上。Title/Widget Title 不需要动

1️⃣7️⃣ Dashboard Column Labels(仪表盘表格列名)

代码现状: 翻译文件有 dashboard.columns.opportunityName: '商机名称',但 dashboard widget 的 table 列定义中是直接引用字段名,理论上会被字段翻译覆盖。

维度 状况
是否独立翻译项 ⚠️ 冗余——如果字段翻译生效,dashboard 列名自动解决
Salesforce Dashboard 不单独翻列名,用字段翻译
评估结论 移除 dashboard.columns 翻译。这些列名就是字段名,应该复用字段翻译,不要维护两份

1️⃣8️⃣ Report Label / Description / Column Labels

维度 状况
翻译文件 ✅ 全有
运行时 ❌ 未接入
Salesforce ✅ Report type label 可翻,但列名复用字段翻译
优先级 P1(label)/ P2(description)/ ⚠️ 列名(同 #17,应复用)

关键优化:reports.columns 里的 orderNumber/account/amountfields.order.name/fields.order.account 是同一个字段。应该删除 reports.columns,让报表列自动从字段翻译获取。


1️⃣9️⃣ Page Title / Content(页面标题和内容)

维度 状况
翻译文件 pages.gettingStarted.title: '开始使用 CRM'
运行时 ❌ 页面元数据中用纯字符串
Salesforce ✅ In-App Guidance / Custom Page labels 可翻
优先级 P2 — 页面内容较长,翻译量大但频率低
评估结论 做。但页面内容体量大(markdown 段落),可考虑后期接 AI 翻译

2️⃣0️⃣ Select Option Color(选项颜色) — 不需要翻译

维度 状况
代码 { value: 'hot', label: 'Hot', color: 'red' }
评估结论 不翻译。颜色是视觉属性,与语言无关

2️⃣1️⃣ Object Icon — 不需要翻译

| 评估结论 | ❌ 不翻译。图标与语言无关 |


2️⃣2️⃣ Field format / searchable / required 等属性 — 不需要翻译

这些是数据行为属性,不是面向用户的文案。


📊 完整评估汇总表

# 类型 当前有翻译 运行时已生效 是否冗余 Salesforce翻 优先级 结论
1 Object label P0 ✅ 做
2 Object description P1 ✅ 做
3 Object pluralLabel P3 🔮 预留
4 Field label P0 ✅ 做
5 Field helpText P3 🔮 预留
6 Field placeholder P3 🔮 预留
7 Select option label P0 ✅ 做
8 View label P1 ✅ 做
9 Form section title P1 ✅ 做
10 Action label P1 ✅ 做
11 Action confirmText ⚠️ P2 ✅ 做
12 Action successMessage P2 ✅ 做
13 Action param label ⚠️ 结构问题 P1 ✅ 做 + 重构 key
14 Action param validation P2 ✅ 框架层
15 Confirm dialog buttons P2 ✅ 框架层
16 Navigation label done ✅ 已完成
17 Dashboard title done ✅ 已完成
18 Dashboard description P2 ✅ 做
19 Widget title done ✅ 已完成
20 Dashboard columns ⚠️ 冗余 删除,复用字段翻译
21 Report label P1 ✅ 做
22 Report description P2 ✅ 做
23 Report columns ⚠️ 冗余 删除,复用字段翻译
24 Page title/content P2 ✅ 做
25 App label done ✅ 已完成
26 App description done ✅ 已完成

🔑 发现的 5 个关键优化点

优化 1:删除冗余翻译(dashboard.columns + reports.columns)

dashboard.columnsreports.columns 里的 key 和字段翻译重复:

冗余 key 实际来源
dashboard.columns.amount: '金额' = fields.opportunity.amount: '金额'
reports.columns.orderNumber: '订单编号' = fields.order.name: '订单编号'
reports.columns.account: '客户' = fields.order.account: '客户'

应该删除这两个节点,让 dashboard table 和 report table 自动从字段翻译获取列名。这减少 ~16 个冗余翻译条目。

优化 2:Action Params 重构为按 Action 分组

当前 flat 结构无法区分同名参数:

// 当前问题
actionParams: {
  subject: 'Subject',       // send_email 的 subject?还是 log_call 的 subject?
  message: 'Message',       // 哪个 action 的 message?
}

应该改为嵌套在 action 节点下:

// 推荐
o.account._actions.send_email.params.subject: '邮件主题'
o.account._actions.send_email.params.body: '邮件正文'
o.contact._actions.log_call.params.call_subject: '通话主题'   // 不同翻译

优化 3:全局选项集(Global Value Set)复用

lead_source 的选项同时出现在 Contact 和 Opportunity 中,翻译完全重复。参考 Salesforce GlobalValueSetTranslation,建议增加全局选项集翻译节点,被多个对象的字段引用。

优化 4:预留 Field helpText / placeholder

虽然 CRM 当前未使用,但翻译节点应预留位置,为未来 helpText/placeholder 国际化做准备。

优化 5:框架级 UI 文案独立翻译层

action-param-dialog.tsx 中的 "Cancel" / "Continue" / "{field} is required" 是框架组件硬编码。这不属于元数据翻译,而是 ObjectUI 框架本身的 UI 文案,需要单独的翻译层(类似 antdlocale)。


📐 最终翻译节点结构(修订版)

const zh = {
  o: {
    account: {
      // ── 对象元属性 ──
      _label: '客户',
      _description: '用于客户关系管理的公司和组织记录',
      // _pluralLabel: '客户',              // 🔮 预留

      // ── 字段标签(非保留 key = 字段名)──
      name: '客户名称',
      industry: '行业',
      rating: '评级',
      type: '类型',
      // ...

      // ── 字段扩展属性 ──
      // _helpText: { industry: '...' },    // 🔮 预留
      // _placeholder: { name: '...' },     // 🔮 预留

      // ── 选项值 ──
      _options: {
        industry: { technology: '科技', finance: '金融' },
        rating: { hot: '热门', warm: '温暖', cold: '冷淡' },
        type: { customer: '客户', partner: '合作伙伴' },
      },

      // ── 视图 ──
      _views: {
        all_accounts: '所有客户',
        active_accounts: '活跃客户',
      },

      // ── 表单分区 ──
      _sections: {
        basicInfo: '基本信息',
        financial: '财务信息',
        address: '地址',
        additionalDetails: '其他信息',
      },

      // ── 操作(含参数)──
      _actions: {
        send_email: {
          label: '发送邮件',
          successMessage: '邮件发送成功',
          params: {                            // ← 新增:参数按 action 归属
            subject: '邮件主题',
            body: '邮件正文',
          },
        },
        assign_owner: {
          label: '分配负责人',
          successMessage: '负责人分配成功',
          params: { newOwner: '新负责人' },
        },
        merge: {
          label: '合并客户',
          confirmText: '确认要合并这些客户吗?此操作不可撤销。',
        },
      },
    },
    // ... 其他对象
  },

  // ── 全局选项集(跨对象复用)──
  _globalOptions: {                              // ← 新增
    lead_source: {
      web: '网络', phone: '电话', partner: '合作伙伴',
      referral: '推荐', trade_show: '展会', other: '其他',
    },
  },

  // ── 全局翻译 ──
  app: { name: 'CRM', description: '销售管道、客户和客户关系管理' },
  nav: { dashboard: '仪表盘', contacts: '联系人', /* ... */ },
  dashboard: {
    title: 'CRM 概览',
    description: '营收指标、管道分析和交易洞察',    // ← 新增
    widgets: { totalRevenue: '总营收', /* ... */ },
    trendLabel: '较上月',
    // columns: 已删除,复用字段翻译
  },
  reports: {
    salesReport: { label: '销售报表', description: '按客户和产品类别的月度销售分析' },
    pipelineReport: { label: '管道报表', description: '销售管道阶段分析' },
    // columns: 已删除,复用字段翻译
  },
  pages: { /* 不变 */ },
};

对比现有结构的变更清单

变更 原因 影响
删除 dashboard.columns 冗余,复用字段翻译 -4 keys × 10 locales = -40 条
删除 reports.columns 冗余,复用字段翻译 -12 keys × 10 locales = -120 条
重构 actionParams → 嵌入 _actions.*.params 消除同名参数歧义 ~18 keys 迁移
新增 _globalOptions 消除跨对象选项值重复 抽取 lead_source 等共享选项集
预留 _helpText / _placeholder / _pluralLabel 未来扩展 0 当前改动,纯约定
结构重组 Category-first → Object-first 翻译者友好、工具友好 一次性迁移

最终减少 ~160 条冗余翻译,新增全局选项集复用机制,为翻译工作台的自动检测扫清了结构障碍。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions