From 0c77de9daf6490febbcbb669e55d8d51246399ae Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Tue, 2 Jun 2026 05:05:39 +0800 Subject: [PATCH] fix(project): correct translation bundle shape so labels localize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The project (pm) template's translation bundles did not match `TranslationData`, so most labels silently fell back to English (the app name stayed "Project Management" in a zh-CN console): - field labels were under a top-level `fields` key instead of `objects..fields.` → never applied; - plural labels used `labelPlural` instead of `pluralLabel` → never applied; - there was no `apps` section → app name + nav were untranslated; - a stray top-level `locale` key (not part of TranslationData). Restructure both en.ts and zh-CN.ts to proper `TranslationData`: nest fields under their object, rename to `pluralLabel`, add `apps.pm` (label + navigation), and drop `locale`. Type both as `TranslationData` so the shape is enforced. Verified in the composed `all` environment: the app now renders Chinese (AI 项目管理 / 项目 / 里程碑 / 风险 / 问题 / 资源) with localized object and field labels. `pnpm --filter @objectlab/project typecheck` passes. Co-Authored-By: Claude Opus 4.8 --- packages/project/src/translations/en.ts | 175 ++++++++++++--------- packages/project/src/translations/zh-CN.ts | 174 +++++++++++--------- 2 files changed, 201 insertions(+), 148 deletions(-) diff --git a/packages/project/src/translations/en.ts b/packages/project/src/translations/en.ts index ef030ce..4b1bc7e 100644 --- a/packages/project/src/translations/en.ts +++ b/packages/project/src/translations/en.ts @@ -1,87 +1,114 @@ // Copyright (c) 2026 ObjectStack contributors. Apache-2.0 license. +import type { TranslationData } from '@objectstack/spec/system'; + /** - * English translations for Project Management template + * English translations for Project Management template. + * + * Shape follows `TranslationData`: field labels live under + * `objects..fields.`, plural labels use `pluralLabel`, and the app + * shell is translated under `apps.`. */ -export const en = { - locale: 'en', - +export const en: TranslationData = { objects: { - pm_project: { label: 'Project', labelPlural: 'Projects' }, - pm_milestone: { label: 'Milestone', labelPlural: 'Milestones' }, - pm_risk: { label: 'Risk', labelPlural: 'Risks' }, - pm_issue: { label: 'Issue', labelPlural: 'Issues' }, - pm_resource: { label: 'Resource', labelPlural: 'Resources' }, - pm_timesheet: { label: 'Timesheet', labelPlural: 'Timesheets' }, - }, - - fields: { pm_project: { - code: { label: 'Project Code' }, - name: { label: 'Project Name' }, - description: { label: 'Description' }, - status: { label: 'Status' }, - priority: { label: 'Priority' }, - health: { label: 'Health' }, - start_date: { label: 'Start Date' }, - target_end_date: { label: 'Target End Date' }, - actual_end_date: { label: 'Actual End Date' }, - progress_percent: { label: 'Progress %' }, - ai_completion_probability: { label: 'AI Completion Probability %' }, - ai_delay_days: { label: 'AI Delay Days' }, - ai_risk_score: { label: 'AI Risk Score' }, - ai_budget_variance_percent: { label: 'AI Budget Variance %' }, - ai_resource_bottleneck: { label: 'AI Resource Bottleneck' }, - ai_recommended_action: { label: 'AI Recommended Action' }, - planned_budget: { label: 'Planned Budget' }, - actual_cost: { label: 'Actual Cost' }, - forecast_cost: { label: 'Forecast Cost' }, - project_manager: { label: 'Project Manager' }, - sponsor: { label: 'Sponsor' }, - team_size: { label: 'Team Size' }, - }, - pm_risk: { - risk_id: { label: 'Risk ID' }, - name: { label: 'Risk Name' }, - description: { label: 'Description' }, - project: { label: 'Project' }, - category: { label: 'Category' }, - status: { label: 'Status' }, - impact: { label: 'Impact' }, - likelihood: { label: 'Likelihood' }, - priority: { label: 'Priority' }, - ai_impact_score: { label: 'AI Impact Score' }, - ai_likelihood: { label: 'AI Likelihood' }, - ai_mitigation_suggestion: { label: 'AI Mitigation Suggestion' }, - ai_similar_risks: { label: 'AI Similar Risks' }, - response_strategy: { label: 'Response Strategy' }, - response_plan: { label: 'Response Plan' }, - response_owner: { label: 'Response Owner' }, - response_cost: { label: 'Response Cost' }, + label: 'Project', + pluralLabel: 'Projects', + fields: { + code: { label: 'Project Code' }, + name: { label: 'Project Name' }, + description: { label: 'Description' }, + status: { label: 'Status' }, + priority: { label: 'Priority' }, + health: { label: 'Health' }, + start_date: { label: 'Start Date' }, + target_end_date: { label: 'Target End Date' }, + actual_end_date: { label: 'Actual End Date' }, + progress_percent: { label: 'Progress %' }, + ai_completion_probability: { label: 'AI Completion Probability %' }, + ai_delay_days: { label: 'AI Delay Days' }, + ai_risk_score: { label: 'AI Risk Score' }, + ai_budget_variance_percent: { label: 'AI Budget Variance %' }, + ai_resource_bottleneck: { label: 'AI Resource Bottleneck' }, + ai_recommended_action: { label: 'AI Recommended Action' }, + planned_budget: { label: 'Planned Budget' }, + actual_cost: { label: 'Actual Cost' }, + forecast_cost: { label: 'Forecast Cost' }, + project_manager: { label: 'Project Manager' }, + sponsor: { label: 'Sponsor' }, + team_size: { label: 'Team Size' }, + }, }, pm_milestone: { - name: { label: 'Milestone Name' }, - description: { label: 'Description' }, - project: { label: 'Project' }, - status: { label: 'Status' }, - due_date: { label: 'Due Date' }, - completed_at: { label: 'Completed At' }, - is_critical_path: { label: 'Critical Path' }, - deliverables: { label: 'Deliverables' }, + label: 'Milestone', + pluralLabel: 'Milestones', + fields: { + name: { label: 'Milestone Name' }, + description: { label: 'Description' }, + project: { label: 'Project' }, + status: { label: 'Status' }, + due_date: { label: 'Due Date' }, + completed_at: { label: 'Completed At' }, + is_critical_path: { label: 'Critical Path' }, + deliverables: { label: 'Deliverables' }, + }, + }, + pm_risk: { + label: 'Risk', + pluralLabel: 'Risks', + fields: { + risk_id: { label: 'Risk ID' }, + name: { label: 'Risk Name' }, + description: { label: 'Description' }, + project: { label: 'Project' }, + category: { label: 'Category' }, + status: { label: 'Status' }, + impact: { label: 'Impact' }, + likelihood: { label: 'Likelihood' }, + priority: { label: 'Priority' }, + ai_impact_score: { label: 'AI Impact Score' }, + ai_likelihood: { label: 'AI Likelihood' }, + ai_mitigation_suggestion: { label: 'AI Mitigation Suggestion' }, + ai_similar_risks: { label: 'AI Similar Risks' }, + response_strategy: { label: 'Response Strategy' }, + response_plan: { label: 'Response Plan' }, + response_owner: { label: 'Response Owner' }, + response_cost: { label: 'Response Cost' }, + }, }, pm_issue: { - issue_number: { label: 'Issue #' }, - name: { label: 'Issue Name' }, - description: { label: 'Description' }, - project: { label: 'Project' }, - type: { label: 'Type' }, - status: { label: 'Status' }, - priority: { label: 'Priority' }, - reported_by: { label: 'Reported By' }, - assigned_to: { label: 'Assigned To' }, - reported_at: { label: 'Reported At' }, - resolved_at: { label: 'Resolved At' }, - resolution: { label: 'Resolution' }, + label: 'Issue', + pluralLabel: 'Issues', + fields: { + issue_number: { label: 'Issue #' }, + name: { label: 'Issue Name' }, + description: { label: 'Description' }, + project: { label: 'Project' }, + type: { label: 'Type' }, + status: { label: 'Status' }, + priority: { label: 'Priority' }, + reported_by: { label: 'Reported By' }, + assigned_to: { label: 'Assigned To' }, + reported_at: { label: 'Reported At' }, + resolved_at: { label: 'Resolved At' }, + resolution: { label: 'Resolution' }, + }, + }, + pm_resource: { label: 'Resource', pluralLabel: 'Resources' }, + pm_timesheet: { label: 'Timesheet', pluralLabel: 'Timesheets' }, + }, + + apps: { + pm: { + label: 'AI Project Management', + description: 'Portfolio tracking with AI risk prediction, delay forecasting, and resource-conflict detection.', + navigation: { + nav_projects: { label: 'Projects' }, + nav_milestones: { label: 'Milestones' }, + nav_risks: { label: 'Risks' }, + nav_issues: { label: 'Issues' }, + nav_resources: { label: 'Resources' }, + }, }, }, }; diff --git a/packages/project/src/translations/zh-CN.ts b/packages/project/src/translations/zh-CN.ts index bfb74d8..acaea66 100644 --- a/packages/project/src/translations/zh-CN.ts +++ b/packages/project/src/translations/zh-CN.ts @@ -1,87 +1,113 @@ // Copyright (c) 2026 ObjectStack contributors. Apache-2.0 license. +import type { TranslationData } from '@objectstack/spec/system'; + /** - * 中文翻译 - 项目管理模板 + * 中文翻译 - 项目管理模板。 + * + * 结构遵循 `TranslationData`:字段标签放在 `objects..fields.`, + * 复数标签使用 `pluralLabel`,应用外壳在 `apps.` 下翻译。 */ -export const zhCN = { - locale: 'zh-CN', - +export const zhCN: TranslationData = { objects: { - pm_project: { label: '项目', labelPlural: '项目' }, - pm_milestone: { label: '里程碑', labelPlural: '里程碑' }, - pm_risk: { label: '风险', labelPlural: '风险' }, - pm_issue: { label: '问题', labelPlural: '问题' }, - pm_resource: { label: '资源', labelPlural: '资源' }, - pm_timesheet: { label: '工时', labelPlural: '工时' }, - }, - - fields: { pm_project: { - code: { label: '项目编号' }, - name: { label: '项目名称' }, - description: { label: '描述' }, - status: { label: '状态' }, - priority: { label: '优先级' }, - health: { label: '健康度' }, - start_date: { label: '开始日期' }, - target_end_date: { label: '目标结束日期' }, - actual_end_date: { label: '实际结束日期' }, - progress_percent: { label: '进度 %' }, - ai_completion_probability: { label: 'AI完成概率 %' }, - ai_delay_days: { label: 'AI预测延期天数' }, - ai_risk_score: { label: 'AI风险评分' }, - ai_budget_variance_percent: { label: 'AI预算偏差 %' }, - ai_resource_bottleneck: { label: 'AI资源瓶颈' }, - ai_recommended_action: { label: 'AI推荐措施' }, - planned_budget: { label: '计划预算' }, - actual_cost: { label: '实际成本' }, - forecast_cost: { label: '预测成本' }, - project_manager: { label: '项目经理' }, - sponsor: { label: '发起人' }, - team_size: { label: '团队规模' }, - }, - pm_risk: { - risk_id: { label: '风险ID' }, - name: { label: '风险名称' }, - description: { label: '描述' }, - project: { label: '所属项目' }, - category: { label: '类别' }, - status: { label: '状态' }, - impact: { label: '影响' }, - likelihood: { label: '可能性' }, - priority: { label: '优先级' }, - ai_impact_score: { label: 'AI影响评分' }, - ai_likelihood: { label: 'AI可能性' }, - ai_mitigation_suggestion: { label: 'AI缓解建议' }, - ai_similar_risks: { label: 'AI相似风险' }, - response_strategy: { label: '应对策略' }, - response_plan: { label: '应对计划' }, - response_owner: { label: '负责人' }, - response_cost: { label: '应对成本' }, + label: '项目', + pluralLabel: '项目', + fields: { + code: { label: '项目编号' }, + name: { label: '项目名称' }, + description: { label: '描述' }, + status: { label: '状态' }, + priority: { label: '优先级' }, + health: { label: '健康度' }, + start_date: { label: '开始日期' }, + target_end_date: { label: '目标结束日期' }, + actual_end_date: { label: '实际结束日期' }, + progress_percent: { label: '进度 %' }, + ai_completion_probability: { label: 'AI 完成概率 %' }, + ai_delay_days: { label: 'AI 预测延期天数' }, + ai_risk_score: { label: 'AI 风险评分' }, + ai_budget_variance_percent: { label: 'AI 预算偏差 %' }, + ai_resource_bottleneck: { label: 'AI 资源瓶颈' }, + ai_recommended_action: { label: 'AI 推荐措施' }, + planned_budget: { label: '计划预算' }, + actual_cost: { label: '实际成本' }, + forecast_cost: { label: '预测成本' }, + project_manager: { label: '项目经理' }, + sponsor: { label: '发起人' }, + team_size: { label: '团队规模' }, + }, }, pm_milestone: { - name: { label: '里程碑名称' }, - description: { label: '描述' }, - project: { label: '所属项目' }, - status: { label: '状态' }, - due_date: { label: '截止日期' }, - completed_at: { label: '完成时间' }, - is_critical_path: { label: '关键路径' }, - deliverables: { label: '交付物' }, + label: '里程碑', + pluralLabel: '里程碑', + fields: { + name: { label: '里程碑名称' }, + description: { label: '描述' }, + project: { label: '所属项目' }, + status: { label: '状态' }, + due_date: { label: '截止日期' }, + completed_at: { label: '完成时间' }, + is_critical_path: { label: '关键路径' }, + deliverables: { label: '交付物' }, + }, + }, + pm_risk: { + label: '风险', + pluralLabel: '风险', + fields: { + risk_id: { label: '风险 ID' }, + name: { label: '风险名称' }, + description: { label: '描述' }, + project: { label: '所属项目' }, + category: { label: '类别' }, + status: { label: '状态' }, + impact: { label: '影响' }, + likelihood: { label: '可能性' }, + priority: { label: '优先级' }, + ai_impact_score: { label: 'AI 影响评分' }, + ai_likelihood: { label: 'AI 可能性' }, + ai_mitigation_suggestion: { label: 'AI 缓解建议' }, + ai_similar_risks: { label: 'AI 相似风险' }, + response_strategy: { label: '应对策略' }, + response_plan: { label: '应对计划' }, + response_owner: { label: '负责人' }, + response_cost: { label: '应对成本' }, + }, }, pm_issue: { - issue_number: { label: '问题编号' }, - name: { label: '问题名称' }, - description: { label: '描述' }, - project: { label: '所属项目' }, - type: { label: '类型' }, - status: { label: '状态' }, - priority: { label: '优先级' }, - reported_by: { label: '报告人' }, - assigned_to: { label: '分配给' }, - reported_at: { label: '报告时间' }, - resolved_at: { label: '解决时间' }, - resolution: { label: '解决方案' }, + label: '问题', + pluralLabel: '问题', + fields: { + issue_number: { label: '问题编号' }, + name: { label: '问题名称' }, + description: { label: '描述' }, + project: { label: '所属项目' }, + type: { label: '类型' }, + status: { label: '状态' }, + priority: { label: '优先级' }, + reported_by: { label: '报告人' }, + assigned_to: { label: '分配给' }, + reported_at: { label: '报告时间' }, + resolved_at: { label: '解决时间' }, + resolution: { label: '解决方案' }, + }, + }, + pm_resource: { label: '资源', pluralLabel: '资源' }, + pm_timesheet: { label: '工时', pluralLabel: '工时' }, + }, + + apps: { + pm: { + label: 'AI 项目管理', + description: '项目组合管理 —— AI 风险预测、延期预测与资源冲突检测。', + navigation: { + nav_projects: { label: '项目' }, + nav_milestones: { label: '里程碑' }, + nav_risks: { label: '风险' }, + nav_issues: { label: '问题' }, + nav_resources: { label: '资源' }, + }, }, }, };