Skip to content

feat(rest,spec): 导出文件名本地化 + 系统字段标签内置多语言回退 - #2911

Merged
os-zhuang merged 2 commits into
mainfrom
claude/export-filename-optimization-5dd15f
Jul 14, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/export-filename-optimization-5dd15f

Conversation

@baozhoutao

@baozhoutao baozhoutao commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

背景

用户反馈两处问题:

  1. 导出功能(CSV/Excel)文件名:直接下载得到 contracts.csv 这种裸 API 名,希望优化为「对象显示名-时间戳」。
  2. 导入模板仍有英文:下载模板的 CSV 里,注入的系统字段表头是英文(如 "Owner"),示例行是 ASCII slug(如 prepare)。

前端配套 PR:objectui(导出文件名前端兜底、导入模板示例值取显示标签、模板文件名本地化)。

变更

@objectstack/rest — 导出下载文件名

  • GET /data/:object/export 的 Content-Disposition 改为「对象显示名-时间戳」,按 RFC 5987/6266 双写:filename="task-20260714-153045.xlsx"(ASCII 兜底)+ filename*=UTF-8''任务-20260714-153045.xlsx(本地化标签)。
  • 新增 exportContentDisposition(objectName, label, ext, now?)。

@objectstack/spec — 系统字段标签内置回退

  • ObjectQL 注册表注入的系统字段(owner_id/created_at/created_by/updated_at/updated_by)只有英文标签,自定义对象没有对应翻译条目,导致中文界面漏出 "Owner"/"Created At"。
  • translateObject 内置这五个字段的 en/zh-CN/ja-JP/es-ES 标签表(措辞与平台翻译包一致),仅当字段标签仍是注入的英文默认值时套用,作者自定义标签绝不覆盖;无翻译包时也生效。
  • REST 元数据翻译路径同步放宽(不再因缺 bundle 提前返回);缓存 ETag 本就按 locale 分键,无串味风险。

@objectstack/plugin-reports — 附件文件名

  • 定时报表附件文件名清洗从「非 ASCII 全替换 _」改为按 Unicode 字母/数字保留(\p{L}\p{N}),中文计划名不再变成下划线串。

showcase

  • 任务对象 In Progress 视图开启 exportOptions: ['csv','xlsx','json'],示例应用可直接演示/实测导出。

测试

  • 单测:spec 6756 通过、rest 260 通过(含 exportContentDisposition 5 例、系统字段回退 6 例)、plugin-reports 29 通过。
  • 真机实测(showcase dev 栈 + objectui console,中文界面):
    • curl -H 'Accept-Language: zh-CN' …/export?format=xlsx → content-disposition: attachment; filename="showcase_task-20260714-063010.xlsx"; filename*=UTF-8''%E4%BB%BB%E5%8A%A1-…(即 任务-….xlsx);en-US → Task-….csv。
    • 控制台 UI 导出 CSV/XLSX,浏览器实际落盘名:任务-20260714-064550.csv、任务-20260714-064607.xlsx。
    • 导入向导「下载模板」:模板首列表头由 "Owner" 变为「所有者」,created_at 显示「创建时间」。

追加(6ab3e7c):导出↔导入选项标签闭环

第二轮实测发现平台级缺陷:导出/模板写出的是翻译后的选项标签(如 待规划),但导入 coercion 只认作者原始标签——用户把自己刚导出的中文文件原样导回,select 字段全报 invalid_option。

  • prepareImportRequest 新增 localizeSchema 钩子;REST 两处导入路由传 translateMetaItem,把翻译标签并入选项匹配同义词(mergeLocalizedOptionSynonyms)。
  • 作者标签、选项 code 照常接受;非法值照常报 invalid_option;钩子抛错时静默降级为原 schema。
  • showcase 补全 showcase_task en/zh-CN 翻译包(status/priority/done/labels/sync_status/sync_error),消除模板残留英文。
  • 单测 rest 265/265(+5 例 import-prepare.test.ts);真机 dry-run:中文标签导回 ok:1、英文标签不回归、非法值仍拦截(详见 PR 评论实测报告)。

Closes #2916

@vercel

vercel Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 14, 2026 12:02pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:system tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface size/m and removed documentation Improvements or additions to documentation protocol:system tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Jul 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/plugin-reports, @objectstack/rest, @objectstack/spec.

97 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via packages/rest, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-reports, @objectstack/rest, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:system tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Jul 14, 2026
@baozhoutao

Copy link
Copy Markdown
Contributor Author

真机 UI 复测报告(第二轮:「下载模板结果中还是有英文」)

环境:objectstack dev :3000(showcase,--seed-admin)+ objectui console Vite :5180,zh-CN 会话,浏览器实测(hook HTMLAnchorElement.click / URL.createObjectURL 抓真实下载物)。

1. 导入模板 — 全中文 ✅

UI 路径:任务 → In Progress 视图 → 导入 → 下载模板。实际下载:

  • 文件名:任务-导入模板.csv
  • 内容(真实 blob 原文):
所有者,标题 *,项目 *,负责人,状态 *,优先级,预计工时,进度,已完成,截止日期,开始日期,结束日期,创建时间,工作地点,封面,标签,备注,同步状态,同步错误
,,,,待规划,低,0,,true,2024-01-31,2024-01-31,2024-01-31,2024-01-31 09:00,,,,,已同步,

第一轮遗留的英文(Done/Labels/Sync Status/Sync Error 表头,Backlog/Low/Synced 示例值)全部消除 —— 根因是 showcase 翻译包缺条目,已补全 en/zh-CN 两侧。

2. 导出 — 文件名 + 单元格全中文 ✅

UI 路径:同视图 → 导出 → 导出为 CSV。实际下载:

  • 文件名:任务-20260714-075156.csv(对象显示名-时间戳)
  • 内容:
标题,项目,负责人,状态,优先级,截止日期
Build homepage,Website Relaunch,sam@example.com,进行中,高,2026-07-24
Ingest pipeline,Data Platform,linus@example.com,进行中,紧急,2026-08-03

3. 导出↔导入闭环(本次新发现并修复的平台缺陷)✅

导出/模板写出的是翻译后的选项标签,但导入 coercion 只认作者原始标签 → 把自己导出的中文文件导回去,select 字段全报 invalid_option。修复(6ab3e7c):prepareImportRequest 新增 localizeSchema 钩子,REST 导入路由传 translateMetaItem,翻译标签并入选项同义词。

实测(dry-run POST /api/v1/data/showcase_task/import,Accept-Language: zh-CN):

输入 结果
中文往返测试,Website Relaunch,待规划,紧急(翻译标签) {"total":1,"ok":1,"errors":0,"created":1} ✅
无locale英文标签,Backlog(作者标签,无 locale) ok:1 ✅ 不回归
非法值仍报错,不存在的状态 invalid_option: "不存在的状态" is not a known option ✅ 仍拦截

4. 测试

@objectstack/rest 265/265 通过(+5 个新 import-prepare.test.ts:同义词合并、en no-op、带/不带 localizeSchema、钩子抛错降级)。

操作截图(导入对话框、In Progress 网格中文状态列)已在开发会话中留存。

…abel fallback

- rest: GET /data/:object/export Content-Disposition now uses the object's
  display label + timestamp via RFC 5987/6266 (ASCII api-name fallback in
  filename=, localized label in filename*=UTF-8''). New exportContentDisposition().
- spec: translateObject gains built-in en/zh-CN/ja-JP/es-ES labels for the
  five registry-injected system fields (owner_id/created_at/created_by/
  updated_at/updated_by), applied only when the label is still the injected
  English default; works without a translation bundle. REST meta translation
  no longer bails out when the bundle is missing (ETag is already locale-keyed).
- plugin-reports: attachment filename sanitizer keeps Unicode letters/digits
  instead of flattening CJK to underscores.
- showcase: enable exportOptions on the task In Progress view so export is
  demonstrated (and UI-testable) in the example app.
@os-zhuang
os-zhuang merged commit 607aaf4 into main Jul 14, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/export-filename-optimization-5dd15f branch July 14, 2026 14:11
…mport round-trip)

The localized export and the import template surface translated option
labels (e.g. 待规划 for backlog), but import coercion only knew the
authored schema labels — re-importing your own localized export failed
every select field with invalid_option.

- prepareImportRequest gains a localizeSchema hook; both REST import
  routes pass translateMetaItem so the request locale's labels merge
  into the field metaMap as matching synonyms (authored labels and
  option codes keep working; unknown values still fail; a throwing
  hook degrades to authored-only matching)
- new mergeLocalizedOptionSynonyms export + import-prepare tests
- app-showcase: complete the showcase_task en/zh-CN translation bundle
  (done/labels/sync_status/sync_error labels, status/priority/sync
  option maps) so templates and exports render fully localized

This branch was successfully deployed

1 active deployment
Preview — 6ab3e7c2 Deployed Jul 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

导出/导入文件名与多语言优化:显示名+视图名+时间戳命名、模板全中文、导出↔导入选项标签闭环

2 participants