mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-15 11:14:31 +08:00
## Summary - expose append-only capability for TDengine and IoTDB targets - constrain the delivery UI to INSERT/append and remove delete propagation - block mutation and delete configurations during backend preflight - add Go and frontend regression coverage ## Verification - Go sync capability and preflight regression tests passed - frontend delivery and Wails DTO regression tests passed - frontend production build passed - Wails desktop build passed Closes #883
873 lines
55 KiB
TypeScript
873 lines
55 KiB
TypeScript
const zhCN = {
|
||
'workbench.title': '数据迁移与同步',
|
||
'workbench.subtitle': '定义、验证并追踪跨数据源任务',
|
||
'workbench.close': '关闭工作台',
|
||
'workbench.new_task': '新建任务',
|
||
'workbench.save': '保存草稿',
|
||
'workbench.saving': '正在保存',
|
||
'workbench.saved': '已保存',
|
||
'workbench.unsaved': '有未保存修改',
|
||
'workbench.run_preflight': '运行预检',
|
||
'workbench.preflighting': '正在预检',
|
||
'workbench.start': '运行任务',
|
||
'workbench.enable': '启用任务',
|
||
'workbench.blocked_action': '先解决预检阻断项',
|
||
'nav.tasks': '任务',
|
||
'nav.runs': '运行记录',
|
||
'nav.schedules': '调度',
|
||
'nav.cdc': 'CDC',
|
||
'task_list.title': '任务',
|
||
'task_list.search': '搜索任务',
|
||
'task_list.empty': '没有匹配的任务',
|
||
'task_list.revision': '版本 {revision}',
|
||
'task_list.lifecycle.draft': '草稿',
|
||
'task_list.lifecycle.ready': '就绪',
|
||
'task_list.lifecycle.enabled': '已启用',
|
||
'task_list.lifecycle.paused': '已暂停',
|
||
'task_list.lifecycle.archived': '已归档',
|
||
'lifecycle.publish_ready': '发布为就绪',
|
||
'lifecycle.enable_schedule': '启用调度',
|
||
'lifecycle.pause': '暂停任务',
|
||
'lifecycle.resume_schedule': '重新启用',
|
||
'lifecycle.archive': '归档',
|
||
'task_kind.title': '选择任务类型',
|
||
'task_kind.subtitle': '类型决定可用的增量和触发策略,创建后仍可复制为其他任务。',
|
||
'task_kind.migration': '一次性迁移',
|
||
'task_kind.migration_desc': '迁移结构和数据,可创建目标对象。',
|
||
'task_kind.reconcile': '批次/差异同步',
|
||
'task_kind.reconcile_desc': '按主键执行快照比较或水位线增量。',
|
||
'task_kind.querySink': 'SQL 结果写入',
|
||
'task_kind.querySink_desc': '执行查询并把稳定结果写入目标表。',
|
||
'task_kind.compare': '只读比较',
|
||
'task_kind.compare_desc': '比较结构或数据,不修改目标端。',
|
||
'task_kind.cdc': '持续增量 CDC',
|
||
'task_kind.cdc_desc': '消费变更日志并持久化 checkpoint。',
|
||
'stage.endpoints': '选择源和目标',
|
||
'stage.mappings': '选择同步数据',
|
||
'stage.delivery': '目标写入',
|
||
'stage.trigger': '运行方式',
|
||
'stage.preflight': '检查并运行',
|
||
'route.source': '源端',
|
||
'route.target': '目标端',
|
||
'route.pending_source': '选择源连接',
|
||
'route.pending_target': '选择目标连接',
|
||
'route.capability.full': '完整支持',
|
||
'route.capability.partial': '兼容模式',
|
||
'route.capability.unsupported': '不支持',
|
||
'route.capability.unknown': '等待能力确认',
|
||
'route.database_fallback': '未选择库',
|
||
'editor.task_name': '任务名称',
|
||
'editor.task_name_placeholder': '例如:订单数据同步到分析库',
|
||
'editor.source_endpoint': '源端点',
|
||
'editor.target_endpoint': '目标端点',
|
||
'editor.connection': '已保存连接',
|
||
'editor.connection_id': '连接 ID',
|
||
'editor.connection_name': '连接名称',
|
||
'editor.database_type': '数据源类型',
|
||
'editor.database': 'Database / Catalog',
|
||
'editor.schema': 'Schema',
|
||
'editor.source_query': '源 SQL 查询',
|
||
'editor.source_query_placeholder': 'SELECT ...',
|
||
'editor.endpoint_help': '从已保存连接中选择端点;任务只保存连接引用,不保存账号、密码或连接串。',
|
||
'metadata.select_connection': '选择连接',
|
||
'metadata.select_database': '选择 Database / Catalog',
|
||
'metadata.not_selected': '未选择',
|
||
'metadata.schema_optional': '可选;留空使用默认命名空间',
|
||
'metadata.loading_connections': '正在加载连接',
|
||
'metadata.loading_databases': '正在加载数据库',
|
||
'metadata.loading_objects': '正在加载对象',
|
||
'metadata.loading_fields': '正在加载字段',
|
||
'metadata.loading_cdc_adapters': '正在加载 CDC 适配器',
|
||
'metadata.load_failed': '元数据加载失败',
|
||
'metadata.retry': '重试',
|
||
'metadata.no_eligible_connections': '没有符合当前读写方向的连接。',
|
||
'metadata.no_databases': '该连接未返回数据库列表,草稿仍可保存。',
|
||
'metadata.endpoint_required': '先选择端点',
|
||
'metadata.object_required': '先选择对象',
|
||
'metadata.objects_count': '{count} 个对象',
|
||
'metadata.fields_count': '{count} 个字段',
|
||
'mapping.title': '选择要同步的数据',
|
||
'mapping.help': '可选择一张、多张或筛选后的全部表。系统会自动匹配同名目标、识别主键并生成映射,你只需处理例外。',
|
||
'mapping.query_help': 'SQL 查询结果只写入一个目标对象;请选择已有目标表并配置写入键。',
|
||
'mapping.add': '添加映射',
|
||
'mapping.select_objects': '选择源对象',
|
||
'mapping.add_target': '添加目标对象',
|
||
'mapping.picker_title': '批量选择源对象',
|
||
'mapping.search_objects': '搜索表、视图或集合',
|
||
'mapping.include_views': '包含视图',
|
||
'mapping.selected_count': '已选 {selected} / 共 {total}',
|
||
'mapping.select_filtered': '全选当前筛选结果({count})',
|
||
'mapping.selection_fixed_scope': '保存时固化本次清单,后续新增表不会自动加入',
|
||
'mapping.object_kind.table': '表',
|
||
'mapping.object_kind.view': '视图',
|
||
'mapping.object_kind.collection': '集合',
|
||
'mapping.already_added': '已添加',
|
||
'mapping.rows_count': '{count} 行',
|
||
'mapping.no_objects': '没有匹配的对象',
|
||
'mapping.add_selected': '添加 {count} 个对象',
|
||
'mapping.detecting_keys': '正在识别主键…',
|
||
'mapping.open_object_list': '展开对象列表',
|
||
'mapping.will_create_named': '目标不存在,将创建“{name}”',
|
||
'mapping.no_matching_objects': '没有匹配的已有对象',
|
||
'mapping.remove': '删除',
|
||
'mapping.enabled': '启用',
|
||
'mapping.source': '源对象',
|
||
'mapping.target': '目标对象',
|
||
'mapping.target_mode': '目标不存在时',
|
||
'mapping.key_columns': '用于识别同一行',
|
||
'mapping.fields': '字段',
|
||
'mapping.status': '状态',
|
||
'mapping.create_or_reuse': '自动创建;已存在则校验后使用',
|
||
'mapping.existing_only': '仅写入已有目标',
|
||
'mapping.edit_exceptions': '编辑例外',
|
||
'mapping.collapse_exceptions': '收起',
|
||
'mapping.fields_count': '{count} 个字段',
|
||
'mapping.fields_pending': '自动同名写入',
|
||
'mapping.fields_automatic': '自动同名写入',
|
||
'mapping.fields_automatic_help': '无需逐列配置;仅在字段改名或转换时编辑。',
|
||
'mapping.fields_required': '需要确认同步字段',
|
||
'mapping.fields_cdc_help': '持续同步必须明确目标字段,避免源端删字段后目标残留旧值。',
|
||
'mapping.ready': '已配置',
|
||
'mapping.needs_attention': '需处理',
|
||
'mapping.key_placeholder': 'id, tenant_id',
|
||
'mapping.key_detected': '已从源端元数据自动识别,可按需修改',
|
||
'mapping.key_when_needed': '差异同步和 CDC 必须有稳定主键;一次性迁移可留空',
|
||
'mapping.source_placeholder': '搜索或选择源对象',
|
||
'mapping.target_placeholder': '搜索已有目标或输入新名称',
|
||
'mapping.query_result_source': '查询结果(唯一映射)',
|
||
'mapping.target_state.exists': '目标已存在',
|
||
'mapping.target_state.create': '将创建',
|
||
'mapping.target_state.missing': '未匹配目标',
|
||
'mapping.empty_title': '尚未选择同步对象',
|
||
'mapping.empty_desc': '先选择源对象。单表和多表使用同一个入口,也可以搜索后全选当前结果。',
|
||
'field_mapping.title': '字段映射',
|
||
'field_mapping.close': '收起',
|
||
'field_mapping.auto_match': '同名自动匹配',
|
||
'field_mapping.add': '添加字段',
|
||
'field_mapping.empty_title': '尚未配置字段映射',
|
||
'field_mapping.empty_desc': '加载两端字段后自动匹配,或手动添加并配置转换表达式。',
|
||
'field_mapping.source': '源字段',
|
||
'field_mapping.target': '目标字段',
|
||
'field_mapping.transform': '转换表达式',
|
||
'field_mapping.transform_placeholder': '留空表示直接写入',
|
||
'field_mapping.transform_identity': '直接写入',
|
||
'field_mapping.transform_argument': '参数 JSON(可选)',
|
||
'field_mapping.type': '类型',
|
||
'field_mapping.select_field': '选择字段',
|
||
'field_mapping.remove': '删除',
|
||
'delivery.title': '设置目标写入',
|
||
'delivery.help': '选择目标端如何写入及处理失败行。多数任务保留默认值即可;高风险和专业参数只在适用时显示。',
|
||
'delivery.write_mode': '写入模式',
|
||
'delivery.write.none': '只读',
|
||
'delivery.write.append': '追加',
|
||
'delivery.write.append_desc': '每次运行都新增记录;重复运行可能产生重复数据,系统会自动关闭重试。',
|
||
'delivery.write.upsert': '新增或更新',
|
||
'delivery.write.upsert_unavailable': '新增或更新(当前目标不支持)',
|
||
'delivery.write.upsert_desc': '按主键或唯一键识别同一行:不存在则新增,已存在则更新。',
|
||
'delivery.write.overwrite': '覆盖',
|
||
'delivery.write.overwrite_unavailable': '覆盖(当前任务系统暂不支持)',
|
||
'delivery.write.overwrite_desc': '当前没有原子替换保障,预检会阻止覆盖任务运行;请改用新增或更新。',
|
||
'delivery.read_only_title': '这是只读比较任务',
|
||
'delivery.read_only_note': '任务不会写入或删除目标端数据,因此无需配置写入、失败行处理和高级设置。',
|
||
'delivery.error_policy': '失败行处理',
|
||
'delivery.error.stop': '遇错停止',
|
||
'delivery.error.stop_desc': '任一行写入失败时立即停止,适合优先保证数据完整性的任务。',
|
||
'delivery.error.skip': '跳过错误行',
|
||
'delivery.error.skip_desc': '记录失败原因并继续处理后续行,不保存完整失败行。',
|
||
'delivery.error.quarantine': '隔离并允许重试',
|
||
'delivery.error.quarantine_desc': '完整失败行会保存在本机任务数据库中,可能包含敏感数据,可在错误行列表中重试。',
|
||
'delivery.batch_size': '批大小',
|
||
'delivery.commit_every': '提交间隔(行)',
|
||
'delivery.commit_every_note': '当前引擎按批大小提交,此值与批大小保持一致。',
|
||
'delivery.retry_limit': '重试次数',
|
||
'delivery.retry_backoff': '重试退避(毫秒)',
|
||
'delivery.row_isolation_note': '当前配置必须遇错停止。逐行跳过只适用于写入已有关系表,且不能同时自动建表、修改结构、同步删除或覆盖写入。',
|
||
'delivery.append_retry_note': '追加写入可能已部分落库,为避免重复写入,自动重试固定为 0。',
|
||
'delivery.append_only_target_note': '当前时序目标仅支持追加写入(INSERT);更新和删除不会同步。',
|
||
'delivery.propagate_deletes': '传播源端删除',
|
||
'delivery.delete_policy_title': '目标端删除策略',
|
||
'delivery.delete_risk_badge': '高风险',
|
||
'delivery.delete.snapshot_label': '删除源端已不存在的目标行',
|
||
'delivery.delete.snapshot_desc': '全量差异同步会按每张表的主键比对,并删除目标端中源端已不存在的行。',
|
||
'delivery.delete.cdc_label': '同步源端删除事件',
|
||
'delivery.delete.cdc_desc': 'CDC 收到删除事件后,会按键删除目标端对应行。',
|
||
'delivery.delete_risk_note': '目标端删除不可撤销。开启前请确认目标不是共享表,并在运行前核对预检范围。',
|
||
'delivery.advanced': '高级设置',
|
||
'delivery.advanced_help': '性能、重试与结构迁移',
|
||
'delivery.performance_title': '性能与重试',
|
||
'delivery.performance_help': '默认值适合多数任务;仅在明确了解目标端负载和幂等性时调整。',
|
||
'delivery.structure_title': '目标结构',
|
||
'delivery.structure_help': '仅对一次性迁移中的同名自动映射生效;显式字段、主键或改名映射不会显示这些选项。',
|
||
'delivery.auto_add_columns': '自动新增缺失字段',
|
||
'delivery.auto_add_columns_desc': '仅新增目标端缺少的字段,不修改或删除已有字段;执行 DDL 时可能短暂锁定目标表。',
|
||
'delivery.create_indexes': '复制可兼容的二级索引',
|
||
'delivery.create_indexes_desc': '仅在自动创建目标对象时复制源端可兼容的非主键索引;索引在数据写入后创建,会增加总耗时。',
|
||
'trigger.title': '设置运行方式',
|
||
'trigger.help': '选择手动、定时或持续运行,并按需要配置快照、水位线或 CDC 增量方式。',
|
||
'trigger.mode': '触发方式',
|
||
'trigger.manual': '手动',
|
||
'trigger.once': '指定时间',
|
||
'trigger.interval': '固定间隔',
|
||
'trigger.interval_seconds': '间隔(秒)',
|
||
'trigger.cron': 'Cron 调度',
|
||
'trigger.continuous': '持续运行',
|
||
'trigger.run_at': '执行时间',
|
||
'trigger.timezone': '时区',
|
||
'trigger.cron_expression': 'Cron 表达式',
|
||
'trigger.overlap': '任务重叠时',
|
||
'trigger.overlap.skip': '跳过本次',
|
||
'trigger.overlap.queue': '排队等待',
|
||
'incremental.mode': '增量策略',
|
||
'incremental.snapshot': '全量快照',
|
||
'incremental.watermark': '水位线',
|
||
'incremental.cdc': 'CDC 日志',
|
||
'incremental.watermark_column': '水位列',
|
||
'incremental.tie_breaker': '并列排序列',
|
||
'incremental.overlap_window': '重叠窗口(毫秒)',
|
||
'incremental.watermark_delivery_note': '水位线任务暂不支持追加语义;InitialValue、重叠窗口和独立提交间隔尚未接入引擎,因此不提供可编辑入口。',
|
||
'incremental.watermark_mixed_note': '此任务包含按对象配置的不同水位字段。当前显示第一项;编辑任一水位字段会统一全部对象。',
|
||
'incremental.initial_snapshot': '首次启动先执行全量快照',
|
||
'incremental.cdc_adapter': 'CDC 适配器',
|
||
'incremental.select_cdc_adapter': '选择适配器',
|
||
'incremental.start_position': '开始位置',
|
||
'incremental.position.latest': '最新位置',
|
||
'incremental.position.earliest': '最早位置',
|
||
'incremental.position.checkpoint': '上次 checkpoint',
|
||
'incremental.cdc_safety_title': 'CDC 起点安全边界',
|
||
'incremental.cdc_safety_note': '当前只支持从创建 latest barrier 之后,或从本任务已有 checkpoint 继续,以 at-least-once 方式消费变更。',
|
||
'incremental.cdc_snapshot_gap_warning': '如先单独执行快照再从 latest 启动,两者之间存在变更窗口,可能漏掉窗口内变更;当前不保证无缝衔接。',
|
||
'incremental.cdc_checkpoint_unavailable': '当前任务没有可用 checkpoint,因此不能选择 checkpoint 起点。',
|
||
'preflight.title': '预检',
|
||
'preflight.stale': '配置已变化,需要重新预检',
|
||
'preflight.not_run': '尚未预检',
|
||
'preflight.running': '正在检查端点、映射和执行策略',
|
||
'preflight.blocked': '{count} 个阻断项',
|
||
'preflight.warning': '{count} 个警告',
|
||
'preflight.passed': '预检通过',
|
||
'preflight.empty': '配置完整后运行预检;问题会定位到对应阶段。',
|
||
'preflight.open_issue': '定位',
|
||
'preflight.current_revision': '基于任务版本 {revision}',
|
||
'preflight.approval_required': '生产写入需要审批',
|
||
'preflight.approval_not_required': '无需生产写入审批',
|
||
'preflight.approval_fail_closed': '尚未完成倒计时确认并取得一次性授权,保存到生产或运行操作保持禁用。',
|
||
'preflight.approval_granted': '一次性生产授权已取得',
|
||
'preflight.approval_begin_countdown': '开始服务端 10 秒确认',
|
||
'preflight.approval_beginning': '正在创建服务端确认',
|
||
'preflight.approval_countdown': '请等待 {seconds} 秒',
|
||
'preflight.approval_confirm': '确认生产写入并获取授权',
|
||
'preflight.approving': '正在获取授权',
|
||
'preflight.approval_expires': '授权仅保存在内存中,将于 {expiresAt} 失效,保存或运行后立即作废。',
|
||
'preflight.severity.blocker': '阻断',
|
||
'preflight.severity.warning': '警告',
|
||
'preflight.severity.info': '提示',
|
||
'preflight.index_remediation.title': '未迁移索引({count})',
|
||
'preflight.index_remediation.columns': '列:{columns}',
|
||
'preflight.index_remediation.copy': '复制补救 DDL',
|
||
'preflight.index_remediation.copy_failed': '复制失败,请从下方清单手动复制 DDL。',
|
||
'runs.title': '运行记录',
|
||
'runs.subtitle': '运行实例由 gateway 提供;后续接入持久化历史与 checkpoint。',
|
||
'runs.empty_title': '还没有运行记录',
|
||
'runs.empty_desc': '保存并运行任务后,这里会显示吞吐、错误行和 checkpoint。',
|
||
'runs.id': '运行 ID',
|
||
'runs.task': '任务',
|
||
'runs.status': '状态',
|
||
'runs.started_at': '开始时间',
|
||
'runs.rows_written': '写入行数',
|
||
'runs.rows_failed': '错误行',
|
||
'runs.checkpoint': 'Checkpoint',
|
||
'runs.view_errors': '查看错误行',
|
||
'runs.actions': '操作',
|
||
'runs.cancel': '取消',
|
||
'runs.resume': '继续',
|
||
'runs.retry': '重试运行',
|
||
'errors.title': '错误行',
|
||
'errors.empty_title': '没有隔离的错误行',
|
||
'errors.empty_desc': '选择失败运行后,可在这里查看、重试或导出错误行。',
|
||
'errors.source': '源对象',
|
||
'errors.reason': '原因',
|
||
'errors.payload': '数据预览',
|
||
'errors.retryable': '可重试',
|
||
'errors.retry': '重试行',
|
||
'errors.retry_unavailable': '后端尚未提供错误行重试接口,此操作保持禁用。',
|
||
'errors.discard': '丢弃',
|
||
'errors.discarded': '已丢弃',
|
||
'checkpoint.title': 'Checkpoint',
|
||
'checkpoint.empty': '所选运行没有持久化 checkpoint。',
|
||
'checkpoint.kind': '类型',
|
||
'checkpoint.phase': '阶段',
|
||
'checkpoint.updated_at': '更新时间',
|
||
'checkpoint.cursor': '游标',
|
||
'checkpoint.reset': '重置 checkpoint',
|
||
'checkpoint.reset_warning': '重置后不能从该位置继续;CDC 任务将只能从新的 latest barrier 开始。',
|
||
'common.yes': '是',
|
||
'common.no': '否',
|
||
'common.refresh': '刷新',
|
||
'common.dismiss': '关闭',
|
||
'common.cancel': '取消',
|
||
'schedules.title': '调度',
|
||
'schedules.subtitle': '集中查看任务时区、Cron 和下一次执行。',
|
||
'schedules.empty_title': '还没有启用调度',
|
||
'schedules.empty_desc': '在任务的“触发与增量”阶段选择指定时间或 Cron。',
|
||
'cdc.title': 'CDC 源状态',
|
||
'cdc.subtitle': '状态来自适配器探测和任务 checkpoint;后端未报告延迟时不会推测。',
|
||
'cdc.empty_title': '还没有可监控的 CDC 源',
|
||
'cdc.empty_desc': '创建 CDC 任务并完成权限探测后,这里会显示健康状态。',
|
||
'cdc.lag_unknown': '延迟未上报',
|
||
'cdc.status.ready': '适配器已就绪',
|
||
'cdc.status.probing': '正在探测',
|
||
'cdc.status.lagging': '延迟较高',
|
||
'cdc.status.offline': '源端离线',
|
||
'cdc.status.unsupported': '不支持',
|
||
'cdc.status.unknown': '状态未知',
|
||
'status.queued': '排队中',
|
||
'status.running': '运行中',
|
||
'status.cancelling': '正在取消',
|
||
'status.preflighting': '预检中',
|
||
'status.snapshotting': '快照中',
|
||
'status.catching_up': '追赶中',
|
||
'status.streaming': '持续同步',
|
||
'status.paused': '已暂停',
|
||
'status.succeeded': '成功',
|
||
'status.partial': '部分完成',
|
||
'status.failed': '失败',
|
||
'status.canceled': '已取消',
|
||
'status.cancelled': '已取消',
|
||
'status.interrupted': '已中断',
|
||
'validation.definition_invalid': '任务定义无效,请检查必填项、对象映射和执行策略。',
|
||
'validation.definition_hash_failed': '无法生成任务定义指纹,请检查任务配置。',
|
||
'validation.task_name_required': '填写任务名称。',
|
||
'validation.source_connection_required': '选择源连接。',
|
||
'validation.target_connection_required': '选择目标连接。',
|
||
'validation.source_connection_failed': '无法解析源连接,请确认已保存连接仍存在且配置完整。',
|
||
'validation.target_connection_failed': '无法解析目标连接,请确认已保存连接仍存在且配置完整。',
|
||
'validation.source_connect_failed': '无法初始化源数据库连接。',
|
||
'validation.source_ping_failed': '源数据库连通性检查失败。',
|
||
'validation.target_connect_failed': '无法初始化目标数据库连接。',
|
||
'validation.target_ping_failed': '目标数据库连通性检查失败。',
|
||
'validation.same_endpoint': '源端和目标端指向同一个位置,请确认不会覆盖源数据。',
|
||
'validation.same_object': '源对象和目标对象指向同一个物理对象,不能执行同步。',
|
||
'validation.route_unsupported': '当前源端与目标端组合不支持执行此同步任务。',
|
||
'validation.source_query_required': '填写源 SQL 查询。',
|
||
'validation.source_query_not_read_only': '源 SQL 必须是单条只读查询。',
|
||
'validation.mapping_required': '至少启用一条对象映射。',
|
||
'validation.source_object_required': '填写源对象名称。',
|
||
'validation.target_object_required': '填写目标对象名称。',
|
||
'validation.duplicate_source_object': '同一个源对象只能添加一次。',
|
||
'validation.duplicate_target_object': '多个映射指向同一个目标对象。',
|
||
'validation.mapping_compile_failed': '对象或字段映射无法编译,请检查映射与转换配置。',
|
||
'validation.source_columns_failed': '读取源对象字段失败,请检查对象名和元数据权限。',
|
||
'validation.target_columns_failed': '读取目标对象字段失败,请检查对象名和元数据权限。',
|
||
'validation.source_column_missing': '配置的源字段不存在。',
|
||
'validation.target_column_missing': '配置的目标字段不存在。',
|
||
'validation.key_column_missing': '配置的源端主键或唯一键字段不存在。',
|
||
'validation.watermark_column_missing': '配置的水位列在源对象中不存在。',
|
||
'validation.target_table_check_failed': '检查目标表是否存在时失败。',
|
||
'validation.target_table_missing': '目标表不存在,且当前任务不能自动创建该表。',
|
||
'validation.target_table_will_be_created': '目标表不存在,运行时将由迁移规划器自动创建。',
|
||
'validation.key_columns_required': '差异同步或 CDC 必须配置主键或唯一键。',
|
||
'validation.batch_size_invalid': '批大小必须是 1 到 10000 的整数。',
|
||
'validation.commit_every_invalid': '提交间隔必须不小于批大小。',
|
||
'validation.target_protection_blocked': '目标连接的安全保护策略禁止此次写入。',
|
||
'validation.row_error_isolation_unsupported': '当前任务不满足逐行跳过/隔离的安全条件。',
|
||
'validation.append_retry_unsupported': '追加写入不允许自动重试,以免重复写入。',
|
||
'validation.append_retry_unsafe': '追加写入不能自动重试,否则可能重复写入已提交的数据。',
|
||
'validation.append_resume_unsafe': '追加写入任务必须禁用断点恢复,否则可能重放已提交批次。',
|
||
'validation.full_overwrite_non_atomic': '持久任务暂不支持非原子全量覆盖,以免失败后留下空表或半表。',
|
||
'validation.write_mode_required': '可执行同步任务必须选择明确的写入模式。',
|
||
'validation.watermark_append_unsupported': '水位线任务暂不支持追加写入语义。',
|
||
'validation.watermark_tie_breaker_required': '水位线任务必须配置稳定的并列排序列或主键。',
|
||
'validation.watermark_initial_value_unsupported': '当前尚未实现水位初始值,请移除该配置。',
|
||
'validation.watermark_runtime_unsupported': '当前源端、目标端或执行策略不满足水位线同步条件。',
|
||
'validation.watermark_overwrite_unsupported': '水位线任务不支持全量覆盖。',
|
||
'validation.watermark_delete_unsupported': '水位线任务无法推断源端删除;请改用 CDC 或快照差异同步。',
|
||
'validation.query_sink_single_mapping_required': 'SQL 结果写入必须且只能配置一条目标映射。',
|
||
'validation.query_key_required': 'SQL 结果更新写入必须配置且只能配置一个稳定键。',
|
||
'validation.query_target_pk_mismatch': 'SQL 结果的稳定键必须映射到目标表唯一的主键。',
|
||
'validation.query_schema_runtime_validation': 'SQL 结果字段名将在实际执行只读查询时再与映射校验。',
|
||
'validation.watermark_column_required': '水位线模式必须配置水位列。',
|
||
'validation.cron_expression_required': '填写 Cron 表达式。',
|
||
'validation.timezone_required': '填写调度时区。',
|
||
'validation.interval_invalid': '固定间隔必须不少于 60 秒。',
|
||
'validation.cdc_incremental_required': 'CDC 任务必须使用 CDC 增量策略。',
|
||
'validation.cdc_trigger_required': 'CDC 任务必须持续运行。',
|
||
'validation.cdc_adapter_required': '选择 CDC 适配器。',
|
||
'validation.cdc_initial_snapshot_unsupported': '当前 CDC 不支持安全的初始快照衔接。',
|
||
'validation.cdc_initial_snapshot_handoff_unsupported': '当前 CDC 无法保证初始快照与变更流无缝衔接,请关闭初始快照。',
|
||
'validation.cdc_earliest_unsupported': '当前 CDC 适配器不支持从最早位置启动。',
|
||
'validation.cdc_probe_failed': 'CDC 能力与权限探测失败。',
|
||
'validation.cdc_adapter_not_ready': '所选 CDC 适配器当前未就绪。',
|
||
'validation.cdc_existing_target_required': 'CDC 任务当前只能写入已存在的目标表。',
|
||
'validation.cdc_upsert_required': 'CDC 任务必须使用“新增或更新”写入模式,以保证可安全重放。',
|
||
'validation.cdc_target_non_atomic': 'CDC 行隔离和 checkpoint 顺序要求目标端支持原子关系型写入。',
|
||
'validation.cdc_authoritative_columns_required': 'CDC 任务必须显式配置源字段到目标字段的映射。',
|
||
'validation.cdc_checkpoint_unavailable': '无法读取 CDC checkpoint。',
|
||
'validation.cdc_checkpoint_required': '选择 checkpoint 起点前必须存在兼容的持久化 checkpoint。',
|
||
'validation.cdc_checkpoint_incompatible': '已存在的 CDC checkpoint 与当前任务定义不兼容,请在暂停任务后显式重置。',
|
||
'validation.compare_route_unsupported': '当前源端与目标端组合不支持执行数据比对。',
|
||
'validation.index_inspection_failed': '无法读取源端索引元数据,不能确认所有索引都已迁移。',
|
||
'validation.unmigrated_index': '有索引无法自动迁移,请在执行前审核候选补救 DDL。',
|
||
'validation.capability_unverified': '当前使用静态 gateway,运行前仍需后端确认数据源组合能力。',
|
||
'validation.unknown': '预检发现未识别的配置问题。',
|
||
} as const;
|
||
|
||
export type DataSyncWorkbenchTextKey = keyof typeof zhCN;
|
||
|
||
/**
|
||
* Literal keys owned by the Data Sync workbench's feature-local catalog.
|
||
* Exported so the repository-wide i18n scanner can validate these calls
|
||
* against the same catalog contract instead of treating them as global keys.
|
||
*/
|
||
export const DATA_SYNC_WORKBENCH_TEXT_KEYS: readonly DataSyncWorkbenchTextKey[] =
|
||
Object.freeze(Object.keys(zhCN) as DataSyncWorkbenchTextKey[]);
|
||
|
||
const enUS: Record<DataSyncWorkbenchTextKey, string> = {
|
||
'workbench.title': 'Data migration and sync',
|
||
'workbench.subtitle': 'Define, validate, and track cross-source jobs',
|
||
'workbench.close': 'Close workbench',
|
||
'workbench.new_task': 'New task',
|
||
'workbench.save': 'Save draft',
|
||
'workbench.saving': 'Saving',
|
||
'workbench.saved': 'Saved',
|
||
'workbench.unsaved': 'Unsaved changes',
|
||
'workbench.run_preflight': 'Run preflight',
|
||
'workbench.preflighting': 'Running preflight',
|
||
'workbench.start': 'Run task',
|
||
'workbench.enable': 'Enable task',
|
||
'workbench.blocked_action': 'Resolve preflight blockers first',
|
||
'nav.tasks': 'Tasks',
|
||
'nav.runs': 'Runs',
|
||
'nav.schedules': 'Schedules',
|
||
'nav.cdc': 'CDC',
|
||
'task_list.title': 'Tasks',
|
||
'task_list.search': 'Search tasks',
|
||
'task_list.empty': 'No matching tasks',
|
||
'task_list.revision': 'Revision {revision}',
|
||
'task_list.lifecycle.draft': 'Draft',
|
||
'task_list.lifecycle.ready': 'Ready',
|
||
'task_list.lifecycle.enabled': 'Enabled',
|
||
'task_list.lifecycle.paused': 'Paused',
|
||
'task_list.lifecycle.archived': 'Archived',
|
||
'lifecycle.publish_ready': 'Publish as ready',
|
||
'lifecycle.enable_schedule': 'Enable schedule',
|
||
'lifecycle.pause': 'Pause task',
|
||
'lifecycle.resume_schedule': 'Re-enable',
|
||
'lifecycle.archive': 'Archive',
|
||
'task_kind.title': 'Choose a task type',
|
||
'task_kind.subtitle': 'The type determines incremental and trigger options. You can copy it into another task later.',
|
||
'task_kind.migration': 'One-time migration',
|
||
'task_kind.migration_desc': 'Move schema and data, with target object creation.',
|
||
'task_kind.reconcile': 'Batch / difference sync',
|
||
'task_kind.reconcile_desc': 'Compare snapshots or use a watermark by key.',
|
||
'task_kind.querySink': 'SQL result sink',
|
||
'task_kind.querySink_desc': 'Run a query and write its stable result to a target table.',
|
||
'task_kind.compare': 'Read-only compare',
|
||
'task_kind.compare_desc': 'Compare schema or data without changing the target.',
|
||
'task_kind.cdc': 'Continuous CDC',
|
||
'task_kind.cdc_desc': 'Consume change logs and persist checkpoints.',
|
||
'stage.endpoints': 'Choose source and target',
|
||
'stage.mappings': 'Choose data',
|
||
'stage.delivery': 'Target writes',
|
||
'stage.trigger': 'Run settings',
|
||
'stage.preflight': 'Check and run',
|
||
'route.source': 'Source',
|
||
'route.target': 'Target',
|
||
'route.pending_source': 'Choose source connection',
|
||
'route.pending_target': 'Choose target connection',
|
||
'route.capability.full': 'Full support',
|
||
'route.capability.partial': 'Compatibility mode',
|
||
'route.capability.unsupported': 'Unsupported',
|
||
'route.capability.unknown': 'Awaiting capability check',
|
||
'route.database_fallback': 'No database selected',
|
||
'editor.task_name': 'Task name',
|
||
'editor.task_name_placeholder': 'For example: Sync orders to analytics',
|
||
'editor.source_endpoint': 'Source endpoint',
|
||
'editor.target_endpoint': 'Target endpoint',
|
||
'editor.connection': 'Saved connection',
|
||
'editor.connection_id': 'Connection ID',
|
||
'editor.connection_name': 'Connection name',
|
||
'editor.database_type': 'Source type',
|
||
'editor.database': 'Database / Catalog',
|
||
'editor.schema': 'Schema',
|
||
'editor.source_query': 'Source SQL query',
|
||
'editor.source_query_placeholder': 'SELECT ...',
|
||
'editor.endpoint_help': 'Choose from saved connections. Tasks store only connection references, never usernames, passwords, or connection strings.',
|
||
'metadata.select_connection': 'Choose a connection',
|
||
'metadata.select_database': 'Choose a database / catalog',
|
||
'metadata.not_selected': 'Not selected',
|
||
'metadata.schema_optional': 'Optional; blank uses the default namespace',
|
||
'metadata.loading_connections': 'Loading connections',
|
||
'metadata.loading_databases': 'Loading databases',
|
||
'metadata.loading_objects': 'Loading objects',
|
||
'metadata.loading_fields': 'Loading fields',
|
||
'metadata.loading_cdc_adapters': 'Loading CDC adapters',
|
||
'metadata.load_failed': 'Metadata failed to load',
|
||
'metadata.retry': 'Retry',
|
||
'metadata.no_eligible_connections': 'No connection supports this read/write direction.',
|
||
'metadata.no_databases': 'This connection returned no databases. The draft can still be saved.',
|
||
'metadata.endpoint_required': 'Choose an endpoint first',
|
||
'metadata.object_required': 'Choose an object first',
|
||
'metadata.objects_count': '{count} objects',
|
||
'metadata.fields_count': '{count} fields',
|
||
'mapping.title': 'Choose data to sync',
|
||
'mapping.help': 'Choose one, many, or all filtered tables. The workbench matches same-name targets, detects keys, and generates mappings so you only handle exceptions.',
|
||
'mapping.query_help': 'A SQL query writes to one target object. Choose an existing target table and configure the write key.',
|
||
'mapping.add': 'Add mapping',
|
||
'mapping.select_objects': 'Choose source objects',
|
||
'mapping.add_target': 'Add target object',
|
||
'mapping.picker_title': 'Choose source objects in bulk',
|
||
'mapping.search_objects': 'Search tables, views, or collections',
|
||
'mapping.include_views': 'Include views',
|
||
'mapping.selected_count': '{selected} selected / {total} total',
|
||
'mapping.select_filtered': 'Select all filtered results ({count})',
|
||
'mapping.selection_fixed_scope': 'This list is fixed when saved; future tables are not added automatically',
|
||
'mapping.object_kind.table': 'Table',
|
||
'mapping.object_kind.view': 'View',
|
||
'mapping.object_kind.collection': 'Collection',
|
||
'mapping.already_added': 'Already added',
|
||
'mapping.rows_count': '{count} rows',
|
||
'mapping.no_objects': 'No matching objects',
|
||
'mapping.add_selected': 'Add {count} objects',
|
||
'mapping.detecting_keys': 'Detecting keys…',
|
||
'mapping.open_object_list': 'Open object list',
|
||
'mapping.will_create_named': 'Target does not exist; “{name}” will be created',
|
||
'mapping.no_matching_objects': 'No matching existing objects',
|
||
'mapping.remove': 'Remove',
|
||
'mapping.enabled': 'Enabled',
|
||
'mapping.source': 'Source object',
|
||
'mapping.target': 'Target object',
|
||
'mapping.target_mode': 'If the target is missing',
|
||
'mapping.key_columns': 'Identify the same row by',
|
||
'mapping.fields': 'Fields',
|
||
'mapping.status': 'Status',
|
||
'mapping.create_or_reuse': 'Create automatically; validate and reuse if present',
|
||
'mapping.existing_only': 'Write only to an existing target',
|
||
'mapping.edit_exceptions': 'Edit exception',
|
||
'mapping.collapse_exceptions': 'Collapse',
|
||
'mapping.fields_count': '{count} fields',
|
||
'mapping.fields_pending': 'Automatic same-name fields',
|
||
'mapping.fields_automatic': 'Automatic same-name fields',
|
||
'mapping.fields_automatic_help': 'No per-column setup is needed unless a field is renamed or transformed.',
|
||
'mapping.fields_required': 'Confirm synchronized fields',
|
||
'mapping.fields_cdc_help': 'Continuous sync needs explicit target fields so removed source fields do not leave stale target values.',
|
||
'mapping.ready': 'Configured',
|
||
'mapping.needs_attention': 'Needs attention',
|
||
'mapping.key_placeholder': 'id, tenant_id',
|
||
'mapping.key_detected': 'Detected from source metadata; edit if needed',
|
||
'mapping.key_when_needed': 'Difference sync and CDC need a stable key; one-time migration may leave this blank',
|
||
'mapping.source_placeholder': 'Search or choose a source object',
|
||
'mapping.target_placeholder': 'Search an existing target or enter a new name',
|
||
'mapping.query_result_source': 'Query result (single mapping)',
|
||
'mapping.target_state.exists': 'Target exists',
|
||
'mapping.target_state.create': 'Will create',
|
||
'mapping.target_state.missing': 'Target not matched',
|
||
'mapping.empty_title': 'No sync objects selected',
|
||
'mapping.empty_desc': 'Choose source objects first. The same picker handles one table, many tables, or all current search results.',
|
||
'field_mapping.title': 'Field mappings',
|
||
'field_mapping.close': 'Collapse',
|
||
'field_mapping.auto_match': 'Match same names',
|
||
'field_mapping.add': 'Add field',
|
||
'field_mapping.empty_title': 'No field mappings yet',
|
||
'field_mapping.empty_desc': 'Load both sides and match by name, or add a row and enter a transform.',
|
||
'field_mapping.source': 'Source field',
|
||
'field_mapping.target': 'Target field',
|
||
'field_mapping.transform': 'Transform',
|
||
'field_mapping.transform_placeholder': 'Blank writes the value directly',
|
||
'field_mapping.transform_identity': 'Identity',
|
||
'field_mapping.transform_argument': 'Argument JSON (optional)',
|
||
'field_mapping.type': 'Type',
|
||
'field_mapping.select_field': 'Choose a field',
|
||
'field_mapping.remove': 'Remove',
|
||
'delivery.title': 'Configure target writes',
|
||
'delivery.help': 'Choose how the target is written and how failed rows are handled. Defaults fit most tasks; risky and specialist options appear only when applicable.',
|
||
'delivery.write_mode': 'Write mode',
|
||
'delivery.write.none': 'Read only',
|
||
'delivery.write.append': 'Append',
|
||
'delivery.write.append_desc': 'Each run inserts new rows. Re-running may create duplicates, so automatic retries are disabled.',
|
||
'delivery.write.upsert': 'Insert or update',
|
||
'delivery.write.upsert_unavailable': 'Insert or update (not supported by this target)',
|
||
'delivery.write.upsert_desc': 'Use a primary or unique key to identify a row: insert when missing and update when present.',
|
||
'delivery.write.overwrite': 'Overwrite',
|
||
'delivery.write.overwrite_unavailable': 'Overwrite (not yet supported for jobs)',
|
||
'delivery.write.overwrite_desc': 'Atomic replacement is not available, so preflight blocks overwrite jobs. Use insert or update instead.',
|
||
'delivery.read_only_title': 'This is a read-only comparison',
|
||
'delivery.read_only_note': 'The task never writes to or deletes from the target, so delivery, failed-row handling, and advanced settings do not apply.',
|
||
'delivery.error_policy': 'Failed-row handling',
|
||
'delivery.error.stop': 'Stop on error',
|
||
'delivery.error.stop_desc': 'Stop as soon as any row fails to write. Use this when data completeness is the priority.',
|
||
'delivery.error.skip': 'Skip bad rows',
|
||
'delivery.error.skip_desc': 'Record the failure and continue with later rows without storing the complete failed row.',
|
||
'delivery.error.quarantine': 'Quarantine and retry later',
|
||
'delivery.error.quarantine_desc': 'Store the complete failed row in the local task database. It may contain sensitive data and can be retried from the error-row list.',
|
||
'delivery.batch_size': 'Batch size',
|
||
'delivery.commit_every': 'Commit interval (rows)',
|
||
'delivery.commit_every_note': 'The current engine commits by batch size, so this value follows batch size.',
|
||
'delivery.retry_limit': 'Retry limit',
|
||
'delivery.retry_backoff': 'Retry backoff (ms)',
|
||
'delivery.row_isolation_note': 'This configuration must stop on error. Row-level skip is available only for existing relational targets without auto-create, schema changes, delete propagation, or overwrite.',
|
||
'delivery.append_retry_note': 'Append writes may be partially committed. Automatic retries stay at zero to prevent duplicates.',
|
||
'delivery.append_only_target_note': 'This time-series target supports append/INSERT-only delivery; updates and deletes are not synchronized.',
|
||
'delivery.propagate_deletes': 'Propagate source deletes',
|
||
'delivery.delete_policy_title': 'Target deletion policy',
|
||
'delivery.delete_risk_badge': 'High risk',
|
||
'delivery.delete.snapshot_label': 'Delete target rows missing from the source',
|
||
'delivery.delete.snapshot_desc': 'A full reconcile compares each table by key and deletes target rows that no longer exist in the source.',
|
||
'delivery.delete.cdc_label': 'Apply source delete events',
|
||
'delivery.delete.cdc_desc': 'When CDC receives a delete event, it deletes the matching target row by key.',
|
||
'delivery.delete_risk_note': 'Target deletes cannot be undone. Confirm the target is not shared and review the preflight scope before running.',
|
||
'delivery.advanced': 'Advanced settings',
|
||
'delivery.advanced_help': 'Performance, retries, and schema migration',
|
||
'delivery.performance_title': 'Performance and retries',
|
||
'delivery.performance_help': 'The defaults fit most tasks. Adjust only when you understand target load and retry idempotency.',
|
||
'delivery.structure_title': 'Target schema',
|
||
'delivery.structure_help': 'Available only for automatic same-name mappings in one-time migrations. Explicit fields, keys, or renamed mappings hide these options.',
|
||
'delivery.auto_add_columns': 'Add missing target columns',
|
||
'delivery.auto_add_columns_desc': 'Only adds columns missing from the target; existing columns are not changed or removed. DDL may briefly lock the target table.',
|
||
'delivery.create_indexes': 'Copy compatible secondary indexes',
|
||
'delivery.create_indexes_desc': 'Copies compatible non-primary indexes only when the target is auto-created. Indexes are created after data is loaded and increase total run time.',
|
||
'trigger.title': 'Configure run settings',
|
||
'trigger.help': 'Choose manual, scheduled, or continuous execution, then configure snapshot, watermark, or CDC incrementality when needed.',
|
||
'trigger.mode': 'Trigger',
|
||
'trigger.manual': 'Manual',
|
||
'trigger.once': 'At a specified time',
|
||
'trigger.interval': 'Fixed interval',
|
||
'trigger.interval_seconds': 'Interval (seconds)',
|
||
'trigger.cron': 'Cron schedule',
|
||
'trigger.continuous': 'Continuous',
|
||
'trigger.run_at': 'Run at',
|
||
'trigger.timezone': 'Timezone',
|
||
'trigger.cron_expression': 'Cron expression',
|
||
'trigger.overlap': 'When runs overlap',
|
||
'trigger.overlap.skip': 'Skip this run',
|
||
'trigger.overlap.queue': 'Queue this run',
|
||
'incremental.mode': 'Incremental policy',
|
||
'incremental.snapshot': 'Full snapshot',
|
||
'incremental.watermark': 'Watermark',
|
||
'incremental.cdc': 'CDC log',
|
||
'incremental.watermark_column': 'Watermark column',
|
||
'incremental.tie_breaker': 'Tie-breaker column',
|
||
'incremental.overlap_window': 'Overlap window (ms)',
|
||
'incremental.watermark_delivery_note': 'Watermark jobs do not yet support append semantics. InitialValue, overlap windows, and independent commit intervals are not wired to the engine and therefore have no editable controls.',
|
||
'incremental.watermark_mixed_note': 'This task has per-object watermark differences. The first is shown; editing either field unifies all object mappings.',
|
||
'incremental.initial_snapshot': 'Run a full snapshot before the first stream',
|
||
'incremental.cdc_adapter': 'CDC adapter',
|
||
'incremental.select_cdc_adapter': 'Choose an adapter',
|
||
'incremental.start_position': 'Start position',
|
||
'incremental.position.latest': 'Latest position',
|
||
'incremental.position.earliest': 'Earliest position',
|
||
'incremental.position.checkpoint': 'Last checkpoint',
|
||
'incremental.cdc_safety_title': 'CDC start-position boundary',
|
||
'incremental.cdc_safety_note': 'The current guarantee is at-least-once consumption after a newly created latest barrier, or continuation from this task\'s existing checkpoint.',
|
||
'incremental.cdc_snapshot_gap_warning': 'A separate snapshot followed by latest leaves a change window and may miss changes in that window. Seamless handoff is not guaranteed.',
|
||
'incremental.cdc_checkpoint_unavailable': 'This task has no usable checkpoint, so checkpoint start is unavailable.',
|
||
'preflight.title': 'Preflight',
|
||
'preflight.stale': 'Configuration changed; run preflight again',
|
||
'preflight.not_run': 'Preflight has not run',
|
||
'preflight.running': 'Checking endpoints, mappings, and execution policy',
|
||
'preflight.blocked': '{count} blockers',
|
||
'preflight.warning': '{count} warnings',
|
||
'preflight.passed': 'Preflight passed',
|
||
'preflight.empty': 'Complete the configuration and run preflight. Issues link back to their stage.',
|
||
'preflight.open_issue': 'Locate',
|
||
'preflight.current_revision': 'Based on task revision {revision}',
|
||
'preflight.approval_required': 'Production write approval required',
|
||
'preflight.approval_not_required': 'No production write approval required',
|
||
'preflight.approval_fail_closed': 'Save-to-production and run stay disabled until countdown confirmation grants a one-time token.',
|
||
'preflight.approval_granted': 'One-time production authorization granted',
|
||
'preflight.approval_begin_countdown': 'Begin server 10-second confirmation',
|
||
'preflight.approval_beginning': 'Starting server confirmation',
|
||
'preflight.approval_countdown': 'Wait {seconds} seconds',
|
||
'preflight.approval_confirm': 'Confirm production write and grant token',
|
||
'preflight.approving': 'Requesting authorization',
|
||
'preflight.approval_expires': 'The token is memory-only, expires at {expiresAt}, and is invalidated after save or run.',
|
||
'preflight.severity.blocker': 'Blocker',
|
||
'preflight.severity.warning': 'Warning',
|
||
'preflight.severity.info': 'Info',
|
||
'preflight.index_remediation.title': 'Unmigrated indexes ({count})',
|
||
'preflight.index_remediation.columns': 'Columns: {columns}',
|
||
'preflight.index_remediation.copy': 'Copy remediation DDL',
|
||
'preflight.index_remediation.copy_failed': 'Copy failed. Copy the DDL manually from the list below.',
|
||
'runs.title': 'Run history',
|
||
'runs.subtitle': 'Run instances come from the gateway; persisted history and checkpoints plug in later.',
|
||
'runs.empty_title': 'No runs yet',
|
||
'runs.empty_desc': 'After a task runs, throughput, error rows, and checkpoints appear here.',
|
||
'runs.id': 'Run ID',
|
||
'runs.task': 'Task',
|
||
'runs.status': 'Status',
|
||
'runs.started_at': 'Started',
|
||
'runs.rows_written': 'Rows written',
|
||
'runs.rows_failed': 'Error rows',
|
||
'runs.checkpoint': 'Checkpoint',
|
||
'runs.view_errors': 'View error rows',
|
||
'runs.actions': 'Actions',
|
||
'runs.cancel': 'Cancel',
|
||
'runs.resume': 'Resume',
|
||
'runs.retry': 'Retry run',
|
||
'errors.title': 'Error rows',
|
||
'errors.empty_title': 'No quarantined rows',
|
||
'errors.empty_desc': 'Choose a failed run to inspect, retry, or export bad rows.',
|
||
'errors.source': 'Source object',
|
||
'errors.reason': 'Reason',
|
||
'errors.payload': 'Payload preview',
|
||
'errors.retryable': 'Retryable',
|
||
'errors.retry': 'Retry row',
|
||
'errors.retry_unavailable': 'The backend does not expose an error-row retry API, so this action stays disabled.',
|
||
'errors.discard': 'Discard',
|
||
'errors.discarded': 'Discarded',
|
||
'checkpoint.title': 'Checkpoint',
|
||
'checkpoint.empty': 'The selected run has no durable checkpoint.',
|
||
'checkpoint.kind': 'Kind',
|
||
'checkpoint.phase': 'Phase',
|
||
'checkpoint.updated_at': 'Updated',
|
||
'checkpoint.cursor': 'Cursor',
|
||
'checkpoint.reset': 'Reset checkpoint',
|
||
'checkpoint.reset_warning': 'Reset removes the resume position. CDC can then start only from a new latest barrier.',
|
||
'common.yes': 'Yes',
|
||
'common.no': 'No',
|
||
'common.refresh': 'Refresh',
|
||
'common.dismiss': 'Dismiss',
|
||
'common.cancel': 'Cancel',
|
||
'schedules.title': 'Schedules',
|
||
'schedules.subtitle': 'Review timezones, Cron expressions, and next runs in one place.',
|
||
'schedules.empty_title': 'No enabled schedules',
|
||
'schedules.empty_desc': 'Choose a one-time or Cron trigger in the task editor.',
|
||
'cdc.title': 'CDC source status',
|
||
'cdc.subtitle': 'Status comes from adapter probes and task checkpoints. Lag is never inferred when the backend does not report it.',
|
||
'cdc.empty_title': 'No CDC sources to monitor',
|
||
'cdc.empty_desc': 'Create a CDC task and probe its permissions to see source health here.',
|
||
'cdc.lag_unknown': 'Lag not reported',
|
||
'cdc.status.ready': 'Adapter ready',
|
||
'cdc.status.probing': 'Probing',
|
||
'cdc.status.lagging': 'Lagging',
|
||
'cdc.status.offline': 'Source offline',
|
||
'cdc.status.unsupported': 'Unsupported',
|
||
'cdc.status.unknown': 'Unknown',
|
||
'status.queued': 'Queued',
|
||
'status.running': 'Running',
|
||
'status.cancelling': 'Cancelling',
|
||
'status.preflighting': 'Preflighting',
|
||
'status.snapshotting': 'Snapshotting',
|
||
'status.catching_up': 'Catching up',
|
||
'status.streaming': 'Streaming',
|
||
'status.paused': 'Paused',
|
||
'status.succeeded': 'Succeeded',
|
||
'status.partial': 'Partial',
|
||
'status.failed': 'Failed',
|
||
'status.canceled': 'Canceled',
|
||
'status.cancelled': 'Cancelled',
|
||
'status.interrupted': 'Interrupted',
|
||
'validation.definition_invalid': 'The task definition is invalid. Check required fields, object mappings, and execution policies.',
|
||
'validation.definition_hash_failed': 'The task definition fingerprint could not be generated. Check the task configuration.',
|
||
'validation.task_name_required': 'Enter a task name.',
|
||
'validation.source_connection_required': 'Choose a source connection.',
|
||
'validation.target_connection_required': 'Choose a target connection.',
|
||
'validation.source_connection_failed': 'The source saved connection could not be resolved. Verify that it still exists and is complete.',
|
||
'validation.target_connection_failed': 'The target saved connection could not be resolved. Verify that it still exists and is complete.',
|
||
'validation.source_connect_failed': 'The source database connection could not be initialized.',
|
||
'validation.source_ping_failed': 'The source database connectivity check failed.',
|
||
'validation.target_connect_failed': 'The target database connection could not be initialized.',
|
||
'validation.target_ping_failed': 'The target database connectivity check failed.',
|
||
'validation.same_endpoint': 'Source and target point to the same location. Confirm that source data cannot be overwritten.',
|
||
'validation.same_object': 'Source and target resolve to the same physical object, so this sync cannot run.',
|
||
'validation.route_unsupported': 'The selected source-target route cannot execute this sync task.',
|
||
'validation.source_query_required': 'Enter the source SQL query.',
|
||
'validation.source_query_not_read_only': 'The source SQL must be one read-only query.',
|
||
'validation.mapping_required': 'Enable at least one object mapping.',
|
||
'validation.source_object_required': 'Enter a source object name.',
|
||
'validation.target_object_required': 'Enter a target object name.',
|
||
'validation.duplicate_source_object': 'Each source object can be added only once.',
|
||
'validation.duplicate_target_object': 'Multiple mappings target the same object.',
|
||
'validation.mapping_compile_failed': 'The object or field mapping could not be compiled. Check mappings and transforms.',
|
||
'validation.source_columns_failed': 'Source fields could not be read. Check the object name and metadata permissions.',
|
||
'validation.target_columns_failed': 'Target fields could not be read. Check the object name and metadata permissions.',
|
||
'validation.source_column_missing': 'A configured source field does not exist.',
|
||
'validation.target_column_missing': 'A configured target field does not exist.',
|
||
'validation.key_column_missing': 'A configured source key field does not exist.',
|
||
'validation.watermark_column_missing': 'The configured watermark field does not exist on the source object.',
|
||
'validation.target_table_check_failed': 'The target table existence check failed.',
|
||
'validation.target_table_missing': 'The target table does not exist and this task cannot create it automatically.',
|
||
'validation.target_table_will_be_created': 'The target table does not exist and will be created by the migration planner.',
|
||
'validation.key_columns_required': 'Difference sync and CDC require a primary or unique key.',
|
||
'validation.batch_size_invalid': 'Batch size must be an integer from 1 to 10000.',
|
||
'validation.commit_every_invalid': 'Commit interval must be at least the batch size.',
|
||
'validation.target_protection_blocked': 'The target connection protection policy blocks this write.',
|
||
'validation.row_error_isolation_unsupported': 'This task does not meet the safety requirements for row skip or quarantine.',
|
||
'validation.append_retry_unsupported': 'Append writes cannot retry automatically because that could duplicate rows.',
|
||
'validation.append_retry_unsafe': 'Append writes cannot retry automatically because committed rows could be duplicated.',
|
||
'validation.append_resume_unsafe': 'Append jobs must disable resume because committed batches cannot be replayed safely.',
|
||
'validation.full_overwrite_non_atomic': 'Persistent jobs cannot use non-atomic full overwrite because failure could leave an empty or partial table.',
|
||
'validation.write_mode_required': 'Executable sync tasks require an explicit write mode.',
|
||
'validation.watermark_append_unsupported': 'Watermark jobs do not yet support append delivery semantics.',
|
||
'validation.watermark_tie_breaker_required': 'Watermark jobs require a stable tie-breaker field or key.',
|
||
'validation.watermark_initial_value_unsupported': 'Watermark initial values are not implemented. Remove this setting.',
|
||
'validation.watermark_runtime_unsupported': 'The selected source, target, or execution policy cannot run watermark sync.',
|
||
'validation.watermark_overwrite_unsupported': 'Watermark jobs cannot use full overwrite.',
|
||
'validation.watermark_delete_unsupported': 'Watermark jobs cannot infer source deletes. Use CDC or snapshot reconcile.',
|
||
'validation.query_sink_single_mapping_required': 'A SQL result sink must have exactly one target mapping.',
|
||
'validation.query_key_required': 'SQL result upsert requires exactly one stable key.',
|
||
'validation.query_target_pk_mismatch': 'The SQL result stable key must map to the target table\'s single primary key.',
|
||
'validation.query_schema_runtime_validation': 'SQL result field names will be checked against the mapping when the read-only query runs.',
|
||
'validation.watermark_column_required': 'Watermark mode requires a watermark column.',
|
||
'validation.cron_expression_required': 'Enter a Cron expression.',
|
||
'validation.timezone_required': 'Enter a scheduling timezone.',
|
||
'validation.interval_invalid': 'Fixed intervals must be at least 60 seconds.',
|
||
'validation.cdc_incremental_required': 'CDC tasks must use the CDC incremental policy.',
|
||
'validation.cdc_trigger_required': 'CDC tasks must run continuously.',
|
||
'validation.cdc_adapter_required': 'Choose a CDC adapter.',
|
||
'validation.cdc_initial_snapshot_unsupported': 'The current CDC reader cannot safely hand off from an initial snapshot.',
|
||
'validation.cdc_initial_snapshot_handoff_unsupported': 'The current CDC reader cannot guarantee a gap-free initial snapshot handoff. Disable initial snapshot.',
|
||
'validation.cdc_earliest_unsupported': 'The current CDC adapter cannot start from the earliest position.',
|
||
'validation.cdc_probe_failed': 'CDC capability and permission probing failed.',
|
||
'validation.cdc_adapter_not_ready': 'The selected CDC adapter is not ready.',
|
||
'validation.cdc_existing_target_required': 'CDC jobs currently require existing target tables.',
|
||
'validation.cdc_upsert_required': 'CDC jobs must use upsert delivery so events can be replayed safely.',
|
||
'validation.cdc_target_non_atomic': 'CDC row isolation and checkpoint ordering require an atomic relational target.',
|
||
'validation.cdc_authoritative_columns_required': 'CDC jobs require explicit source-to-target field mappings.',
|
||
'validation.cdc_checkpoint_unavailable': 'The CDC checkpoint could not be read.',
|
||
'validation.cdc_checkpoint_required': 'Checkpoint start requires a compatible durable checkpoint for this task.',
|
||
'validation.cdc_checkpoint_incompatible': 'The stored CDC checkpoint is incompatible with this task. Pause the task and reset it explicitly.',
|
||
'validation.compare_route_unsupported': 'The selected source-target route cannot execute compare tasks.',
|
||
'validation.index_inspection_failed': 'Source index metadata could not be read, so complete index migration cannot be verified.',
|
||
'validation.unmigrated_index': 'An index could not be migrated automatically. Review the remediation DDL before execution.',
|
||
'validation.capability_unverified': 'This task uses the static gateway. The backend must still verify the source-target capability before execution.',
|
||
'validation.unknown': 'Preflight found an unrecognized configuration issue.',
|
||
};
|
||
|
||
export type DataSyncWorkbenchLocale = 'zh-CN' | 'en-US';
|
||
|
||
export const resolveDataSyncWorkbenchLocale = (
|
||
language?: string,
|
||
): DataSyncWorkbenchLocale =>
|
||
String(language || '').toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US';
|
||
|
||
export type DataSyncWorkbenchTranslate = (
|
||
key: DataSyncWorkbenchTextKey,
|
||
params?: Record<string, string | number>,
|
||
) => string;
|
||
|
||
export const createDataSyncWorkbenchTranslate = (
|
||
language?: string,
|
||
): DataSyncWorkbenchTranslate => {
|
||
const catalog = resolveDataSyncWorkbenchLocale(language) === 'zh-CN' ? zhCN : enUS;
|
||
return (key, params) => {
|
||
let value = catalog[key] || key;
|
||
Object.entries(params || {}).forEach(([name, replacement]) => {
|
||
value = value.split(`{${name}}`).join(String(replacement));
|
||
});
|
||
return value;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Stable validation codes are the localization contract. Backend messages are
|
||
* retained only as a diagnostic fallback for unknown driver/runtime errors.
|
||
*/
|
||
export const dataSyncValidationIssueText = (
|
||
issue: { code: string; message?: string },
|
||
t: DataSyncWorkbenchTranslate,
|
||
): string => {
|
||
const key = `validation.${issue.code}` as DataSyncWorkbenchTextKey;
|
||
const localized = t(key);
|
||
if (localized !== key) return localized;
|
||
return String(issue.message || '').trim() || t('validation.unknown');
|
||
};
|